Emacs/GDB: always display source in specific window with gdb-many-windows

若如初见. 提交于 2019-12-21 10:06:01

问题


I use GDB in Emacs 24 with gdb-many-windows set to t, usually in its own frame. I like to have a separate editing frame. It looks like this (apologies for my crude ASCII diagram):

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

This works pretty well except for one big problem. Whenever gdb needs to display a different source buffer, e.g., after up/down/step, it doesn't always show it in the "source" window. For example, if I have the same buffer open in a window in a different frame, it will raise that frame while keeping keyboard focus in the gdb frame. This is really annoying on a single-monitor setup when the frames cover each other.

I'd like gdb to always use the source window in the gdb-many-windows setup to display source, no matter if the same source buffer is displayed elsewhere. How can I do that?


EDIT: More detailed instructions to reproduce. I'm using Emacs 24.2.1 with GDB 7.5-ubuntu. I've seen this problem on Ubuntu 10.04 and Linux Mint Nadia with Cinnamon.

  • Evaluate this expression: (setq gdb-many-windows t)
  • Compile a C program with at least two files.

For example:

// 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
  • Let bar.c be displayed in the main frame. Open a new frame with M-x 5 2. In that frame, start gdb with M-x gdb. There should be six windows in that frame as shown above. Position the gdb frame on top of the source frame.
  • Set a breakpoint in main and step through calls to foo and bar. When bar is called, the main frame will be raised over the gdb frame since bar.c is already visible there, but keyboard focus will stay in the gdb frame.

I think the problem function is gdb-display-source-buffer in gud.el.gz. I'm planning to try overriding this with defadvice, but I'm not really familiar with advice. If I figure it out, I'll post an answer here.


回答1:


I have 24.3. And I cannot reproduce the problem with this version. There gud-display-line looks as follows:

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

The window setting is completely different from yours. Maybe, the above code is helpful or maybe you should upgrade to the new gud/gdb stuff.




回答2:


The function causing this problem is actually gud-display-line in gud.el.gz. This function is responsible for positioning the overlay arrow in the source window on the current line and making sure it is visible. Here's the logic:

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

I used defadvice to override the whole function; basically, I copied the source and changed the window selection logic.

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

Obviously not the most elegant solution. It also doesn't help when switching frames (with up/down/frame), so I'll edit this when I figure that out.




回答3:


I run Emacs 24.5 and for me this is still an issue. I manage my windows manually with dedicated windows now, mainly with the following function:

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

This shows the GUD window at the top left, the IO buffer at the bottom left and sets the source buffer to the right side. The GUD and the IO buffer are set to dedicated.



来源:https://stackoverflow.com/questions/20226626/emacs-gdb-always-display-source-in-specific-window-with-gdb-many-windows

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!