在Emacs的 Perl调试器中,如何更方便地查看调用栈回溯中提到的代码?
在Perl调试器中使用 T 命令会产生一个类似于以下的栈跟踪:
$ = main::infested called from file 'Ambulation.pm' line 10
@ = Ambulation::legs(1, 2, 3, 4) called from file 'camel_flea' line 7
$ = main::pests('bactrian', 4) called from file 'camel_flea' line 4
(示例取自https://perldoc.perl.org/perldebug)。当通过Emacs运行Perl调试器(通过 M-x perldb)时,这样的栈跟踪会以普通文本的形式出现在调试缓冲区中,无法通过任何“神奇的跳转”快速定位到提到的文件中的相应行以查看上下文。我得手动打开相关文件,然后导航至提到的那一行。这能否变得更方便?
解决方案
在GNU Emacs 30.2上,到目前为止我所找到的最佳方法是修改栈跟踪格式,使其与 compilation-mode 兼容,然后使用该模式的导航功能来实现跳转。有没有更好的办法?
要修改栈跟踪格式,请将以下内容添加到perl调试器初始化文件中的 sub afterinit(Windows上为 perldb.ini,其他操作系统为 .perldb,参见 perldb):
my $old_print_trace = \&DB::print_trace;
*{DB::print_trace} = sub {
my $trace = '';
open my $fh, '>', \$trace;
$old_print_trace->($fh, 1); # write old trace to $trace
close $fh;
# transform trace to compilation-mode format
my @lines = split /\n/, $trace;
# this override introduces one extra stack frame; omit it from the
# trace
shift @lines;
my $ix = 0;
foreach (@lines) {
++$ix;
s/^(.*?) called from file '(.*?)' line (\d+)/$2:$3:[$ix]$1/;
}
print $DB::OUT join("\n", @lines), "\n";
}
这段代码会覆盖 DB::print_trace(由调试器的 T 命令调用)以在输出前重新格式化追踪信息。修改完成后,别忘了再次将perldb文件设为只读,否则Perl将不接受它。
然后启动调试器,最终执行 T 命令时,会产生如下所示的栈跟踪:
Ambulation.pm:10:[1]$ = main::infested
camel_flea:7:[2]@ = Ambulation::legs(1, 2, 3, 4)
camel_flea:4[3]$ = main::pests('bactrian', 4) called from file 'camel_flea' line 4
紧跟在文件名和行号之后的方括号数字(如 [1])表示该栈帧的编号,供调试器的 y 命令使用。在我的系统上,执行两次 M-x compilation-minor-mode(可以缩写为 M-x co-mi),然后 C-x ` to select the current stack trace and open the corresponding file/line in a separate buffer just like when navigating the errors of a compilation. Further C-x ` 依次选择更旧的栈帧。
第一步 M-x co-mi 会把回溯行变成可点击的链接,但会禁用进入更多调试命令。第二步 M-x co-mi 会重新启用输入调试命令,但会再次移除可见的链接。随后执行的 C-x ` 会再次把回溯行变成可点击的链接,同时仍然可以输入更多调试命令。
在我的系统上,执行 C-x ` without having earlier done M-x co-mi 两次似乎不起作用。