New functions to set and use context of window points (bug#33871)

* lisp/dired.el (dired-mode): Set buffer-local
'window-point-context-set-function' to remember 'dired-filename'
or 'position' in the window with the Dired buffer.
Set buffer-local 'window-point-context-use-function' to restore
the remembered position of the window point.

* lisp/tab-bar.el (tab-bar--tab): Use window-point-context-set.
(tab-bar-select-restore-context): New user option.
(tab-bar-select-tab): Use window-point-context-use.

* lisp/window.el: Add '(context . writable)' to
'window-persistent-parameters'.
(window-point-context-set, window-point-context-use): New functions.
(window-point-context-set-default-function)
(window-point-context-use-default-function): New functions.
(window-point-context-set-function)
(window-point-context-use-function): New variables.
This commit is contained in:
Juri Linkov 2024-04-02 20:17:41 +03:00
parent 617debf673
commit c3781bf59e
4 changed files with 124 additions and 0 deletions

View file

@ -309,8 +309,24 @@ It specifies how 'set-window-configuration' and 'window-state-put'
should proceed with windows whose buffer was killed after the
corresponding configuration or state was recorded.
*** New variable 'window-point-context-set-function'.
It can be used to set a context for window point in all windows by
'window-point-context-set' before calling 'current-window-configuration'
and 'window-state-get'. Then later another new variable
'window-point-context-use-function' can be used by
'window-point-context-use' after 'set-window-configuration' and
'window-state-put' to restore positions of window points
according to the context stored in a window parameter.
** Tab Bars and Tab Lines
---
*** New user option 'tab-bar-select-restore-context'.
It uses 'window-point-context-set' to save contexts where
window points were located before switching away from the tab,
and 'window-point-context-use' to restore positions of window
points after switching back to that tab.
---
*** New user option 'tab-bar-select-restore-windows'.
It defines what to do with windows whose buffer was killed

View file

@ -2743,6 +2743,26 @@ Keybindings:
'(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-point-context-set-function
(lambda (w)
(with-current-buffer (window-buffer w)
(let ((point (window-point w)))
(save-excursion
(goto-char point)
(if-let ((f (dired-get-filename nil t)))
`((dired-filename . ,f))
`((position . ,(point)))))))))
(setq-local window-point-context-use-function
(lambda (w context)
(with-current-buffer (window-buffer w)
(let ((point (window-point w)))
(save-excursion
(if-let ((f (alist-get 'dired-filename context)))
(dired-goto-file f)
(when-let ((p (alist-get 'position context)))
(goto-char p)))
(setq point (point)))
(set-window-point w point)))))
(setq dired-switches-alist nil)
(hack-dir-local-variables-non-file-buffer) ; before sorting
(dired-sort-other dired-actual-switches t)

View file

@ -1292,6 +1292,9 @@ tab bar might wrap to the second line when it shouldn't.")
frame 'buffer-list)))
(bbl (seq-filter #'buffer-live-p (frame-parameter
frame 'buried-buffer-list))))
(when tab-bar-select-restore-context
(window-point-context-set))
`(tab
(name . ,(if tab-explicit-name
(alist-get 'name tab)
@ -1442,6 +1445,16 @@ if it was visiting a file."
(setq buffer-read-only t)
(set-window-buffer window new-buffer))))))
(defcustom tab-bar-select-restore-context t
"If this is non-nil, try to restore window points from their contexts.
This will try to find the same position in every window where point was
before switching away from this tab. After selecting this tab,
point in every window will be moved to its previous position
in the buffer even when the buffer was modified."
:type 'boolean
:group 'tab-bar
:version "30.1")
(defvar tab-bar-minibuffer-restore-tab nil
"Tab number for `tab-bar-minibuffer-restore-tab'.")
@ -1539,6 +1552,9 @@ Negative TAB-NUMBER counts tabs from the end of the tab bar."
(select-window (get-mru-window)))
(window-state-put ws nil 'safe)))
(when tab-bar-select-restore-context
(window-point-context-use))
;; Select the minibuffer when it was active before switching tabs
(when (and minibuffer-was-active (active-minibuffer-window))
(select-window (active-minibuffer-window)))

View file

@ -10838,6 +10838,78 @@ displaying that processes's buffer."
(set-process-window-size process (cdr size) (car size))))))))))
(add-hook 'window-configuration-change-hook 'window--adjust-process-windows)
;;; Window point context
(defun window-point-context-set ()
"Set context near the window point.
Call function specified by `window-point-context-set-function' for every
live window on the selected frame with that window as sole argument.
The function called is supposed to return a context of the window's point
that can be later used as argument for `window-point-context-use-function'.
Remember the returned context in the window parameter `context'."
(walk-windows
(lambda (w)
(when-let ((fn (buffer-local-value 'window-point-context-set-function
(window-buffer w)))
((functionp fn))
(context (funcall fn w)))
(set-window-parameter w 'context (cons (buffer-name) context))))
'nomini))
(defun window-point-context-use ()
"Use context to relocate the window point.
Call function specified by `window-point-context-use-function' to move the
window point according to the previously saved context. For every live
window on the selected frame this function is called with two arguments:
the window and the context data structure saved by
`window-point-context-set-function' in the window parameter `context'.
The function called is supposed to set the window point to the location
found by the provided context."
(walk-windows
(lambda (w)
(when-let ((fn (buffer-local-value 'window-point-context-use-function
(window-buffer w)))
((functionp fn))
(context (window-parameter w 'context))
((equal (buffer-name) (car context))))
(funcall fn w (cdr context))
(set-window-parameter w 'context nil)))
'nomini))
(add-to-list 'window-persistent-parameters '(context . writable))
(defun window-point-context-set-default-function (w)
"Set context of file buffers to the front and rear strings."
(with-current-buffer (window-buffer w)
(when buffer-file-name
(let ((point (window-point w)))
`((front-context-string
. ,(buffer-substring-no-properties
point (min (+ point 16) (point-max))))
(rear-context-string
. ,(buffer-substring-no-properties
point (max (- point 16) (point-min)))))))))
(defun window-point-context-use-default-function (w context)
"Restore context of file buffers by the front and rear strings."
(with-current-buffer (window-buffer w)
(let ((point (window-point w)))
(save-excursion
(goto-char point)
(when-let ((f (alist-get 'front-context-string context))
((search-forward f (point-max) t)))
(goto-char (match-beginning 0))
(when-let ((r (alist-get 'rear-context-string context))
((search-backward r (point-min) t)))
(goto-char (match-end 0))
(setq point (point)))))
(set-window-point w point))))
(defvar window-point-context-set-function 'window-point-context-set-default-function)
(defvar window-point-context-use-function 'window-point-context-use-default-function)
;; Some of these are in tutorial--default-keys, so update that if you
;; change these.