Mostra il numero di riga in caso di errore


15

Supponiamo che emacs generi un errore che non capisco. O forse l'errore dice "Il valore del simbolo come variabile è nullo: modi", ma ci sono molte occorrenze del simbolo modesnel mio codice, quindi ho bisogno di un po 'di contesto. Emacs può essere configurato per indicare il numero di riga del codice lisp in modo che io possa sapere quale codice sta causando l'errore?

Ho provato a farlo (setq stack-trace-on-error '(buffer-read-only))ed ho eseguito il codice perpetrato nel tentativo di ottenere una traccia dello stack. Nessuna traccia dello stack neanche.

Ho anche provato a chiamare la edebug-defunmia funzione e ad approfondirla. Solo quando esco dalla funzione viene generato l'errore.

(Non sono davvero interessato alla causa del particolare errore che sto riscontrando attualmente come lo sono nello sviluppo di abilità di debug generali per elisp. Si prega di avvisare su come posso brillare un numero di riga, o un sexp o una traccia dello stack da un errore.)


Hai già provato a non- nil debug-on-error? Non aiuta?
Estratto il

No. Non sembra fare nulla. (Dopo averlo impostato su te quindi procedere a valutare una funzione di lancio degli errori.)
Jackson

Probabilmente ciò che accade è che un altro codice rileva l'errore e stampa semplicemente il messaggio di errore. Controlla anche che debug-ignored-errorsnon sia presente alcun errore. Se si imposta debug-on-signalsu non- niled è stato il caso in cui l'altro codice ha gestito l'errore, sarà possibile ottenere l'errore prima dell'altro codice.
wvxvw,

Sono attualmente in una situazione simile e stavo leggendo questa domanda. Mi chiedo dello stack-trace-on-error. Questa variabile non è documentata in Emacs 25.1.
Matthias,

Risposte:


15

Emacs fornisce una buona quantità di funzioni di debug tra cui M-x toggle-debug-on-error, M-x toggle-debug-on-quitdebug su segnale (che può essere utilizzato inviando USR2a Emacs dall'esterno), debug-on-entry(di una funzione), debug-on-message(quando si vede una corrispondenza regexp specifica di un messaggio) e, infine, debugsi è un'alternativa alla strumentazione di una funzione con C-u C-M-x.

Entrambi debuge edebugoffrono funzionalità sufficienti per ispezionare lo stato di Emacs durante la valutazione del codice che ti interessa, premere ee inserire un'espressione.

Tuttavia, mentre edebugsalta al posto nella funzione strumentata e quindi ti dà un indizio su dove guardare (che è un po 'sciocco poiché sai già cosa hai esattamente strumentato), debugnon lo fa affatto. Ho tirato fuori un hack più piccolo dopo aver scoperto che ogni volta che debugvaluta un buffer, emette il valore del punto associato all'errore; in altre parole, l'utilizzo di queste informazioni nel buffer può fornire un numero di riga nel 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)))

Con questo si dovrebbe rispondere alla domanda originale nel titolo. Per quanto riguarda il tuo problema con ottenere un backtrace in primo luogo, non ho idee utili.


Grazie per l'aiuto, ma ancora non capisco come ottenere il numero di riga. M-x debug...? Quindi cosa premo?
Jackson,

Con questo codice vedrai un numero di riga nei backtrace creati da debug, puoi controllare visitando un file elisp difettoso, facendo M-x toggle-debug-on-errore M-x eval-buffer, quindi dovrebbe apparire un backtrace con un numero di riga nella posizione problematica.
Wasamasa,

Funzionerà se non lo usi eval-buffer? Ad esempio, se si preme semplicemente una scorciatoia da tastiera che esegue un comando privato che non riesce e apre il debugger nel *Backtrace*buffer ..
Håkon Hægland

No, non lo farà. Ottieni il valore della funzione del simbolo (che può essere un elenco o qualcosa compilato in byte) e il gioco è fatto.
Wasamasa,

4

Forse perché è il 2018 ora, ma nel mio caso, ho dovuto solo attivare il debug come suggerito wasamasa: Mx toggle-debug-on-error

Dopo questo, Mx eval-buffer sul mio file Elisp difettoso ha dato il contesto fornendo la posizione dell'errore, in questo modo: Debugger entered--Lisp error: (invalid-read-syntax ")") eval-buffer() ; Reading at buffer position 523 [....]

Mx goto-char passa alla posizione di errore: M-x goto-char 523


Bella scoperta! Sembra che questo sia stato aggiunto nel 2017, quando hanno rielaborato quella funzione per lavorare su un elenco di elementi di backtrace.
Wasamasa,

1

Ho esteso la risposta di wasamasa per includere ulteriori informazioni:

(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))))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.