* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
@ 2024-01-03 20:48 Dan McCarthy
2024-01-04 6:09 ` Eli Zaretskii
0 siblings, 1 reply; 85+ messages in thread
From: Dan McCarthy @ 2024-01-03 20:48 UTC (permalink / raw)
To: 68235
[-- Attachment #1: Type: text/plain, Size: 7109 bytes --]
With two tabs open, start a compilation or some other long-running
job. Move point to the bottom with M->. Switch to the other tab, then
switch back. Point will now be fixed at wherever it was when you first
switched.
If the compilation window isn't selected, however, switching tabs does
what I expected: point continues to be at the bottom, following the
output as it appears.
In GNU Emacs 29.1.90 (build 1, x86_64-pc-linux-gnu, GTK+ Version
2.24.33, cairo version 1.16.0) of 2023-10-23 built on solstice
Windowing system distributor 'The X.Org Foundation', version 11.0.12101007
System Description: Debian GNU/Linux 12 (bookworm)
Configured using:
'configure --with-dbus'
Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG
LIBSELINUX LIBXML2 MODULES NOTIFY INOTIFY PDUMPER PNG SECCOMP SOUND
SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINPUT2 XPM
GTK2 ZLIB
Important settings:
value of $LANG: en_US.UTF-8
locale-coding-system: utf-8-unix
Major mode: Shell
Minor modes in effect:
bug-reference-mode: t
desktop-save-mode: t
global-git-commit-mode: t
magit-auto-revert-mode: t
server-mode: t
shell-dirtrack-mode: t
hexl-follow-ascii: t
projectile-mode: t
comint-fontify-input-mode: t
tooltip-mode: t
global-eldoc-mode: t
electric-indent-mode: t
mouse-wheel-mode: t
tab-bar-history-mode: t
tab-bar-mode: t
file-name-shadow-mode: t
global-font-lock-mode: t
font-lock-mode: t
column-number-mode: t
line-number-mode: t
indent-tabs-mode: t
transient-mark-mode: t
auto-composition-mode: t
auto-encryption-mode: t
auto-compression-mode: t
Load-path shadows:
~/emacs-lisp/ecf-mode/dcm-general hides ~/emacs-lisp/dcm-general
~/emacs-lisp/c-eldoc hides
/home/dan/.emacs.d/elpa/c-eldoc-20201004.2347/c-eldoc
~/emacs-lisp/connection hides
/home/dan/.emacs.d/elpa/connection-20191111.446/connection
~/emacs-lisp/link hides /home/dan/.emacs.d/elpa/link-20191111.446/link
/home/dan/.emacs.d/elpa/transient-20231019.1421/transient hides
/home/dan/build/emacs-29.1.90/lisp/transient
~/emacs-lisp/css-mode hides
/home/dan/build/emacs-29.1.90/lisp/textmodes/css-mode
/home/dan/.emacs.d/elpa/csharp-mode-20221126.2005/csharp-mode hides
/home/dan/build/emacs-29.1.90/lisp/progmodes/csharp-mode
/home/dan/.emacs.d/elpa/dictionary-20201001.1727/dictionary hides
/home/dan/build/emacs-29.1.90/lisp/net/dictionary
~/emacs-lisp/greek hides /home/dan/build/emacs-29.1.90/lisp/language/greek
Features:
(shadow sort mail-extr emacsbug vc-svn pcmpl-gnu sgml-mode facemenu dom
dabbrev cus-edit cus-start mm-archive gnutls network-stream url-cache
url-http url-auth url-gw nsm term/xterm xterm vc git-rebase mule-diag
python emacs-news-mode pcmpl-linux ffap magit-patch display-line-numbers
rect tabify man tramp-cmds doc-view jka-compr js c-ts-common find-dired
rfc2104 noutline outline view cl-print make-mode image-mode exif
cal-move shortdoc help-fns radix-tree pp wid-edit descr-text pcmpl-unix
conf-mode misearch multi-isearch ruler-mode hl-line vc-hg vc-bzr
goto-addr etags fileloop generator xref magit-extras magit-svn
face-remap sh-script smie treesit executable tramp-cache time-stamp
tramp-sh dired-aux term disp-table ehelp mule-util diary-lib
diary-loaddefs cal-menu calendar cal-loaddefs bug-reference desktop
frameset cua-base cus-load clang-format+ clang-format acme-search quack
cmuscheme scheme advice clone-log-mode scc-mode 608-unicode ecf-mode
dcm-general tar-mode arc-mode archive-mode notifications dbus xml
dictionary link connection magit-submodule magit-blame magit-stash
magit-reflog magit-bisect magit-push magit-pull magit-fetch magit-clone
magit-remote magit-commit magit-sequence magit-notes magit-worktree
magit-tag magit-merge magit-branch magit-reset magit-files magit-refs
magit-status magit magit-repos magit-apply magit-wip magit-log
magit-diff smerge-mode diff git-commit log-edit message sendmail
yank-media puny dired dired-loaddefs rfc822 mml mml-sec epa epg rfc6068
epg-config gnus-util mm-decode mm-bodies mm-encode mail-parse rfc2231
rfc2047 rfc2045 mm-util ietf-drums mail-prsvr mailabbrev mail-utils
gmm-utils mailheader pcvs-util add-log magit-core magit-autorevert
autorevert filenotify magit-margin magit-transient magit-process
with-editor server magit-mode derived transient cl-extra edmacro kmacro
help-mode magit-git magit-base which-func vc-git diff-mode easy-mmode
vc-dispatcher ido magit-section cursor-sensor crm dash compat tramp
tramp-loaddefs trampver tramp-integration files-x tramp-compat shell
pcomplete parse-time iso8601 time-date format-spec vanc-init bindat
vanc-mode hexl php-mode mode-local find-func imenu speedbar ezimage
dframe php-face php rx php-project projectile lisp-mnt grep ibuf-ext
ibuffer ibuffer-loaddefs flymake-proc flymake project compile
text-property-search comint ansi-osc ansi-color ring warnings icons
thingatpt css-mode cc-mode cc-fonts cc-guess cc-menus cc-cmds cc-styles
cc-align cc-engine cc-vars cc-defs cl finder-inf archive-rpm-autoloads
c-eldoc-autoloads clang-format-autoloads indent-tools-autoloads
hydra-autoloads lv-autoloads magit-svn-autoloads magit-autoloads pcase
magit-section-autoloads git-commit-autoloads dash-autoloads
php-mode-autoloads projectile-autoloads pydoc-autoloads s-autoloads
tramp-term-autoloads transient-autoloads with-editor-autoloads info
compat-autoloads yafolding-autoloads yaml-mode-autoloads
yaml-pro-autoloads yaml-autoloads package browse-url url url-proxy
url-privacy url-expand url-methods url-history url-cookie
generate-lisp-file url-domsuf url-util mailcap url-handlers url-parse
auth-source cl-seq eieio eieio-core cl-macs password-cache json subr-x
map byte-opt gv bytecomp byte-compile url-vars cl-loaddefs cl-lib rmc
iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook
vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win
term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe
tabulated-list replace newcomment text-mode lisp-mode prog-mode register
page tab-bar menu-bar rfn-eshadow isearch easymenu timer select
scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors
frame minibuffer nadvice seq simple cl-generic indonesian philippine
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese composite emoji-zwj charscript
charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure
cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp
files window text-properties overlay sha1 md5 base64 format env
code-pages mule custom widget keymap hashtable-print-readable backquote
threads dbusbind inotify dynamic-setting system-font-setting
font-render-setting cairo move-toolbar gtk x-toolkit xinput2 x multi-tty
make-network-process emacs)
Memory information:
((conses 16 2656374 298496)
(symbols 48 52033 4)
(strings 32 391623 32488)
(string-bytes 1 14644301)
(vectors 16 100900)
(vector-slots 8 2407891 129759)
(floats 8 246 538)
(intervals 56 300877 27375)
(buffers 976 170))
[-- Attachment #2: Type: text/html, Size: 7624 bytes --]
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Eli Zaretskii @ 2024-01-04 6:09 UTC (permalink / raw)
To: Dan McCarthy, martin rudalics; +Cc: 68235
> From: Dan McCarthy <daniel.c.mccarthy@gmail.com>
> Date: Wed, 3 Jan 2024 15:48:21 -0500
>
> With two tabs open, start a compilation or some other long-running
> job. Move point to the bottom with M->. Switch to the other tab, then
> switch back. Point will now be fixed at wherever it was when you first
> switched.
>
> If the compilation window isn't selected, however, switching tabs does
> what I expected: point continues to be at the bottom, following the
> output as it appears.
Does playing with the value of switch-to-buffer-preserve-window-point
change anything in what you see?
Martin, is saving and restoring window configuration supposed to
preserve the output following in *compilation* windows?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 2 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-04 10:23 UTC (permalink / raw)
To: Eli Zaretskii, Dan McCarthy; +Cc: 68235
> Martin, is saving and restoring window configuration supposed to
> preserve the output following in *compilation* windows?
It's supposed to preserve markers other than in the selected window. So
it will depend on whether the *compilation* window gets selected. But
note that 'current-window-configuration' uses
'window-point-insertion-type' for the point marker which by default
stays behind inserted text (IIRC).
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
1 sibling, 0 replies; 85+ messages in thread
From: Eli Zaretskii @ 2024-01-04 10:42 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, 68235
> Date: Thu, 4 Jan 2024 11:23:45 +0100
> Cc: 68235@debbugs.gnu.org
> From: martin rudalics <rudalics@gmx.at>
>
> > Martin, is saving and restoring window configuration supposed to
> > preserve the output following in *compilation* windows?
>
> It's supposed to preserve markers other than in the selected window. So
> it will depend on whether the *compilation* window gets selected. But
> note that 'current-window-configuration' uses
> 'window-point-insertion-type' for the point marker which by default
> stays behind inserted text (IIRC).
So I guess what the OP sees is expected behavior, or am I missing
something?
In general, IME the fact that a window follows the end of compilation
output is indeed very ephemeral in Emacs, so hearing that it happens
as result of tab-bing away doesn't surprise me at all.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
1 sibling, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-04 17:07 UTC (permalink / raw)
To: martin rudalics; +Cc: Dan McCarthy, Eli Zaretskii, 68235
>> Martin, is saving and restoring window configuration supposed to
>> preserve the output following in *compilation* windows?
>
> It's supposed to preserve markers other than in the selected window. So
> it will depend on whether the *compilation* window gets selected. But
> note that 'current-window-configuration' uses
> 'window-point-insertion-type' for the point marker which by default
> stays behind inserted text (IIRC).
Everything works nicely, and point follows the output,
when this code is removed from 'tab-bar-select-tab':
;; set-window-configuration does not restore the value of
;; point in the current buffer, so restore it separately.
(when (and (markerp wc-point)
(marker-buffer wc-point)
;; FIXME: After dired-revert, marker relocates to 1.
;; window-configuration restores point to global point
;; in this dired buffer, not to its window point,
;; but this is slightly better than 1.
;; Maybe better to save dired-filename in each window?
(not (eq 1 (marker-position wc-point))))
(goto-char wc-point))
The problem is that I still can't figure out in what cases point should be
restored manually. For example, when a buffer was reverted in another
window configuration, then better to restore point manually to override
an invalidated marker?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Eli Zaretskii @ 2024-01-04 17:48 UTC (permalink / raw)
To: Juri Linkov; +Cc: rudalics, 68235, daniel.c.mccarthy
> From: Juri Linkov <juri@linkov.net>
> Cc: Eli Zaretskii <eliz@gnu.org>, Dan McCarthy
> <daniel.c.mccarthy@gmail.com>, 68235@debbugs.gnu.org
> Date: Thu, 04 Jan 2024 19:07:39 +0200
>
> Everything works nicely, and point follows the output,
> when this code is removed from 'tab-bar-select-tab':
>
> ;; set-window-configuration does not restore the value of
> ;; point in the current buffer, so restore it separately.
> (when (and (markerp wc-point)
> (marker-buffer wc-point)
> ;; FIXME: After dired-revert, marker relocates to 1.
> ;; window-configuration restores point to global point
> ;; in this dired buffer, not to its window point,
> ;; but this is slightly better than 1.
> ;; Maybe better to save dired-filename in each window?
> (not (eq 1 (marker-position wc-point))))
> (goto-char wc-point))
Maybe we should make exceptions in buffers like *completions*?
In general, restoring point is a good idea.
> The problem is that I still can't figure out in what cases point should be
> restored manually.
When the buffer was shown in another window, I think. Martin might
have a definite answer.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-05 9:24 UTC (permalink / raw)
To: Eli Zaretskii, Juri Linkov; +Cc: daniel.c.mccarthy, 68235
>> Everything works nicely, and point follows the output,
>> when this code is removed from 'tab-bar-select-tab':
>>
>> ;; set-window-configuration does not restore the value of
>> ;; point in the current buffer, so restore it separately.
>> (when (and (markerp wc-point)
>> (marker-buffer wc-point)
>> ;; FIXME: After dired-revert, marker relocates to 1.
>> ;; window-configuration restores point to global point
>> ;; in this dired buffer, not to its window point,
>> ;; but this is slightly better than 1.
>> ;; Maybe better to save dired-filename in each window?
>> (not (eq 1 (marker-position wc-point))))
>> (goto-char wc-point))
>
> Maybe we should make exceptions in buffers like *completions*?
>
> In general, restoring point is a good idea.
>
>> The problem is that I still can't figure out in what cases point should be
>> restored manually.
>
> When the buffer was shown in another window, I think. Martin might
> have a definite answer.
I think the snippet above should be executed iff the buffer's
'window-point-insertion-type' is nil.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-06 17:36 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>>> Everything works nicely, and point follows the output,
>>> when this code is removed from 'tab-bar-select-tab':
>>>
>>> ;; set-window-configuration does not restore the value of
>>> ;; point in the current buffer, so restore it separately.
>>> (when (and (markerp wc-point)
>>> (marker-buffer wc-point)
>>> ;; FIXME: After dired-revert, marker relocates to 1.
>>> ;; window-configuration restores point to global point
>>> ;; in this dired buffer, not to its window point,
>>> ;; but this is slightly better than 1.
>>> ;; Maybe better to save dired-filename in each window?
>>> (not (eq 1 (marker-position wc-point))))
>>> (goto-char wc-point))
>>
>> Maybe we should make exceptions in buffers like *completions*?
>>
>> In general, restoring point is a good idea.
>>
>>> The problem is that I still can't figure out in what cases point should be
>>> restored manually.
>>
>> When the buffer was shown in another window, I think. Martin might
>> have a definite answer.
>
> I think the snippet above should be executed iff the buffer's
> 'window-point-insertion-type' is nil.
window-point-insertion-type is nil by default, but I'd definitely want
point to follow the output, that means not using the snippet above.
OTOH, this snippet can't be removed because it supports tab-local point.
For example, open the same buffer in two tabs and move point to another
place. Like with window-point, the position of point in tabs should be
preserved as well. So probably we need to add special-casing for comint
buffers to follow the output.
But could you explain why such special-casing is not needed for
non-selected windows? How set-window-configuration does the right
thing for points in non-selected windows to follow the output?
Maybe it's possible to do the same with point in the selected window?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-07 16:49 ` Juri Linkov
0 siblings, 2 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-07 14:54 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> window-point-insertion-type is nil by default, but I'd definitely want
> point to follow the output, that means not using the snippet above.
But 'window-point-insertion-type' is buffer-locally t in all sorts of
compilation buffers and that is the subject of this bug report. Right?
> OTOH, this snippet can't be removed because it supports tab-local point.
> For example, open the same buffer in two tabs and move point to another
> place. Like with window-point, the position of point in tabs should be
> preserved as well. So probably we need to add special-casing for comint
> buffers to follow the output.
And I meant to use the buffer-local value of
'window-point-insertion-type' as insertion type for 'wc-point'.
> But could you explain why such special-casing is not needed for
> non-selected windows? How set-window-configuration does the right
> thing for points in non-selected windows to follow the output?
> Maybe it's possible to do the same with point in the selected window?
For an unselected window, 'set-window-configuration' uses that window's
point marker from the saved configuration and that one should follow
inserted text according to the value of 'window-point-insertion-type' in
that window's buffer. For the selected window, that window's buffer's
point is "usually" unchanged from where it was just before restoring the
configuration.
In either case I doubt that the 'set-window-configuration' code does
anything wrong here. IIRC there were problems in the dired buffer
reverting code, namely that it did not preserve the position of point
reasonably and you tried to handle that via 'wc-point'.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-07 16:49 ` Juri Linkov
1 sibling, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-07 16:45 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> window-point-insertion-type is nil by default, but I'd definitely want
>> point to follow the output, that means not using the snippet above.
>
> But 'window-point-insertion-type' is buffer-locally t in all sorts of
> compilation buffers and that is the subject of this bug report. Right?
Thanks, now I see that 'comint-mode', 'compilation-mode' and some
other modes set buffer-local 'window-point-insertion-type' to t.
> And I meant to use the buffer-local value of
> 'window-point-insertion-type' as insertion type for 'wc-point'.
Ah, now I see that 'copy-marker' supports the argument for
'window-point-insertion-type'.
>> But could you explain why such special-casing is not needed for
>> non-selected windows? How set-window-configuration does the right
>> thing for points in non-selected windows to follow the output?
>> Maybe it's possible to do the same with point in the selected window?
>
> For an unselected window, 'set-window-configuration' uses that window's
> point marker from the saved configuration and that one should follow
> inserted text according to the value of 'window-point-insertion-type' in
> that window's buffer. For the selected window, that window's buffer's
> point is "usually" unchanged from where it was just before restoring the
> configuration.
Indeed, the difference between selected/non-selected windows is here:
/* Save w's value of point in the window configuration. If w
is the selected window, then get the value of point from
the buffer; pointm is garbage in the selected window. */
if (EQ (window, selected_window))
p->pointm = build_marker (XBUFFER (w->contents),
BUF_PT (XBUFFER (w->contents)),
BUF_PT_BYTE (XBUFFER (w->contents)));
else
p->pointm = Fcopy_marker (w->pointm, Qnil);
p->old_pointm = Fcopy_marker (w->old_pointm, Qnil);
XMARKER (p->pointm)->insertion_type = window_point_insertion_type;
XMARKER (p->old_pointm)->insertion_type = window_point_insertion_type;
So the complete fix is just in 1 line:
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 7d491dc2f38..80cf94016b8 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -1302,7 +1302,7 @@ tab-bar--tab
(ws . ,(window-state-get
(frame-root-window (or frame (selected-frame))) 'writable))
(wc . ,(current-window-configuration))
- (wc-point . ,(point-marker))
+ (wc-point . ,(copy-marker (window-point) window-point-insertion-type))
(wc-bl . ,bl)
(wc-bbl . ,bbl)
,@(when tab-bar-history-mode
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-07 16:49 ` Juri Linkov
2024-01-09 17:25 ` Juri Linkov
1 sibling, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-07 16:49 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> In either case I doubt that the 'set-window-configuration' code does
> anything wrong here. IIRC there were problems in the dired buffer
> reverting code, namely that it did not preserve the position of point
> reasonably and you tried to handle that via 'wc-point'.
The dired revert is a separate problem unrelated to this bug report.
But still we need to remove this ad-hoc condition:
(when (and (markerp wc-point)
(marker-buffer wc-point)
;; FIXME: After dired-revert, marker relocates to 1.
;; window-configuration restores point to global point
;; in this dired buffer, not to its window point,
;; but this is slightly better than 1.
;; Maybe better to save dired-filename in each window?
(not (eq 1 (marker-position wc-point))))
(goto-char wc-point))
Checking for (not (eq 1 (marker-position wc-point)))
is the wrong thing to do because it also affects non-dired buffers.
But I have no idea how to handle dired revert that moves the marker
to the top of the buffer. Adding special-handling for dired here
also doesn't look right.
Maybe it's possible to mark the marker as invalidated after reverting?
Then could check for the invalidated status here.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-08 8:55 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> Indeed, the difference between selected/non-selected windows is here:
>
> /* Save w's value of point in the window configuration. If w
> is the selected window, then get the value of point from
> the buffer; pointm is garbage in the selected window. */
This is one difference among many. Fset_window_configuration also deals
with the cases that the selected window and/or the current buffer
changed in between saving and restoring the configuration.
> + (wc-point . ,(copy-marker (window-point) window-point-insertion-type))
I didn't look but note that the window's buffer must be current here to
get the buffer-local value of 'window-point-insertion-type'.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 0 replies; 85+ messages in thread
From: Juri Linkov @ 2024-01-09 17:23 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
close 68235 30.0.50
thanks
>> + (wc-point . ,(copy-marker (window-point) window-point-insertion-type))
>
> I didn't look but note that the window's buffer must be current here to
> get the buffer-local value of 'window-point-insertion-type'.
Thanks for the notice. This looks correct since the buffer
is expected to be current.
This change took so unexpected shape that I'm unsure about fixing this
on the emacs-29 branch. So now pushed to master, and closed.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-09 17:25 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> The dired revert is a separate problem unrelated to this bug report.
> But still we need to remove this ad-hoc condition:
>
> (when (and (markerp wc-point)
> (marker-buffer wc-point)
> ;; FIXME: After dired-revert, marker relocates to 1.
> ;; window-configuration restores point to global point
> ;; in this dired buffer, not to its window point,
> ;; but this is slightly better than 1.
> ;; Maybe better to save dired-filename in each window?
> (not (eq 1 (marker-position wc-point))))
> (goto-char wc-point))
>
> Checking for (not (eq 1 (marker-position wc-point)))
> is the wrong thing to do because it also affects non-dired buffers.
>
> But I have no idea how to handle dired revert that moves the marker
> to the top of the buffer. Adding special-handling for dired here
> also doesn't look right.
>
> Maybe it's possible to mark the marker as invalidated after reverting?
> Then could check for the invalidated status here.
Actually the problem is somewhere else because after dired revert
point is relocated to the top of the buffer even in non-selected windows
in window-configuration. So trying to manually preserve point
in the selected window is not of much help. Therefore I just
removed the special-handling of dired revert in master.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-10 8:37 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> Actually the problem is somewhere else because after dired revert
> point is relocated to the top of the buffer even in non-selected windows
> in window-configuration. So trying to manually preserve point
> in the selected window is not of much help. Therefore I just
> removed the special-handling of dired revert in master.
Do you remember the bug this was supposed to fix?
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-02-04 17:27 ` Juri Linkov
0 siblings, 2 replies; 85+ messages in thread
From: Juri Linkov @ 2024-01-10 17:08 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> Actually the problem is somewhere else because after dired revert
>> point is relocated to the top of the buffer even in non-selected windows
>> in window-configuration. So trying to manually preserve point
>> in the selected window is not of much help. Therefore I just
>> removed the special-handling of dired revert in master.
>
> Do you remember the bug this was supposed to fix?
The dedicated bug report is this:
bug#33871: Revert Dired window saved in window configuration
Also something related was discussed in:
bug#27243: dired-auto-revert-buffer jumps point to beginning of buffer
bug#33458: dired loses position when reverted from outside place
and maybe more.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-02-04 17:27 ` Juri Linkov
1 sibling, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-11 9:14 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>>> Actually the problem is somewhere else because after dired revert
>>> point is relocated to the top of the buffer even in non-selected windows
>>> in window-configuration. So trying to manually preserve point
>>> in the selected window is not of much help. Therefore I just
>>> removed the special-handling of dired revert in master.
>>
>> Do you remember the bug this was supposed to fix?
>
> The dedicated bug report is this:
>
> bug#33871: Revert Dired window saved in window configuration
>
> Also something related was discussed in:
>
> bug#27243: dired-auto-revert-buffer jumps point to beginning of buffer
> bug#33458: dired loses position when reverted from outside place
>
> and maybe more.
IIUC 'dired-save-positions' and 'dired-restore-positions' are supposed
to handle these bug scenarios in "normal" (user driven) dired reverting.
Do they? If so, why does saving and restoring a window configuration
not use them?
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-12 7:37 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>>>> Actually the problem is somewhere else because after dired revert
>>>> point is relocated to the top of the buffer even in non-selected windows
>>>> in window-configuration. So trying to manually preserve point
>>>> in the selected window is not of much help. Therefore I just
>>>> removed the special-handling of dired revert in master.
>>>
>>> Do you remember the bug this was supposed to fix?
>>
>> The dedicated bug report is this:
>>
>> bug#33871: Revert Dired window saved in window configuration
>>
>> Also something related was discussed in:
>>
>> bug#27243: dired-auto-revert-buffer jumps point to beginning of buffer
>> bug#33458: dired loses position when reverted from outside place
>>
>> and maybe more.
>
> IIUC 'dired-save-positions' and 'dired-restore-positions' are supposed
> to handle these bug scenarios in "normal" (user driven) dired reverting.
> Do they? If so, why does saving and restoring a window configuration
> not use them?
This is because 'dired-save-positions' and 'dired-restore-positions'
can't update positions in all existing window configurations
that are not yet garbage-collected.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-13 10:38 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> IIUC 'dired-save-positions' and 'dired-restore-positions' are supposed
>> to handle these bug scenarios in "normal" (user driven) dired reverting.
>> Do they? If so, why does saving and restoring a window configuration
>> not use them?
>
> This is because 'dired-save-positions' and 'dired-restore-positions'
> can't update positions in all existing window configurations
> that are not yet garbage-collected.
So we'd need a persistent window parameter
(1) whose value is set to dired's file name at point in
'current-window-configuration'
(2) and allows to restore the window's point appropriately in
'set-window-configuration'.
For (1) we have two possibilities. Either dired itself maintains it
every time its window point changes which is very tedious. Or we make
the parameter a function that is run by 'current-window-configuration'
here:
/* If the window has a value for the parameter,
save it. */
p->window_parameters = Fcons (Fcons (XCAR (par), XCDR (par)),
p->window_parameters);
When XCAR (par) is a function, that function would store the current
file name at the window's point in the cdr of the saved parameter. This
would mean to offer one more facility for people to shoot themselves in
their foot.
For (2) we can either provide a hook that 'set-window-configuration'
runs or in
/* Always restore a non-nil value. */
Fset_window_parameter (window, XCAR (pers), XCDR (pers));
restore the saved position when XCAR (pers) is a function - the file
name would be in XCDR (pers). Not for the faint of heart either,
because of the current buffer/selected window dances in
'set-window-configuration'.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-13 15:02 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> So we'd need a persistent window parameter
>
> (1) whose value is set to dired's file name at point in
> 'current-window-configuration'
>
> (2) and allows to restore the window's point appropriately in
> 'set-window-configuration'.
I now think that we need two or three hooks:
- 'pre-current-window-configuration-functions', an abnormal hook that
receives one argument - the frame whose configuration shall be
recorded. 'dired' has to set a persistent window parameter, for each
window on that frame it uses, whose value is whatever is needed to
restore the present state of the buffer in that window.
- 'pre-set-window-configuration', an abnormal hook that receives one
argument - the frame whose configuration is about to be restored.
'dired' would have to save away its parameter values of all windows
it currently owns on that frame.
- 'post-set-window-configuration-functions', an abnormal hook that
receives one argument - the frame whose configuration was just
restored. 'dired' would have to examine its persistent parameters of
all windows on that frame and restore the previous state for them
unless maybe a parameter in 'pre-set-window-configuration' tells it
not to do that.
The latter would be responsible for resolving conflicts like what to do
when the same dired buffer is shown in the selected window of the saved
and current configuration but their points are on different file names.
Whether 'pre-set-window-configuration' is really need for that or some
simpler approach would suffice is something I can't tell yet. Also
considering the case where the same directory is shown in a non-selected
window with saved and current points on different file names and the
saved name's file has been deleted meanwhile.
For dired the value to save in a parameter would at least be that of the
file name point is on - maybe also the number of that line. It's
completely up to the major mode like 'dired' to store there whatever it
wants.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-13 18:20 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> So we'd need a persistent window parameter
>>
>> (1) whose value is set to dired's file name at point in
>> 'current-window-configuration'
>>
>> (2) and allows to restore the window's point appropriately in
>> 'set-window-configuration'.
>
> I now think that we need two or three hooks:
>
> - 'pre-current-window-configuration-functions', an abnormal hook that
> receives one argument - the frame whose configuration shall be
> recorded. 'dired' has to set a persistent window parameter, for each
> window on that frame it uses, whose value is whatever is needed to
> restore the present state of the buffer in that window.
Actually one hook 'pre-current-window-configuration-functions' should be
sufficient. Like there is only 'isearch-push-state-function' that can
be used to save a lambda that can restore the current window-start, then
on going back this lambda is called and restores the previous window-start.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-14 8:13 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> Actually one hook 'pre-current-window-configuration-functions' should be
> sufficient. Like there is only 'isearch-push-state-function' that can
> be used to save a lambda that can restore the current window-start, then
> on going back this lambda is called and restores the previous window-start.
IIUC we have to move some point to some position somewhere in
'set-window-configuration'. Who would trigger that? Calling a function
from within 'set-window-configuration' seems hairy to me.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-14 18:53 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> Actually one hook 'pre-current-window-configuration-functions' should be
>> sufficient. Like there is only 'isearch-push-state-function' that can
>> be used to save a lambda that can restore the current window-start, then
>> on going back this lambda is called and restores the previous window-start.
>
> IIUC we have to move some point to some position somewhere in
> 'set-window-configuration'. Who would trigger that? Calling a function
> from within 'set-window-configuration' seems hairy to me.
I see no other way than calling this hook from 'set-window-configuration'.
The problem is that running the hook afterwards would be too late.
What I mean here is the annoying problem that when a buffer is killed,
then on restoring a window configuration its window is deleted.
This case could be fixed here with the same change as well.
When a window parameter will contain a lambda called from
'set-window-configuration', this lambda could do something useful
to preserve the window whose buffer was killed. Something like
displaying a placeholder with a button to restore the buffer.
The same window parameter could be used in a window with
a reverted dired buffer to move point to a previous file name.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-15 10:24 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> IIUC we have to move some point to some position somewhere in
>> 'set-window-configuration'. Who would trigger that? Calling a function
>> from within 'set-window-configuration' seems hairy to me.
>
> I see no other way than calling this hook from 'set-window-configuration'.
Agreed. But I meant to use one or two hooks 'set-window-configuration'
would call.
> The problem is that running the hook afterwards would be too late.
> What I mean here is the annoying problem that when a buffer is killed,
> then on restoring a window configuration its window is deleted.
If there is only one window left, we have to show another buffer in it.
> This case could be fixed here with the same change as well.
> When a window parameter will contain a lambda called from
> 'set-window-configuration', this lambda could do something useful
> to preserve the window whose buffer was killed. Something like
> displaying a placeholder with a button to restore the buffer.
We'd have to handle that here
/* Scan dead buffer windows. */
for (; CONSP (dead_buffer_windows);
dead_buffer_windows = XCDR (dead_buffer_windows))
{
window = XCAR (dead_buffer_windows);
if (WINDOW_LIVE_P (window) && !EQ (window, FRAME_ROOT_WINDOW (f)))
delete_deletable_window (window);
}
which will be a bit hairy to be on the safe side. This could not be
solved with a 'post-set-window-configuration-hook' because at that time
the window would have been deleted already.
> The same window parameter could be used in a window with
> a reverted dired buffer to move point to a previous file name.
Finding the right place to do that within 'set-window-configuration'
might be non-trivial. Here using 'post-set-window-configuration-hook'
would be probably better.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-15 17:53 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> /* Scan dead buffer windows. */
> for (; CONSP (dead_buffer_windows);
> dead_buffer_windows = XCDR (dead_buffer_windows))
> {
> window = XCAR (dead_buffer_windows);
> if (WINDOW_LIVE_P (window) && !EQ (window, FRAME_ROOT_WINDOW (f)))
> delete_deletable_window (window);
> }
> which will be a bit hairy to be on the safe side. This could not be
> solved with a 'post-set-window-configuration-hook' because at that time
> the window would have been deleted already.
Maybe then at least would be possible to display a message
that will list the names of dead buffers. That might help
the users to restore the buffers killed accidentally.
OTOH, this is not needed in case of using the tab-bar
because before switching to the tab with the killed buffer,
the name of the killed buffer is visible as the tab name.
>> The same window parameter could be used in a window with
>> a reverted dired buffer to move point to a previous file name.
>
> Finding the right place to do that within 'set-window-configuration'
> might be non-trivial. Here using 'post-set-window-configuration-hook'
> would be probably better.
Or maybe instead of 'post-set-window-configuration-hook' it's easy
to call a post-processing function after 'set-window-configuration'.
BTW, there is another problem when the same buffer is displayed
in two tabs/window-configurations. For example, in the first tab
point is near the top of the buffer, and in the second tab point
is near the bottom of the same buffer. The user edits the top
of the buffer in the first tab and saves writable window states
to the desktop.
At this point, all positions saved in the second tab are wrong
because writable window states save point instead of the marker.
One workaround is before saving the desktop to revisit all tabs
that will update points from markers in writable window states.
But this won't help too much because there is still the same
problem after restoring the desktop. When the desktop is
restored with right positions of all points, and the user
edits the top of the buffer in the first tab before visiting
the second tab, then after switching to the second tab
point will be at wrong position, because the tab is
restored from window states.
Here the same workaround is possible: to revisit all tabs after
restoring the desktop, that will create window configurations
from window states.
But automatically revisiting all tabs is too harmful
because some tabs might lost their names: when a buffer
was killed, then the tab will be renamed to the name
of the buffer that replaces the killed buffer,
and the user loses the hint what buffer was displayed
in the tab originally.
To solve the problem of outdated points/markers in window states
maybe in addition to point, window states could also store
context strings like bookmark.el does?
I don't know how reliable these bookmark contexts are.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-16 10:19 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> Maybe then at least would be possible to display a message
> that will list the names of dead buffers. That might help
> the users to restore the buffers killed accidentally.
The name of a killed buffer is nil as long as the buffer object has not
been collected. But would buffer names be of great use anyway? Isn't it
the name of the file, the info node, or the directory name the buffer
was visiting that counts?
> OTOH, this is not needed in case of using the tab-bar
> because before switching to the tab with the killed buffer,
> the name of the killed buffer is visible as the tab name.
Does the tab-bar code store the buffer name separately? But again -
that name won't help you much anyway once the buffer was killed.
Incidentally, the name of the file a killed buffer was visiting will be
available as long as the buffer object exists. Do you mean that?
> Or maybe instead of 'post-set-window-configuration-hook' it's easy
> to call a post-processing function after 'set-window-configuration'.
'post-set-window-configuration-functions' that's what I meant earlier -
with the frame as argument. But if a buffer is dead now, this won't
help in neither regard. First and foremost, 'set-window-configuration'
must be able to deal with dead buffers in a safe fashion. We could,
optionally, display *scratch* in all windows that have a dead buffer
now. Still 'post-set-window-configuration-functions' (and also the
desktop routines) would have to know enough about how to restore the
earlier state. This is something only a buffer's major mode itself may
know.
> BTW, there is another problem when the same buffer is displayed
> in two tabs/window-configurations. For example, in the first tab
> point is near the top of the buffer, and in the second tab point
> is near the bottom of the same buffer. The user edits the top
> of the buffer in the first tab and saves writable window states
> to the desktop.
>
> At this point, all positions saved in the second tab are wrong
> because writable window states save point instead of the marker.
But 'window--state-get-1' does
(let ((point (window-point window))
which should reliable give the value of point in window and then
(point . ,(if writable
point
(with-current-buffer buffer
(copy-marker point
(buffer-local-value
'window-point-insertion-type
buffer)))))
'window--state-put-2' OTOH does
(set-window-point window (cdr (assq 'point state))))
Do you see the problem here?
> One workaround is before saving the desktop to revisit all tabs
> that will update points from markers in writable window states.
>
> But this won't help too much because there is still the same
> problem after restoring the desktop. When the desktop is
> restored with right positions of all points, and the user
> edits the top of the buffer in the first tab before visiting
> the second tab, then after switching to the second tab
> point will be at wrong position, because the tab is
> restored from window states.
So IIUC you mean that restoring the desktop (writable) does things
differently than restoring tabs (non-writable)? Can you tell me more
precisely the order of desktop/tab-bar operations involved in that
scenario?
> Here the same workaround is possible: to revisit all tabs after
> restoring the desktop, that will create window configurations
> from window states.
I'd still have to understand: A non-writable state should behave like a
window configuration. A writable state should do the same but for using
numbers instead of markers for positions.
> But automatically revisiting all tabs is too harmful
> because some tabs might lost their names: when a buffer
> was killed, then the tab will be renamed to the name
> of the buffer that replaces the killed buffer,
> and the user loses the hint what buffer was displayed
> in the tab originally.
Again I'm not sure how you would retrieve the name of a killed buffer.
What am I missing?
> To solve the problem of outdated points/markers in window states
> maybe in addition to point, window states could also store
> context strings like bookmark.el does?
> I don't know how reliable these bookmark contexts are.
It would help when the file a buffer is visiting was modified outside
Emacs. In all other cases, the stored point should suffice.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-16 16:30 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> Maybe then at least would be possible to display a message
>> that will list the names of dead buffers. That might help
>> the users to restore the buffers killed accidentally.
>
> The name of a killed buffer is nil as long as the buffer object has not
> been collected. But would buffer names be of great use anyway? Isn't it
> the name of the file, the info node, or the directory name the buffer
> was visiting that counts?
The buffer name often has a hint about the file/directory name.
>> OTOH, this is not needed in case of using the tab-bar
>> because before switching to the tab with the killed buffer,
>> the name of the killed buffer is visible as the tab name.
>
> Does the tab-bar code store the buffer name separately? But again -
> that name won't help you much anyway once the buffer was killed.
By default the buffer name is stored as a tab name. And it helps
to know the purpose of why that tab was created. When the buffer
was killed in another tab, it helps to decide whether the tab
that displayed the killed buffer should be closed as well.
> Incidentally, the name of the file a killed buffer was visiting will be
> available as long as the buffer object exists. Do you mean that?
What would be more useful to keep for the killed buffer
is the value of its revert-buffer-function. Often calling
this function can reconstruct the buffer contents.
>> Or maybe instead of 'post-set-window-configuration-hook' it's easy
>> to call a post-processing function after 'set-window-configuration'.
>
> 'post-set-window-configuration-functions' that's what I meant earlier -
> with the frame as argument. But if a buffer is dead now, this won't
> help in neither regard. First and foremost, 'set-window-configuration'
> must be able to deal with dead buffers in a safe fashion. We could,
> optionally, display *scratch* in all windows that have a dead buffer now.
Instead of *scratch*, is it possible to display some special buffer
that will display the name of the killed buffer, and a button
that runs its revert-buffer-function?
> Still 'post-set-window-configuration-functions' (and also the
> desktop routines) would have to know enough about how to restore the
> earlier state. This is something only a buffer's major mode itself may
> know.
Or revert-buffer-function.
>> BTW, there is another problem when the same buffer is displayed
>> in two tabs/window-configurations. For example, in the first tab
>> point is near the top of the buffer, and in the second tab point
>> is near the bottom of the same buffer. The user edits the top
>> of the buffer in the first tab and saves writable window states
>> to the desktop.
>>
>> At this point, all positions saved in the second tab are wrong
>> because writable window states save point instead of the marker.
>
> But 'window--state-get-1' does
>
> (let ((point (window-point window))
>
> which should reliable give the value of point in window and then
>
> (point . ,(if writable
> point
> (with-current-buffer buffer
> (copy-marker point
> (buffer-local-value
> 'window-point-insertion-type
> buffer)))))
>
> 'window--state-put-2' OTOH does
>
> (set-window-point window (cdr (assq 'point state))))
>
> Do you see the problem here?
The problem is that for writable window states 'window--state-get-1'
saves point as a number from the marker.
>> One workaround is before saving the desktop to revisit all tabs
>> that will update points from markers in writable window states.
>>
>> But this won't help too much because there is still the same
>> problem after restoring the desktop. When the desktop is
>> restored with right positions of all points, and the user
>> edits the top of the buffer in the first tab before visiting
>> the second tab, then after switching to the second tab
>> point will be at wrong position, because the tab is
>> restored from window states.
>
> So IIUC you mean that restoring the desktop (writable) does things
> differently than restoring tabs (non-writable)? Can you tell me more
> precisely the order of desktop/tab-bar operations involved in that
> scenario?
The desktop saves writable window states with point as a number.
Switching tabs uses window configurations with point as a marker.
>> Here the same workaround is possible: to revisit all tabs after
>> restoring the desktop, that will create window configurations
>> from window states.
>
> I'd still have to understand: A non-writable state should behave like a
> window configuration. A writable state should do the same but for using
> numbers instead of markers for positions.
Indeed. Only writable window states saved to the desktop.
>> But automatically revisiting all tabs is too harmful
>> because some tabs might lost their names: when a buffer
>> was killed, then the tab will be renamed to the name
>> of the buffer that replaces the killed buffer,
>> and the user loses the hint what buffer was displayed
>> in the tab originally.
>
> Again I'm not sure how you would retrieve the name of a killed buffer.
> What am I missing?
Currently there is no solution to this problem.
>> To solve the problem of outdated points/markers in window states
>> maybe in addition to point, window states could also store
>> context strings like bookmark.el does?
>> I don't know how reliable these bookmark contexts are.
>
> It would help when the file a buffer is visiting was modified outside
> Emacs. In all other cases, the stored point should suffice.
The stored point is not sufficient when saved as a number to the desktop file.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-17 11:42 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> The buffer name often has a hint about the file/directory name.
But not the name of a dead buffer.
> By default the buffer name is stored as a tab name. And it helps
> to know the purpose of why that tab was created. When the buffer
> was killed in another tab, it helps to decide whether the tab
> that displayed the killed buffer should be closed as well.
How do you synchronize tabs with 'kill-buffer'? If, in a tab, you
retain a link to a killed buffer, that buffer can't be collected as long
as the tab exists. If you just keep the buffer name and the user
creates a new buffer with the same name but for a different file, things
may get confusing.
> What would be more useful to keep for the killed buffer
> is the value of its revert-buffer-function. Often calling
> this function can reconstruct the buffer contents.
But that function should be available even for a killed buffer as long
as its object is referenced by a tab.
> Instead of *scratch*, is it possible to display some special buffer
> that will display the name of the killed buffer, and a button
> that runs its revert-buffer-function?
We can set up a buffer local variable whose value is a function that
'set-window-configuration' would call whenever it finds a window with
that buffer dead. 'set-window-configuration' would then check whether
that function correctly returned a live buffer to show in that window.
If the function succeeded, 'set-window-configuration' could try to
restore the earlier values of window point and start in the window. If
the function failed, 'set-window-configuration' would either delete the
window or display *scratch* in it.
>> Still 'post-set-window-configuration-functions' (and also the
>> desktop routines) would have to know enough about how to restore the
>> earlier state. This is something only a buffer's major mode itself may
>> know.
>
> Or revert-buffer-function.
Which is usually set up by the major mode.
> The stored point is not sufficient when saved as a number to the desktop file.
In what sense? You have a state you store in a desktop file and restore
from that file. The stored state is immutable. If a file whose buffer
is stored in that state gets modified in between, any positions stored
in the state must be considered invalid.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-17 16:36 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> Instead of *scratch*, is it possible to display some special buffer
>> that will display the name of the killed buffer, and a button
>> that runs its revert-buffer-function?
>
> We can set up a buffer local variable whose value is a function that
> 'set-window-configuration' would call whenever it finds a window with
> that buffer dead. 'set-window-configuration' would then check whether
> that function correctly returned a live buffer to show in that window.
> If the function succeeded, 'set-window-configuration' could try to
> restore the earlier values of window point and start in the window. If
> the function failed, 'set-window-configuration' would either delete the
> window or display *scratch* in it.
Probably better to keep this function in a window parameter
like you proposed earlier to restore dired positions.
>> The stored point is not sufficient when saved as a number to the desktop file.
>
> In what sense? You have a state you store in a desktop file and restore
> from that file. The stored state is immutable. If a file whose buffer
> is stored in that state gets modified in between, any positions stored
> in the state must be considered invalid.
Indeed. And bookmark.el solves the problem of invalid positions
by adding more context: `front-context-string' and `rear-context-string'.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-18 10:47 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> We can set up a buffer local variable whose value is a function that
>> 'set-window-configuration' would call whenever it finds a window with
>> that buffer dead. 'set-window-configuration' would then check whether
>> that function correctly returned a live buffer to show in that window.
>> If the function succeeded, 'set-window-configuration' could try to
>> restore the earlier values of window point and start in the window. If
>> the function failed, 'set-window-configuration' would either delete the
>> window or display *scratch* in it.
>
> Probably better to keep this function in a window parameter
> like you proposed earlier to restore dired positions.
I just tried what I proposed above and noticed that it's virtually
impossible to come up with a safe solution. Running Lisp from the
middle of 'set-window-configuration' is madness because the respective
frame may be still under construction at that time with windows, their
respective links, sizes and buffers missing.
What we can safely do is the following: Give 'set-window-configuration'
a new argument, say 'keep-dead-buffer-windows'. If non-nil,
'set-window-configuration' does not delete dead buffer windows but shows
*scratch* in them. 'post-set-window-configuration-functions' would then
pass two arguments: the respective frame and a list of four entries for
each dead buffer window it found: The window, the buffer it previously
showed, its window point and its window start position. A function run
by that hook would then be able to replace *scratch* with, for example,
a new buffer visiting the file the previously shown buffer visited and
also restore point and window start of that window.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-18 16:50 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> What we can safely do is the following: Give 'set-window-configuration'
> a new argument, say 'keep-dead-buffer-windows'. If non-nil,
> 'set-window-configuration' does not delete dead buffer windows but shows
> *scratch* in them. 'post-set-window-configuration-functions' would then
> pass two arguments: the respective frame and a list of four entries for
> each dead buffer window it found: The window, the buffer it previously
> showed, its window point and its window start position. A function run
> by that hook would then be able to replace *scratch* with, for example,
> a new buffer visiting the file the previously shown buffer visited and
> also restore point and window start of that window.
This looks promising. One thing I don't understand is how to get
the previously visited file name from this list of four entries?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-02-05 7:17 ` Juri Linkov
0 siblings, 2 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-20 9:44 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
[-- Attachment #1: Type: text/plain, Size: 2103 bytes --]
> This looks promising.
I attach a patch. Note that in my Emacs, window configurations are much
more lightweight so I cannot reliably test it. You would have to do all
the testing yourself.
> One thing I don't understand is how to get
> the previously visited file name from this list of four entries?
But it's still there in the dead buffer (the only things that can get
collected as long as a window is in a tab are the previous and next
buffers shown in that window). Try the scenario below, using some
suitable file as argument to 'find-file-noselect'.
(defun foo (frame windows)
(while windows
(let* ((quad (car windows))
(window (car quad))
(buffer (find-file-noselect
(buffer-file-name (nth 1 quad)))))
(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 'post-set-window-configuration-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 nil nil t)
(message "Configuration restored"))
Note that window point and start are stored as positions and not as
markers which means that if you modify the buffer after the call of
'current-window-configuration', they may not be accurate any more.
One could try to get their last position before the buffer was deleted
but that would mean to give ‘marker-position’ an extra argument to omit
the
if (XMARKER (marker)->buffer)
check with some "use at your own risk" caveats ('marker-buffer' at the
same time would still have to return nil).
martin
[-- Attachment #2: keep-windows.diff --]
[-- Type: text/x-patch, Size: 8862 bytes --]
diff --git a/src/keyboard.c b/src/keyboard.c
index e1d738dd6ef..b6ba3c57ff8 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -2281,7 +2281,7 @@ read_char_help_form_unwind (void)
Lisp_Object window_config = XCAR (help_form_saved_window_configs);
help_form_saved_window_configs = XCDR (help_form_saved_window_configs);
if (!NILP (window_config))
- Fset_window_configuration (window_config, Qnil, Qnil);
+ Fset_window_configuration (window_config, Qnil, Qnil, Qnil);
}
#define STOP_POLLING \
diff --git a/src/window.c b/src/window.c
index 3a54f7ce7b1..c33b987c24f 100644
--- a/src/window.c
+++ b/src/window.c
@@ -7037,6 +7037,7 @@ DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
union vectorlike_header header;
Lisp_Object window, buffer, start, pointm, old_pointm;
+ Lisp_Object start_pos, pointm_pos;
Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width;
Lisp_Object left_col, top_line, total_cols, total_lines;
Lisp_Object normal_cols, normal_lines;
@@ -7079,7 +7080,7 @@ DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_config
}
DEFUN ("set-window-configuration", Fset_window_configuration,
- Sset_window_configuration, 1, 3, 0,
+ Sset_window_configuration, 1, 4, 0,
doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION.
CONFIGURATION must be a value previously returned
by `current-window-configuration' (which see).
@@ -7090,16 +7091,35 @@ 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 KEEP-WINDOWS 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
+'post-set-window-configuration-functions' with two arguments - the frame
+whose layout is has restored and, provided KEEP-WINDOWS is non-nil, 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 positions of `window-start' and `window-point' of
+that window at the time CONFIGURATION was made. Note that these
+positions are no markers and may be no more accurate if the buffer has
+been modified afterwards. If KEEP-WINDOWS is nil, the second argument
+is nil.
+
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. */)
(Lisp_Object configuration, Lisp_Object dont_set_frame,
- Lisp_Object dont_set_miniwindow)
+ Lisp_Object dont_set_miniwindow, Lisp_Object keep_windows)
{
register struct save_window_data *data;
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 +7360,10 @@ 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 (keep_windows))
+ kept_windows = Fcons (list4 (window, p->buffer,
+ p->start_pos, p->pointm_pos),
+ kept_windows);
}
else if (!NILP (w->start))
/* Leaf window has no live buffer, get one. */
@@ -7360,6 +7384,10 @@ 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 (keep_windows))
+ kept_windows = Fcons (list4 (window, p->buffer,
+ p->start_pos, p->pointm_pos),
+ kept_windows);
}
}
@@ -7411,12 +7439,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 (keep_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);
+ }
/* Record the selected window's buffer here. The window should
already be the selected one from the call above. */
@@ -7463,6 +7492,11 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
minibuf_selected_window = data->minibuf_selected_window;
SAFE_FREE ();
+
+ if (!NILP (Vrun_hooks) && !NILP (Vpost_set_window_configuration_functions))
+ run_hook_with_args_2 (Qpost_set_window_configuration_functions, frame,
+ kept_windows);
+
return FRAME_LIVE_P (f) ? Qt : Qnil;
}
@@ -7472,12 +7506,12 @@ restore_window_configuration (Lisp_Object configuration)
if (CONSP (configuration))
Fset_window_configuration (XCAR (configuration),
Fcar_safe (XCDR (configuration)),
- Fcar_safe (Fcdr_safe (XCDR (configuration))));
+ Fcar_safe (Fcdr_safe (XCDR (configuration))),
+ Qnil);
else
- Fset_window_configuration (configuration, Qnil, Qnil);
+ Fset_window_configuration (configuration, Qnil, Qnil, Qnil);
}
-
/* If WINDOW is an internal window, recursively delete all child windows
reachable via the next and contents slots of WINDOW. Otherwise setup
WINDOW to not show any buffer. */
@@ -7685,16 +7719,24 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, ptrdiff_t i)
is the selected window, then get the value of point from
the buffer; pointm is garbage in the selected window. */
if (EQ (window, selected_window))
- p->pointm = build_marker (XBUFFER (w->contents),
- BUF_PT (XBUFFER (w->contents)),
- BUF_PT_BYTE (XBUFFER (w->contents)));
+ {
+ p->pointm = build_marker (XBUFFER (w->contents),
+ BUF_PT (XBUFFER (w->contents)),
+ BUF_PT_BYTE (XBUFFER (w->contents)));
+ p->pointm_pos = make_fixnum (BUF_PT (XBUFFER (w->contents)));
+ }
else
- p->pointm = Fcopy_marker (w->pointm, Qnil);
+ {
+ p->pointm = Fcopy_marker (w->pointm, Qnil);
+ p->pointm_pos = make_fixnum (marker_position (w->pointm));
+ }
+
p->old_pointm = Fcopy_marker (w->old_pointm, Qnil);
XMARKER (p->pointm)->insertion_type = window_point_insertion_type;
XMARKER (p->old_pointm)->insertion_type = window_point_insertion_type;
p->start = Fcopy_marker (w->start, Qnil);
+ p->start_pos = make_fixnum (marker_position (w->start));
p->start_at_line_beg = w->start_at_line_beg ? Qt : Qnil;
}
else
@@ -8460,6 +8502,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 (Qpost_set_window_configuration_functions,
+ "post-set-window-configuration-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 +8661,21 @@ syms_of_window (void)
call is performed with the frame temporarily selected. */);
Vwindow_configuration_change_hook = Qnil;
+ DEFVAR_LISP ("post-set-window-configuration-functions",
+ Vpost_set_window_configuration_functions,
+ doc: /* Functions called after restoring a window configuration.
+The value should be a list of functions that take two arguments.
+
+This function is called by `set-window-configuration' after it has
+restored the layout of a frame. 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' 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. */);
+ Vpost_set_window_configuration_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
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-02-05 7:17 ` Juri Linkov
1 sibling, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-22 7:43 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> I attach a patch. Note that in my Emacs, window configurations are much
> more lightweight so I cannot reliably test it. You would have to do all
> the testing yourself.
Thanks, this works great. Some observations:
1. 'post-set-window-configuration-functions' is called even
after 'delete-other-windows' and 'kill-buffer', albeit with
windows=nil, so no problems.
2. It seems there is no way to get the name of the killed buffer
from '(nth 1 quad)'?
Here is what I tried:
(defun foo (frame windows)
(while windows
(let* ((quad (car windows))
(window (car quad))
(buffer (generate-new-buffer
(format " *Old buffer %s*" (nth 1 quad)))))
(with-current-buffer buffer
(insert (format "Restore the original buffer named %s:\n"
(nth 1 quad)))
(insert-button
"[Restore]"
'action
(lambda (_button)
(set-window-buffer window (find-file-noselect
(buffer-file-name (nth 1 quad))))
(set-window-point window (nth 3 quad))
(set-window-start window (nth 2 quad) t)))
(set-window-buffer window buffer)))
(setq windows (cdr windows))))
It inserts to the transient buffer this text without the real buffer name:
Restore the original buffer named #<killed buffer>:
[Restore]
But the button really restores the original buffer.
3. It seems the buffer-local value of 'revert-buffer-function'
is not preserved in the killed buffer?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-23 9:30 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> 1. 'post-set-window-configuration-functions' is called even
> after 'delete-other-windows' and 'kill-buffer', albeit with
> windows=nil, so no problems.
I don't understand what you mean here. Do you mean that it gets called
because for some reason 'set-window-configuration' gets called after
'delete-other-windows' and 'kill-buffer'?
> 2. It seems there is no way to get the name of the killed buffer
> from '(nth 1 quad)'?
No way. 'buffer-name' with a killed buffer as argument has to return
nil - too many functions may rely on that.
> Here is what I tried:
>
> (defun foo (frame windows)
> (while windows
> (let* ((quad (car windows))
> (window (car quad))
> (buffer (generate-new-buffer
> (format " *Old buffer %s*" (nth 1 quad)))))
> (with-current-buffer buffer
> (insert (format "Restore the original buffer named %s:\n"
> (nth 1 quad)))
> (insert-button
> "[Restore]"
> 'action
> (lambda (_button)
> (set-window-buffer window (find-file-noselect
> (buffer-file-name (nth 1 quad))))
> (set-window-point window (nth 3 quad))
> (set-window-start window (nth 2 quad) t)))
> (set-window-buffer window buffer)))
> (setq windows (cdr windows))))
>
> It inserts to the transient buffer this text without the real buffer name:
>
> Restore the original buffer named #<killed buffer>:
> [Restore]
I'd say Restore buffer from ... and use the file name here.
> But the button really restores the original buffer.
Because many functions with a buffer as argument like 'buffer-file-name'
don't check whether that buffer is live. You can find such functions by
looking for "decode_buffer (buffer)" in buffer.c. 'buffer-name' fails
because the name of the buffer _is_ reset to nil when the buffer is
killed. We could add a new field to the buffer structure and a function
say 'buffer-last-name' which would return the last name a buffer had
before it was renamed: nil for a new buffer, the old name before the
last 'rename-buffer' and the last buffer name for a dead buffer.
And always think about what to propose when a new buffer with the same
name has been created meanwhile.
> 3. It seems the buffer-local value of 'revert-buffer-function'
> is not preserved in the killed buffer?
'kill-buffer' calls reset_buffer_local_variables which scans the local
variables alist of the buffer and resets all values to their default
values. Giving the variable either a 'permanent-local' property or
binding the default value to the buffer local value around 'kill-buffer'
could work around that but I'd rather try to save this (and other buffer
local values) in a separate alist for buffers stored in a configuration.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-24 7:54 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> 1. 'post-set-window-configuration-functions' is called even
>> after 'delete-other-windows' and 'kill-buffer', albeit with
>> windows=nil, so no problems.
>
> I don't understand what you mean here. Do you mean that it gets called
> because for some reason 'set-window-configuration' gets called after
> 'delete-other-windows' and 'kill-buffer'?
When I instrumented the function 'foo', it entered edebug
between 'y-or-n-p' in
(y-or-n-p "Configuration saved ...")
(delete-other-windows window)
(kill-buffer buffer)
(y-or-n-p "Configuration reset ...")
So I supposed that maybe from 'delete-other-windows' and 'kill-buffer',
but now I understand this is because exiting the minibuffer from
'y-or-n-p' calls 'set-window-configuration'.
> We could add a new field to the buffer structure and a function
> say 'buffer-last-name' which would return the last name a buffer had
> before it was renamed: nil for a new buffer, the old name before the
> last 'rename-buffer' and the last buffer name for a dead buffer.
Looks nice.
> And always think about what to propose when a new buffer with the same
> name has been created meanwhile.
Something using uniquify could help.
>> 3. It seems the buffer-local value of 'revert-buffer-function'
>> is not preserved in the killed buffer?
>
> 'kill-buffer' calls reset_buffer_local_variables which scans the local
> variables alist of the buffer and resets all values to their default
> values. Giving the variable either a 'permanent-local' property or
> binding the default value to the buffer local value around 'kill-buffer'
> could work around that but I'd rather try to save this (and other buffer
> local values) in a separate alist for buffers stored in a configuration.
To save revert-buffer-functions like saving positions of dired files
in window parameters?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-25 9:39 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
[-- Attachment #1: Type: text/plain, Size: 1883 bytes --]
> When I instrumented the function 'foo', it entered edebug
> between 'y-or-n-p' in
>
> (y-or-n-p "Configuration saved ...")
> (delete-other-windows window)
> (kill-buffer buffer)
> (y-or-n-p "Configuration reset ...")
>
> So I supposed that maybe from 'delete-other-windows' and 'kill-buffer',
> but now I understand this is because exiting the minibuffer from
> 'y-or-n-p' calls 'set-window-configuration'.
Unless 'read-minibuffer-restore-windows' is nil. Saving and restoring
the configuration with 'y-or-n-p' makes no sense because in practice the
user cannot change the configuration while 'y-or-n-p' is in progress.
>> We could add a new field to the buffer structure and a function
>> say 'buffer-last-name' which would return the last name a buffer had
>> before it was renamed: nil for a new buffer, the old name before the
>> last 'rename-buffer' and the last buffer name for a dead buffer.
>
> Looks nice.
I attach a patch.
>> And always think about what to propose when a new buffer with the same
>> name has been created meanwhile.
>
> Something using uniquify could help.
Maybe. Here I had problems with uniquify not always restoring the base
name of a buffer when I killed the last other buffer with the same base
name. Maybe the fault is all mine.
>> 'kill-buffer' calls reset_buffer_local_variables which scans the local
>> variables alist of the buffer and resets all values to their default
>> values. Giving the variable either a 'permanent-local' property or
>> binding the default value to the buffer local value around 'kill-buffer'
>> could work around that but I'd rather try to save this (and other buffer
>> local values) in a separate alist for buffers stored in a configuration.
>
> To save revert-buffer-functions like saving positions of dired files
> in window parameters?
For example, yes.
martin
[-- Attachment #2: buffer-last-name.diff --]
[-- Type: text/x-patch, Size: 3873 bytes --]
diff --git a/src/buffer.c b/src/buffer.c
index 352aca8ddfd..f79b1e06119 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -327,6 +327,11 @@ bset_name (struct buffer *b, Lisp_Object val)
b->name_ = val;
}
static void
+bset_lastname (struct buffer *b, Lisp_Object val)
+{
+ b->lastname_ = val;
+}
+static void
bset_overwrite_mode (struct buffer *b, Lisp_Object val)
{
b->overwrite_mode_ = val;
@@ -1276,6 +1281,19 @@ DEFUN ("buffer-name", Fbuffer_name, Sbuffer_name, 0, 1, 0,
return BVAR (decode_buffer (buffer), name);
}
+DEFUN ("buffer-last-name", Fbuffer_last_name, Sbuffer_last_name, 0, 1, 0,
+ doc: /* Return last name of BUFFER, as a string.
+BUFFER defaults to the current buffer.
+
+The return value is nil if BUFFER is live and has never been renamed.
+If BUFFER is live and has been renamed at least once, it is the name it
+had before the last rename changed it. For a dead buffer it is the name
+the buffer had before it was killed. */)
+ (Lisp_Object buffer)
+{
+ return BVAR (decode_buffer (buffer), lastname);
+}
+
DEFUN ("buffer-file-name", Fbuffer_file_name, Sbuffer_file_name, 0, 1, 0,
doc: /* Return name of file BUFFER is visiting, or nil if none.
No argument or nil as argument means use the current buffer. */)
@@ -1647,6 +1665,7 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
{
register Lisp_Object tem, buf;
Lisp_Object requestedname = newname;
+ Lisp_Object oldname = BVAR (current_buffer, name);
CHECK_STRING (newname);
@@ -1661,14 +1680,14 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
with the original name. It makes UNIQUE equivalent to
(rename-buffer (generate-new-buffer-name NEWNAME)). */
if (NILP (unique) && XBUFFER (tem) == current_buffer)
- return BVAR (current_buffer, name);
+ return oldname;
if (!NILP (unique))
- newname = Fgenerate_new_buffer_name (newname,
- BVAR (current_buffer, name));
+ newname = Fgenerate_new_buffer_name (newname, oldname);
else
error ("Buffer name `%s' is in use", SDATA (newname));
}
+ bset_lastname (current_buffer, oldname);
bset_name (current_buffer, newname);
/* Catch redisplay's attention. Unless we do this, the mode lines for
@@ -2081,6 +2100,7 @@ DEFUN ("kill-buffer", Fkill_buffer, Skill_buffer, 0, 1, "bKill buffer: ",
This gets rid of them for certain. */
reset_buffer_local_variables (b, 1);
+ bset_lastname (b, b->name_);
bset_name (b, Qnil);
block_input ();
@@ -4647,6 +4667,7 @@ init_buffer_once (void)
/* 0 means not a lisp var, -1 means always local, else mask. */
memset (&buffer_local_flags, 0, sizeof buffer_local_flags);
+ bset_lastname (&buffer_local_flags, make_fixnum (-1));
bset_filename (&buffer_local_flags, make_fixnum (-1));
bset_directory (&buffer_local_flags, make_fixnum (-1));
bset_backed_up (&buffer_local_flags, make_fixnum (-1));
@@ -6030,6 +6051,7 @@ Functions (implicitly) running this hook are `get-buffer-create',
defsubr (&Smake_indirect_buffer);
defsubr (&Sgenerate_new_buffer_name);
defsubr (&Sbuffer_name);
+ defsubr (&Sbuffer_last_name);
defsubr (&Sbuffer_file_name);
defsubr (&Sbuffer_base_buffer);
defsubr (&Sbuffer_local_value);
diff --git a/src/buffer.h b/src/buffer.h
index 80edfdcbc22..7e009397f4d 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -309,6 +309,12 @@ #define BVAR(buf, field) ((buf)->field ## _)
/* The name of this buffer. */
Lisp_Object name_;
+ /* The last name of this buffer. Initially nil, for a renamed live
+ buffer the name the buffer had before the last Frename_buffer
+ changed it, for a dead buffer the last name the buffer had before
+ it was killed. */
+ Lisp_Object lastname_;
+
/* The name of the file visited in this buffer, or nil. */
Lisp_Object filename_;
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-25 17:46 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>>> We could add a new field to the buffer structure and a function
>>> say 'buffer-last-name' which would return the last name a buffer had
>>> before it was renamed: nil for a new buffer, the old name before the
>>> last 'rename-buffer' and the last buffer name for a dead buffer.
>>
>> Looks nice.
>
> I attach a patch.
Thanks, will try to use.
>>> 'kill-buffer' calls reset_buffer_local_variables which scans the local
>>> variables alist of the buffer and resets all values to their default
>>> values. Giving the variable either a 'permanent-local' property or
>>> binding the default value to the buffer local value around 'kill-buffer'
>>> could work around that but I'd rather try to save this (and other buffer
>>> local values) in a separate alist for buffers stored in a configuration.
>>
>> To save revert-buffer-functions like saving positions of dired files
>> in window parameters?
>
> For example, yes.
OTOH, since there is a need to save more variables together with the
window configuration such as dired-filename and revert-buffer-function
anyway, maybe it would be possible to save the last buffer name in the
same alist? Or the last buffer name should be used as a key in such
an alist? Probably no. It seems a key should be a window unless
such data is saved in a window parameter.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-26 9:56 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> OTOH, since there is a need to save more variables together with the
> window configuration such as dired-filename and revert-buffer-function
> anyway, maybe it would be possible to save the last buffer name in the
> same alist? Or the last buffer name should be used as a key in such
> an alist? Probably no. It seems a key should be a window unless
> such data is saved in a window parameter.
Note that the name of a buffer may change in the period lasting from
when you saved the window configuration until the buffer gets killed.
Any such change is handled by 'kill-buffer' but cannot be easily traced
when you save the name together with a window configuration. You could
try 'buffer-list-update-hook' but that might be overkill. And if you
saved that name in a permanent window parameter, you are lost anyway
because you cannot access the parameter in the saved configuration.
A similar thing may happen to dired-filename and revert-buffer-function
but there are hardly any suitable means to reasonably trace changes to
what these stand for in the first place.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-01-27 17:58 UTC (permalink / raw)
To: martin rudalics; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
>> OTOH, since there is a need to save more variables together with the
>> window configuration such as dired-filename and revert-buffer-function
>> anyway, maybe it would be possible to save the last buffer name in the
>> same alist? Or the last buffer name should be used as a key in such
>> an alist? Probably no. It seems a key should be a window unless
>> such data is saved in a window parameter.
>
> Note that the name of a buffer may change in the period lasting from
> when you saved the window configuration until the buffer gets killed.
> Any such change is handled by 'kill-buffer' but cannot be easily traced
> when you save the name together with a window configuration. You could
> try 'buffer-list-update-hook' but that might be overkill. And if you
> saved that name in a permanent window parameter, you are lost anyway
> because you cannot access the parameter in the saved configuration.
Depends on the needs. With your patch that adds 'keep_windows'
it doesn't matter what an old buffer name to show in the window
with the killed buffer. It even makes more sense to show the
same buffer name that was displayed in that window configuration
before the buffer was renamed later.
> A similar thing may happen to dired-filename and revert-buffer-function
> but there are hardly any suitable means to reasonably trace changes to
> what these stand for in the first place.
Indeed, currently 'dired-revert' can't reasonably handle the
situation with the deleted files even in another window.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 0 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-01-28 10:06 UTC (permalink / raw)
To: Juri Linkov; +Cc: daniel.c.mccarthy, Eli Zaretskii, 68235
> Depends on the needs. With your patch that adds 'keep_windows'
> it doesn't matter what an old buffer name to show in the window
> with the killed buffer. It even makes more sense to show the
> same buffer name that was displayed in that window configuration
> before the buffer was renamed later.
But you must have stowed away that name somewhere because 'kill-buffer'
will have reset it to nil without mercy.
> Indeed, currently 'dired-revert' can't reasonably handle the
> situation with the deleted files even in another window.
Can you give a scenario?
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-02-04 17:27 ` Juri Linkov
1 sibling, 0 replies; 85+ messages in thread
From: Juri Linkov @ 2024-02-04 17:27 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
[-- Attachment #1: Type: text/plain, Size: 413 bytes --]
>> Do you remember the bug this was supposed to fix?
>
> The dedicated bug report is this:
>
> bug#33871: Revert Dired window saved in window configuration
I finished designing the feature that will restore Dired positions
in window-configurations and window-states used on the tab-bar.
It will be easy also to add a default more general function
that would use bookmark-like rear/front context in any buffer.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: window-context.patch --]
[-- Type: text/x-diff, Size: 2565 bytes --]
diff --git a/lisp/dired.el b/lisp/dired.el
index cef93ab757c..3a80cfffc04 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -2743,6 +2745,8 @@ dired-mode
'(dired-font-lock-keywords t nil nil beginning-of-line))
(setq-local desktop-save-buffer 'dired-desktop-buffer-misc-data)
(setq-local grep-read-files-function #'dired-grep-read-files)
+ (setq-local window-set-context-function (lambda () (dired-get-filename nil t)))
+ (setq-local window-use-context-function (lambda (context) (dired-goto-file context)))
(setq dired-switches-alist nil)
(hack-dir-local-variables-non-file-buffer) ; before sorting
(dired-sort-other dired-actual-switches t)
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 3e1d8278b04..6c6f3ece9c2 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -1283,6 +1283,10 @@ frameset-filter-tabs
(push '(tabs . frameset-filter-tabs) frameset-filter-alist)
+(defvar window-set-context-function nil)
+(defvar window-use-context-function nil)
+(add-to-list 'window-persistent-parameters '(context . writable))
+
(defun tab-bar--tab (&optional frame)
"Make a new tab data structure that can be added to tabs on the FRAME."
(let* ((tab (tab-bar--current-tab-find nil frame))
@@ -1292,6 +1296,14 @@ tab-bar--tab
frame 'buffer-list)))
(bbl (seq-filter #'buffer-live-p (frame-parameter
frame 'buried-buffer-list))))
+ (walk-windows
+ (lambda (w)
+ (with-selected-window w
+ (when (functionp window-set-context-function)
+ (when-let ((context (funcall window-set-context-function)))
+ (set-window-parameter w 'context (cons (buffer-name) context))))))
+ 'nomini)
+
`(tab
(name . ,(if tab-explicit-name
(alist-get 'name tab)
@@ -1479,6 +1491,15 @@ tab-bar-select-tab
(select-window (get-mru-window)))
(window-state-put ws nil 'safe)))
+ (walk-windows
+ (lambda (w)
+ (with-selected-window w
+ (when-let ((context (window-parameter w 'context)))
+ (when (and (functionp window-use-context-function)
+ (equal (buffer-name) (car context)))
+ (funcall window-use-context-function (cdr context))))))
+ 'nomini)
+
;; Select the minibuffer when it was active before switching tabs
(when (and minibuffer-was-active (active-minibuffer-window))
(select-window (active-minibuffer-window)))
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-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
1 sibling, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-02-05 7:17 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
> I attach a patch. Note that in my Emacs, window configurations are much
> more lightweight so I cannot reliably test it. You would have to do all
> the testing yourself.
> [...]
> DEFUN ("set-window-configuration", Fset_window_configuration,
> - Sset_window_configuration, 1, 3, 0,
> + Sset_window_configuration, 1, 4, 0,
> [...]
> - Lisp_Object dont_set_miniwindow)
> + Lisp_Object dont_set_miniwindow, Lisp_Object keep_windows)
Is 'keep-windows' doable for 'window-state-put' as well?
It seems windows are deleted here:
(while window-state-put-stale-windows
(let ((window (pop window-state-put-stale-windows)))
;; 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))))
After commenting out the code above, this test doesn't delete windows:
(let (ws)
(pop-to-buffer "*Messages*")
(setq ws (window-state-get nil 'writable))
(kill-buffer "*Messages*")
(window-state-put ws nil 'safe))
So maybe the same option 'keep-windows' could call the same hook
'post-set-window-configuration-functions' from 'window-state-put' too?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 2 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-06 10:34 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
[-- Attachment #1: Type: text/plain, Size: 1957 bytes --]
> Is 'keep-windows' doable for 'window-state-put' as well?
I attach a patch that adds a fourth argument to 'window-state-put'. It
and a new 'set-window-configuration' now use a new function I called
'marker-last-position' that returns the last position of a marker even
after its buffer was killed.
The patch also fixes a bug in 'window--state-put-2' that can be
reproduced with the following simple scenario
(let ((buffer (get-buffer-create "*foo*"))
state)
(pop-to-buffer buffer)
(setq state (window-state-get))
(kill-buffer buffer)
(window-state-put state))
Did you never see it?
> So maybe the same option 'keep-windows' could call the same hook
> 'post-set-window-configuration-functions' from 'window-state-put' too?
I added a new hook called 'window-state-put-keep-window-functions' with
the same arguments as 'post-set-window-configuration-functions'. Maybe
people wanted to keep them apart. If you think the hook should be also
run when there are no "kept" windows, we can do that as well.
I tested it here with
(defun foo (frame windows)
(while windows
(let* ((quad (car windows))
(window (car quad))
(buffer (find-file-noselect
(buffer-file-name (nth 1 quad)))))
(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-state-put-keep-window-functions 'foo)
(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 nil nil t)
(message "State restored"))
martin
[-- Attachment #2: keep-windows-2.diff --]
[-- Type: text/x-patch, Size: 14106 bytes --]
diff --git a/lisp/window.el b/lisp/window.el
index e100f25526b..3fa06b0708c 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -6168,12 +6168,25 @@ window-state-get
(min-pixel-width-safe . ,(window-min-size window t 'safe t)))
(window--state-get-1 window writable)))
+(defvar window-state-put-keep-window-functions nil
+ "List of functions run by `window-state-put' for windows to keep.
+These functions are called when `window-state-put' has been
+invoked with KEEP-WINDOWS non-nil. `window-state-put' runs them
+after it has restored STATE, for each window whose buffer has
+been deleted since STATE was saved. Each function is called with
+two arguments. The frame on which the window was restored and a
+quadruple of four entries - the window, its old buffer and that
+buffer's start and point positions.")
+
(defvar window-state-put-list nil
"Helper variable for `window-state-put'.")
(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)))
@@ -6258,7 +6271,7 @@ window--state-put-1
;; Continue with the last window split off.
(setq window new))))))))
-(defun window--state-put-2 (ignore pixelwise)
+(defun window--state-put-2 (ignore pixelwise keep-windows)
"Helper function for `window-state-put'."
(dolist (item window-state-put-list)
(let ((window (car item))
@@ -6278,9 +6291,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,9 +6389,22 @@ 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)))))))
-
-(defun window-state-put (state &optional window ignore)
+ (if keep-windows
+ (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 keep-windows)
"Put window state STATE into WINDOW.
STATE should be the state of a window returned by an earlier
invocation of `window-state-get'. Optional argument WINDOW must
@@ -6388,8 +6415,19 @@ 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'.
+
+Optional argument KEEP-WINDOWS non-nil means to never delete any
+windows saved by STATE whose buffers were deleted since STATE was
+saved. `window-state-put' records such windows in a list and
+calls the functions in `window-state-put-keep-window-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.
+KEEP-WINDOWS nil means such windows are deleted, if possible."
(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.
@@ -6489,15 +6527,21 @@ window-state-put
(with-temp-buffer
(set-window-buffer window (current-buffer))
(window--state-put-1 state window nil totals pixelwise)
- (window--state-put-2 ignore pixelwise))
+ (window--state-put-2 ignore pixelwise keep-windows))
(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-state-put-kept-windows
+ (when window-state-put-keep-window-functions
+ (run-hook-with-args
+ 'window-state-put-keep-window-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/keyboard.c b/src/keyboard.c
index e1d738dd6ef..b6ba3c57ff8 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -2281,7 +2281,7 @@ read_char_help_form_unwind (void)
Lisp_Object window_config = XCAR (help_form_saved_window_configs);
help_form_saved_window_configs = XCDR (help_form_saved_window_configs);
if (!NILP (window_config))
- Fset_window_configuration (window_config, Qnil, Qnil);
+ Fset_window_configuration (window_config, Qnil, Qnil, Qnil);
}
#define STOP_POLLING \
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..cb37983b648 100644
--- a/src/window.c
+++ b/src/window.c
@@ -7079,7 +7079,7 @@ DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_config
}
DEFUN ("set-window-configuration", Fset_window_configuration,
- Sset_window_configuration, 1, 3, 0,
+ Sset_window_configuration, 1, 4, 0,
doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION.
CONFIGURATION must be a value previously returned
by `current-window-configuration' (which see).
@@ -7090,16 +7090,35 @@ 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 KEEP-WINDOWS 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
+'post-set-window-configuration-functions' with two arguments - the frame
+whose layout is has restored and, provided KEEP-WINDOWS is non-nil, 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 positions of `window-start' and `window-point' of
+that window at the time CONFIGURATION was made. Note that these
+positions are no markers and may be no more accurate if the buffer has
+been modified afterwards. If KEEP-WINDOWS is nil, the second argument
+is nil.
+
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. */)
(Lisp_Object configuration, Lisp_Object dont_set_frame,
- Lisp_Object dont_set_miniwindow)
+ Lisp_Object dont_set_miniwindow, Lisp_Object keep_windows)
{
register struct save_window_data *data;
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 (keep_windows))
+ 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 (keep_windows))
+ 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 (keep_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);
+ }
/* 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 (Vpost_set_window_configuration_functions))
+ run_hook_with_args_2 (Qpost_set_window_configuration_functions, frame,
+ kept_windows);
+
return FRAME_LIVE_P (f) ? Qt : Qnil;
}
@@ -7472,12 +7507,12 @@ restore_window_configuration (Lisp_Object configuration)
if (CONSP (configuration))
Fset_window_configuration (XCAR (configuration),
Fcar_safe (XCDR (configuration)),
- Fcar_safe (Fcdr_safe (XCDR (configuration))));
+ Fcar_safe (Fcdr_safe (XCDR (configuration))),
+ Qnil);
else
- Fset_window_configuration (configuration, Qnil, Qnil);
+ Fset_window_configuration (configuration, Qnil, Qnil, Qnil);
}
-
/* If WINDOW is an internal window, recursively delete all child windows
reachable via the next and contents slots of WINDOW. Otherwise setup
WINDOW to not show any buffer. */
@@ -7690,6 +7725,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, ptrdiff_t i)
BUF_PT_BYTE (XBUFFER (w->contents)));
else
p->pointm = Fcopy_marker (w->pointm, Qnil);
+
p->old_pointm = Fcopy_marker (w->old_pointm, Qnil);
XMARKER (p->pointm)->insertion_type = window_point_insertion_type;
XMARKER (p->old_pointm)->insertion_type = window_point_insertion_type;
@@ -8460,6 +8496,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 (Qpost_set_window_configuration_functions,
+ "post-set-window-configuration-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 +8655,21 @@ syms_of_window (void)
call is performed with the frame temporarily selected. */);
Vwindow_configuration_change_hook = Qnil;
+ DEFVAR_LISP ("post-set-window-configuration-functions",
+ Vpost_set_window_configuration_functions,
+ doc: /* Functions called after restoring a window configuration.
+The value should be a list of functions that take two arguments.
+
+This function is called by `set-window-configuration' after it has
+restored the layout of a frame. 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' 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. */);
+ Vpost_set_window_configuration_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
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
1 sibling, 0 replies; 85+ messages in thread
From: Juri Linkov @ 2024-02-06 18:03 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> Is 'keep-windows' doable for 'window-state-put' as well?
>
> I attach a patch that adds a fourth argument to 'window-state-put'. It
> and a new 'set-window-configuration' now use a new function I called
> 'marker-last-position' that returns the last position of a marker even
> after its buffer was killed.
Thanks, will test it.
> The patch also fixes a bug in 'window--state-put-2' that can be
> reproduced with the following simple scenario
>
> (let ((buffer (get-buffer-create "*foo*"))
> state)
> (pop-to-buffer buffer)
> (setq state (window-state-get))
> (kill-buffer buffer)
> (window-state-put state))
>
> Did you never see it?
I have seen it when created the first version of the test case:
(let (ws)
(pop-to-buffer "*Messages*")
(setq ws (window-state-get))
(kill-buffer "*Messages*")
(window-state-put ws))
But then added both 'writable' to 'window-state-get'
and at the same time 'safe' to 'window-state-put':
(let (ws)
(pop-to-buffer "*Messages*")
(setq ws (window-state-get nil 'writable))
(kill-buffer "*Messages*")
(window-state-put ws nil 'safe))
And it didn't fail anymore, so I assumed that
'safe' fixed it ;-)
But now I see that actually 'writable' "fixed" it.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
1 sibling, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-02-15 7:34 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> Is 'keep-windows' doable for 'window-state-put' as well?
>
> I attach a patch that adds a fourth argument to 'window-state-put'. It
> and a new 'set-window-configuration' now use a new function I called
> 'marker-last-position' that returns the last position of a marker even
> after its buffer was killed.
Thanks, I tested, and both hooks work nicely.
One problem is that whether to run the hook is defined by the fourth argument.
This means that it a user needs to use the hook, there is no way to change
the fourth argument of the existing function calls in core commands.
Maybe better to keep windows when the hook is not empty?
I.e. something like this for 'window--state-put-2':
(when window-state-put-keep-window-functions
...
(push (list window old-buffer-or-name start-pos point-pos)
window-state-put-kept-windows))
> I added a new hook called 'window-state-put-keep-window-functions' with
> the same arguments as 'post-set-window-configuration-functions'. Maybe
> people wanted to keep them apart. If you think the hook should be also
> run when there are no "kept" windows, we can do that as well.
Running the hook with an empty list of windows makes sense as well.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-16 9:40 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
> One problem is that whether to run the hook is defined by the fourth argument.
> This means that it a user needs to use the hook, there is no way to change
> the fourth argument of the existing function calls in core commands.
>
> Maybe better to keep windows when the hook is not empty?
> I.e. something like this for 'window--state-put-2':
>
> (when window-state-put-keep-window-functions
> ...
> (push (list window old-buffer-or-name start-pos point-pos)
> window-state-put-kept-windows))
You mean to do away with the KEEP-WINDOWS argument and keep windows iff
`window-state-put-keep-window-functions' is non-nil? This would be up
to you to decide. Only some practice can tell what's better here.
>> I added a new hook called 'window-state-put-keep-window-functions' with
>> the same arguments as 'post-set-window-configuration-functions'. Maybe
>> people wanted to keep them apart. If you think the hook should be also
>> run when there are no "kept" windows, we can do that as well.
>
> Running the hook with an empty list of windows makes sense as well.
For some time we don't run hooks any more when windows and their buffers
change but rather wait until redisplay detects that some change occurred.
`window-state-put-keep-window-functions' already opens the backdoor to
the previous behavior so I'm not sure about opening it even further.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-02-18 7:35 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> One problem is that whether to run the hook is defined by the fourth argument.
>> This means that it a user needs to use the hook, there is no way to change
>> the fourth argument of the existing function calls in core commands.
>>
>> Maybe better to keep windows when the hook is not empty?
>> I.e. something like this for 'window--state-put-2':
>>
>> (when window-state-put-keep-window-functions
>> ...
>> (push (list window old-buffer-or-name start-pos point-pos)
>> window-state-put-kept-windows))
>
> 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.
> 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.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
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
0 siblings, 2 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-19 9:42 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
[-- 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
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-02-19 9:42 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 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
1 sibling, 0 replies; 85+ messages in thread
From: Juri Linkov @ 2024-02-20 17:44 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
> 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'.
Thanks, it works nicely with
(defun default-window-keep-windows (_frame windows)
(dolist (quad windows)
(unless (window-minibuffer-p (nth 0 quad))
(let* ((window (nth 0 quad))
(old-buffer (nth 1 quad))
(file (when (bufferp old-buffer)
(buffer-file-name old-buffer)))
(name (or file old-buffer))
(new-buffer (generate-new-buffer
(format "*Old buffer %s*" name))))
(with-current-buffer new-buffer
(set-auto-mode)
(insert "This window displayed the "
(if file "file" "buffer")
(format " %s\n" name))
(when file
(insert-button
"[Restore]" 'action
(lambda (_button)
(set-window-buffer window (find-file-noselect file))
(set-window-point window (nth 3 quad))
(set-window-start window (nth 2 quad) t))))
(goto-char (point-min))
(setq buffer-read-only t)
(set-window-buffer window new-buffer))))))
(add-hook 'window-kept-windows-functions 'default-window-keep-windows)
that works even for (window-state-get nil 'writable).
In this case only the old buffer name is displayed as a string.
I guess there is no more data that could be extracted
from buffer's writable state.
> 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
Indeed, this required adding such guard:
(unless (window-minibuffer-p (nth 0 quad))
> (for example, have the tab code bind it exclusively
> around its calls of 'set-window-configuration').
Thanks for suggestion, will let-bind it in 'tab-bar-select-tab'.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-02-19 9:42 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
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:37 ` Juri Linkov
1 sibling, 2 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-04 9:40 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
> 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'.
Should be on master now.
Thanks for testing, martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-05 17:37 ` Juri Linkov
1 sibling, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-03-05 17:27 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
[-- Attachment #1: Type: text/plain, Size: 236 bytes --]
>> 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'.
>
> Should be on master now.
Thanks. This will allow such option:
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tab-bar-select-keep-windows-function.patch --]
[-- Type: text/x-diff, Size: 2541 bytes --]
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 61efa332e0b..b2eb1c9d576 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -1393,6 +1405,44 @@ tab-bar-tab-post-select-functions
:group 'tab-bar
:version "30.1")
+(defcustom tab-bar-select-keep-windows-function #'tab-bar-select-keep-windows
+ "Function that handles the killed buffers after selecting a tab."
+ :type '(choice (const :tag "Show placeholder buffers"
+ tab-bar-select-keep-windows)
+ (function :tag "Function"))
+ :group 'tab-bar
+ :version "30.1")
+
+(defun tab-bar-select-keep-windows (_frame windows)
+ (dolist (quad windows)
+ (when (and (window-live-p (nth 0 quad))
+ (not (window-minibuffer-p (nth 0 quad))))
+ (let* ((window (nth 0 quad))
+ (old-buffer (nth 1 quad))
+ (file (when (bufferp old-buffer)
+ (buffer-file-name old-buffer)))
+ (name (or file
+ (and (fboundp 'buffer-last-name)
+ (buffer-last-name old-buffer))
+ old-buffer))
+ (new-buffer (generate-new-buffer
+ (format "*Old buffer %s*" name))))
+ (with-current-buffer new-buffer
+ (set-auto-mode)
+ (insert (format-message "This window displayed the %s `%s'.\n"
+ (if file "file" "buffer")
+ name))
+ (when file
+ (insert-button
+ "[Restore]" 'action
+ (lambda (_button)
+ (set-window-buffer window (find-file-noselect file))
+ (set-window-start window (nth 2 quad) t)
+ (set-window-point window (nth 3 quad)))))
+ (goto-char (point-min))
+ (setq buffer-read-only t)
+ (set-window-buffer window new-buffer))))))
+
(defvar tab-bar-minibuffer-restore-tab nil
"Tab number for `tab-bar-minibuffer-restore-tab'.")
@@ -1438,7 +1488,10 @@ tab-bar-select-tab
(let* ((from-tab (tab-bar--tab))
(to-tab (nth to-index tabs))
(wc (alist-get 'wc to-tab))
- (ws (alist-get 'ws to-tab)))
+ (ws (alist-get 'ws to-tab))
+ (window-kept-windows-functions
+ (delq nil (cons tab-bar-select-keep-windows-function
+ window-kept-windows-functions))))
;; During the same session, use window-configuration to switch
;; tabs, because window-configurations are more reliable
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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:37 ` Juri Linkov
2024-03-06 10:19 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-03-05 17:37 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> 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'.
>
> Should be on master now.
In addition to the previous patch I also have more questions:
1. window-kept-windows-functions should be announced in etc/NEWS?
2. window-kept-windows-functions is called too often.
Most of the calls contain just the minibuffer:
((#<window 4 on *Minibuf-0*> #<buffer *Minibuf-0*> 1 1))
Is it possible not to include the minibuffer window?
So when most of the time this list of kept windows will be empty,
then maybe better to not call the hook at all?
3. Very often the message inserted by the patch that I posted
are quite useless because they look like this:
This window displayed the buffer #<killed buffer>.
This would be much more informative:
This window displayed the buffer *Help*.
Maybe 'buffer-last-name' could help to achieve this?
4. I don't understand this part, but maybe this is already correct:
/* Scan dead buffer windows. */
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);
}
Should it be if(NILP (Vwindow_kept_windows_functions)) instead?
However, this already works correctly in my tests.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-03-05 17:27 ` Juri Linkov
@ 2024-03-05 17:45 ` Eli Zaretskii
2024-03-06 18:03 ` Juri Linkov
0 siblings, 1 reply; 85+ messages in thread
From: Eli Zaretskii @ 2024-03-05 17:45 UTC (permalink / raw)
To: Juri Linkov; +Cc: rudalics, 68235
> Cc: 68235@debbugs.gnu.org
> From: Juri Linkov <juri@linkov.net>
> Date: Tue, 05 Mar 2024 19:27:18 +0200
>
> +(defcustom tab-bar-select-keep-windows-function #'tab-bar-select-keep-windows
> + "Function that handles the killed buffers after selecting a tab."
This doc string doesn't explain enough: it begs the question "what
does selecting a tab have to do with killing buffers?"
Thanks.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-06 10:19 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
[-- Attachment #1: Type: text/plain, Size: 2531 bytes --]
> In addition to the previous patch I also have more questions:
>
> 1. window-kept-windows-functions should be announced in etc/NEWS?
Maybe, once we fixed all bugs and know how to make good use of it.
> 2. window-kept-windows-functions is called too often.
> Most of the calls contain just the minibuffer:
>
> ((#<window 4 on *Minibuf-0*> #<buffer *Minibuf-0*> 1 1))
>
> Is it possible not to include the minibuffer window?
Yes. Emacs master never deletes a minibuffer window unless it's about
to delete its frame.
> So when most of the time this list of kept windows will be empty,
> then maybe better to not call the hook at all?
But earlier you said "Running the hook with an empty list of windows
makes sense as well." So it's up to you.
> 3. Very often the message inserted by the patch that I posted
> are quite useless because they look like this:
>
> This window displayed the buffer #<killed buffer>.
>
> This would be much more informative:
>
> This window displayed the buffer *Help*.
>
> Maybe 'buffer-last-name' could help to achieve this?
I tried to implement it. Tested with
(let ((buffer (get-buffer-create "*foo*")))
(y-or-n-p (format "current %s last %s"
(buffer-name buffer) (buffer-last-name buffer)))
(with-current-buffer buffer
(rename-buffer "*bar*"))
(y-or-n-p (format "current %s last %s"
(buffer-name buffer) (buffer-last-name buffer)))
(kill-buffer buffer)
(y-or-n-p (format "current %s last %s"
(buffer-name buffer) (buffer-last-name buffer))))
> 4. I don't understand this part, but maybe this is already correct:
>
> /* Scan dead buffer windows. */
> 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);
> }
>
> Should it be if(NILP (Vwindow_kept_windows_functions)) instead?
It should. Thanks for catching it.
> However, this already works correctly in my tests.
Because 'set-window-configuration' does not try to delete a window with
a dead buffer unless that window was dedicated to its buffer. That's
the way it was coded back in 2011. 'window-state-put' OTOH deletes
such a window even if it was not dedicated to its buffer. I now made
'window-state-put' behave like 'set-window-configuration' in this
regard.
Have a look at the attached patch.
martin
[-- Attachment #2: buffer-last-name.diff --]
[-- Type: text/x-patch, Size: 14055 bytes --]
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index fe3dc573df5..b6937b7fd48 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -6264,15 +6264,15 @@ Window Configurations
@code{minibuffer-selected-window}. In this case, the function returns
@code{nil}. Otherwise, it returns @code{t}.
-If the buffer of a window of @var{configuration} has been killed since
-@var{configuration} was made, that window is, as a rule, removed from
-the restored configuration. However, if that window is the last window
-remaining in the restored configuration, another live buffer is shown in
-it. Also, if the variable @var{window-kept-windows-functions} is
-non-@code{nil}, any window whose buffer is now dead is not deleted.
-Rather, this function will show another live buffer in that window and
-include an entry for that window when calling any function in
-@var{window-kept-windows-functions} (@pxref{Window Hooks}).
+If this function tries to restore a non-minibuffer window whose buffer
+was killed since @var{configuration} was made, it will proceed as
+follows: If the abnormal hook @code{window-kept-windows-functions} is
+@code{nil} and the window is dedicated to its buffer, it will try to
+delete that window. Otherwise, or if it cannot delete the window, it
+will show another live buffer in it.
+
+This function runs the abnormal hook @var{window-kept-windows-functions}
+(@pxref{Window Hooks}).
Here is a way of using this function to get the same effect as
@code{save-window-excursion}:
@@ -6361,19 +6361,20 @@ Window Configurations
frame before putting @var{state} into it. If @var{window} is @code{nil},
it puts the window state into a new window.
-If the buffer of any window recorded in @var{state} has been killed
-since @var{state} was made, that window is, as a rule, not restored.
-However, if that window is the only window in @var{state}, another live
-buffer will be shown in it. Also, if the variable
-@var{window-kept-windows-functions} is non-@code{nil}, any window whose
-buffer is now dead is restored. This function will show another live
-buffer in it and include an entry for that window when calling a
-function in @var{window-kept-windows-functions} (@pxref{Window Hooks}).
+If this function tries to restore a non-minibuffer window whose buffer
+was killed since @var{state} was made, it will proceed as follows: If
+the abnormal hook @code{window-kept-windows-functions} is @code{nil} and
+the window is dedicated to its buffer, it will try to delete that
+window. Otherwise, or if it cannot delete the window, it will show
+another live buffer in it.
If the optional argument @var{ignore} is non-@code{nil}, it means to ignore
minimum window sizes and fixed-size restrictions. If @var{ignore}
is @code{safe}, this means windows can get as small as one line
and/or two columns.
+
+This function runs the abnormal hook @var{window-kept-windows-functions}
+(@pxref{Window Hooks}).
@end defun
The functions @code{window-state-get} and @code{window-state-put} also
@@ -6641,7 +6642,7 @@ Window Hooks
This variable holds a list of functions that Emacs will call after
restoring a window configuration via @code{set-window-configuration} or
state via @code{window-state-put} (@pxref{Window Configurations}). When
-the value of this variable is non-@code{nil}, these functions will not
+the value of this variable is non-@code{nil}, these functions will never
delete any window whose buffer has been killed since the corresponding
configuration or state was saved, but show some live buffer in it.
diff --git a/lisp/window.el b/lisp/window.el
index 29336f573f8..11ef490ec68 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -6393,7 +6393,9 @@ window--state-put-2
;; save the window with the intention of deleting it later
;; if possible.
(switch-to-prev-buffer window)
- (if window-kept-windows-functions
+ (unless (window-minibuffer-p window)
+ (cond
+ (window-kept-windows-functions
(let* ((start (cdr (assq 'start state)))
;; Handle both - marker positions from writable
;; states and markers from non-writable states.
@@ -6401,12 +6403,14 @@ window--state-put-2
(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))))))))
+ (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)))
+ ((window-dedicated-p window)
+ (push window window-state-put-stale-windows)))
+ (set-window-dedicated-p window nil))))))))
(defun window-state-put (state &optional window ignore)
"Put window state STATE into WINDOW.
@@ -6421,16 +6425,22 @@ window-state-put
windows can get as small as `window-safe-min-height' and
`window-safe-min-width'.
-If the abnormal hook `window-kept-windows-functions' is non-nil,
-do not delete any windows saved by STATE whose buffers were
-deleted since STATE was saved. Rather, show some live buffer in
-them and call the functions 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."
+If this function tries to restore a non-minibuffer window whose buffer
+was killed since STATE was made, it will proceed as follows:
+
+- If the abnormal hook `window-kept-windows-functions' is nil and the
+ window is dedicated to its buffer, it will try to delete that window.
+
+- Otherwise, or if it cannot delete the window, it will show another
+ buffer in it.
+
+Call the functions in `window-kept-windows-functions' with a list of two
+arguments: the frame where STATE was put and a list of entries for each
+window whose buffer has been killed since STATE was made. 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)
diff --git a/src/buffer.c b/src/buffer.c
index 126f3eb055a..e8daa93c2d9 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -327,6 +327,11 @@ bset_name (struct buffer *b, Lisp_Object val)
b->name_ = val;
}
static void
+bset_last_name (struct buffer *b, Lisp_Object val)
+{
+ b->last_name_ = val;
+}
+static void
bset_overwrite_mode (struct buffer *b, Lisp_Object val)
{
b->overwrite_mode_ = val;
@@ -647,6 +652,7 @@ DEFUN ("get-buffer-create", Fget_buffer_create, Sget_buffer_create, 1, 2, 0,
name = Fcopy_sequence (buffer_or_name);
set_string_intervals (name, NULL);
bset_name (b, name);
+ bset_last_name (b, name);
b->inhibit_buffer_hooks = !NILP (inhibit_buffer_hooks);
bset_undo_list (b, SREF (name, 0) != ' ' ? Qnil : Qt);
@@ -866,6 +872,7 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
name = Fcopy_sequence (name);
set_string_intervals (name, NULL);
bset_name (b, name);
+ bset_last_name (b, name);
/* An indirect buffer shares undo list of its base (Bug#18180). */
bset_undo_list (b, BVAR (b->base_buffer, undo_list));
@@ -1282,6 +1289,16 @@ DEFUN ("buffer-name", Fbuffer_name, Sbuffer_name, 0, 1, 0,
return BVAR (decode_buffer (buffer), name);
}
+DEFUN ("buffer-last-name", Fbuffer_last_name, Sbuffer_last_name, 0, 1, 0,
+ doc: /* Return last name of BUFFER, as a string.
+BUFFER defaults to the current buffer.
+
+This is the last name of BUFFER before it has been renamed or killed. */)
+ (Lisp_Object buffer)
+{
+ return BVAR (decode_buffer (buffer), last_name);
+}
+
DEFUN ("buffer-file-name", Fbuffer_file_name, Sbuffer_file_name, 0, 1, 0,
doc: /* Return name of file BUFFER is visiting, or nil if none.
No argument or nil as argument means use the current buffer. */)
@@ -1652,6 +1669,7 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
(register Lisp_Object newname, Lisp_Object unique)
{
register Lisp_Object tem, buf;
+ Lisp_Object oldname = BVAR (current_buffer, name);
Lisp_Object requestedname = newname;
CHECK_STRING (newname);
@@ -1669,12 +1687,12 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
if (NILP (unique) && XBUFFER (tem) == current_buffer)
return BVAR (current_buffer, name);
if (!NILP (unique))
- newname = Fgenerate_new_buffer_name (newname,
- BVAR (current_buffer, name));
+ newname = Fgenerate_new_buffer_name (newname, oldname);
else
error ("Buffer name `%s' is in use", SDATA (newname));
}
+ bset_last_name (current_buffer, oldname);
bset_name (current_buffer, newname);
/* Catch redisplay's attention. Unless we do this, the mode lines for
@@ -2087,6 +2105,7 @@ DEFUN ("kill-buffer", Fkill_buffer, Skill_buffer, 0, 1, "bKill buffer: ",
This gets rid of them for certain. */
reset_buffer_local_variables (b, 1);
+ bset_last_name (b, BVAR (b, name));
bset_name (b, Qnil);
block_input ();
@@ -4658,6 +4677,7 @@ init_buffer_once (void)
/* These used to be stuck at 0 by default, but now that the all-zero value
means Qnil, we have to initialize them explicitly. */
bset_name (&buffer_local_flags, make_fixnum (0));
+ bset_last_name (&buffer_local_flags, make_fixnum (0));
bset_mark (&buffer_local_flags, make_fixnum (0));
bset_local_var_alist (&buffer_local_flags, make_fixnum (0));
bset_keymap (&buffer_local_flags, make_fixnum (0));
@@ -6018,6 +6038,7 @@ Functions (implicitly) running this hook are `get-buffer-create',
defsubr (&Smake_indirect_buffer);
defsubr (&Sgenerate_new_buffer_name);
defsubr (&Sbuffer_name);
+ defsubr (&Sbuffer_last_name);
defsubr (&Sbuffer_file_name);
defsubr (&Sbuffer_base_buffer);
defsubr (&Sbuffer_local_value);
diff --git a/src/buffer.h b/src/buffer.h
index 87ba2802b39..bbe1aeff668 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -309,6 +309,9 @@ #define BVAR(buf, field) ((buf)->field ## _)
/* The name of this buffer. */
Lisp_Object name_;
+ /* The last name of this buffer before it was renamed or killed. */
+ Lisp_Object last_name_;
+
/* The name of the file visited in this buffer, or nil. */
Lisp_Object filename_;
diff --git a/src/window.c b/src/window.c
index ea761fad8bc..c0fadbdff43 100644
--- a/src/window.c
+++ b/src/window.c
@@ -7109,11 +7109,14 @@ 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.
+If this function tries to restore a non-minibuffer window whose buffer
+was killed since CONFIGURATION was made, it will proceed as follows:
+
+- If the abnormal hook `window-kept-windows-functions' is nil and the
+ window is dedicated to its buffer, it will try to delete that window.
+
+- Otherwise, or if it cannot delete the window, it will 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
@@ -7378,7 +7381,7 @@ 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))
+ if (!NILP (Vwindow_kept_windows_functions) && !MINI_WINDOW_P (w))
kept_windows = Fcons (list4 (window, p->buffer,
Fmarker_last_position (p->start),
Fmarker_last_position (p->pointm)),
@@ -7398,16 +7401,20 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
set_marker_restricted_both (w->pointm, w->contents, 0, 0);
set_marker_restricted_both (w->old_pointm, w->contents, 0, 0);
w->start_at_line_beg = true;
- if (!NILP (w->dedicated))
- /* Record this window as dead. */
- 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);
+ if (!MINI_WINDOW_P (w))
+ {
+ 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->dedicated))
+ /* Try to delete this window later. */
+ dead_windows = Fcons (window, dead_windows);
+ /* Make sure window is no more dedicated. */
+ wset_dedicated (w, Qnil);
+ }
}
}
@@ -7459,7 +7466,7 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
unblock_input ();
/* Scan dead buffer windows. */
- if (!NILP (Vwindow_kept_windows_functions))
+ if (NILP (Vwindow_kept_windows_functions))
for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows))
{
window = XCAR (dead_windows);
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-03-06 17:57 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> So when most of the time this list of kept windows will be empty,
>> then maybe better to not call the hook at all?
>
> But earlier you said "Running the hook with an empty list of windows
> makes sense as well." So it's up to you.
We could leave it called on every set-window-configuration
even with an empty window list, as a general post-hook.
BTW, I didn't test yet what happens when
window-kept-windows-functions is non-nil but does nothing.
Here is what happens:
Error muted by safe_call: (get-scratch-buffer-create)
signaled (wrong-type-argument window-live-p #<window 7>)
But maybe this is ok.
>> 3. Very often the message inserted by the patch that I posted
>> are quite useless because they look like this:
>>
>> This window displayed the buffer #<killed buffer>.
>>
>> This would be much more informative:
>>
>> This window displayed the buffer *Help*.
>>
>> Maybe 'buffer-last-name' could help to achieve this?
>
> I tried to implement it. Tested with
>
> (let ((buffer (get-buffer-create "*foo*")))
> (y-or-n-p (format "current %s last %s"
> (buffer-name buffer) (buffer-last-name buffer)))
> (with-current-buffer buffer
> (rename-buffer "*bar*"))
> (y-or-n-p (format "current %s last %s"
> (buffer-name buffer) (buffer-last-name buffer)))
> (kill-buffer buffer)
> (y-or-n-p (format "current %s last %s"
> (buffer-name buffer) (buffer-last-name buffer))))
> [...]
> Have a look at the attached patch.
Thanks. I tested, and everything works nicely.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-03-05 17:45 ` Eli Zaretskii
@ 2024-03-06 18:03 ` Juri Linkov
2024-03-09 8:35 ` Eli Zaretskii
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-03-06 18:03 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: rudalics, 68235
[-- Attachment #1: Type: text/plain, Size: 312 bytes --]
>> +(defcustom tab-bar-select-keep-windows-function #'tab-bar-select-keep-windows
>> + "Function that handles the killed buffers after selecting a tab."
>
> This doc string doesn't explain enough: it begs the question "what
> does selecting a tab have to do with killing buffers?"
Here is a better docstring:
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tab-bar-select-keep-windows.patch --]
[-- Type: text/x-diff, Size: 3131 bytes --]
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 61efa332e0b..f05596d5ed9 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -1393,6 +1405,53 @@ tab-bar-tab-post-select-functions
:group 'tab-bar
:version "30.1")
+(defcustom tab-bar-select-keep-windows-function #'tab-bar-select-keep-windows
+ "Function that keeps windows after selecting a tab.
+When a previously selected tab displayed a buffer that was later killed,
+this function defines what to do with the window that displayed that buffer
+after switching back to the previous tab. By default, either a random
+buffer is displayed instead of the killed buffer, or the window gets deleted.
+However, with the help of `window-kept-windows-functions' it's possible
+to handle such situations better by displaying an information about
+the killed buffer."
+ :type '(choice (const :tag "No special handling" nil)
+ (const :tag "Show placeholder buffers"
+ tab-bar-select-keep-windows)
+ (function :tag "Function"))
+ :group 'tab-bar
+ :version "30.1")
+
+(defun tab-bar-select-keep-windows (_frame windows)
+ "Display a placeholder buffer in the window with killed buffer.
+A button allows to restore a killed file buffer."
+ (dolist (quad windows)
+ (when (window-live-p (nth 0 quad))
+ (let* ((window (nth 0 quad))
+ (old-buffer (nth 1 quad))
+ (file (when (bufferp old-buffer)
+ (buffer-file-name old-buffer)))
+ (name (or file
+ (and (fboundp 'buffer-last-name)
+ (buffer-last-name old-buffer))
+ old-buffer))
+ (new-buffer (generate-new-buffer
+ (format "*Old buffer %s*" name))))
+ (with-current-buffer new-buffer
+ (set-auto-mode)
+ (insert (format-message "This window displayed the %s `%s'.\n"
+ (if file "file" "buffer")
+ name))
+ (when file
+ (insert-button
+ "[Restore]" 'action
+ (lambda (_button)
+ (set-window-buffer window (find-file-noselect file))
+ (set-window-start window (nth 2 quad) t)
+ (set-window-point window (nth 3 quad)))))
+ (goto-char (point-min))
+ (setq buffer-read-only t)
+ (set-window-buffer window new-buffer))))))
+
(defvar tab-bar-minibuffer-restore-tab nil
"Tab number for `tab-bar-minibuffer-restore-tab'.")
@@ -1438,7 +1497,10 @@ tab-bar-select-tab
(let* ((from-tab (tab-bar--tab))
(to-tab (nth to-index tabs))
(wc (alist-get 'wc to-tab))
- (ws (alist-get 'ws to-tab)))
+ (ws (alist-get 'ws to-tab))
+ (window-kept-windows-functions
+ (delq nil (cons tab-bar-select-keep-windows-function
+ window-kept-windows-functions))))
;; During the same session, use window-configuration to switch
;; tabs, because window-configurations are more reliable
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-15 10:11 ` Andreas Schwab
0 siblings, 2 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-08 9:21 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
[-- Attachment #1: Type: text/plain, Size: 3957 bytes --]
> We could leave it called on every set-window-configuration
> even with an empty window list, as a general post-hook.
I've now reworked the patch for the following reasons:
- Changing the existing behavior of 'window-state-put' in order to make
it behave like 'set-window-configuration' in certain regards is a bad
idea IMO. Someone, somewhere might be used to the current behavior.
- The entire idea of deleting windows when their buffers are dead might
annoy people who prefer a fixed frame layout with a predefined number
of windows.
The new patch attached renames 'window-kept-windows-functions' to
`window-restore-dead-buffer-windows'. That variable is no more a hook
but may be
- t to never delete a dead buffer window,
- 'delete' to do what 'window-state-put' does now
- 'dedicated' to do what 'set-window-configuration' does now
- nil to keep the current behavior
- a function to do what 'window-kept-windows-functions' did.
I abandoned the hook idea because having more than one function work on
a list of kept windows means asking for troubles. In addition, I now
pass a third argument to that function - 'configuration' if called by
'set-window-configuration' and 'state' if called by 'window-state-put'.
When looking into this I (re)discovered that 'set-window-configuration'
leaves dead buffer windows alone if they do have a buffer in the
configuration that function is about to replace. This comment
/* Kludge Alert!
Mark all windows now on frame as "deleted".
Restoring the new configuration "undeletes" any that are in it.
Save their current buffers in their height fields, since we may
need it later, if a buffer saved in the configuration is now
dead. */
tells how this was done in the past and these two snippets
/* Since combination limit makes sense for an internal windows
only, we use this slot to save the buffer for the sake of
possible resurrection in Fset_window_configuration. */
wset_combination_limit (w, w->contents);
and
/* If we squirreled away the buffer, restore it now. */
if (BUFFERP (w->combination_limit))
wset_buffer (w, w->combination_limit);
explain how this is done now. (Calling delete_all_child_windows and
running SAFE_NALLOCA in 'set-window-configuration' is a bad idea given
the fact that the body of 'save-window-excursion' practically never
changes the existing configuration, but I won't discuss that here.)
Suffice it to say that 'set-window-configuration' leaves a dead buffer
window alone if it shows a buffer in the configuration it is about to
replace. 'window-state-put' does not do that because it has no idea of
the identity of windows and making it map the current window tree into
the window tree it is about to restore does not look like an appealing
endeavor to me (besides the fact that it would change existing behavior
again).
Now what I did was to add two more entries for each window passed to the
'window-restore-dead-buffer-windows' function:
- One for the dedicated status of the window in the saved configuration
or state. If you restore the old buffer, you should also set that, I
suppose.
- One that is t if the window was live in the configuration replaced by
'set-window-configuration'. It might help to decide whether the new
buffer would be a better alternative than restoring the dead buffer.
I don't think the tab bar code would need it.
Have a look.
> BTW, I didn't test yet what happens when
> window-kept-windows-functions is non-nil but does nothing.
> Here is what happens:
>
> Error muted by safe_call: (get-scratch-buffer-create)
> signaled (wrong-type-argument window-live-p #<window 7>)
>
> But maybe this is ok.
I now made it call 'window-restore-dead-buffer-windows' iff it is a
function (it may still have the wrong number of arguments though). BTW
the "Error muted by safe_call" messages are helpful - once you get used
to them.
martin
[-- Attachment #2: window-restore-dead-buffer-windows.diff --]
[-- Type: text/x-patch, Size: 25468 bytes --]
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index fe3dc573df5..951c898a6ee 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -6264,15 +6264,10 @@ Window Configurations
@code{minibuffer-selected-window}. In this case, the function returns
@code{nil}. Otherwise, it returns @code{t}.
-If the buffer of a window of @var{configuration} has been killed since
-@var{configuration} was made, that window is, as a rule, removed from
-the restored configuration. However, if that window is the last window
-remaining in the restored configuration, another live buffer is shown in
-it. Also, if the variable @var{window-kept-windows-functions} is
-non-@code{nil}, any window whose buffer is now dead is not deleted.
-Rather, this function will show another live buffer in that window and
-include an entry for that window when calling any function in
-@var{window-kept-windows-functions} (@pxref{Window Hooks}).
+This function consults the variable
+@code{window-restore-dead-buffer-windows} (see below) when it tries to
+restore a window whose buffer was killed after @var{configuration} was
+recorded.
Here is a way of using this function to get the same effect as
@code{save-window-excursion}:
@@ -6361,14 +6356,9 @@ Window Configurations
frame before putting @var{state} into it. If @var{window} is @code{nil},
it puts the window state into a new window.
-If the buffer of any window recorded in @var{state} has been killed
-since @var{state} was made, that window is, as a rule, not restored.
-However, if that window is the only window in @var{state}, another live
-buffer will be shown in it. Also, if the variable
-@var{window-kept-windows-functions} is non-@code{nil}, any window whose
-buffer is now dead is restored. This function will show another live
-buffer in it and include an entry for that window when calling a
-function in @var{window-kept-windows-functions} (@pxref{Window Hooks}).
+This function consults the variable
+@code{window-restore-dead-buffer-windows} (see below) when it tries to
+restore a window whose buffer was killed after @var{state} was recorded.
If the optional argument @var{ignore} is non-@code{nil}, it means to ignore
minimum window sizes and fixed-size restrictions. If @var{ignore}
@@ -6376,6 +6366,74 @@ Window Configurations
and/or two columns.
@end defun
+By default, @code{set-window-configuration} and @code{window-state-put}
+may delete a window from the restored configuration when they find out
+that its buffer was killed since the corresponding configuration or
+state has been recorded. The variable described next can be used to
+fine-tune that behavior.
+
+@cindex restoring windows whose buffers are dead
+@defvar window-restore-dead-buffer-windows
+This variable specifies how @code{set-window-configuration} or
+@code{window-state-put} shall handle a window whose buffer has been
+killed since the corresponding configuration or state was made. Any
+such window may be live - in which case it shows some other buffer - or
+dead at the time one of these functions is called. As a rule,
+@code{set-window-configuration} leaves the window alone if it is live
+while @code{window-state-put} deletes it.
+
+The following values can be used to override the default behavior for
+dead windows in the case of @code{set-window-configuration} and for dead
+and live windows in the case of @code{window-state-put}.
+
+@table @asis
+@item @code{t}
+This value means to restore the window and show some other buffer in it.
+
+@item @code{delete}
+This means to unconditionally try to delete the window.
+
+@item @code{dedicated}
+This means to try to delete the window if and only if it is dedicated to
+its buffer.
+
+@item @code{nil}
+This is the default and means that @code{set-window-configuration} will
+try to delete the window if and only if it is dedicated to its buffer
+and @code{window-state-put} will unconditionally try to delete it.
+
+@item a function
+This means to restore the window, show some other buffer in it and add
+an entry for that window to a list that will be later passed as argument
+to that function.
+@end table
+
+If a window cannot be deleted (typically, because it is the last window
+on its frame), @code{set-window-configuration} and
+@code{window-state-put} will show another buffer in it.
+
+If the value of this variable is a function, that function should take
+three arguments. The first argument specifies the frame whose windows
+have been restored. The third argument is either the constant
+@code{configuration} if the windows are restored by
+@code{set-window-configuration} or the constant @code{state} if the
+windows are restored by @code{window-state-put}.
+
+The second argument specifies a list of entries for @emph{any} window
+whose previous buffer has been encountered dead at the time
+@code{set-window-configuration} or @code{window-state-put} tried to
+restore it in that window (minibuffer windows are excluded). This means
+that the function specified by this variable may also delete windows
+encountered live by @code{set-window-configuration}.
+
+Each entry is a list of six values - the window whose buffer was found
+dead, the dead buffer or its name, the positions of start and point of
+the buffer in that window, the dedicated status of the window as
+previously reported by @code{window-dedicated-p} and a flag that is
+@code{t} if the window has been encountered live by
+@code{set-window-configuration} and @code{nil} otherwise.
+@end defvar
+
The functions @code{window-state-get} and @code{window-state-put} also
allow exchanging the contents of two live windows. The following
function does precisely that:
@@ -6636,27 +6694,6 @@ Window Hooks
buffer are (re)fontified because a window was scrolled or its size
changed. @xref{Other Font Lock Variables}.
-@cindex window kept windows functions
-@defvar window-kept-windows-functions
- This variable holds a list of functions that Emacs will call after
-restoring a window configuration via @code{set-window-configuration} or
-state via @code{window-state-put} (@pxref{Window Configurations}). When
-the value of this variable is non-@code{nil}, these functions will not
-delete any window whose buffer has been killed since the corresponding
-configuration or state was saved, but 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 windows have been restored.
-The second argument specifies a list of entries for each window whose
-buffer has been found dead at the time @code{set-window-configuration}
-or @code{window-state-put} tried to restore it. Each entry is a list of
-four values - the window whose buffer was found dead, the dead buffer,
-and the last known positions of start and point of the buffer in that
-window. Any function run by this hook should check that the window is
-live since another function run by this hook may have deleted it in the
-meantime.
-@end defvar
-
@cindex window change functions
The remainder of this section covers six hooks that are called
during redisplay provided a significant, non-scrolling change of a
diff --git a/lisp/window.el b/lisp/window.el
index 29336f573f8..90094d020e4 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -6286,7 +6286,8 @@ window--state-put-2
(when state
(let* ((old-buffer-or-name (car state))
(buffer (get-buffer old-buffer-or-name))
- (state (cdr state)))
+ (state (cdr state))
+ (dedicated (cdr (assq 'dedicated state))))
(if (buffer-live-p buffer)
(with-current-buffer buffer
(set-window-buffer window buffer)
@@ -6345,7 +6346,7 @@ window--state-put-2
window delta t ignore nil nil nil pixelwise))
(window-resize window delta t ignore pixelwise))))
;; Set dedicated status.
- (set-window-dedicated-p window (cdr (assq 'dedicated state)))
+ (set-window-dedicated-p window dedicated)
;; Install positions (maybe we should do this after all
;; windows have been created and sized).
(ignore-errors
@@ -6388,12 +6389,14 @@ window--state-put-2
(set-marker (make-marker) m2
buffer))))))
prev-buffers))))
- ;; We don't want to raise an error in case the buffer does
- ;; not exist anymore, so we switch to a previous one and
- ;; save the window with the intention of deleting it later
- ;; if possible.
- (switch-to-prev-buffer window)
- (if window-kept-windows-functions
+ (unless (window-minibuffer-p window)
+ ;; We don't want to raise an error in case the buffer does
+ ;; not exist anymore, so we switch to a previous one and
+ ;; save the window with the intention of deleting it later
+ ;; if possible.
+ (switch-to-prev-buffer window)
+ (cond
+ ((functionp window-restore-dead-buffer-windows)
(let* ((start (cdr (assq 'start state)))
;; Handle both - marker positions from writable
;; states and markers from non-writable states.
@@ -6404,9 +6407,15 @@ window--state-put-2
(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))))))))
+ (push (list window old-buffer-or-name
+ start-pos point-pos dedicated nil)
+ window-state-put-kept-windows)))
+ ((or (and dedicated
+ (eq window-restore-dead-buffer-windows 'dedicated))
+ (memq window-restore-dead-buffer-windows '(nil delete)))
+ ;; Try to delete the window.
+ (push window window-state-put-stale-windows)))
+ (set-window-dedicated-p window nil))))))))
(defun window-state-put (state &optional window ignore)
"Put window state STATE into WINDOW.
@@ -6421,16 +6430,9 @@ window-state-put
windows can get as small as `window-safe-min-height' and
`window-safe-min-width'.
-If the abnormal hook `window-kept-windows-functions' is non-nil,
-do not delete any windows saved by STATE whose buffers were
-deleted since STATE was saved. Rather, show some live buffer in
-them and call the functions 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."
+If this function tries to restore a non-minibuffer window whose buffer
+was killed since STATE was made, it will consult the variable
+`window-restore-dead-buffer-windows' on how to proceed."
(setq window-state-put-stale-windows nil)
(setq window-state-put-kept-windows nil)
@@ -6544,10 +6546,9 @@ window-state-put
(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)
+ (when (functionp window-restore-dead-buffer-windows)
+ (funcall window-restore-dead-buffer-windows
+ frame window-state-put-kept-windows 'state)
(setq window-state-put-kept-windows nil))
(window--check frame))))
diff --git a/src/buffer.c b/src/buffer.c
index 126f3eb055a..e8daa93c2d9 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -327,6 +327,11 @@ bset_name (struct buffer *b, Lisp_Object val)
b->name_ = val;
}
static void
+bset_last_name (struct buffer *b, Lisp_Object val)
+{
+ b->last_name_ = val;
+}
+static void
bset_overwrite_mode (struct buffer *b, Lisp_Object val)
{
b->overwrite_mode_ = val;
@@ -647,6 +652,7 @@ DEFUN ("get-buffer-create", Fget_buffer_create, Sget_buffer_create, 1, 2, 0,
name = Fcopy_sequence (buffer_or_name);
set_string_intervals (name, NULL);
bset_name (b, name);
+ bset_last_name (b, name);
b->inhibit_buffer_hooks = !NILP (inhibit_buffer_hooks);
bset_undo_list (b, SREF (name, 0) != ' ' ? Qnil : Qt);
@@ -866,6 +872,7 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
name = Fcopy_sequence (name);
set_string_intervals (name, NULL);
bset_name (b, name);
+ bset_last_name (b, name);
/* An indirect buffer shares undo list of its base (Bug#18180). */
bset_undo_list (b, BVAR (b->base_buffer, undo_list));
@@ -1282,6 +1289,16 @@ DEFUN ("buffer-name", Fbuffer_name, Sbuffer_name, 0, 1, 0,
return BVAR (decode_buffer (buffer), name);
}
+DEFUN ("buffer-last-name", Fbuffer_last_name, Sbuffer_last_name, 0, 1, 0,
+ doc: /* Return last name of BUFFER, as a string.
+BUFFER defaults to the current buffer.
+
+This is the last name of BUFFER before it has been renamed or killed. */)
+ (Lisp_Object buffer)
+{
+ return BVAR (decode_buffer (buffer), last_name);
+}
+
DEFUN ("buffer-file-name", Fbuffer_file_name, Sbuffer_file_name, 0, 1, 0,
doc: /* Return name of file BUFFER is visiting, or nil if none.
No argument or nil as argument means use the current buffer. */)
@@ -1652,6 +1669,7 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
(register Lisp_Object newname, Lisp_Object unique)
{
register Lisp_Object tem, buf;
+ Lisp_Object oldname = BVAR (current_buffer, name);
Lisp_Object requestedname = newname;
CHECK_STRING (newname);
@@ -1669,12 +1687,12 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
if (NILP (unique) && XBUFFER (tem) == current_buffer)
return BVAR (current_buffer, name);
if (!NILP (unique))
- newname = Fgenerate_new_buffer_name (newname,
- BVAR (current_buffer, name));
+ newname = Fgenerate_new_buffer_name (newname, oldname);
else
error ("Buffer name `%s' is in use", SDATA (newname));
}
+ bset_last_name (current_buffer, oldname);
bset_name (current_buffer, newname);
/* Catch redisplay's attention. Unless we do this, the mode lines for
@@ -2087,6 +2105,7 @@ DEFUN ("kill-buffer", Fkill_buffer, Skill_buffer, 0, 1, "bKill buffer: ",
This gets rid of them for certain. */
reset_buffer_local_variables (b, 1);
+ bset_last_name (b, BVAR (b, name));
bset_name (b, Qnil);
block_input ();
@@ -4658,6 +4677,7 @@ init_buffer_once (void)
/* These used to be stuck at 0 by default, but now that the all-zero value
means Qnil, we have to initialize them explicitly. */
bset_name (&buffer_local_flags, make_fixnum (0));
+ bset_last_name (&buffer_local_flags, make_fixnum (0));
bset_mark (&buffer_local_flags, make_fixnum (0));
bset_local_var_alist (&buffer_local_flags, make_fixnum (0));
bset_keymap (&buffer_local_flags, make_fixnum (0));
@@ -6018,6 +6038,7 @@ Functions (implicitly) running this hook are `get-buffer-create',
defsubr (&Smake_indirect_buffer);
defsubr (&Sgenerate_new_buffer_name);
defsubr (&Sbuffer_name);
+ defsubr (&Sbuffer_last_name);
defsubr (&Sbuffer_file_name);
defsubr (&Sbuffer_base_buffer);
defsubr (&Sbuffer_local_value);
diff --git a/src/buffer.h b/src/buffer.h
index 87ba2802b39..bbe1aeff668 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -309,6 +309,9 @@ #define BVAR(buf, field) ((buf)->field ## _)
/* The name of this buffer. */
Lisp_Object name_;
+ /* The last name of this buffer before it was renamed or killed. */
+ Lisp_Object last_name_;
+
/* The name of the file visited in this buffer, or nil. */
Lisp_Object filename_;
diff --git a/src/window.c b/src/window.c
index ea761fad8bc..031019de7fe 100644
--- a/src/window.c
+++ b/src/window.c
@@ -7109,23 +7109,9 @@ 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 such a window for
-liveness because another function run by this hook may have deleted it
-in the meantime."
+This function consults the variable `window-restore-dead-buffer-windows'
+when restoring a window whose buffer was killed after CONFIGURATION was
+recorded.
If CONFIGURATION was made from a frame that is now deleted,
only frame-independent values can be restored. In this case,
@@ -7378,10 +7364,12 @@ 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,
+ if (FUNCTIONP (Vwindow_restore_dead_buffer_windows)
+ && !MINI_WINDOW_P (w))
+ kept_windows = Fcons (listn (6, window, p->buffer,
Fmarker_last_position (p->start),
- Fmarker_last_position (p->pointm)),
+ Fmarker_last_position (p->pointm),
+ p->dedicated, Qt),
kept_windows);
}
else if (!NILP (w->start))
@@ -7398,16 +7386,25 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
set_marker_restricted_both (w->pointm, w->contents, 0, 0);
set_marker_restricted_both (w->old_pointm, w->contents, 0, 0);
w->start_at_line_beg = true;
- if (!NILP (w->dedicated))
- /* Record this window as dead. */
- 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);
+ if (!MINI_WINDOW_P (w))
+ {
+ if (FUNCTIONP (Vwindow_restore_dead_buffer_windows))
+ kept_windows
+ = Fcons (listn (6, window, p->buffer,
+ Fmarker_last_position (p->start),
+ Fmarker_last_position (p->pointm),
+ p->dedicated, Qnil),
+ kept_windows);
+ else if (EQ (Vwindow_restore_dead_buffer_windows, Qdelete)
+ || (!NILP (p->dedicated)
+ && (NILP (Vwindow_restore_dead_buffer_windows)
+ || EQ (Vwindow_restore_dead_buffer_windows,
+ Qdedicated))))
+ /* Try to delete this window later. */
+ dead_windows = Fcons (window, dead_windows);
+ /* Make sure window is no more dedicated. */
+ wset_dedicated (w, Qnil);
+ }
}
}
@@ -7459,13 +7456,12 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
unblock_input ();
/* Scan dead buffer windows. */
- 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);
- }
+ 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. */
@@ -7513,9 +7509,9 @@ DEFUN ("set-window-configuration", Fset_window_configuration,
SAFE_FREE ();
- if (!NILP (Vrun_hooks) && !NILP (Vwindow_kept_windows_functions))
- run_hook_with_args_2 (Qwindow_kept_windows_functions, frame,
- kept_windows);
+ if (!NILP (Vrun_hooks) && FUNCTIONP (Vwindow_restore_dead_buffer_windows))
+ safe_calln (Vwindow_restore_dead_buffer_windows,
+ frame, kept_windows, Qconfiguration);
return FRAME_LIVE_P (f) ? Qt : Qnil;
}
@@ -8514,8 +8510,9 @@ 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");
+ DEFSYM (Qconfiguration, "configuration");
+ DEFSYM (Qdelete, "delete");
+ DEFSYM (Qdedicated, "dedicated");
DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function,
doc: /* Non-nil means call as function to display a help buffer.
@@ -8673,27 +8670,59 @@ 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 ("window-restore-dead-buffer-windows",
+ Vwindow_restore_dead_buffer_windows,
+ doc: /* Control restoration of dead buffer windows.
+This variable specifies how the functions `set-window-configuration' and
+`window-state-put' shall handle a window whose buffer has been killed
+since the corresponding configuration or state was made. Any such
+window may be live - in which case it shows some other buffer - or dead
+at the time one of these functions is called.
+
+As a rule, `set-window-configuration' leaves the window alone if it is
+live while `window-state-put' deletes it. The following values can be
+used to override the default behavior for dead windows in the case of
+`set-window-configuration' and for dead and live windows in the case of
+`window-state-put'.
+
+- t means to restore the window and show some other buffer in it.
+
+- `delete' means to try to delete the window.
+
+- `dedicated' means to try to delete the window if and only if it is
+ dedicated to its buffer.
+
+- nil, the default, means that `set-window-configuration' will try to
+ delete the window if and only if it is dedicated to its buffer and
+ `window-state-put' will unconditionally try to delete it.
+
+- a function means to restore the window, show some other buffer in it
+ and add an entry for that window to a list that will be later passed
+ as argument to that function.
+
+If a window cannot be deleted (typically, because it is the last window
+on its frame), show another buffer in it.
+
+If the value is a function, it should take three arguments. The first
+argument specifies the frame whose windows have been restored. The
+third argument is the constant `configuration' if the windows are
+restored by `set-window-configuration' and the constant `state' if the
+windows are restored by `window-state-put'.
+
+The second argument specifies a list of entries for @emph{any} window
+whose previous buffer has been encountered dead at the time
+`set-window-configuration' or `window-state-put' tried to restore it in
+that window (minibuffer windows are excluded). This means that the
+function specified by this variable may also delete windows encountered
+live by `set-window-configuration'.
+
+Each entry is a list of six values - the window whose buffer was found
+dead, the dead buffer or its name, the positions of start and point of
+the buffer in that window, the dedicated status of the window as
+reported by `window-dedicated-p' and a boolean - t if the window was
+live when `set-window-configuration' tried to restore it and nil
+otherwise. */);
+ Vwindow_restore_dead_buffer_windows = Qnil;
DEFVAR_LISP ("recenter-redisplay", Vrecenter_redisplay,
doc: /* Non-nil means `recenter' redraws entire frame.
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-03-06 18:03 ` Juri Linkov
@ 2024-03-09 8:35 ` Eli Zaretskii
2024-03-17 17:57 ` Juri Linkov
0 siblings, 1 reply; 85+ messages in thread
From: Eli Zaretskii @ 2024-03-09 8:35 UTC (permalink / raw)
To: Juri Linkov; +Cc: rudalics, 68235
> From: Juri Linkov <juri@linkov.net>
> Cc: rudalics@gmx.at, 68235@debbugs.gnu.org
> Date: Wed, 06 Mar 2024 20:03:50 +0200
>
> > This doc string doesn't explain enough: it begs the question "what
> > does selecting a tab have to do with killing buffers?"
>
> Here is a better docstring:
>
> +(defcustom tab-bar-select-keep-windows-function #'tab-bar-select-keep-windows
> + "Function that keeps windows after selecting a tab.
> +When a previously selected tab displayed a buffer that was later killed,
> +this function defines what to do with the window that displayed that buffer
> +after switching back to the previous tab.
Thanks, this is much more clear now. I suggest a slight rewording:
Function called when selecting a tab to handle windows whose buffer was killed.
When a tab-bar tab displays a window whose buffer was killed since
this tab was last selected, this function determines what to do with
that window.
> +(defun tab-bar-select-keep-windows (_frame windows)
> + "Display a placeholder buffer in the window with killed buffer.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"...in the window whose buffer was killed."
> +A button allows to restore a killed file buffer."
"A button in the window allows to restore the killed buffer, if
it was visiting a file."
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-03-15 9:38 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-03-15 10:11 ` Andreas Schwab
1 sibling, 2 replies; 85+ messages in thread
From: Juri Linkov @ 2024-03-10 17:23 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
> The new patch attached renames 'window-kept-windows-functions' to
> `window-restore-dead-buffer-windows'.
Thanks. I finished testing your new patch, and everything works nicely.
Regarding the name `window-restore-dead-buffer-windows',
I thought that the epithet "dead" is applied only to windows,
but buffers are called "killed", but maybe I got the wrong impression.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-03-15 9:38 ` martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-11 9:13 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
> Regarding the name `window-restore-dead-buffer-windows',
> I thought that the epithet "dead" is applied only to windows,
> but buffers are called "killed", but maybe I got the wrong impression.
I'll call it `window-restore-killed-buffer-windows' and install in a
week unless new issues come up.
Thanks, martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-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
1 sibling, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-15 9:38 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
>> The new patch attached renames 'window-kept-windows-functions' to
>> `window-restore-dead-buffer-windows'.
>
> Thanks. I finished testing your new patch, and everything works nicely.
>
> Regarding the name `window-restore-dead-buffer-windows',
> I thought that the epithet "dead" is applied only to windows,
> but buffers are called "killed", but maybe I got the wrong impression.
Pushed to master now. Please check again.
Thanks, martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-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
1 sibling, 1 reply; 85+ messages in thread
From: Andreas Schwab @ 2024-03-15 10:11 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235, Juri Linkov
On Mär 08 2024, martin rudalics wrote:
> diff --git a/src/buffer.h b/src/buffer.h
> index 87ba2802b39..bbe1aeff668 100644
> --- a/src/buffer.h
> +++ b/src/buffer.h
> @@ -309,6 +309,9 @@ #define BVAR(buf, field) ((buf)->field ## _)
> /* The name of this buffer. */
> Lisp_Object name_;
>
> + /* The last name of this buffer before it was renamed or killed. */
> + Lisp_Object last_name_;
> +
> /* The name of the file visited in this buffer, or nil. */
> Lisp_Object filename_;
>
../../emacs/src/pdumper.c: In function ‘dump_buffer’:
../../emacs/src/pdumper.c:2800:3: error: #error "buffer changed. See CHECK_STRUCTS comment in config.h."
2800 | # error "buffer changed. See CHECK_STRUCTS comment in config.h."
| ^~~~~
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1
"And now for something completely different."
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 0 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-15 10:56 UTC (permalink / raw)
To: Andreas Schwab; +Cc: 68235, Juri Linkov
> ../../emacs/src/pdumper.c: In function ‘dump_buffer’:
> ../../emacs/src/pdumper.c:2800:3: error: #error "buffer changed. See CHECK_STRUCTS comment in config.h."
> 2800 | # error "buffer changed. See CHECK_STRUCTS comment in config.h."
> | ^~~~~
Hopefully fixed now. Please try again.
Thanks, martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-03-17 17:47 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
> Pushed to master now. Please check again.
Thank you very much. Everything is working nicely.
One thing I don't understand what is the purpose of
`marker-last-position'? It's intended to be used in
a function in `window-restore-killed-buffer-windows'?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-03-09 8:35 ` Eli Zaretskii
@ 2024-03-17 17:57 ` Juri Linkov
0 siblings, 0 replies; 85+ messages in thread
From: Juri Linkov @ 2024-03-17 17:57 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: rudalics, 68235
> Thanks, this is much more clear now. I suggest a slight rewording:
>
> Function called when selecting a tab to handle windows whose buffer was killed.
> When a tab-bar tab displays a window whose buffer was killed since
> this tab was last selected, this function determines what to do with
> that window.
>
>> +(defun tab-bar-select-keep-windows (_frame windows)
>> + "Display a placeholder buffer in the window with killed buffer.
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> "...in the window whose buffer was killed."
>
>> +A button allows to restore a killed file buffer."
>
> "A button in the window allows to restore the killed buffer, if
> it was visiting a file."
So now the patch is pushed with these changes.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 0 replies; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-03-18 10:13 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
> One thing I don't understand what is the purpose of
> `marker-last-position'? It's intended to be used in
> a function in `window-restore-killed-buffer-windows'?
It's needed in 'set-window-configuration' and 'window-state-put' to
provide the last positions of a window's start and point when its buffer
was killed. It could be used in 'window-restore-killed-buffer-windows'
to restore other markers as well but I'm currently not aware of whether
such markers exist and whether restoring them would be useful.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 2 replies; 85+ messages in thread
From: Juri Linkov @ 2024-04-09 6:53 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
> I'll call it `window-restore-killed-buffer-windows' and install in a
> week unless new issues come up.
I found one interesting problem with `window-restore-killed-buffer-windows'.
Here is a reproducible test case:
0. emacs -Q
1. cd etc/images/
2. RET to visit the first image
3. C-x t 2
4. n to visit the next image
5. C-x t o
The previous tab shows:
"This window displayed the buffer ‘ **lose**’."
What it expected here instead of **lose**
is the real file buffer with the previous image.
The problem is that 'image-next-file' calls 'find-alternate-file'
that does such buffer renaming:
(if (get-buffer " **lose**")
(kill-buffer " **lose**"))
(rename-buffer " **lose**")
and 'rename-buffer' changes the buffer's last name to **lose**.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
1 sibling, 0 replies; 85+ messages in thread
From: Eli Zaretskii @ 2024-04-09 7:36 UTC (permalink / raw)
To: Juri Linkov; +Cc: rudalics, 68235
> Cc: 68235@debbugs.gnu.org
> From: Juri Linkov <juri@linkov.net>
> Date: Tue, 09 Apr 2024 09:53:41 +0300
>
> The previous tab shows:
>
> "This window displayed the buffer ‘ **lose**’."
>
> What it expected here instead of **lose**
> is the real file buffer with the previous image.
>
> The problem is that 'image-next-file' calls 'find-alternate-file'
> that does such buffer renaming:
>
> (if (get-buffer " **lose**")
> (kill-buffer " **lose**"))
> (rename-buffer " **lose**")
>
> and 'rename-buffer' changes the buffer's last name to **lose**.
Any idea why does image-next-file do that? Or is this problem
specific to using tabs?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
1 sibling, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-09 9:22 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
[-- Attachment #1: Type: text/plain, Size: 381 bytes --]
> The problem is that 'image-next-file' calls 'find-alternate-file'
> that does such buffer renaming:
>
> (if (get-buffer " **lose**")
> (kill-buffer " **lose**"))
> (rename-buffer " **lose**")
>
> and 'rename-buffer' changes the buffer's last name to **lose**.
Isn't the problem that it leaves the last name nil? Does the attached
diff fix it?
Thanks, martin
[-- Attachment #2: rename-buffer.diff --]
[-- Type: text/x-patch, Size: 611 bytes --]
diff --git a/src/buffer.c b/src/buffer.c
index 291c7d3f911..5e2386c94fa 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1686,7 +1686,11 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
with the original name. It makes UNIQUE equivalent to
(rename-buffer (generate-new-buffer-name NEWNAME)). */
if (NILP (unique) && XBUFFER (tem) == current_buffer)
- return BVAR (current_buffer, name);
+ {
+ bset_last_name (current_buffer, oldname);
+
+ return BVAR (current_buffer, name);
+ }
if (!NILP (unique))
newname = Fgenerate_new_buffer_name (newname, oldname);
else
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-04-09 16:40 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> The problem is that 'image-next-file' calls 'find-alternate-file'
>> that does such buffer renaming:
>>
>> (if (get-buffer " **lose**")
>> (kill-buffer " **lose**"))
>> (rename-buffer " **lose**")
>>
>> and 'rename-buffer' changes the buffer's last name to **lose**.
>
> Isn't the problem that it leaves the last name nil? Does the attached
> diff fix it?
>
> diff --git a/src/buffer.c b/src/buffer.c
> index 291c7d3f911..5e2386c94fa 100644
> --- a/src/buffer.c
> +++ b/src/buffer.c
> @@ -1686,7 +1686,11 @@ DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
> with the original name. It makes UNIQUE equivalent to
> (rename-buffer (generate-new-buffer-name NEWNAME)). */
> if (NILP (unique) && XBUFFER (tem) == current_buffer)
> - return BVAR (current_buffer, name);
> + {
> + bset_last_name (current_buffer, oldname);
> +
> + return BVAR (current_buffer, name);
> + }
> if (!NILP (unique))
> newname = Fgenerate_new_buffer_name (newname, oldname);
> else
Alas, this doesn't help. Because 'find-alternate-file' renames
the buffer with (rename-buffer " **lose**") before killing it.
So 'kill-buffer' remembers the last buffer name " **lose**".
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-10 8:47 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
> Alas, this doesn't help.
I will have to install it nonetheless. Otherwise, I would have to
change the doc-string of 'buffer-last-name' which says
This is the name BUFFER had before the last time it was renamed or
immediately before it was killed.
> Because 'find-alternate-file' renames
> the buffer with (rename-buffer " **lose**") before killing it.
> So 'kill-buffer' remembers the last buffer name " **lose**".
But that's correct and reflects what the doc-string says. The problem
must be elsewhere. Basically, it seems to me that when we have a live
buffer whose name is " **lose**" and a killed buffer with the same last
name (or maybe two or more killed buffers with the same last name) we
have a conflict that we have to resolve somehow. Right? I don't
understand why we can't "prefer" the live buffer to the dead buffer
here. For dead buffers, the problem might be that of finding the right
one, in particular when they have different file names.
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-04-10 17:35 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> Because 'find-alternate-file' renames
>> the buffer with (rename-buffer " **lose**") before killing it.
>> So 'kill-buffer' remembers the last buffer name " **lose**".
>
> But that's correct and reflects what the doc-string says. The problem
> must be elsewhere. Basically, it seems to me that when we have a live
> buffer whose name is " **lose**" and a killed buffer with the same last
> name (or maybe two or more killed buffers with the same last name) we
> have a conflict that we have to resolve somehow. Right? I don't
> understand why we can't "prefer" the live buffer to the dead buffer
> here. For dead buffers, the problem might be that of finding the right
> one, in particular when they have different file names.
What is worse is that 'find-alternate-file' also resets
'buffer-file-name' to nil before killing the " **lose**" buffer.
So even can't use a file name.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-11 9:16 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
> What is worse is that 'find-alternate-file' also resets
> 'buffer-file-name' to nil before killing the " **lose**" buffer.
> So even can't use a file name.
Would replacing
(kill-buffer obuf))))))
with
(setq buffer-file-name ofile)
(setq buffer-file-number onum)
(setq buffer-file-truename otrue)
(kill-buffer obuf))))))
fix that?
I never used 'find-alternate-file' and, after looking at its code for
the first time now, wouldn't touch it with a ten foot pole. Using it in
'image-next-file' seems a very bad idea: Is there any guarantee that the
assumptions about which buffer is current hold when running things like
'kill-buffer-query-functions' or 'kill-buffer-hook' manually?
martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-04-12 6:30 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> What is worse is that 'find-alternate-file' also resets
>> 'buffer-file-name' to nil before killing the " **lose**" buffer.
>> So even can't use a file name.
>
> Would replacing
>
> (kill-buffer obuf))))))
>
> with
>
> (setq buffer-file-name ofile)
> (setq buffer-file-number onum)
> (setq buffer-file-truename otrue)
> (kill-buffer obuf))))))
>
> fix that?
>
> I never used 'find-alternate-file' and, after looking at its code for
> the first time now, wouldn't touch it with a ten foot pole.
Indeed, I have the same impression.
> Using it in
> 'image-next-file' seems a very bad idea: Is there any guarantee that the
> assumptions about which buffer is current hold when running things like
> 'kill-buffer-query-functions' or 'kill-buffer-hook' manually?
Using 'find-alternate-file' in 'image-next-file' looks fine.
There are no other problems. And revealing " **lose**"
while restoring windows is not a bug deal.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-12 8:18 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
[-- Attachment #1: Type: text/plain, Size: 757 bytes --]
> Using 'find-alternate-file' in 'image-next-file' looks fine.
> There are no other problems. And revealing " **lose**"
> while restoring windows is not a bug deal.
OK. Please try the attached patch. With something like
(let ((buffer (find-file-noselect "~/foo.el")))
(with-current-buffer buffer
(find-alternate-file "~/bar.el")
(message "%s..%s" (buffer-last-name buffer) (buffer-file-name buffer))))
it should work fine thus fixing the image mode problem. With
(let ((buffer (find-file-noselect "~/foo/bar.el")))
(with-current-buffer buffer
(find-alternate-file "~/bar/bar.el")
(message "%s..%s" (buffer-last-name buffer) (buffer-file-name buffer))))
you can still use the old file name to restore the buffer.
martin
[-- Attachment #2: files.el.diff --]
[-- Type: text/x-patch, Size: 787 bytes --]
diff --git a/lisp/files.el b/lisp/files.el
index e8a5e5783b6..48a39c242b7 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -2105,6 +2105,15 @@ find-alternate-file
(rename-buffer oname)))
(unless (eq (current-buffer) obuf)
(with-current-buffer obuf
+ (unless (get-buffer oname)
+ ;; Restore original's buffer name so 'kill-buffer' can use it
+ ;; to assign its last name (Bug#68235).
+ (rename-buffer oname))
+ ;; Restore original buffer's file names so they can be still
+ ;; used when referencing the now defunct buffer (Bug#68235).
+ (setq buffer-file-name ofile)
+ (setq buffer-file-number onum)
+ (setq buffer-file-truename otrue)
;; We already ran these; don't run them again.
(let (kill-buffer-query-functions kill-buffer-hook)
(kill-buffer obuf))))))
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-04-12 16:20 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
> OK. Please try the attached patch. With something like
>
> (let ((buffer (find-file-noselect "~/foo.el")))
> (with-current-buffer buffer
> (find-alternate-file "~/bar.el")
> (message "%s..%s" (buffer-last-name buffer) (buffer-file-name buffer))))
>
> it should work fine thus fixing the image mode problem. With
>
> (let ((buffer (find-file-noselect "~/foo/bar.el")))
> (with-current-buffer buffer
> (find-alternate-file "~/bar/bar.el")
> (message "%s..%s" (buffer-last-name buffer) (buffer-file-name buffer))))
>
> you can still use the old file name to restore the buffer.
Thanks, I confirm this completely fixes the original test case.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-15 9:21 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
> Thanks, I confirm this completely fixes the original test case.
Should be installed now. Please have a look.
Thanks, martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-21 9:27 ` Eli Zaretskii
0 siblings, 2 replies; 85+ messages in thread
From: Juri Linkov @ 2024-04-21 6:59 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> Thanks, I confirm this completely fixes the original test case.
>
> Should be installed now. Please have a look.
I noticed that now 'find-alternate-file' has such a problem
that it updates the modification timestamp of the directory.
This is because 'find-alternate-file' calls 'rename-buffer'
before setting back the value of 'buffer-file-name'.
So this code in 'rename-buffer' is fired and changes
the directory modification timestamp:
if (NILP (BVAR (current_buffer, filename))
&& !NILP (BVAR (current_buffer, auto_save_file_name)))
call0 (intern ("rename-auto-save-file"));
A possible fix would be to swap the order of
setting of 'buffer-file-name' and 'rename-buffer':
diff --git a/lisp/files.el b/lisp/files.el
index 1e11dd44bad..5ef1160ab18 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -2113,15 +2113,15 @@ find-alternate-file
(rename-buffer oname)))
(unless (eq (current-buffer) obuf)
(with-current-buffer obuf
+ ;; Restore original buffer's file names so they can be still
+ ;; used when referencing the now defunct buffer (Bug#68235).
+ (setq buffer-file-name ofile)
+ (setq buffer-file-number onum)
+ (setq buffer-file-truename otrue)
(unless (get-buffer oname)
;; Restore original's buffer name so 'kill-buffer' can use it
;; to assign its last name (Bug#68235).
(rename-buffer oname))
- ;; Restore original buffer's file names so they can be still
- ;; used when referencing the now defunct buffer (Bug#68235).
- (setq buffer-file-name ofile)
- (setq buffer-file-number onum)
- (setq buffer-file-truename otrue)
;; We already ran these; don't run them again.
(let (kill-buffer-query-functions kill-buffer-hook)
(kill-buffer obuf))))))
^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
1 sibling, 1 reply; 85+ messages in thread
From: martin rudalics via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-04-21 8:56 UTC (permalink / raw)
To: Juri Linkov; +Cc: 68235
> I noticed that now 'find-alternate-file' has such a problem
> that it updates the modification timestamp of the directory.
>
> This is because 'find-alternate-file' calls 'rename-buffer'
> before setting back the value of 'buffer-file-name'.
> So this code in 'rename-buffer' is fired and changes
> the directory modification timestamp:
>
> if (NILP (BVAR (current_buffer, filename))
> && !NILP (BVAR (current_buffer, auto_save_file_name)))
> call0 (intern ("rename-auto-save-file"));
Why does an auto-save file exist at all in this situation? If the
original buffer was modified, 'find-alternate-file' should have saved it
into its file and deleted the auto-save file. Does your code rely on
fine tuned directory timestamps?
> A possible fix would be to swap the order of
> setting of 'buffer-file-name' and 'rename-buffer':
I see no problems doing that so please install.
Thanks, martin
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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-21 9:27 ` Eli Zaretskii
2024-04-22 6:40 ` Juri Linkov
1 sibling, 1 reply; 85+ messages in thread
From: Eli Zaretskii @ 2024-04-21 9:27 UTC (permalink / raw)
To: Juri Linkov; +Cc: rudalics, 68235
> Cc: 68235@debbugs.gnu.org
> From: Juri Linkov <juri@linkov.net>
> Date: Sun, 21 Apr 2024 09:59:28 +0300
>
> >> Thanks, I confirm this completely fixes the original test case.
> >
> > Should be installed now. Please have a look.
>
> I noticed that now 'find-alternate-file' has such a problem
> that it updates the modification timestamp of the directory.
Why is this a problem?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-04-21 9:27 ` Eli Zaretskii
@ 2024-04-22 6:40 ` Juri Linkov
2024-04-22 7:00 ` Eli Zaretskii
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-04-22 6:40 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: rudalics, 68235
>> >> Thanks, I confirm this completely fixes the original test case.
>> >
>> > Should be installed now. Please have a look.
>>
>> I noticed that now 'find-alternate-file' has such a problem
>> that it updates the modification timestamp of the directory.
>
> Why is this a problem?
Because it doesn't do any modification.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
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
0 siblings, 0 replies; 85+ messages in thread
From: Juri Linkov @ 2024-04-22 6:46 UTC (permalink / raw)
To: martin rudalics; +Cc: 68235
>> I noticed that now 'find-alternate-file' has such a problem
>> that it updates the modification timestamp of the directory.
>>
>> This is because 'find-alternate-file' calls 'rename-buffer'
>> before setting back the value of 'buffer-file-name'.
>> So this code in 'rename-buffer' is fired and changes
>> the directory modification timestamp:
>>
>> if (NILP (BVAR (current_buffer, filename))
>> && !NILP (BVAR (current_buffer, auto_save_file_name)))
>> call0 (intern ("rename-auto-save-file"));
>
> Why does an auto-save file exist at all in this situation? If the
> original buffer was modified, 'find-alternate-file' should have saved it
> into its file and deleted the auto-save file. Does your code rely on
> fine tuned directory timestamps?
Nothing special is done. The problem is reproducible in 'emacs -Q'
with the original test case.
This is because image-mode modifies the timestamp unless a special handling
is used such as in 'image-toggle-display-image':
(let ((create-lockfiles nil)) ; avoid changing dir mtime by lock_file
(add-text-properties (point-min) (point-max) props)
(restore-buffer-modified-p modified))
But 'rename-buffer' can't do the same.
>> A possible fix would be to swap the order of
>> setting of 'buffer-file-name' and 'rename-buffer':
>
> I see no problems doing that so please install.
Thanks, so now installed.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-04-22 6:40 ` Juri Linkov
@ 2024-04-22 7:00 ` Eli Zaretskii
2024-04-22 16:36 ` Juri Linkov
0 siblings, 1 reply; 85+ messages in thread
From: Eli Zaretskii @ 2024-04-22 7:00 UTC (permalink / raw)
To: Juri Linkov; +Cc: rudalics, 68235
> From: Juri Linkov <juri@linkov.net>
> Cc: rudalics@gmx.at, 68235@debbugs.gnu.org
> Date: Mon, 22 Apr 2024 09:40:06 +0300
>
> >> >> Thanks, I confirm this completely fixes the original test case.
> >> >
> >> > Should be installed now. Please have a look.
> >>
> >> I noticed that now 'find-alternate-file' has such a problem
> >> that it updates the modification timestamp of the directory.
> >
> > Why is this a problem?
>
> Because it doesn't do any modification.
Sorry, I don't understand: you said it renames a file, didn't you?
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-04-22 7:00 ` Eli Zaretskii
@ 2024-04-22 16:36 ` Juri Linkov
2024-04-22 19:22 ` Eli Zaretskii
0 siblings, 1 reply; 85+ messages in thread
From: Juri Linkov @ 2024-04-22 16:36 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: rudalics, 68235
>> >> >> Thanks, I confirm this completely fixes the original test case.
>> >> >
>> >> > Should be installed now. Please have a look.
>> >>
>> >> I noticed that now 'find-alternate-file' has such a problem
>> >> that it updates the modification timestamp of the directory.
>> >
>> > Why is this a problem?
>>
>> Because it doesn't do any modification.
>
> Sorry, I don't understand: you said it renames a file, didn't you?
It renames a buffer.
^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#68235: 29.1.90; Switching tabs stops following process output in selected window
2024-04-22 16:36 ` Juri Linkov
@ 2024-04-22 19:22 ` Eli Zaretskii
0 siblings, 0 replies; 85+ messages in thread
From: Eli Zaretskii @ 2024-04-22 19:22 UTC (permalink / raw)
To: Juri Linkov; +Cc: rudalics, 68235
> From: Juri Linkov <juri@linkov.net>
> Cc: rudalics@gmx.at, 68235@debbugs.gnu.org
> Date: Mon, 22 Apr 2024 19:36:16 +0300
>
> >> >> >> Thanks, I confirm this completely fixes the original test case.
> >> >> >
> >> >> > Should be installed now. Please have a look.
> >> >>
> >> >> I noticed that now 'find-alternate-file' has such a problem
> >> >> that it updates the modification timestamp of the directory.
> >> >
> >> > Why is this a problem?
> >>
> >> Because it doesn't do any modification.
> >
> > Sorry, I don't understand: you said it renames a file, didn't you?
>
> It renames a buffer.
Could you possibly be a bit more friendly by explaining the issue in
more than just 4 words? Renaming a buffer will not cause a change in
directory's timestamp, so there must be something else involved.
And my original question, which is still unanswered, was why this is a
problem. My point is that I don't see why changing the timestamp of
some directory should be a problem for Emacs users. I'd still would
like to understand this.
^ permalink raw reply [flat|nested] 85+ messages in thread
end of thread, other threads:[~2024-04-22 19:22 UTC | newest]
Thread overview: 85+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.