aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurence Warne2022-12-22 17:16:08 +0000
committerEli Zaretskii2023-01-14 10:36:15 +0200
commitf0ac01812f93ea8bea95e37415987e8d7a82fb1c (patch)
tree886de06bd731871393aeffe34e7e98c8f27dcdc6
parent4514b7ecc6fdf8d2642ea6ff84f0af3868a3a658 (diff)
downloademacs-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.el104
-rw-r--r--test/lisp/proced-tests.el17
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
798The returned information will have the form `(PID KEY COLUMN)' where
799PID is the process ID of the process at point, KEY is the value of the
800proced-key text property at point, and COLUMN is the column for which the
801current 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
819Attempt to find the first position on the current line where the
820text property proced-key is equal to KEY. If this is not possible, return
821the 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