在Emacs gud缓冲区中使文件名/行号可链接

13 投票
4 回答
883 浏览
提问于 2025-04-15 18:10

我在Python中通过gud缓冲区运行pdb来调试我的测试用例。当我的测试用例出现堆栈跟踪或失败时,它看起来像这样:

FAIL: test_foo_function (__main__.TestFoo)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test/testfoo.py", line 499, in test_foo_function
    self.assertEqual('foo', 'foo')

我希望能让像这样的行:

File "test/testfoo.py", line 499, in test_foo_function

变得可点击,这样我就能直接跳到testfoo.py的第499行。

(编辑)在python-mode的讨论组里,有人推荐了pdbtrack,我成功地在那儿让它工作了。请看下面的回答...

4 个回答

0

补充一下Justin的回答:

我在我的slime配置中有一些设置,目的是从clojure的堆栈跟踪中跳转到特定的文件和行。

不过我得承认,目前这个功能对我来说并不管用——它找不到正确的文件。不过我觉得这个问题应该可以通过改变project-root的定义,或者调整我项目在文件系统中的结构来解决(我只是没时间去研究这个)。

不过这确实提到了一个好问题,像这样的功能,通常很难以一种通用和可移植的方式来确定项目的根目录。在这个例子中,我们依赖一个src目录,但这可能不适合你的python项目。

所以接着Justin的思路,你应该能从下面的函数中得到一些提示,从测试用例的错误中解析出文件名和行号,创建一个指向行号的链接,并使用compilation-parse-errors-filename-functionpropertize来让gud缓冲区中的行变成一个链接。

如果你能让它工作,请在你自己的问题下添加一个回答。我觉得很多人会觉得这个很有用。

  (defun slime-jump-to-trace (&optional on)
    "Jump to the file/line that the current stack trace line references.
    Only works with files in your project root's src/, not in dependencies."
    (interactive)
    (save-excursion
      (beginning-of-line)
      (search-forward-regexp "[0-9]: \\([^$(]+\\).*?\\([0-9]*\\))")
      (let ((line (string-to-number (match-string 2)))
            (ns-path (split-string (match-string 1) "\\."))
            (project-root (locate-dominating-file default-directory "src/")))

        (find-file (format "%s/src/%s.clj" project-root
                           (mapconcat 'identity ns-path "/")))
        (goto-line line))))

我还应该提到,我是从网上某个地方复制了这个函数,但我记不清具体网址了。它似乎来自Phil Hagelberg(technomancy)出色的Emacs入门包。

2

我觉得你想要自定义的是 compilation-parse-errors-filename-function,这个函数的作用是接收一个文件名,然后返回一个修改过的文件名,用来显示。这个变量是局部的,也就是说你需要在每个会显示Python错误的地方设置它(可能有合适的钩子可以使用,不过我没有安装Python模式,所以无法查找)。你可以用 propertize 来返回一个可以点击的文件名,这样就能直接打开实际的文件。关于propertize的使用,elisp手册里有详细的说明。

如果 compilation-parse-errors-filename-function 没有被调用,那么你需要往 compilation-error-regexp-alist-alist 里添加一个列表(注意,这里确实是alist-alist,不是打错了),这个列表包含模式名称,后面跟着用来匹配错误的正则表达式,以及匹配到的行号、文件名等信息的数字索引。

5

感谢Gerard B的提示,我终于搞明白了。我是在pdbtrack(命令行)中操作的,而不是纯粹的pdb,但我觉得这两者应该都能用。你需要开启编译模式的小功能。然后在你的.emacs文件里加上以下代码:

;; if compilation-shell-minor-mode is on, then these regexes
;; will make errors linkable
(defun matt-add-global-compilation-errors (list)
  (dolist (x list)
    (add-to-list 'compilation-error-regexp-alist (car x))
    (setq compilation-error-regexp-alist-alist
      (cons x
            (assq-delete-all (car x)
                             compilation-error-regexp-alist-alist)))))

(matt-add-global-compilation-errors
 `(
   (matt-python ,(concat "^ *File \\(\"?\\)\\([^,\" \n    <>]+\\)\\1"
                    ", lines? \\([0-9]+\\)-?\\([0-9]+\\)?")
           2 (3 . 4) nil 2 2)
   (matt-pdb-stack ,(concat "^>?[[:space:]]*\\(\\([-_./a-zA-Z0-9 ]+\\)"
                       "(\\([0-9]+\\))\\)"
                       "[_a-zA-Z0-9]+()[[:space:]]*->")
              2 3 nil 0 1)
   (matt-python-unittest-err "^  File \"\\([-_./a-zA-Z0-9 ]+\\)\", line \\([0-9]+\\).*" 1 2)
   )
 )

(defun matt-set-local-compilation-errors (errors)
  "Set the buffer local compilation errors.

Ensures than any symbols given are defined in
compilation-error-regexp-alist-alist."
  (dolist (e errors)
     (when (symbolp e)
      (unless (assoc e compilation-error-regexp-alist-alist)
        (error (concat "Error %s is not listed in "
                       "compilation-error-regexp-alist-alist")
               e))))
  (set (make-local-variable 'compilation-error-regexp-alist)
       errors))

这样你就可以用标准的编译模式导航,快速浏览错误堆栈信息了。

撰写回答