From: martin rudalics via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: Juri Linkov <juri@linkov.net>
Cc: 68235@debbugs.gnu.org
Subject: bug#68235: 29.1.90; Switching tabs stops following process output in selected window
Date: Mon, 19 Feb 2024 10:42:09 +0100 [thread overview]
Message-ID: <3fe7e4b4-bc9a-4303-a87f-a360765c597f@gmx.at> (raw)
In-Reply-To: <86il2mxmxd.fsf@mail.linkov.net>
[-- Attachment #1: Type: text/plain, Size: 2293 bytes --]
>> You mean to do away with the KEEP-WINDOWS argument and keep windows iff
>> `window-state-put-keep-window-functions' is non-nil?
>
> Yes, I meant removing the KEEP-WINDOWS argument.
Patch attached. I now provide only one hook I called
'window-kept-windows-functions' which is run by both
'set-window-configuration' and 'window-state-put'.
Tested with
(defun foo (frame windows)
(while windows
(let* ((quad (car windows))
(window (car quad))
(name (buffer-file-name (nth 1 quad)))
(buffer
(and name (find-file-noselect name))))
(when buffer
(set-window-buffer window buffer)
(set-window-point window (nth 3 quad))
(set-window-start window (nth 2 quad) t)))
(setq windows (cdr windows))))
(add-hook 'window-kept-windows-functions 'foo)
(let ((window (selected-window))
(buffer (pop-to-buffer
(find-file-noselect "...")))
(window-1 (split-window))
(window-2 (split-window nil nil t))
configuration)
(set-window-point window-1 5000)
(set-window-point window-2 10000)
(setq configuration (current-window-configuration))
(y-or-n-p "Configuration saved ...")
(delete-other-windows window)
(kill-buffer buffer)
(y-or-n-p "Configuration reset ...")
(set-window-configuration configuration)
(message "Configuration restored"))
(let ((window (selected-window))
(buffer (pop-to-buffer
(find-file-noselect "...")))
(window-1 (split-window))
(window-2 (split-window nil nil t))
state)
(set-window-point window-1 5000)
(set-window-point window-2 10000)
(setq state (window-state-get))
(y-or-n-p "State saved ...")
(delete-other-windows window)
(kill-buffer buffer)
(y-or-n-p "State reset ...")
(window-state-put state)
(message "State restored"))
>> This would be up to you to decide. Only some practice can tell what's
>> better here.
>
> Otherwise users won't be able to use this hook for existing commands
> that don't set the KEEP-WINDOWS argument.
OK. But note that we now run this hook even if nothing in the window
configuration changes, typically, when calling 'read-minibuffer'. So
use it with due care (for example, have the tab code bind it exclusively
around its calls of 'set-window-configuration').
martin
[-- Attachment #2: keep-windows.diff --]
[-- Type: text/x-patch, Size: 10808 bytes --]
diff --git a/lisp/window.el b/lisp/window.el
index e100f25526b..868eef0b63c 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -6174,6 +6174,9 @@ window-state-put-list
(defvar window-state-put-stale-windows nil
"Helper variable for `window-state-put'.")
+(defvar window-state-put-kept-windows nil
+ "Helper variable for `window-state-put'.")
+
(defun window--state-put-1 (state &optional window ignore totals pixelwise)
"Helper function for `window-state-put'."
(let ((type (car state)))
@@ -6278,9 +6281,10 @@ window--state-put-2
(set-window-parameter window (car parameter) (cdr parameter))))
;; Process buffer related state.
(when state
- (let ((buffer (get-buffer (car state)))
- (state (cdr state)))
- (if buffer
+ (let* ((old-buffer-or-name (car state))
+ (buffer (get-buffer old-buffer-or-name))
+ (state (cdr state)))
+ (if (buffer-live-p buffer)
(with-current-buffer buffer
(set-window-buffer window buffer)
(set-window-hscroll window (cdr (assq 'hscroll state)))
@@ -6375,7 +6379,20 @@ window--state-put-2
;; save the window with the intention of deleting it later
;; if possible.
(switch-to-prev-buffer window)
- (push window window-state-put-stale-windows)))))))
+ (if window-kept-windows-functions
+ (let* ((start (cdr (assq 'start state)))
+ ;; Handle both - marker positions from writable
+ ;; states and markers from non-writable states.
+ (start-pos (if (markerp start)
+ (marker-last-position start)
+ start))
+ (point (cdr (assq 'point state)))
+ (point-pos (if (markerp point)
+ (marker-last-position point)
+ point)))
+ (push (list window old-buffer-or-name start-pos point-pos)
+ window-state-put-kept-windows))
+ (push window window-state-put-stale-windows))))))))
(defun window-state-put (state &optional window ignore)
"Put window state STATE into WINDOW.
@@ -6388,8 +6405,20 @@ window-state-put
Optional argument IGNORE non-nil means ignore minimum window
sizes and fixed size restrictions. IGNORE equal `safe' means
windows can get as small as `window-safe-min-height' and
-`window-safe-min-width'."
+`window-safe-min-width'.
+
+If the abnormal hook `window-kept-windows-functions' is non-nil,
+never delete any windows saved by STATE whose buffers were
+deleted since STATE was saved. Rather show some live buffer in
+them and call each function in `window-kept-windows-functions'
+with a list of two arguments: the frame where STATE was put and a
+list of entries for each such window. Each entry contains four
+elements - the window, its old buffer and the last positions of
+`window-start' and `window-point' for the buffer in that window.
+Always check the window for liveness because another function run
+by this hook may have deleted it."
(setq window-state-put-stale-windows nil)
+ (setq window-state-put-kept-windows nil)
;; When WINDOW is internal or nil, reduce it to a live one,
;; then create a new window on the same frame to put STATE into.
@@ -6492,12 +6521,17 @@ window-state-put
(window--state-put-2 ignore pixelwise))
(while window-state-put-stale-windows
(let ((window (pop window-state-put-stale-windows)))
- ;; Avoid that 'window-deletable-p' throws an error if window
+ ;; Avoid that 'window-deletable-p' throws an error if window
;; was already deleted when exiting 'with-temp-buffer' above
;; (Bug#54028).
(when (and (window-valid-p window)
(eq (window-deletable-p window) t))
(delete-window window))))
+ (when window-kept-windows-functions
+ (run-hook-with-args
+ 'window-kept-windows-functions
+ frame window-state-put-kept-windows)
+ (setq window-state-put-kept-windows nil))
(window--check frame))))
(defun window-state-buffers (state)
diff --git a/src/marker.c b/src/marker.c
index 377f6fbe8db..14b9f63f0cd 100644
--- a/src/marker.c
+++ b/src/marker.c
@@ -458,6 +458,18 @@ DEFUN ("marker-position", Fmarker_position, Smarker_position, 1, 1, 0,
return Qnil;
}
+DEFUN ("marker-last-position", Fmarker_last_position, Smarker_last_position, 1, 1, 0,
+ doc: /* Return last position of MARKER in its buffer.
+This is like `marker-position' with one exception: If the buffer of
+MARKER is dead, it returns the last position of MARKER in that buffer
+before it was killed. */)
+ (Lisp_Object marker)
+{
+ CHECK_MARKER (marker);
+
+ return make_fixnum (XMARKER (marker)->charpos);
+}
+
/* Change M so it points to B at CHARPOS and BYTEPOS. */
static void
@@ -825,6 +837,7 @@ verify_bytepos (ptrdiff_t charpos)
syms_of_marker (void)
{
defsubr (&Smarker_position);
+ defsubr (&Smarker_last_position);
defsubr (&Smarker_buffer);
defsubr (&Sset_marker);
defsubr (&Scopy_marker);
diff --git a/src/window.c b/src/window.c
index 3a54f7ce7b1..8e002d70db6 100644
--- a/src/window.c
+++ b/src/window.c
@@ -7090,6 +7090,24 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
the mini-window of the frame doesn't get set to the corresponding element
of CONFIGURATION.
+Normally, this function will try to delete any dead window in
+CONFIGURATION whose buffer has been deleted since CONFIGURATION was
+made. However, if the abnormal hook `window-kept-windows-functions' is
+non-nil, it will preserve such a window in the restored layout and show
+another buffer in it.
+
+After restoring the frame layout, this function runs the abnormal hook
+`window-kept-windows-functions' with two arguments - the frame whose
+layout it has restored and a list of entries for each window whose
+buffer has been found dead when it tried to restore CONFIGURATION: Each
+entry is a list of four elements <window, buffer, start, point> where
+`window' denotes the window whose buffer was found dead, `buffer'
+denotes the dead buffer, and `start' and `point' denote the last known
+positions of `window-start' and `window-point' of the buffer in that
+window. Any function run by this hook should check the window for
+liveness because another function run by this hook may have deleted it
+in the meantime."
+
If CONFIGURATION was made from a frame that is now deleted,
only frame-independent values can be restored. In this case,
the return value is nil. Otherwise the value is t. */)
@@ -7100,6 +7118,7 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
struct Lisp_Vector *saved_windows;
Lisp_Object new_current_buffer;
Lisp_Object frame;
+ Lisp_Object kept_windows = Qnil;
Lisp_Object old_frame = selected_frame;
struct frame *f;
ptrdiff_t old_point = -1;
@@ -7340,6 +7359,11 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
BUF_PT (XBUFFER (w->contents)),
BUF_PT_BYTE (XBUFFER (w->contents)));
w->start_at_line_beg = true;
+ if (!NILP (Vwindow_kept_windows_functions))
+ kept_windows = Fcons (list4 (window, p->buffer,
+ Fmarker_last_position (p->start),
+ Fmarker_last_position (p->pointm)),
+ kept_windows);
}
else if (!NILP (w->start))
/* Leaf window has no live buffer, get one. */
@@ -7360,6 +7384,11 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
dead_windows = Fcons (window, dead_windows);
/* Make sure window is no more dedicated. */
wset_dedicated (w, Qnil);
+ if (!NILP (Vwindow_kept_windows_functions))
+ kept_windows = Fcons (list4 (window, p->buffer,
+ Fmarker_last_position (p->start),
+ Fmarker_last_position (p->pointm)),
+ kept_windows);
}
}
@@ -7411,12 +7440,13 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
unblock_input ();
/* Scan dead buffer windows. */
- for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows))
- {
- window = XCAR (dead_windows);
- if (WINDOW_LIVE_P (window) && !EQ (window, FRAME_ROOT_WINDOW (f)))
- delete_deletable_window (window);
- }
+ if (!NILP (Vwindow_kept_windows_functions))
+ for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows))
+ {
+ window = XCAR (dead_windows);
+ if (WINDOW_LIVE_P (window) && !EQ (window, FRAME_ROOT_WINDOW (f)))
+ delete_deletable_window (window);
+ }
/* Record the selected window's buffer here. The window should
already be the selected one from the call above. */
@@ -7463,6 +7493,11 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
minibuf_selected_window = data->minibuf_selected_window;
SAFE_FREE ();
+
+ if (!NILP (Vrun_hooks) && !NILP (Vwindow_kept_windows_functions))
+ run_hook_with_args_2 (Qwindow_kept_windows_functions, frame,
+ kept_windows);
+
return FRAME_LIVE_P (f) ? Qt : Qnil;
}
@@ -8460,6 +8495,8 @@ syms_of_window (void)
DEFSYM (Qheader_line_format, "header-line-format");
DEFSYM (Qtab_line_format, "tab-line-format");
DEFSYM (Qno_other_window, "no-other-window");
+ DEFSYM (Qwindow_kept_windows_functions,
+ "window-kept-windows-functions");
DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function,
doc: /* Non-nil means call as function to display a help buffer.
@@ -8617,6 +8654,28 @@ syms_of_window (void)
call is performed with the frame temporarily selected. */);
Vwindow_configuration_change_hook = Qnil;
+ DEFVAR_LISP ("window-kept-windows-functions",
+ Vwindow_kept_windows_functions,
+ doc: /* Functions run after restoring a window configuration or state.
+These functions are called by `set-window-configuration' and
+`window-state-put'. When the value of this variable is non-nil, these
+functions restore any window whose buffer has been deleted since the
+corresponding configuration or state was saved. Rather than deleting
+such a window, `set-window-configuration' and `window-state-put' show
+some live buffer in it.
+
+The value should be a list of functions that take two arguments. The
+first argument specifies the frame whose configuration has been
+restored. The second argument, if non-nil, specifies a list of entries
+for each window whose buffer has been found dead at the time
+'set-window-configuration' or `window-state-put' tried to restore it in
+that window. Each entry is a list of four values - the window whose
+buffer was found dead, the dead buffer, and the positions of start and
+point of the buffer in that window. Note that the window may be already
+dead since another function on this list may have deleted it in the
+meantime. */);
+ Vwindow_kept_windows_functions = Qnil;
+
DEFVAR_LISP ("recenter-redisplay", Vrecenter_redisplay,
doc: /* Non-nil means `recenter' redraws entire frame.
If this option is non-nil, then the `recenter' command with a nil
next prev parent reply other threads:[~2024-02-19 9:42 UTC|newest]
Thread overview: 85+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-03 20:48 bug#68235: 29.1.90; Switching tabs stops following process output in selected window Dan McCarthy
2024-01-04 6:09 ` Eli Zaretskii
2024-01-04 10:23 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-04 10:42 ` Eli Zaretskii
2024-01-04 17:07 ` Juri Linkov
2024-01-04 17:48 ` Eli Zaretskii
2024-01-05 9:24 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-06 17:36 ` Juri Linkov
2024-01-07 14:54 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-07 16:45 ` Juri Linkov
2024-01-08 8:55 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-09 17:23 ` Juri Linkov
2024-01-07 16:49 ` Juri Linkov
2024-01-09 17:25 ` Juri Linkov
2024-01-10 8:37 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-10 17:08 ` Juri Linkov
2024-01-11 9:14 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-12 7:37 ` Juri Linkov
2024-01-13 10:38 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-13 15:02 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-13 18:20 ` Juri Linkov
2024-01-14 8:13 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-14 18:53 ` Juri Linkov
2024-01-15 10:24 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-15 17:53 ` Juri Linkov
2024-01-16 10:19 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-16 16:30 ` Juri Linkov
2024-01-17 11:42 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-17 16:36 ` Juri Linkov
2024-01-18 10:47 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-18 16:50 ` Juri Linkov
2024-01-20 9:44 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-22 7:43 ` Juri Linkov
2024-01-23 9:30 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-24 7:54 ` Juri Linkov
2024-01-25 9:39 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-25 17:46 ` Juri Linkov
2024-01-26 9:56 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-01-27 17:58 ` Juri Linkov
2024-01-28 10:06 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-05 7:17 ` Juri Linkov
2024-02-06 10:34 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-06 18:03 ` Juri Linkov
2024-02-15 7:34 ` Juri Linkov
2024-02-16 9:40 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-18 7:35 ` Juri Linkov
2024-02-19 9:42 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2024-02-20 17:44 ` Juri Linkov
2024-03-04 9:40 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-03-05 17:27 ` Juri Linkov
2024-03-05 17:45 ` Eli Zaretskii
2024-03-06 18:03 ` Juri Linkov
2024-03-09 8:35 ` Eli Zaretskii
2024-03-17 17:57 ` Juri Linkov
2024-03-05 17:37 ` Juri Linkov
2024-03-06 10:19 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-03-06 17:57 ` Juri Linkov
2024-03-08 9:21 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-03-10 17:23 ` Juri Linkov
2024-03-11 9:13 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-09 6:53 ` Juri Linkov
2024-04-09 7:36 ` Eli Zaretskii
2024-04-09 9:22 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-09 16:40 ` Juri Linkov
2024-04-10 8:47 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-10 17:35 ` Juri Linkov
2024-04-11 9:16 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-12 6:30 ` Juri Linkov
2024-04-12 8:18 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-12 16:20 ` Juri Linkov
2024-04-15 9:21 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-21 6:59 ` Juri Linkov
2024-04-21 8:56 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-22 6:46 ` Juri Linkov
2024-04-21 9:27 ` Eli Zaretskii
2024-04-22 6:40 ` Juri Linkov
2024-04-22 7:00 ` Eli Zaretskii
2024-04-22 16:36 ` Juri Linkov
2024-04-22 19:22 ` Eli Zaretskii
2024-03-15 9:38 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-03-17 17:47 ` Juri Linkov
2024-03-18 10:13 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-03-15 10:11 ` Andreas Schwab
2024-03-15 10:56 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-04 17:27 ` Juri Linkov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3fe7e4b4-bc9a-4303-a87f-a360765c597f@gmx.at \
--to=bug-gnu-emacs@gnu.org \
--cc=68235@debbugs.gnu.org \
--cc=juri@linkov.net \
--cc=rudalics@gmx.at \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).