Показать номер строки при ошибке

15

Скажем, что Emacs выдает ошибку, которую я не понимаю. Или, возможно, ошибка говорит: «Значение символа как переменной - void: mode», но modesв моем коде встречается много символов , поэтому мне нужен некоторый контекст. Можно ли настроить Emacs для указания номера строки кода lisp, чтобы я мог знать, какой код вызывает ошибку?

Я попытался сделать (setq stack-trace-on-error '(buffer-read-only))и запустил исполняющий код, чтобы получить трассировку стека. Нет трассировки стека либо.

Я также попытался вызвать edebug-defunсвою функцию и пройти через нее. Только когда я выхожу из функции, появляется ошибка.

(Я на самом деле не так интересуюсь причиной конкретной ошибки, с которой я сталкиваюсь в настоящее время, поскольку я занимаюсь разработкой общих навыков отладки для elisp. Пожалуйста, посоветуйте, как я могу подсвечивать номер строки, или sexp, или трассировку стека из ошибка.)

Джексон
источник
Вы уже пробовали не nil debug-on-error? Разве это не помогает?
Дрю
Нет. Кажется, это ничего не делает. (После того, как я установил его, tа затем приступил к оценке функции, генерирующей ошибки.)
Джексон,
Вероятно, происходит то, что какой-то другой код перехватывает ошибку и просто печатает сообщение об ошибке. Также проверьте, что debug-ignored-errorsне перечисляет никаких ошибок. Если вы установили debug-on-signalnon- nil, и это был случай, когда другой код обрабатывал ошибку, вы сможете получить ошибку раньше, чем другой код.
wvxvw
Я в настоящее время нахожусь в подобной ситуации и читал этот вопрос. Я задаюсь вопросом о трассировке стека при ошибке. Эта переменная не документирована в Emacs 25.1.
Матиас

Ответы:

15

Emacs обеспечивает хорошее количество средств отладки , включая M-x toggle-debug-on-error, M-x toggle-debug-on-quit, отлаживать на сигнал (который может быть использован, посылая USR2в Emacs извне), debug-on-entry(из функции), debug-on-message(при виде конкретных регулярное выражение матч сообщения) и , наконец, debugв качестве альтернативы чтобы оснастить функцию с C-u C-M-x.

И то, debugи другое edebugпредлагает достаточно функций для проверки состояния Emacs при оценке кода, который вас интересует, нажмите eи введите выражение.

Однако, хотя edebugпереходит к месту в инструментальной функции и, следовательно, дает вам подсказку, где искать (что довольно глупо, поскольку вы уже знаете, что именно вы инструментировали), это debugвообще не делается. Я выполнил небольшой хак, обнаружив, что всякий раз, когда debugоценивается буфер, он выдает значение точки, связанной с ошибкой; другими словами, использование этой информации в буфере может дать вам номер строки в обратном следе!

(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)))

При этом следует ответить на оригинальный вопрос в названии. Что касается вашей проблемы с получением обратного следа, то у меня нет полезных идей.

wasamasa
источник
Спасибо за вашу помощь, но я все еще не понимаю, как получить номер строки. M-x debug...? Тогда что я нажимаю?
Джексон,
С помощью этого кода вы увидите номер строки в сделанных возвратах debug, вы можете проверить, посетив неисправный файл elisp, выполнив команду M-x toggle-debug-on-errorи M-x eval-buffer, затем должна появиться обратная трассировка с номером строки в проблемной позиции.
Васамаса
Будет ли это работать, если вы не используете eval-buffer? Например, если вы просто нажмете комбинацию клавиш, которая запускает частную команду, которая не работает и открывает отладчик в *Backtrace*буфере.
Håkon Hægland
Нет не будет Вы получаете значение функции символа (которое может быть либо списком, либо чем-то скомпилированным байтом), и это почти все.
Васамаса
4

Может быть, потому что сейчас 2018, но в моем случае мне нужно было только включить отладку, как предложил васамаса: Mx toggle-debug-on-error

После этого Mx eval-buffer в моем неисправном файле Elisp предоставил контекст, указав позицию ошибки, например: Debugger entered--Lisp error: (invalid-read-syntax ")") eval-buffer() ; Reading at buffer position 523 [....]

Mx goto-char переходит в позицию ошибки: M-x goto-char 523

mistige
источник
Хорошая находка! Похоже, что это было добавлено в 2017 году, когда они переработали эту функцию для работы со списком элементов отслеживания.
Васамаса
1

Я расширил ответ Васамасы, включив в него дополнительную информацию:

(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))))
Джексон
источник