Mostrar número da linha com erro

15

Digamos que o emacs lança algum erro que eu não entendo. Ou talvez o erro diga "O valor do símbolo como variável é nulo: modos", mas há muitas ocorrências do símbolo modesno meu código, portanto, preciso de algum contexto. O Emacs pode ser configurado para mencionar o número da linha do código lisp para que eu possa saber qual código está causando o erro?

Eu tentei fazer (setq stack-trace-on-error '(buffer-read-only))e executei o código perpetrante em um esforço para obter um rastreamento de pilha. Nenhum rastreamento de pilha também.

Também tentei chamar edebug-defunminha função e percorrê-la. Não é até sair da função que o erro é gerado.

(Na verdade, não estou tão interessado na causa do erro específico que estou enfrentando atualmente quanto no desenvolvimento de habilidades gerais de depuração para elisp. Por favor, informe sobre como posso ver um número de linha, um sexp ou um rastreamento de pilha de um elisp. erro.)

Jackson
fonte
Você já tentou não nil debug-on-error? Isso não ajuda?
Desenhou
Não. Isso não parece fazer nada. (Depois de configurá-lo para te, em seguida, proceder à eval uma função de arremesso de erro.)
Jackson
Provavelmente o que acontece é que algum outro código captura o erro e apenas imprime a mensagem de erro. Verifique também debug-ignored-errorsse não há erros. Se você definir debug-on-signalnão nil, e foi o caso do outro código lidar com o erro, você poderá obter o erro antes do outro código.
Wvxvw
Atualmente, estou em uma situação semelhante e estava lendo esta pergunta. Eu estou querendo saber sobre rastreamento de pilha em erro. Esta variável não está documentada no Emacs 25.1.
Matthias

Respostas:

15

Emacs fornece uma boa quantidade de depuração instalações, incluindo M-x toggle-debug-on-error, M-x toggle-debug-on-quit, depuração no sinal (que pode ser usado enviando USR2a Emacs de fora), debug-on-entry(de uma função), debug-on-message(quando vendo um jogo específico regexp de uma mensagem) e, finalmente, debugse como alternativa para instrumentar uma função com C-u C-M-x.

Ambos debuge edebugoferecem funcionalidade suficiente para inspecionar o estado de Emacs ao avaliar o código que você está em interessado, hit ee introduzir uma expressão.

No entanto, enquanto edebugpula para o lugar na função instrumentada e, portanto, fornece uma pista para onde procurar (o que é meio bobo, já que você já sabe exatamente o que instrumentou), debugnão faz isso. Fiz um hack menor depois de descobrir que, sempre que debugavalia um buffer, ele emite o valor do ponto associado ao erro; em outras palavras, usar essas informações no buffer pode fornecer um número de linha no backtrace!

(with-eval-after-load 'debug
  (defun debugger-setup-buffer (debugger-args)
    "Initialize the `*Backtrace*' buffer for entry to the debugger.
That buffer should be current already."
    (setq buffer-read-only nil)
    (erase-buffer)
    (set-buffer-multibyte t)        ;Why was it nil ?  -stef
    (setq buffer-undo-list t)
    (let ((standard-output (current-buffer))
          (print-escape-newlines t)
          (print-level 8)
          (print-length 50))
      (backtrace))
    (goto-char (point-min))
    (delete-region (point)
                   (progn
                     (search-forward "\n  debug(")
                     (forward-line (if (eq (car debugger-args) 'debug)
                                       2    ; Remove implement-debug-on-entry frame.
                                     1))
                     (point)))
    (insert "Debugger entered")
    ;; lambda is for debug-on-call when a function call is next.
    ;; debug is for debug-on-entry function called.
    (pcase (car debugger-args)
      ((or `lambda `debug)
       (insert "--entering a function:\n"))
      ;; Exiting a function.
      (`exit
       (insert "--returning value: ")
       (setq debugger-value (nth 1 debugger-args))
       (prin1 debugger-value (current-buffer))
       (insert ?\n)
       (delete-char 1)
       (insert ? )
       (beginning-of-line))
      ;; Debugger entered for an error.
      (`error
       (insert "--Lisp error: ")
       (prin1 (nth 1 debugger-args) (current-buffer))
       (insert ?\n))
      ;; debug-on-call, when the next thing is an eval.
      (`t
       (insert "--beginning evaluation of function call form:\n"))
      ;; User calls debug directly.
      (_
       (insert ": ")
       (prin1 (if (eq (car debugger-args) 'nil)
                  (cdr debugger-args) debugger-args)
              (current-buffer))
       (insert ?\n)))
    ;; After any frame that uses eval-buffer,
    ;; insert a line that states the buffer position it's reading at.
    (save-excursion
      (let ((tem eval-buffer-list))
        (while (and tem
                    (re-search-forward "^  eval-\\(buffer\\|region\\)(" nil t))
          (beginning-of-line)
          (insert (format "Error at line %d in %s: "
                          (with-current-buffer (car tem)
                            (line-number-at-pos (point)))
                          (with-current-buffer (car tem)
                            (buffer-name))))
          (pop tem))))
    (debugger-make-xrefs)))

Com isso, a pergunta original no título deve ser respondida. Quanto ao seu problema em obter um retorno, em primeiro lugar, estou sem idéias úteis.

wasamasa
fonte
Obrigado pela ajuda, mas ainda não entendo como obter o número da linha. M-x debug...? Então o que eu pressiono?
7285 Jackson
Com esse código, você verá um número de linha nos backtraces feitos por debug, você pode verificar visitando um arquivo elisp com defeito, fazendo M-x toggle-debug-on-errore M-x eval-buffer, em seguida, um backtrace com um número de linha na posição problemática deve aparecer.
Wasamasa
Isso funcionará se você não usar eval-buffer? Por exemplo, se você apenas pressiona um atalho de teclado que executa um comando particular que falha e abre o depurador no *Backtrace*tampão ..
Håkon Hægland
Não, não vai. Você obtém o valor da função do símbolo (que pode ser uma lista ou algo compilado em bytes) e é praticamente isso.
wasamasa
4

Talvez porque seja 2018 agora, mas no meu caso, eu só precisei ativar a depuração, como wasamasa sugeriu: Mx toggle-debug-on-error

Depois disso, o Mx eval-buffer no meu arquivo Elisp defeituoso deu contexto, fornecendo a posição do erro, assim: Debugger entered--Lisp error: (invalid-read-syntax ")") eval-buffer() ; Reading at buffer position 523 [....]

Mx goto-char pula para a posição de erro: M-x goto-char 523

mistige
fonte
Boa descoberta! Parece que isso foi adicionado em 2017, quando eles reformularam essa função para trabalhar em uma lista de itens de backtrace.
Wasamasa 11/09/19
1

Estendi a resposta do wasamasa para incluir informações adicionais:

(save-excursion
  (let ((tem eval-buffer-list))
    (while (and tem
                (re-search-forward "^  eval-\\(buffer\\|region\\)(" nil t))
      (beginning-of-line)
      (insert (apply 'format "Error at line %d, column %d (point %d) in %s\n"
                     (with-current-buffer (car tem)
                       (list (line-number-at-pos (point))
                             (current-column)
                             (point)
                             (buffer-name)))))
      (pop tem))))
Jackson
fonte