[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/native-comp e57d5a7 5/5: Merge remote-tracking branch 'savannah/
From: |
Andrea Corallo |
Subject: |
feature/native-comp e57d5a7 5/5: Merge remote-tracking branch 'savannah/master' into HEAD |
Date: |
Tue, 17 Mar 2020 04:28:54 -0400 (EDT) |
branch: feature/native-comp
commit e57d5a71ba765bbd225974b3d61ecd9d80f73220
Merge: 159f61b 9dccaf8
Author: Andrea Corallo <address@hidden>
Commit: Andrea Corallo <address@hidden>
Merge remote-tracking branch 'savannah/master' into HEAD
---
lisp/progmodes/gdb-mi.el | 293 ++++++++++++++++++++++++++++++++++++++++-------
lisp/window.el | 18 +++
src/alloc.c | 22 ++--
3 files changed, 285 insertions(+), 48 deletions(-)
diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el
index c262232..ea3b1b8 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))
@@ -253,6 +255,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
@@ -603,6 +626,25 @@ 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")
+
(defvar gdbmi-debug-mode nil
"When non-nil, print the messages sent/received from GDB/MI in *Messages*.")
@@ -761,6 +803,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)
@@ -4494,6 +4542,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))
@@ -4532,9 +4600,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]
@@ -4609,41 +4674,172 @@ 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 (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)
+ ((equal (selected-window) gdb-source-window) '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)
+ (setq gdb-source-window (selected-window))))
+ ('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.
@@ -4661,7 +4857,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)
@@ -4708,11 +4909,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))))
diff --git a/lisp/window.el b/lisp/window.el
index fc1e7d4..b54f163 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -278,6 +278,24 @@ displays the buffer specified by BUFFER-OR-NAME before
running BODY."
(funcall ,vquit-function ,window ,value)
,value)))))
+(defmacro with-window-non-dedicated (window &rest body)
+ "Evaluate BODY with WINDOW temporarily made non-dedicated.
+If WINDOW is nil, use the selected window. Return the value of
+the last form in BODY."
+ (declare (indent 1) (debug t))
+ (let ((window-dedicated-sym (gensym))
+ (window-sym (gensym)))
+ `(let* ((,window-sym (window-normalize-window ,window t))
+ (,window-dedicated-sym (window-dedicated-p ,window-sym)))
+ (set-window-dedicated-p ,window-sym nil)
+ (unwind-protect
+ (progn ,@body)
+ ;; `window-dedicated-p' returns the value set by
+ ;; `set-window-dedicated-p', which differentiates non-nil and
+ ;; t, so we cannot simply use t here. That's why we use
+ ;; `window-dedicated-sym'.
+ (set-window-dedicated-p ,window-sym ,window-dedicated-sym)))))
+
;; The following two functions are like `window-next-sibling' and
;; `window-prev-sibling' but the WINDOW argument is _not_ optional (so
;; they don't substitute the selected window for nil), and they return
diff --git a/src/alloc.c b/src/alloc.c
index ac17307..db0646c 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -4604,21 +4604,23 @@ live_vector_p (struct mem_node *m, void *p)
return !NILP (live_vector_holding (m, p));
}
-/* If P is a pointer into a live buffer, return the buffer.
- Otherwise, return nil. M is a pointer to the mem_block for P. */
+/* If P is a pointer into a valid buffer object, return the buffer.
+ Otherwise, return nil. M is a pointer to the mem_block for P.
+ If IGNORE_KILLED is non-zero, treat killed buffers as invalid. */
static Lisp_Object
-live_buffer_holding (struct mem_node *m, void *p)
+live_buffer_holding (struct mem_node *m, void *p, bool ignore_killed)
{
- /* P must point into the block, and the buffer
- must not have been killed. */
+ /* P must point into the block, and the buffer must not
+ have been killed unless ALL-BUFFERS is true. */
if (m->type == MEM_TYPE_BUFFER)
{
struct buffer *b = m->start;
char *cb = m->start;
char *cp = p;
ptrdiff_t offset = cp - cb;
- if (0 <= offset && offset < sizeof *b && !NILP (b->name_))
+ if (0 <= offset && offset < sizeof *b
+ && !(ignore_killed && NILP (b->name_)))
{
Lisp_Object obj;
XSETBUFFER (obj, b);
@@ -4628,10 +4630,12 @@ live_buffer_holding (struct mem_node *m, void *p)
return Qnil;
}
+/* If P is a pointer into a live (valid and not killed) buffer object,
+ return non-zero. */
static bool
live_buffer_p (struct mem_node *m, void *p)
{
- return !NILP (live_buffer_holding (m, p));
+ return !NILP (live_buffer_holding (m, p, true));
}
/* Mark OBJ if we can prove it's a Lisp_Object. */
@@ -4689,7 +4693,7 @@ mark_maybe_object (Lisp_Object obj)
case Lisp_Vectorlike:
mark_p = (EQ (obj, live_vector_holding (m, po))
- || EQ (obj, live_buffer_holding (m, po)));
+ || EQ (obj, live_buffer_holding (m, po, false)));
break;
default:
@@ -4759,7 +4763,7 @@ mark_maybe_pointer (void *p)
break;
case MEM_TYPE_BUFFER:
- obj = live_buffer_holding (m, p);
+ obj = live_buffer_holding (m, p, false);
break;
case MEM_TYPE_CONS: