diff options
| author | Laurence Warne | 2022-12-22 17:16:08 +0000 |
|---|---|---|
| committer | Eli Zaretskii | 2023-01-14 10:36:15 +0200 |
| commit | f0ac01812f93ea8bea95e37415987e8d7a82fb1c (patch) | |
| tree | 886de06bd731871393aeffe34e7e98c8f27dcdc6 | |
| parent | 4514b7ecc6fdf8d2642ea6ff84f0af3868a3a658 (diff) | |
| download | emacs-f0ac01812f93ea8bea95e37415987e8d7a82fb1c.tar.gz emacs-f0ac01812f93ea8bea95e37415987e8d7a82fb1c.zip | |
Preserve the window position with proced (bug#60381)
Preserve the window position for windows which display a proced
buffer, but are not the selected window when a proced buffer is
updated. Previously, the window position would be set to the
start of the buffer when a proced buffer was updated and it was
not displayed in the selected window.
Similarly, preserve the position in proced buffers which are not
displayed in any window by setting
'switch-to-buffer-preserve-window-point' to nil in proced buffers.
* lisp/proced.el (proced-auto-update-timer): Only update a given
proced buffer if it is displayed in a window.
(proced-update): Set the window position if the proced buffer is
displayed in a window.
(proced--position-info, proced--determine-pos): New Functions.
(proced-mode): Set 'switch-to-buffer-preserve-window-point' to
nil in proced buffers.
* test/lisp/proced-tests.el
(proced-update-preserves-pid-at-point-test): New test.
| -rw-r--r-- | lisp/proced.el | 104 | ||||
| -rw-r--r-- | test/lisp/proced-tests.el | 17 |
2 files changed, 88 insertions, 33 deletions
diff --git a/lisp/proced.el b/lisp/proced.el index 839b36b528f..29a05f2d5db 100644 --- a/lisp/proced.el +++ b/lisp/proced.el | |||
| @@ -792,6 +792,52 @@ Return nil if point is not on a process line." | |||
| 792 | (if (looking-at "^. .") | 792 | (if (looking-at "^. .") |
| 793 | (get-text-property (match-end 0) 'proced-pid)))) | 793 | (get-text-property (match-end 0) 'proced-pid)))) |
| 794 | 794 | ||
| 795 | (defun proced--position-info (pos) | ||
| 796 | "Return information of the process at POS. | ||
| 797 | |||
| 798 | The returned information will have the form `(PID KEY COLUMN)' where | ||
| 799 | PID is the process ID of the process at point, KEY is the value of the | ||
| 800 | proced-key text property at point, and COLUMN is the column for which the | ||
| 801 | current value of the proced-key text property starts, or 0 if KEY is nil." | ||
| 802 | ;; If point is on a field, we try to return point to that field. | ||
| 803 | ;; Otherwise we try to return to the same column | ||
| 804 | (save-excursion | ||
| 805 | (goto-char pos) | ||
| 806 | (let ((pid (proced-pid-at-point)) | ||
| 807 | (key (get-text-property (point) 'proced-key))) | ||
| 808 | (list pid key ; can both be nil | ||
| 809 | (if key | ||
| 810 | (if (get-text-property (1- (point)) 'proced-key) | ||
| 811 | (- (point) (previous-single-property-change | ||
| 812 | (point) 'proced-key)) | ||
| 813 | 0) | ||
| 814 | (current-column)))))) | ||
| 815 | |||
| 816 | (defun proced--determine-pos (key column) | ||
| 817 | "Return the point in the current line using KEY and COLUMN. | ||
| 818 | |||
| 819 | Attempt to find the first position on the current line where the | ||
| 820 | text property proced-key is equal to KEY. If this is not possible, return | ||
| 821 | the point of column COLUMN on the current line." | ||
| 822 | (save-excursion | ||
| 823 | (let (new-pos) | ||
| 824 | (if key | ||
| 825 | (let ((limit (line-end-position)) pos) | ||
| 826 | (while (and (not new-pos) | ||
| 827 | (setq pos (next-property-change (point) nil limit))) | ||
| 828 | (goto-char pos) | ||
| 829 | (when (eq key (get-text-property (point) 'proced-key)) | ||
| 830 | (forward-char (min column (- (next-property-change (point)) | ||
| 831 | (point)))) | ||
| 832 | (setq new-pos (point)))) | ||
| 833 | (unless new-pos | ||
| 834 | ;; we found the process, but the field of point | ||
| 835 | ;; is not listed anymore | ||
| 836 | (setq new-pos (proced-move-to-goal-column)))) | ||
| 837 | (setq new-pos (min (+ (line-beginning-position) column) | ||
| 838 | (line-end-position)))) | ||
| 839 | new-pos))) | ||
| 840 | |||
| 795 | ;; proced mode | 841 | ;; proced mode |
| 796 | 842 | ||
| 797 | (define-derived-mode proced-mode special-mode "Proced" | 843 | (define-derived-mode proced-mode special-mode "Proced" |
| @@ -847,6 +893,7 @@ normal hook `proced-post-display-hook'. | |||
| 847 | (setq-local revert-buffer-function #'proced-revert) | 893 | (setq-local revert-buffer-function #'proced-revert) |
| 848 | (setq-local font-lock-defaults | 894 | (setq-local font-lock-defaults |
| 849 | '(proced-font-lock-keywords t nil nil beginning-of-line)) | 895 | '(proced-font-lock-keywords t nil nil beginning-of-line)) |
| 896 | (setq-local switch-to-buffer-preserve-window-point nil) | ||
| 850 | (if (and (not proced-auto-update-timer) proced-auto-update-interval) | 897 | (if (and (not proced-auto-update-timer) proced-auto-update-interval) |
| 851 | (setq proced-auto-update-timer | 898 | (setq proced-auto-update-timer |
| 852 | (run-at-time t proced-auto-update-interval | 899 | (run-at-time t proced-auto-update-interval |
| @@ -1889,17 +1936,10 @@ After updating a displayed Proced buffer run the normal hook | |||
| 1889 | (if (consp buffer-undo-list) | 1936 | (if (consp buffer-undo-list) |
| 1890 | (setq buffer-undo-list nil)) | 1937 | (setq buffer-undo-list nil)) |
| 1891 | (let ((buffer-undo-list t) | 1938 | (let ((buffer-undo-list t) |
| 1892 | ;; If point is on a field, we try to return point to that field. | 1939 | (window-pos-infos |
| 1893 | ;; Otherwise we try to return to the same column | 1940 | (mapcar (lambda (w) `(,w . ,(proced--position-info (window-point w)))) |
| 1894 | (old-pos (let ((pid (proced-pid-at-point)) | 1941 | (get-buffer-window-list (current-buffer) nil t))) |
| 1895 | (key (get-text-property (point) 'proced-key))) | 1942 | (old-pos (proced--position-info (point))) |
| 1896 | (list pid key ; can both be nil | ||
| 1897 | (if key | ||
| 1898 | (if (get-text-property (1- (point)) 'proced-key) | ||
| 1899 | (- (point) (previous-single-property-change | ||
| 1900 | (point) 'proced-key)) | ||
| 1901 | 0) | ||
| 1902 | (current-column))))) | ||
| 1903 | buffer-read-only mp-list) | 1943 | buffer-read-only mp-list) |
| 1904 | ;; remember marked processes (whatever the mark was) | 1944 | ;; remember marked processes (whatever the mark was) |
| 1905 | (goto-char (point-min)) | 1945 | (goto-char (point-min)) |
| @@ -1932,7 +1972,8 @@ After updating a displayed Proced buffer run the normal hook | |||
| 1932 | ;; Sometimes this puts point in the middle of the proced buffer | 1972 | ;; Sometimes this puts point in the middle of the proced buffer |
| 1933 | ;; where it is not interesting. Is there a better / more flexible solution? | 1973 | ;; where it is not interesting. Is there a better / more flexible solution? |
| 1934 | (goto-char (point-min)) | 1974 | (goto-char (point-min)) |
| 1935 | (let (pid mark new-pos) | 1975 | |
| 1976 | (let (pid mark new-pos win-points) | ||
| 1936 | (if (or mp-list (car old-pos)) | 1977 | (if (or mp-list (car old-pos)) |
| 1937 | (while (not (eobp)) | 1978 | (while (not (eobp)) |
| 1938 | (setq pid (proced-pid-at-point)) | 1979 | (setq pid (proced-pid-at-point)) |
| @@ -1941,28 +1982,25 @@ After updating a displayed Proced buffer run the normal hook | |||
| 1941 | (delete-char 1) | 1982 | (delete-char 1) |
| 1942 | (beginning-of-line)) | 1983 | (beginning-of-line)) |
| 1943 | (when (eq (car old-pos) pid) | 1984 | (when (eq (car old-pos) pid) |
| 1944 | (if (nth 1 old-pos) | 1985 | (setq new-pos (proced--determine-pos (nth 1 old-pos) |
| 1945 | (let ((limit (line-end-position)) pos) | 1986 | (nth 2 old-pos)))) |
| 1946 | (while (and (not new-pos) | 1987 | (mapc (lambda (w-pos) |
| 1947 | (setq pos (next-property-change (point) nil limit))) | 1988 | (when (eq (cadr w-pos) pid) |
| 1948 | (goto-char pos) | 1989 | (push `(,(car w-pos) . ,(proced--determine-pos |
| 1949 | (when (eq (nth 1 old-pos) | 1990 | (nth 1 (cdr w-pos)) |
| 1950 | (get-text-property (point) 'proced-key)) | 1991 | (nth 2 (cdr w-pos)))) |
| 1951 | (forward-char (min (nth 2 old-pos) | 1992 | win-points))) |
| 1952 | (- (next-property-change (point)) | 1993 | window-pos-infos) |
| 1953 | (point)))) | ||
| 1954 | (setq new-pos (point)))) | ||
| 1955 | (unless new-pos | ||
| 1956 | ;; we found the process, but the field of point | ||
| 1957 | ;; is not listed anymore | ||
| 1958 | (setq new-pos (proced-move-to-goal-column)))) | ||
| 1959 | (setq new-pos (min (+ (line-beginning-position) (nth 2 old-pos)) | ||
| 1960 | (line-end-position))))) | ||
| 1961 | (forward-line))) | 1994 | (forward-line))) |
| 1962 | (if new-pos | 1995 | (let ((fallback (save-excursion (goto-char (point-min)) |
| 1963 | (goto-char new-pos) | 1996 | (proced-move-to-goal-column) |
| 1964 | (goto-char (point-min)) | 1997 | (point)))) |
| 1965 | (proced-move-to-goal-column))) | 1998 | (goto-char (or new-pos fallback)) |
| 1999 | ;; Update window points | ||
| 2000 | (mapc (lambda (w-pos) | ||
| 2001 | (set-window-point (car w-pos) | ||
| 2002 | (alist-get (car w-pos) win-points fallback))) | ||
| 2003 | window-pos-infos))) | ||
| 1966 | ;; update mode line | 2004 | ;; update mode line |
| 1967 | ;; Does the long `mode-name' clutter the mode line? It would be nice | 2005 | ;; Does the long `mode-name' clutter the mode line? It would be nice |
| 1968 | ;; to have some other location for displaying the values of the various | 2006 | ;; to have some other location for displaying the values of the various |
diff --git a/test/lisp/proced-tests.el b/test/lisp/proced-tests.el index 3c1f5493e74..1f475665298 100644 --- a/test/lisp/proced-tests.el +++ b/test/lisp/proced-tests.el | |||
| @@ -101,5 +101,22 @@ | |||
| 101 | (should (string= pid (word-at-point))) | 101 | (should (string= pid (word-at-point))) |
| 102 | (forward-line))))) | 102 | (forward-line))))) |
| 103 | 103 | ||
| 104 | (ert-deftest proced-update-preserves-pid-at-point-test () | ||
| 105 | (proced--within-buffer | ||
| 106 | 'medium | ||
| 107 | 'user | ||
| 108 | (goto-char (point-min)) | ||
| 109 | (search-forward (number-to-string (emacs-pid))) | ||
| 110 | (proced--move-to-column "PID") | ||
| 111 | (save-window-excursion | ||
| 112 | (let ((pid (proced-pid-at-point)) | ||
| 113 | (new-window (split-window)) | ||
| 114 | (old-window (get-buffer-window))) | ||
| 115 | (select-window new-window) | ||
| 116 | (with-current-buffer "*Proced*" | ||
| 117 | (proced-update t t)) | ||
| 118 | (select-window old-window) | ||
| 119 | (should (= pid (proced-pid-at-point))))))) | ||
| 120 | |||
| 104 | (provide 'proced-tests) | 121 | (provide 'proced-tests) |
| 105 | ;;; proced-tests.el ends here | 122 | ;;; proced-tests.el ends here |