Pokaż numer linii w przypadku błędu

15

Powiedzmy, że emacs generuje błąd, którego nie rozumiem. A może błąd mówi „Wartość symbolu jako zmienna jest nieważna: tryby”, ale modesw moim kodzie jest wiele wystąpień tego symbolu , więc potrzebuję trochę kontekstu. Czy Emacsa można skonfigurować tak, aby podawał numer wiersza kodu lisp, aby wiedzieć, który kod powoduje błąd?

Próbowałem to zrobić (setq stack-trace-on-error '(buffer-read-only))i uruchomiłem odpowiedni kod, aby uzyskać ślad stosu. Brak śladu stosu.

Próbowałem także wywołać edebug-defunmoją funkcję i przejść przez nią. Błąd pojawia się dopiero po wyjściu z funkcji.

(Naprawdę nie jestem tak zainteresowany przyczyną konkretnego błędu, jaki napotykam obecnie, jak rozwijaniem ogólnych umiejętności debugowania dla elisp. Proszę doradzić, jak mogę uzyskać numer linii, seksu lub ślad stosu z błąd.)

Jackson
źródło
Czy próbowałeś już nie nil debug-on-error? Czy to nie pomaga?
Drew
Nie. To wydaje się nic nie robić. (Po ustawieniu go, ta następnie przejściu do ewaluacji funkcji zgłaszania błędów)
Jackson
Prawdopodobnie dzieje się tak, że jakiś inny kod łapie błąd i po prostu drukuje komunikat o błędzie. Sprawdź również, debug-ignored-errorsczy nie zawiera żadnych błędów. Jeśli wybierzesz debug-on-signalopcję nilinną niż , i tak było w przypadku, gdy inny kod obsługiwał błąd, będziesz w stanie uzyskać błąd, zanim zrobi to drugi kod.
wvxvw
Jestem obecnie w podobnej sytuacji i czytałem to pytanie. Zastanawiam się nad stosem śledzenia śledzenia po błędzie. Ta zmienna nie jest udokumentowana w Emacsie 25.1.
Matthias

Odpowiedzi:

15

Emacs zapewnia dobrą ilość debugowanie obiekty w tym M-x toggle-debug-on-error, M-x toggle-debug-on-quit, debugowania sygnału (który może być używany przez wysłanie USR2do Emacs od zewnątrz), debug-on-entry(z funkcji), debug-on-message(po obejrzeniu meczu specyficzny regexp komunikatu) i wreszcie debugsię jako alternatywa do instrumentowania funkcji za pomocą C-u C-M-x.

Zarówno debugi edebugoferuje wystarczającą funkcjonalność wglądu do stanu z Emacs przy ocenie kod, który cię interesuje, hit ei wprowadź wyraz.

Jednak podczas gdy edebugprzeskakuje do miejsca w funkcji instrumentowanej i dlatego daje ci wskazówkę, gdzie szukać (co jest trochę głupie, ponieważ już wiesz, co dokładnie instrumentowałeś), debugwcale tego nie robi. Ściągnąłem mniejszy hack po odkryciu, że ilekroć debugocenia bufor, emituje wartość punktu związanego z błędem; innymi słowy, użycie tej informacji w buforze może dać ci numer linii w śladzie wstecznym!

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

Dzięki temu należy odpowiedzieć na pierwotne pytanie w tytule. Jeśli chodzi o twój problem z uzyskaniem śladu wstecznego, brakuje mi przydatnych pomysłów.

wasamasa
źródło
Dziękuję za pomoc, ale nadal nie rozumiem, jak uzyskać numer linii. M-x debug... Więc co mam nacisnąć?
Jackson,
Z tego kodu zobaczysz numer linii w śladów czynności dokonywanych przez debug, można sprawdzić odwiedzając uszkodzony plik Elisp, robi M-x toggle-debug-on-errori M-x eval-buffer, a następnie backtrace z numerem linii w problematycznej pozycji powinno wyskoczyć.
wasamasa,
Czy to zadziała, jeśli nie będziesz używać eval-buffer? Na przykład, jeśli po prostu naciśniesz skrót klawiaturowy, który uruchamia prywatne polecenie, które kończy się niepowodzeniem i otwiera debugger w *Backtrace*buforze ..
Håkon Hægland
Nie zrobi tego. Otrzymujesz wartość funkcji symbolu (która może być albo listą, albo kompilacją bajtów) i tyle.
wasamasa
4

Może dlatego, że jest teraz 2018, ale w moim przypadku musiałem włączyć debugowanie tylko tak, jak sugeruje wasamasa: Mx toggle-debug-on-error

Następnie bufor ewaluacyjny Mx na moim wadliwym pliku Elisp podał kontekst, podając pozycję błędu, jak poniżej: Debugger entered--Lisp error: (invalid-read-syntax ")") eval-buffer() ; Reading at buffer position 523 [....]

MX goto-char przeskakuje do pozycji błędu: M-x goto-char 523

mistige
źródło
Niezłe znalezisko! Wygląda na to, że zostało to dodane w 2017 r., Kiedy przerobili tę funkcję, aby działała na liście elementów śledzenia.
wasamasa,
1

Rozszerzyłem odpowiedź wasamasa o dodatkowe informacje:

(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
źródło