diff options
Diffstat (limited to 'lisp/progmodes/gdb-mi.el')
-rw-r--r-- | lisp/progmodes/gdb-mi.el | 443 |
1 files changed, 365 insertions, 78 deletions
diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el index e785acd2840..c1184211d06 100644 --- a/lisp/progmodes/gdb-mi.el +++ b/lisp/progmodes/gdb-mi.el @@ -92,6 +92,8 @@ (require 'json) (require 'bindat) (require 'cl-lib) +(require 'cl-seq) +(eval-when-compile (require 'pcase)) (declare-function speedbar-change-initial-expansion-list "speedbar" (new-default)) @@ -105,13 +107,24 @@ (defvar speedbar-initial-expansion-list-name) (defvar speedbar-frame) -(defvar gdb-memory-address "main") -(defvar gdb-memory-last-address nil +(defvar-local gdb-memory-address-expression "main" + "This expression is passed to gdb. +Possible value: main, $rsp, x+3.") +(defvar-local gdb-memory-address nil + "Address of memory display.") +(defvar-local gdb-memory-last-address nil "Last successfully accessed memory address.") (defvar gdb-memory-next-page nil "Address of next memory page for program memory buffer.") (defvar gdb-memory-prev-page nil "Address of previous memory page for program memory buffer.") +(defvar-local gdb--memory-display-warning nil + "Display warning on memory header if t. + +When error occurs when retrieving memory, gdb-mi displays the +last successful page. In that case the expression might not +match the memory displayed. We want to let the user be aware of +that, so display a warning exclamation mark in the header line.") (defvar gdb-thread-number nil "Main current thread. @@ -211,7 +224,9 @@ Only used for files that Emacs can't find.") (defvar gdb-source-file-list nil "List of source files for the current executable.") (defvar gdb-first-done-or-error t) -(defvar gdb-source-window nil) +(defvar gdb-source-window-list nil + "List of windows used for displaying source files. +Sorted in most-recently-visited-first order.") (defvar gdb-inferior-status nil) (defvar gdb-continuation nil) (defvar gdb-supports-non-stop nil) @@ -242,6 +257,27 @@ Possible values are these symbols: disposition of output generated by commands that gdb mode sends to gdb on its own behalf.") +(defvar gdb--window-configuration-before nil + "Stores the window configuration before starting GDB.") + +(defcustom gdb-restore-window-configuration-after-quit nil + "If non-nil, restore window configuration as of before GDB started. + +Possible values are: + t -- Always restore. + nil -- Don't restore. + `if-gdb-show-main' -- Restore only if variable `gdb-show-main' + is non-nil + `if-gdb-many-windows' -- Restore only if variable `gdb-many-windows' + is non-nil." + :type '(choice + (const :tag "Always restore" t) + (const :tag "Don't restore" nil) + (const :tag "Depends on `gdb-show-main'" 'if-gdb-show-main) + (const :tag "Depends on `gdb-many-windows'" 'if-gdb-many-windows)) + :group 'gdb + :version "28.1") + (defcustom gdb-discard-unordered-replies t "Non-nil means discard any out-of-order GDB replies. This protects against lost GDB replies, assuming that GDB always @@ -592,6 +628,40 @@ Also display the main routine in the disassembly buffer if present." :group 'gdb :version "22.1") +(defcustom gdb-window-configuration-directory user-emacs-directory + "Directory where GDB window configuration files are stored. +If nil, use `default-directory'." + :type 'string + :group 'gdb + :version "28.1") + +(defcustom gdb-default-window-configuration-file nil + "If non-nil, load this window configuration (layout) on startup. +This should be the full name of the window configuration file. +If this is not an absolute path, GDB treats it as a relative path +and looks under `gdb-window-configuration-directory'. + +Note that this variable only takes effect when variable +`gdb-many-windows' is t." + :type 'string + :group 'gdb + :version "28.1") + +(defcustom gdb-display-source-buffer-action '(nil . ((inhibit-same-window . t))) + "`display-buffer' action used when GDB displays a source buffer." + :type 'list + :group 'gdb + :version "28.1") + +(defcustom gdb-max-source-window-count 1 + "Maximum number of source windows to use. +Until there are such number of source windows on screen, GDB +tries to open a new window when visiting a new source file; after +that GDB starts to reuse existing source windows." + :type 'number + :group 'gdb + :version "28.1") + (defvar gdbmi-debug-mode nil "When non-nil, print the messages sent/received from GDB/MI in *Messages*.") @@ -750,6 +820,12 @@ detailed description of this mode. (gdb-restore-windows) (error "Multiple debugging requires restarting in text command mode")) + + ;; Save window configuration before starting gdb so we can restore + ;; it after gdb quits. Save it regardless of the value of + ;; `gdb-restore-window-configuration-after-quit'. + (setq gdb--window-configuration-before (window-state-get)) + ;; (gud-common-init command-line nil 'gud-gdbmi-marker-filter) @@ -925,7 +1001,7 @@ detailed description of this mode. gdb-first-done-or-error t gdb-buffer-fringe-width (car (window-fringes)) gdb-debug-log nil - gdb-source-window nil + gdb-source-window-list nil gdb-inferior-status nil gdb-continuation nil gdb-buf-publisher '() @@ -1035,7 +1111,10 @@ no input, and GDB is waiting for input." (declare-function tooltip-show "tooltip" (text &optional use-echo-area)) -(defconst gdb--string-regexp "\"\\(?:[^\\\"]\\|\\\\.\\)*\"") +(defconst gdb--string-regexp (rx "\"" + (* (or (seq "\\" nonl) + (not (any "\"\\")))) + "\"")) (defun gdb-tooltip-print (expr) (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer) @@ -1667,25 +1746,25 @@ this trigger is subscribed to `gdb-buf-publisher' and called with "Interrupt the program being debugged." (interactive) (interrupt-process - (get-buffer-process gud-comint-buffer) comint-ptyp)) + (get-buffer-process (gdb-get-buffer-create 'gdb-inferior-io)) comint-ptyp)) (defun gdb-io-quit () "Send quit signal to the program being debugged." (interactive) (quit-process - (get-buffer-process gud-comint-buffer) comint-ptyp)) + (get-buffer-process (gdb-get-buffer-create 'gdb-inferior-io)) comint-ptyp)) (defun gdb-io-stop () "Stop the program being debugged." (interactive) (stop-process - (get-buffer-process gud-comint-buffer) comint-ptyp)) + (get-buffer-process (gdb-get-buffer-create 'gdb-inferior-io)) comint-ptyp)) (defun gdb-io-eof () "Send end-of-file to the program being debugged." (interactive) (process-send-eof - (get-buffer-process gud-comint-buffer))) + (get-buffer-process (gdb-get-buffer-create 'gdb-inferior-io)))) (defun gdb-clear-inferior-io () (with-current-buffer (gdb-get-buffer-create 'gdb-inferior-io) @@ -1788,7 +1867,8 @@ static char *magick[] = { "\\|def\\(i\\(ne?\\)?\\)?\\|doc\\(u\\(m\\(e\\(nt?\\)?\\)?\\)?\\)?\\|" gdb-python-guile-commands-regexp "\\|while-stepping\\|stepp\\(i\\(ng?\\)?\\)?\\|ws\\|actions" - "\\)\\([[:blank:]]+\\([^[:blank:]]*\\)\\)?$") + "\\|expl\\(o\\(re?\\)?\\)?" + "\\)\\([[:blank:]]+\\([^[:blank:]]*\\)\\)*$") "Regexp matching GDB commands that enter a recursive reading loop. As long as GDB is in the recursive reading loop, it does not expect commands to be prefixed by \"-interpreter-exec console\".") @@ -2007,17 +2087,36 @@ is running." ;; GDB frame (after up, down etc). If no GDB frame is visible but the last ;; visited breakpoint is, use that window. (defun gdb-display-source-buffer (buffer) - (let* ((last-window (if gud-last-last-frame - (get-buffer-window - (gud-find-file (car gud-last-last-frame))))) - (source-window (or last-window - (if (and gdb-source-window - (window-live-p gdb-source-window)) - gdb-source-window)))) - (when source-window - (setq gdb-source-window source-window) - (set-window-buffer source-window buffer)) - source-window)) + "Find a window to display BUFFER. +Always find a window to display buffer, and return it." + ;; This function doesn't take care of setting up source window(s) at startup, + ;; that's handled by `gdb-setup-windows' (if `gdb-many-windows' is non-nil). + ;; If `buffer' is already shown in a window, use that window. + (or (get-buffer-window buffer) + (progn + ;; First, update the window list. + (setq gdb-source-window-list + (cl-remove-duplicates + (cl-remove-if-not + (lambda (win) + (and (window-live-p win) + (eq (window-frame win) + (selected-frame)))) + gdb-source-window-list))) + ;; Should we create a new window or reuse one? + (if (> gdb-max-source-window-count + (length gdb-source-window-list)) + ;; Create a new window, push it to window list and return it. + (car (push (display-buffer buffer gdb-display-source-buffer-action) + gdb-source-window-list)) + ;; Reuse a window, we use the oldest window and put that to + ;; the front of the window list. + (let ((last-win (car (last gdb-source-window-list))) + (rest (butlast gdb-source-window-list))) + (set-window-buffer last-win buffer) + (setq gdb-source-window-list + (cons last-win rest)) + last-win))))) (defun gdbmi-start-with (str offset match) @@ -2446,7 +2545,13 @@ file names include non-ASCII characters." gdb-filter-output) -(defun gdb-gdb (_output-field)) +(defun gdb-gdb (_output-field) + ;; This is needed because the "explore" command is not ended by the + ;; likes of "end" or "quit", but instead by a RET at the approriate + ;; place, and we know we have exited "explore" when we get the + ;; "(gdb)" prompt. + (and (> gdb-control-level 0) + (setq gdb-control-level (1- gdb-control-level)))) (defun gdb-shell (output-field) (setq gdb-filter-output @@ -3450,7 +3555,7 @@ line." (def-gdb-trigger-and-handler gdb-invalidate-memory (format "-data-read-memory %s %s %d %d %d" - gdb-memory-address + (gdb-mi-quote gdb-memory-address-expression) gdb-memory-format gdb-memory-unit gdb-memory-rows @@ -3490,6 +3595,9 @@ in `gdb-memory-format'." (err-msg (bindat-get-field res 'msg))) (if (not err-msg) (let ((memory (bindat-get-field res 'memory))) + (when gdb-memory-last-address + ;; Nil means last retrieve emits error or just started the session. + (setq gdb--memory-display-warning nil)) (setq gdb-memory-address (bindat-get-field res 'addr)) (setq gdb-memory-next-page (bindat-get-field res 'next-page)) (setq gdb-memory-prev-page (bindat-get-field res 'prev-page)) @@ -3503,10 +3611,15 @@ in `gdb-memory-format'." gdb-memory-format))))) (newline))) ;; Show last page instead of empty buffer when out of bounds - (progn - (let ((gdb-memory-address gdb-memory-last-address)) + (when gdb-memory-last-address + (let ((gdb-memory-address-expression gdb-memory-last-address)) + ;; If we don't set `gdb-memory-last-address' to nil, + ;; `gdb-invalidate-memory' eventually calls + ;; `gdb-read-memory-custom', making an infinite loop. + (setq gdb-memory-last-address nil + gdb--memory-display-warning t) (gdb-invalidate-memory 'update) - (error err-msg)))))) + (user-error "Error when retrieving memory: %s Displaying last successful page" err-msg)))))) (defvar gdb-memory-mode-map (let ((map (make-sparse-keymap))) @@ -3540,7 +3653,7 @@ in `gdb-memory-format'." "Set the start memory address." (interactive) (let ((arg (read-from-minibuffer "Memory address: "))) - (setq gdb-memory-address arg)) + (setq gdb-memory-address-expression arg)) (gdb-invalidate-memory 'update)) (defmacro def-gdb-set-positive-number (name variable echo-string &optional doc) @@ -3723,7 +3836,19 @@ DOC is an optional documentation string." (defvar gdb-memory-header '(:eval (concat - "Start address[" + "Start address " + ;; If `gdb-memory-address-expression' is nil, `propertize' would error. + (propertize (or gdb-memory-address-expression "N/A") + 'face font-lock-warning-face + 'help-echo "mouse-1: set start address" + 'mouse-face 'mode-line-highlight + 'local-map (gdb-make-header-line-mouse-map + 'mouse-1 + #'gdb-memory-set-address-event)) + (if gdb--memory-display-warning + (propertize " !" 'face '(:inherit error :weight bold)) + "") + " [" (propertize "-" 'face font-lock-warning-face 'help-echo "mouse-1: decrement address" @@ -3740,13 +3865,9 @@ DOC is an optional documentation string." 'mouse-1 #'gdb-memory-show-next-page)) "]: " - (propertize gdb-memory-address - 'face font-lock-warning-face - 'help-echo "mouse-1: set start address" - 'mouse-face 'mode-line-highlight - 'local-map (gdb-make-header-line-mouse-map - 'mouse-1 - #'gdb-memory-set-address-event)) + ;; If `gdb-memory-address' is nil, `propertize' would error. + (propertize (or gdb-memory-address "N/A") + 'face font-lock-warning-face) " Rows: " (propertize (number-to-string gdb-memory-rows) 'face font-lock-warning-face @@ -3986,9 +4107,7 @@ DOC is an optional documentation string." (let* ((buffer (find-file-noselect (if (file-exists-p file) file (cdr (assoc bptno gdb-location-alist))))) - (window (or (gdb-display-source-buffer buffer) - (display-buffer buffer)))) - (setq gdb-source-window window) + (window (gdb-display-source-buffer buffer))) (with-current-buffer buffer (goto-char (point-min)) (forward-line (1- (string-to-number line))) @@ -4464,6 +4583,26 @@ SPLIT-HORIZONTAL and show BUF in the new window." (define-key gud-menu-map [displays] `(menu-item "GDB-Windows" ,menu :visible (eq gud-minor-mode 'gdbmi))) + (define-key menu [gdb-restore-windows] + '(menu-item "Restore Initial Layout" gdb-restore-windows + :help "Restore the initial GDB window layout.")) + ;; Window layout vs window configuration: We use "window layout" in + ;; GDB UI. Internally we refer to "window configuration" because + ;; that's the data structure used to store window layouts. Though + ;; bare in mind that there is a small difference between what we + ;; store and what normal window configuration functions + ;; output. Because GDB buffers (source, local, breakpoint, etc) are + ;; different between each debugging sessions, simply save/load + ;; window configurations doesn't + ;; work. `gdb-save-window-configuration' and + ;; `gdb-load-window-configuration' do some tricks to store and + ;; recreate each buffer in the layout. + (define-key menu [load-layout] '("Load Layout" "Load GDB window configuration (layout) from a file" . gdb-load-window-configuration)) + (define-key menu [save-layout] '("Save Layout" "Save current GDB window configuration (layout) to a file" . gdb-save-window-configuration)) + (define-key menu [restore-layout-after-quit] + '(menu-item "Restore Layout After Quit" gdb-toggle-restore-window-configuration + :button (:toggle . gdb-restore-window-configuration-after-quit) + :help "Toggle between always restore the window configuration (layout) after GDB quits and never restore.\n You can also change this setting in Customize to conditionally restore.")) (define-key menu [gdb] '("Gdb" . gdb-display-gdb-buffer)) (define-key menu [threads] '("Threads" . gdb-display-threads-buffer)) (define-key menu [memory] '("Memory" . gdb-display-memory-buffer)) @@ -4502,9 +4641,6 @@ SPLIT-HORIZONTAL and show BUF in the new window." '(menu-item "Display Other Windows" gdb-many-windows :help "Toggle display of locals, stack and breakpoint information" :button (:toggle . gdb-many-windows))) - (define-key menu [gdb-restore-windows] - '(menu-item "Restore Window Layout" gdb-restore-windows - :help "Restore standard layout for debug session.")) (define-key menu [sep1] '(menu-item "--")) (define-key menu [all-threads] @@ -4579,41 +4715,173 @@ window is dedicated." (set-window-buffer window (get-buffer name)) (set-window-dedicated-p window t)) +(defun gdb-toggle-restore-window-configuration () + "Toggle whether to restore window configuration when GDB quits." + (interactive) + (setq gdb-restore-window-configuration-after-quit + (not gdb-restore-window-configuration-after-quit))) + +(defun gdb-get-source-buffer () + "Return a buffer displaying source file or nil if we can't find one. +The source file is the file that contains the source location +where GDB stops. There could be multiple source files during a +debugging session, we get the most recently showed one. If +program hasn't started running yet, the source file is the \"main +file\" where the GDB session starts (see `gdb-main-file')." + (if gud-last-last-frame + (gud-find-file (car gud-last-last-frame)) + (when gdb-main-file + (gud-find-file gdb-main-file)))) + (defun gdb-setup-windows () - "Layout the window pattern for option `gdb-many-windows'." - (gdb-get-buffer-create 'gdb-locals-buffer) - (gdb-get-buffer-create 'gdb-stack-buffer) - (gdb-get-buffer-create 'gdb-breakpoints-buffer) - (set-window-dedicated-p (selected-window) nil) - (switch-to-buffer gud-comint-buffer) - (delete-other-windows) - (let ((win0 (selected-window)) - (win1 (split-window nil ( / ( * (window-height) 3) 4))) - (win2 (split-window nil ( / (window-height) 3))) - (win3 (split-window-right))) - (gdb-set-window-buffer (gdb-locals-buffer-name) nil win3) - (select-window win2) - (set-window-buffer - win2 - (if gud-last-last-frame - (gud-find-file (car gud-last-last-frame)) - (if gdb-main-file - (gud-find-file gdb-main-file) - ;; Put buffer list in window if we - ;; can't find a source file. - (list-buffers-noselect)))) - (setq gdb-source-window (selected-window)) - (let ((win4 (split-window-right))) - (gdb-set-window-buffer - (gdb-get-buffer-create 'gdb-inferior-io) nil win4)) - (select-window win1) - (gdb-set-window-buffer (gdb-stack-buffer-name)) - (let ((win5 (split-window-right))) - (gdb-set-window-buffer (if gdb-show-threads-by-default - (gdb-threads-buffer-name) - (gdb-breakpoints-buffer-name)) - nil win5)) - (select-window win0))) + "Lay out the window pattern for option `gdb-many-windows'." + (if gdb-default-window-configuration-file + (gdb-load-window-configuration + (if (file-name-absolute-p gdb-default-window-configuration-file) + gdb-default-window-configuration-file + (expand-file-name gdb-default-window-configuration-file + gdb-window-configuration-directory))) + ;; Create default layout as before. + (gdb-get-buffer-create 'gdb-locals-buffer) + (gdb-get-buffer-create 'gdb-stack-buffer) + (gdb-get-buffer-create 'gdb-breakpoints-buffer) + (set-window-dedicated-p (selected-window) nil) + (switch-to-buffer gud-comint-buffer) + (delete-other-windows) + (let ((win0 (selected-window)) + (win1 (split-window nil ( / ( * (window-height) 3) 4))) + (win2 (split-window nil ( / (window-height) 3))) + (win3 (split-window-right))) + (gdb-set-window-buffer (gdb-locals-buffer-name) nil win3) + (select-window win2) + (set-window-buffer win2 (or (gdb-get-source-buffer) + (list-buffers-noselect))) + (setq gdb-source-window-list (list (selected-window))) + (let ((win4 (split-window-right))) + (gdb-set-window-buffer + (gdb-get-buffer-create 'gdb-inferior-io) nil win4)) + (select-window win1) + (gdb-set-window-buffer (gdb-stack-buffer-name)) + (let ((win5 (split-window-right))) + (gdb-set-window-buffer (if gdb-show-threads-by-default + (gdb-threads-buffer-name) + (gdb-breakpoints-buffer-name)) + nil win5)) + (select-window win0)))) + +(defun gdb-buffer-p (buffer) + "Return t if BUFFER is GDB-related." + (with-current-buffer buffer + (eq gud-minor-mode 'gdbmi))) + +(defun gdb-function-buffer-p (buffer) + "Return t if BUFFER is a GDB function buffer. + +Function buffers are locals buffer, registers buffer, etc, but +not including main command buffer (the one where you type GDB +commands) or source buffers (that display program source code)." + (with-current-buffer buffer + (derived-mode-p 'gdb-parent-mode 'gdb-inferior-io-mode))) + +(defun gdb--buffer-type (buffer) + "Return the type of BUFFER if it is a function buffer. +Buffer type is like `gdb-registers-type', `gdb-stack-buffer'. +These symbols are used by `gdb-get-buffer-create'. + +Return nil if BUFFER is not a GDB function buffer." + (with-current-buffer buffer + (cl-loop for rule in gdb-buffer-rules + for mode-name = (gdb-rules-buffer-mode rule) + for type = (car rule) + if (eq mode-name major-mode) + return type + finally return nil))) + +(defun gdb-save-window-configuration (file) + "Save current window configuration (layout) to FILE. +You can later restore this configuration from that file by +`gdb-load-window-configuration'." + (interactive (list (read-file-name + "Save window configuration to file: " + (or gdb-window-configuration-directory + default-directory)))) + ;; We replace the buffer in each window with a placeholder, store + ;; the buffer type (register, breakpoint, etc) in window parameters, + ;; and write the window configuration to the file. + (save-window-excursion + (let ((placeholder (get-buffer-create " *gdb-placeholder*")) + (window-persistent-parameters + (cons '(gdb-buffer-type . writable) window-persistent-parameters))) + (unwind-protect + (dolist (win (window-list nil 'no-minibuffer)) + (select-window win) + (when (gdb-buffer-p (current-buffer)) + (set-window-parameter + nil 'gdb-buffer-type + (cond ((gdb-function-buffer-p (current-buffer)) + ;; 1) If a user arranged the window + ;; configuration herself and saves it, windows + ;; are probably not dedicated. 2) We use the + ;; same dedication flag as in + ;; `gdb-display-buffer'. + (set-window-dedicated-p nil t) + ;; We save this gdb-buffer-type symbol so + ;; we can later pass it to `gdb-get-buffer-create'; + ;; one example: `gdb-registers-buffer'. + (or (gdb--buffer-type (current-buffer)) + (error "Unrecognized gdb buffer mode: %s" major-mode))) + ;; Command buffer. + ((derived-mode-p 'gud-mode) 'command) + ;; Consider everything else as source buffer. + (t 'source))) + (with-window-non-dedicated nil + (set-window-buffer nil placeholder) + (set-window-prev-buffers (selected-window) nil) + (set-window-next-buffers (selected-window) nil)))) + ;; Save the window configuration to FILE. + (let ((window-config (window-state-get nil t))) + (with-temp-buffer + (prin1 window-config (current-buffer)) + (write-file file t))) + (kill-buffer placeholder))))) + +(defun gdb-load-window-configuration (file) + "Restore window configuration (layout) from FILE. +FILE should be a window configuration file saved by +`gdb-save-window-configuration'." + (interactive (list (read-file-name + "Restore window configuration from file: " + (or gdb-window-configuration-directory + default-directory)))) + ;; Basically, we restore window configuration and go through each + ;; window and restore the function buffers. + (let* ((placeholder (get-buffer-create " *gdb-placeholder*"))) + (unwind-protect ; Don't leak buffer. + (let ((window-config (with-temp-buffer + (insert-file-contents file) + ;; We need to go to point-min because + ;; `read' reads from point + (goto-char (point-min)) + (read (current-buffer)))) + (source-buffer (or (gdb-get-source-buffer) + ;; Do the same thing as in + ;; `gdb-setup-windows' if no source + ;; buffer is found. + (list-buffers-noselect))) + buffer-type) + (window-state-put window-config (frame-root-window)) + (dolist (window (window-list nil 'no-minibuffer)) + (with-selected-window window + (setq buffer-type (window-parameter nil 'gdb-buffer-type)) + (pcase buffer-type + ('source (when source-buffer + (set-window-buffer nil source-buffer) + (push (selected-window) gdb-source-window-list))) + ('command (switch-to-buffer gud-comint-buffer)) + (_ (let ((buffer (gdb-get-buffer-create buffer-type))) + (with-window-non-dedicated nil + (set-window-buffer nil buffer)))))))) + (kill-buffer placeholder)))) (define-minor-mode gdb-many-windows "If nil just pop up the GUD buffer unless `gdb-show-main' is t. @@ -4631,7 +4899,12 @@ of the debugged program. Non-nil means display the layout shown for (defun gdb-restore-windows () "Restore the basic arrangement of windows used by gdb. -This arrangement depends on the value of option `gdb-many-windows'." +This arrangement depends on the values of variable +`gdb-many-windows' and `gdb-default-window-configuration-file'." + ;; This function is used when the user messed up window + ;; configuration and wants to "reset to default". The function that + ;; sets up window configuration on start up is + ;; `gdb-get-source-file'. (interactive) (switch-to-buffer gud-comint-buffer) ;Select the right window and frame. (delete-other-windows) @@ -4644,7 +4917,7 @@ This arrangement depends on the value of option `gdb-many-windows'." (if gud-last-last-frame (gud-find-file (car gud-last-last-frame)) (gud-find-file gdb-main-file))) - (setq gdb-source-window win))))) + (setq gdb-source-window-list (list win)))))) ;; Called from `gud-sentinel' in gud.el: (defun gdb-reset () @@ -4678,11 +4951,25 @@ Kills the gdb buffers, and resets variables and the source buffers." (if (boundp 'speedbar-frame) (speedbar-timer-fn)) (setq gud-running nil) (setq gdb-active-process nil) - (remove-hook 'after-save-hook 'gdb-create-define-alist t)) + (remove-hook 'after-save-hook 'gdb-create-define-alist t) + ;; Recover window configuration. + (when (or (eq gdb-restore-window-configuration-after-quit t) + (and (eq gdb-restore-window-configuration-after-quit + 'if-gdb-show-main) + gdb-show-main) + (and (eq gdb-restore-window-configuration-after-quit + 'if-gdb-many-windows) + gdb-many-windows)) + (when gdb--window-configuration-before + (window-state-put gdb--window-configuration-before) + ;; This way we don't accidentally restore an outdated window + ;; configuration. + (setq gdb--window-configuration-before nil)))) (defun gdb-get-source-file () "Find the source file where the program starts and display it with related buffers, if required." + ;; This function is called only once on startup. (goto-char (point-min)) (if (re-search-forward gdb-source-file-regexp nil t) (setq gdb-main-file (read (match-string 1)))) |