Emacs/GDB:如何在gdb-many-windows模式下始终在特定窗口中显示源代码

8

我通常在Emacs 24中使用GDB,并将gdb-many-windows设置为t,通常在其自己的框架中。我喜欢有一个单独的编辑框架。它看起来像这样(对于我粗略的ASCII图表,表示歉意):

+-------------+-------------+
| gdb         | locals      |
+-------------+-------------+
| source      | I/O         |
|             |             |
+-------------+-------------+
| stack       | breakpoints |
+-------------+-------------+

这个方法很好,但存在一个大问题。每当 gdb 需要显示不同的源缓冲区时(例如,up/down/step 后),它并不总是在“source”窗口中显示。例如,如果我在另一个框架的窗口中打开了相同的缓冲区,则它将升起该框架,同时保持键盘焦点在 gdb 框架中。在单监视器设置中,当帧互相覆盖时,这真的很烦人。
我想让 gdb 在 gdb-many-windows 设置中始终使用源窗口来显示源代码,无论其他地方是否显示了相同的源缓冲区。怎么做?
编辑:更详细的说明以重现此问题。我正在使用 Emacs 24.2.1 和 GDB 7.5-ubuntu。我在 Ubuntu 10.04 和 Linux Mint Nadia with Cinnamon 上看到了这个问题。
请执行以下步骤:
  • 评估此表达式:(setq gdb-many-windows t)
  • 用至少两个文件编译 C 程序。
例如:
// foo.c
void bar(int);
void foo(int c) {
  if (c > 0)
    bar(c - 1);
}
int main(void) {
  foo(100);
  return 0;
}

// bar.c
void foo(int c);
void bar(int c) {
  if (c > 0)
    foo(c - 2);
}

// compile with gcc -g -O0 foo.c bar.c -o test
  • 让bar.c在主框架中显示。使用 M-x 5 2 打开一个新的框架,在该框架中,使用 M-x gdb 启动gdb。如上图所示,该框架应具有6个窗口。将gdb框架放在源框架之上。
  • main函数中设置断点,并跟踪调用foobar。当调用bar时,因为bar.c已经在主框架中可见,所以主框架将覆盖gdb框架,但键盘焦点仍停留在gdb框架中。

我认为问题函数是gud.el.gz中的gdb-display-source-buffer。我计划尝试使用defadvice覆盖它,但我并不熟悉这个技术。如果我成功了,我会在这里发布答案。


无法复现问题。 - abo-abo
@Jay Conrod:请问您是否仍然遇到这个问题。如果有,请提供您的Emacs和gdb的完整版本号。此外,请尝试使用 emacs -q 命令来检测您的配置是否存在潜在问题。另外,请尝试提供一个最小化的示例,即小型源文件和逐步复现该问题的指令。 - Tobias
@Tobias,添加了详细的说明以重现。如果还有什么需要澄清的,请让我知道。 - Jay Conrod
1
在Debian上使用Emacs 24.4.1,我仍然遇到了这个问题。顺便说一下,我找到了一个错误报告,但是还没有(至今)任何补丁:http://lists.gnu.org/archive/html/bug-gnu-emacs/2014-06/msg00097.html - pestophagous
3个回答

2
造成这个问题的函数实际上是 gud.el.gz 中的 gud-display-line。该函数负责将覆盖箭头定位在源窗口当前行并确保其可见。以下是其逻辑:
(let* ...
 (window (and buffer
          (or (get-buffer-window buffer)
          (if (eq gud-minor-mode 'gdbmi)
              (or (if (get-buffer-window buffer 'visible)
                  (display-buffer buffer nil 'visible))
              (unless (gdb-display-source-buffer buffer)
                (gdb-display-buffer buffer nil 'visible))))
          (display-buffer buffer))))

我使用了defadvice来覆盖整个函数;基本上,我复制了源代码并更改了窗口选择逻辑。
(defadvice gud-display-line (around do-it-better activate)
  (let* ...
     (window (and buffer
                  (or (if (eq gud-minor-mode 'gdbmi)
                          (unless (gdb-display-source-buffer buffer)
                            (gdb-display-buffer buffer nil 'visible)))
                      (get-buffer-window buffer)
                      (display-buffer buffer))))
  ...)

显然这不是最优雅的解决方案。当使用up/down/frame切换框架时也没有帮助,所以当我找到解决方法后会进行编辑。


使用defadvice的方法在Debian Jessie上的emacs24-common 24.4+1-5上能够正常工作。是否有人已经将此作为错误报告和修补程序提交了?即使它在某些方面并不完美,似乎也值得重新报告并修复。如果维护者知道问题,他们可以将其足够地改进以应用。 - Brad Spencer

1

我使用的版本是24.3,但我无法重现这个问题。 gud-display-line的代码如下:

(defun gud-display-line (true-file line)
  (let* ((last-nonmenu-event t)  ; Prevent use of dialog box for questions.
     (buffer
      (with-current-buffer gud-comint-buffer
        (gud-find-file true-file)))
     (window (and buffer
              (or (get-buffer-window buffer)
              (display-buffer buffer))))
     (pos))
    (when buffer
      (with-current-buffer buffer
    (unless (or (verify-visited-file-modtime buffer) gud-keep-buffer)
      (if (yes-or-no-p
           (format "File %s changed on disk.  Reread from disk? "
               (buffer-name)))
          (revert-buffer t t)
        (setq gud-keep-buffer t)))
    (save-restriction
      (widen)
      (goto-char (point-min))
      (forward-line (1- line))
      (setq pos (point))
      (or gud-overlay-arrow-position
          (setq gud-overlay-arrow-position (make-marker)))
      (set-marker gud-overlay-arrow-position (point) (current-buffer))
      ;; If they turned on hl-line, move the hl-line highlight to
      ;; the arrow's line.
      (when (featurep 'hl-line)
        (cond
         (global-hl-line-mode
          (global-hl-line-highlight))
         ((and hl-line-mode hl-line-sticky-flag)
          (hl-line-highlight)))))
    (cond ((or (< pos (point-min)) (> pos (point-max)))
           (widen)
           (goto-char pos))))
      (when window
    (set-window-point window gud-overlay-arrow-position)
    (if (eq gud-minor-mode 'gdbmi)
        (setq gdb-source-window window))))))

window 设置与您的完全不同。也许,上面的代码有所帮助,或者您应该升级到新的 gud/gdb 工具。


谢谢,我会尝试在接下来的一两天内尽快升级。但我有点怀疑,因为 get-buffer-window 仍然在其中,我认为这可能是之前问题的原因。 - Jay Conrod
我尝试了多种情况,例如:使用 emacs -q 启动,打开多个 C 文件,打开三个框架,最大化框架。在这些情况下,我无法在 Emacs 24.3 中重现该问题。你是否尝试过使用 emacs -q - Tobias
我在家里将我的emacs升级到了24.3版本,现在问题已经不再出现了。同时,up/down/frame也能够正常工作了。虽然不确定为什么它现在能够正常工作,但还是非常感谢你的帮助。 - Jay Conrod

-1

我使用Emacs 24.5,对我来说这仍然是一个问题。现在我主要使用以下函数手动管理我的窗口:

(defun gdb-restore-windows-gud-io-and-source ()
  "Restore GUD buffer, IO buffer and source buffer next to each other."
  (interactive)
  ;; Select dedicated GUD buffer.
  (switch-to-buffer gud-comint-buffer)
  (delete-other-windows)
  (set-window-dedicated-p (get-buffer-window) t)
  (when (or gud-last-last-frame gdb-show-main)
    (let ((side-win (split-window nil nil t))
          (bottom-win (split-window)))
      ;; Put source to the right.
      (set-window-buffer
       side-win
       (if gud-last-last-frame
           (gud-find-file (car gud-last-last-frame))
         (gud-find-file gdb-main-file)))
      (setq gdb-source-window side-win)
      ;; Show dedicated IO buffer at the bottom.
      (set-window-buffer
       bottom-win
       (gdb-get-buffer-create 'gdb-inferior-io))
      (set-window-dedicated-p bottom-win t))))

这将在左上角显示GUD窗口,在左下角显示IO缓冲区,并将源缓冲区设置为右侧。 GUD和IO缓冲区均设置为专用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接