unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Customize ‘window-state-get/put’
@ 2019-10-07 16:19 Yuan Fu
  2019-10-07 22:01 ` Juri Linkov
  2019-10-08  8:45 ` martin rudalics
  0 siblings, 2 replies; 15+ messages in thread
From: Yuan Fu @ 2019-10-07 16:19 UTC (permalink / raw)
  To: Emacs developers

I’m adding the ability to store and restore window configuration for
gdb-mi. To make it work for gdb-mi I need to change what
‘window-state-get’ save - now it saves buffers and I need to not save
buffers. That’s because the buffer names for each window will change
across gdb sessions debugging different programs. Instead of buffer
name I need to store a symbol representing the ”buffer type” of the
window. E.g., register, memory, breakpoint, etc.

So instead of

    (buffer "*scratch*"
              (selected . t)
              (hscroll . 0)
              (fringes 8 8 nil)
              (margins nil)
              (scroll-bars nil 0 t nil 0 t)
              (vscroll . 0)
              (dedicated)
              (point . #<marker at 193 in *scratch*>)
              (start . #<marker at 1 in *scratch*>))

I would store something like

    (buffer 'register)

I would just add an optional argument that handles the extraction of
buffer information and another to restore a buffer from that
information. Does it sound like a good idea?




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-07 16:19 Customize ‘window-state-get/put’ Yuan Fu
@ 2019-10-07 22:01 ` Juri Linkov
  2019-10-08  0:13   ` Yuan Fu
  2019-10-08  8:05   ` Eli Zaretskii
  2019-10-08  8:45 ` martin rudalics
  1 sibling, 2 replies; 15+ messages in thread
From: Juri Linkov @ 2019-10-07 22:01 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Emacs developers

> I’m adding the ability to store and restore window configuration for
> gdb-mi. To make it work for gdb-mi I need to change what
> ‘window-state-get’ save - now it saves buffers and I need to not save
> buffers. That’s because the buffer names for each window will change
> across gdb sessions debugging different programs. Instead of buffer
> name I need to store a symbol representing the ”buffer type” of the
> window. E.g., register, memory, breakpoint, etc.
>
> So instead of
>
>     (buffer "*scratch*"
>               (selected . t)
>               (hscroll . 0)
>               (fringes 8 8 nil)
>               (margins nil)
>               (scroll-bars nil 0 t nil 0 t)
>               (vscroll . 0)
>               (dedicated)
>               (point . #<marker at 193 in *scratch*>)
>               (start . #<marker at 1 in *scratch*>))
>
> I would store something like
>
>     (buffer 'register)
>
> I would just add an optional argument that handles the extraction of
> buffer information and another to restore a buffer from that
> information. Does it sound like a good idea?

Is this needed because of such dynamically generated buffer names?

  (defun gdb-memory-buffer-name ()
    (concat "*memory of " (gdb-get-target-string) "*"))

Not too long ago we discussed an idea of defining a “window layout” -
a data structure similar to the returned by ‘window-state-get’, but
where instead of buffer names there are buffer regexps, so when
‘display-buffer’ needs to display a buffer, it consults a predefined
layout, finds the right window in its window tree, and displays the
buffer in the window whose buffer regexp matches the displayed
buffer name.  A new function like ‘window-state-get’ could generate
a layout from the current window configuration, or even from the
window state.  Then such layout could be exported to anywhere:
saved in the init file, in packages, etc.

BTW, while you are working on gdb-mi, you could also try to replace
the ad-hoc tabs implemented in the header-line, with real tabs in
the tab-line for “Locals”, “Registers”, “Breakpoints”, “Threads”, etc.
Just display these buffers in their dedicated window, and the tab-line
will show them as tabs.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-07 22:01 ` Juri Linkov
@ 2019-10-08  0:13   ` Yuan Fu
  2019-10-09 22:31     ` Juri Linkov
  2019-10-08  8:05   ` Eli Zaretskii
  1 sibling, 1 reply; 15+ messages in thread
From: Yuan Fu @ 2019-10-08  0:13 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Emacs developers

Juri Linkov <juri@linkov.net> writes:

> Is this needed because of such dynamically generated buffer names?
>
>   (defun gdb-memory-buffer-name ()
>     (concat "*memory of " (gdb-get-target-string) "*"))

Yes.

> Not too long ago we discussed an idea of defining a “window layout” -
> a data structure similar to the returned by ‘window-state-get’, but
> where instead of buffer names there are buffer regexps, so when
> ‘display-buffer’ needs to display a buffer, it consults a predefined
> layout, finds the right window in its window tree, and displays the
> buffer in the window whose buffer regexp matches the displayed
> buffer name.  A new function like ‘window-state-get’ could generate
> a layout from the current window configuration, or even from the
> window state.  Then such layout could be exported to anywhere:
> saved in the init file, in packages, etc.

Did you reach any conclusions? What was the title of that thread? I
couldn’t find it on emacs-devel archive with keywords like ”window
layout” or ”window-state-get”.

> BTW, while you are working on gdb-mi, you could also try to replace
> the ad-hoc tabs implemented in the header-line, with real tabs in
> the tab-line for “Locals”, “Registers”, “Breakpoints”, “Threads”, etc.
> Just display these buffers in their dedicated window, and the tab-line
> will show them as tabs.

I’ll add that to my list.

Yuan



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-07 22:01 ` Juri Linkov
  2019-10-08  0:13   ` Yuan Fu
@ 2019-10-08  8:05   ` Eli Zaretskii
  1 sibling, 0 replies; 15+ messages in thread
From: Eli Zaretskii @ 2019-10-08  8:05 UTC (permalink / raw)
  To: Juri Linkov; +Cc: casouri, emacs-devel

> From: Juri Linkov <juri@linkov.net>
> Date: Tue, 08 Oct 2019 01:01:14 +0300
> Cc: Emacs developers <emacs-devel@gnu.org>
> 
> BTW, while you are working on gdb-mi, you could also try to replace
> the ad-hoc tabs implemented in the header-line

It's not tabs, it's a kind-of tool bar.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-07 16:19 Customize ‘window-state-get/put’ Yuan Fu
  2019-10-07 22:01 ` Juri Linkov
@ 2019-10-08  8:45 ` martin rudalics
  1 sibling, 0 replies; 15+ messages in thread
From: martin rudalics @ 2019-10-08  8:45 UTC (permalink / raw)
  To: Yuan Fu, Emacs developers

 > I would store something like
 >
 >      (buffer 'register)
 >
 > I would just add an optional argument that handles the extraction of
 > buffer information and another to restore a buffer from that
 > information. Does it sound like a good idea?

As long as such values do not end up in a desktop file I see no
problems with it.

martin



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-08  0:13   ` Yuan Fu
@ 2019-10-09 22:31     ` Juri Linkov
  2019-10-10  0:35       ` Yuan Fu
  0 siblings, 1 reply; 15+ messages in thread
From: Juri Linkov @ 2019-10-09 22:31 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Emacs developers

>> Not too long ago we discussed an idea of defining a “window layout” -
>> a data structure similar to the returned by ‘window-state-get’, but
>> where instead of buffer names there are buffer regexps, so when
>> ‘display-buffer’ needs to display a buffer, it consults a predefined
>> layout, finds the right window in its window tree, and displays the
>> buffer in the window whose buffer regexp matches the displayed
>> buffer name.  A new function like ‘window-state-get’ could generate
>> a layout from the current window configuration, or even from the
>> window state.  Then such layout could be exported to anywhere:
>> saved in the init file, in packages, etc.
>
> Did you reach any conclusions? What was the title of that thread? I
> couldn’t find it on emacs-devel archive with keywords like ”window
> layout” or ”window-state-get”.

I tried to find a more recent discussion but search found this:
https://lists.gnu.org/archive/html/emacs-devel/2010-05/msg00458.html

But fortunately now we have window-states that are better suitable to build
the feature that you are adding.  So if you will have such template based
on exported window-state layout:

(hc (vc (leaf (buffer "\\`\\*\\(locals\\|registers\\) of .*\\*\\'"))
        (leaf (buffer "\\`\\*\\(breakpoints\\|threads\\) of .*\\*\\'")))
    (vc (leaf (buffer "\\`\\*memory of .*\\*\\'"))
        (leaf (buffer "\\`\\*stack frames of .*\\*\\'"))))

(window-sizes are omitted in this example, but they could be expressed
as percentage of relative window dimensions)

then calling (display-buffer "*memory of emacs*") could search in
such window-tree, find a window that matches the buffer name and
display this buffer in it.

This could be implemented by just adding a new display-buffer action.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-09 22:31     ` Juri Linkov
@ 2019-10-10  0:35       ` Yuan Fu
  2019-10-10 21:54         ` Juri Linkov
  0 siblings, 1 reply; 15+ messages in thread
From: Yuan Fu @ 2019-10-10  0:35 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Emacs developers

[-- Attachment #1: Type: text/plain, Size: 1727 bytes --]

> But fortunately now we have window-states that are better suitable to build
> the feature that you are adding.  So if you will have such template based
> on exported window-state layout:
>
> (hc (vc (leaf (buffer "\\`\\*\\(locals\\|registers\\) of .*\\*\\'"))
>         (leaf (buffer "\\`\\*\\(breakpoints\\|threads\\) of .*\\*\\'")))
>     (vc (leaf (buffer "\\`\\*memory of .*\\*\\'"))
>         (leaf (buffer "\\`\\*stack frames of .*\\*\\'"))))
>
> (window-sizes are omitted in this example, but they could be expressed
> as percentage of relative window dimensions)
>
> then calling (display-buffer "*memory of emacs*") could search in
> such window-tree, find a window that matches the buffer name and
> display this buffer in it.
>
> This could be implemented by just adding a new display-buffer action.

I’m not sure what are you trying to do overall. Why don’t I just create
the buffer by the buffer configurations I saved when saving the window
configuration?

OTOH, here is an experiment I did earlier today. I optionally replace
the buffer names and configurations with a function when saving window
config. So instead of

    (buffer "*scratch*"
             (selected . t)             
             ...
             (dedicated)
             (point . 290)
             (start . 1))

I save

    (buffer lambda nil
             (create-my-buffer "some useful info"))

And when window-state-put finds out the data is not buffer name but a
function, it simply calls the function to restore the buffer. This way
we can store information about the buffer and how to restore it in a
rather compact way. The change to existing code is pretty small, too.

WDYT?

Yuan


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-window.patch --]
[-- Type: text/x-patch, Size: 14739 bytes --]

From 9853d8e0f529be0b495415674e96346e575787e9 Mon Sep 17 00:00:00 2001
From: Yuan Fu <casouri@gmail.com>
Date: Wed, 9 Oct 2019 16:26:35 -0400
Subject: [PATCH] window

---
 lisp/window.el | 261 ++++++++++++++++++++++++++-----------------------
 1 file changed, 136 insertions(+), 125 deletions(-)

diff --git a/lisp/window.el b/lisp/window.el
index d93ec0add6..b2cebdb194 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -5669,7 +5669,7 @@ balance-windows-area
     ))
 
 ;;; Window states, how to get them and how to put them in a window.
-(defun window--state-get-1 (window &optional writable)
+(defun window--state-get-1 (window &optional writable buffer-fn)
   "Helper function for `window-state-get'."
   (let* ((type
 	  (cond
@@ -5718,28 +5718,30 @@ window--state-get-1
                   `((parameters . ,list))))
             ,@(when buffer
                 ;; All buffer related things go in here.
-		(let ((point (window-point window))
-		      (start (window-start window)))
-		  `((buffer
-		     ,(if writable (buffer-name buffer) buffer)
-		     (selected . ,selected)
-		     (hscroll . ,(window-hscroll window))
-		     (fringes . ,(window-fringes window))
-		     (margins . ,(window-margins window))
-		     (scroll-bars . ,(window-scroll-bars window))
-		     (vscroll . ,(window-vscroll window))
-		     (dedicated . ,(window-dedicated-p window))
-		     (point . ,(if writable
-                                   point
-                                 (with-current-buffer buffer
-                                   (copy-marker point
-                                                (buffer-local-value
-                                                 'window-point-insertion-type
-                                                 buffer)))))
-		     (start . ,(if writable
-                                   start
-                                 (with-current-buffer buffer
-                                   (copy-marker start))))))))
+		(if buffer-fn
+                    `((buffer . ,(funcall buffer-fn buffer)))
+                  (let ((point (window-point window))
+		        (start (window-start window)))
+		    `((buffer
+		       ,(if writable (buffer-name buffer) buffer)
+		       (selected . ,selected)
+		       (hscroll . ,(window-hscroll window))
+		       (fringes . ,(window-fringes window))
+		       (margins . ,(window-margins window))
+		       (scroll-bars . ,(window-scroll-bars window))
+		       (vscroll . ,(window-vscroll window))
+		       (dedicated . ,(window-dedicated-p window))
+		       (point . ,(if writable
+                                     point
+                                   (with-current-buffer buffer
+                                     (copy-marker point
+                                                  (buffer-local-value
+                                                   'window-point-insertion-type
+                                                   buffer)))))
+		       (start . ,(if writable
+                                     start
+                                   (with-current-buffer buffer
+                                     (copy-marker start)))))))))
             ,@(when next-buffers
                 `((next-buffers
                    . ,(if writable
@@ -5765,7 +5767,7 @@ window--state-get-1
 	      (nreverse list)))))
     (append head tail)))
 
-(defun window-state-get (&optional window writable)
+(defun window-state-get (&optional window writable buffer-fn)
   "Return state of WINDOW as a Lisp object.
 WINDOW can be any window and defaults to the root window of the
 selected frame.
@@ -5779,6 +5781,13 @@ window-state-get
 an `invalid-read-syntax' error while attempting to read back the
 value from file.
 
+Optional argument BUFFER-FN is a function that takes a buffer
+object and returns a function that takes no argument and
+recreates the buffer.  If you set WRITABLE to t, you shouldn't
+return any function with non-readable value in it.  And it is
+recommended to quote the lambda form you return in order to avoid
+lexical context.
+
 The return value can be used as argument for `window-state-put'
 to put the state recorded here into an arbitrary window.  The
 value can be also stored on disk and read back in a new session."
@@ -5806,7 +5815,7 @@ window-state-get
      (min-pixel-width-ignore  . ,(window-min-size window t t t))
      (min-pixel-height-safe   . ,(window-min-size window nil 'safe t))
      (min-pixel-width-safe    . ,(window-min-size window t 'safe t)))
-   (window--state-get-1 window writable)))
+   (window--state-get-1 window writable buffer-fn)))
 
 (defvar window-state-put-list nil
   "Helper variable for `window-state-put'.")
@@ -5911,106 +5920,108 @@ 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
-	      (with-current-buffer buffer
-		(set-window-buffer window buffer)
-		(set-window-hscroll window (cdr (assq 'hscroll state)))
-		(apply 'set-window-fringes
-		       (cons window (cdr (assq 'fringes state))))
-		(let ((margins (cdr (assq 'margins state))))
-		  (set-window-margins window (car margins) (cdr margins)))
-		(let ((scroll-bars (cdr (assq 'scroll-bars state))))
-		  (set-window-scroll-bars
-		   window (car scroll-bars) (nth 2 scroll-bars)
-		   (nth 3 scroll-bars) (nth 5 scroll-bars) (nth 6 scroll-bars)))
-		(set-window-vscroll window (cdr (assq 'vscroll state)))
-		;; Adjust vertically.
-		(if (or (memq window-size-fixed '(t height))
-                        (window-preserved-size window))
-		    ;; A fixed height window, try to restore the
-		    ;; original size.
-		    (let ((delta
-			   (- (cdr (assq
-				    (if pixelwise 'pixel-height 'total-height)
-				    item))
-			      (window-size window nil pixelwise)))
-			  window-size-fixed)
-		      (when (window--resizable-p
-			     window delta nil nil nil nil nil pixelwise)
-			(window-resize window delta nil nil pixelwise)))
-		  ;; Else check whether the window is not high enough.
-		  (let* ((min-size
-			  (window-min-size window nil ignore pixelwise))
-			 (delta
-			  (- min-size (window-size window nil pixelwise))))
-		    (when (and (> delta 0)
-			       (window--resizable-p
-				window delta nil ignore nil nil nil pixelwise))
-		      (window-resize window delta nil ignore pixelwise))))
-		;; Adjust horizontally.
-		(if (or (memq window-size-fixed '(t width))
-                        (window-preserved-size window t))
-		    ;; A fixed width window, try to restore the original
-		    ;; size.
-		    (let ((delta
-			   (- (cdr (assq
-				    (if pixelwise 'pixel-width 'total-width)
-				    item))
-			      (window-size window t pixelwise)))
-			  window-size-fixed)
-		      (when (window--resizable-p
-			     window delta t nil nil nil nil pixelwise)
-			(window-resize window delta t nil pixelwise)))
-		  ;; Else check whether the window is not wide enough.
-		  (let* ((min-size (window-min-size window t ignore pixelwise))
-			 (delta (- min-size (window-size window t pixelwise))))
-		    (when (and (> delta 0)
-			       (window--resizable-p
-				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)))
-		;; Install positions (maybe we should do this after all
-		;; windows have been created and sized).
-		(ignore-errors
-                  ;; Set 'noforce argument to avoid that window start
-                  ;; overrides window point set below (Bug#24240).
-		  (set-window-start window (cdr (assq 'start state)) 'noforce)
-		  (set-window-point window (cdr (assq 'point state))))
-		;; Select window if it's the selected one.
-		(when (cdr (assq 'selected state))
-		  (select-window window))
-                (when next-buffers
-                  (set-window-next-buffers
-                   window
-                   (delq nil (mapcar (lambda (buffer)
-                                       (setq buffer (get-buffer buffer))
-                                       (when (buffer-live-p buffer) buffer))
-                                     next-buffers))))
-                (when prev-buffers
-                  (set-window-prev-buffers
-                   window
-                   (delq nil (mapcar (lambda (entry)
-                                       (let ((buffer (get-buffer (nth 0 entry)))
-                                             (m1 (nth 1 entry))
-                                             (m2 (nth 2 entry)))
-                                         (when (buffer-live-p buffer)
-                                           (list buffer
-                                                 (if (markerp m1) m1
-                                                   (set-marker (make-marker) m1
-                                                               buffer))
-                                                 (if (markerp m2) m2
-                                                   (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)
-	    (push window window-state-put-stale-windows)))))))
+	(if (functionp state)
+            (funcall state)
+          (let ((buffer (get-buffer (car state)))
+	        (state (cdr state)))
+	    (if buffer
+	        (with-current-buffer buffer
+		  (set-window-buffer window buffer)
+		  (set-window-hscroll window (cdr (assq 'hscroll state)))
+		  (apply 'set-window-fringes
+		         (cons window (cdr (assq 'fringes state))))
+		  (let ((margins (cdr (assq 'margins state))))
+		    (set-window-margins window (car margins) (cdr margins)))
+		  (let ((scroll-bars (cdr (assq 'scroll-bars state))))
+		    (set-window-scroll-bars
+		     window (car scroll-bars) (nth 2 scroll-bars)
+		     (nth 3 scroll-bars) (nth 5 scroll-bars) (nth 6 scroll-bars)))
+		  (set-window-vscroll window (cdr (assq 'vscroll state)))
+		  ;; Adjust vertically.
+		  (if (or (memq window-size-fixed '(t height))
+                          (window-preserved-size window))
+		      ;; A fixed height window, try to restore the
+		      ;; original size.
+		      (let ((delta
+			     (- (cdr (assq
+				      (if pixelwise 'pixel-height 'total-height)
+				      item))
+			        (window-size window nil pixelwise)))
+			    window-size-fixed)
+		        (when (window--resizable-p
+			       window delta nil nil nil nil nil pixelwise)
+			  (window-resize window delta nil nil pixelwise)))
+		    ;; Else check whether the window is not high enough.
+		    (let* ((min-size
+			    (window-min-size window nil ignore pixelwise))
+			   (delta
+			    (- min-size (window-size window nil pixelwise))))
+		      (when (and (> delta 0)
+			         (window--resizable-p
+				  window delta nil ignore nil nil nil pixelwise))
+		        (window-resize window delta nil ignore pixelwise))))
+		  ;; Adjust horizontally.
+		  (if (or (memq window-size-fixed '(t width))
+                          (window-preserved-size window t))
+		      ;; A fixed width window, try to restore the original
+		      ;; size.
+		      (let ((delta
+			     (- (cdr (assq
+				      (if pixelwise 'pixel-width 'total-width)
+				      item))
+			        (window-size window t pixelwise)))
+			    window-size-fixed)
+		        (when (window--resizable-p
+			       window delta t nil nil nil nil pixelwise)
+			  (window-resize window delta t nil pixelwise)))
+		    ;; Else check whether the window is not wide enough.
+		    (let* ((min-size (window-min-size window t ignore pixelwise))
+			   (delta (- min-size (window-size window t pixelwise))))
+		      (when (and (> delta 0)
+			         (window--resizable-p
+				  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)))
+		  ;; Install positions (maybe we should do this after all
+		  ;; windows have been created and sized).
+		  (ignore-errors
+                    ;; Set 'noforce argument to avoid that window start
+                    ;; overrides window point set below (Bug#24240).
+		    (set-window-start window (cdr (assq 'start state)) 'noforce)
+		    (set-window-point window (cdr (assq 'point state))))
+		  ;; Select window if it's the selected one.
+		  (when (cdr (assq 'selected state))
+		    (select-window window))
+                  (when next-buffers
+                    (set-window-next-buffers
+                     window
+                     (delq nil (mapcar (lambda (buffer)
+                                         (setq buffer (get-buffer buffer))
+                                         (when (buffer-live-p buffer) buffer))
+                                       next-buffers))))
+                  (when prev-buffers
+                    (set-window-prev-buffers
+                     window
+                     (delq nil (mapcar (lambda (entry)
+                                         (let ((buffer (get-buffer (nth 0 entry)))
+                                               (m1 (nth 1 entry))
+                                               (m2 (nth 2 entry)))
+                                           (when (buffer-live-p buffer)
+                                             (list buffer
+                                                   (if (markerp m1) m1
+                                                     (set-marker (make-marker) m1
+                                                                 buffer))
+                                                   (if (markerp m2) m2
+                                                     (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)
+	      (push window window-state-put-stale-windows))))))))
 
 (defun window-state-put (state &optional window ignore)
   "Put window state STATE into WINDOW.
-- 
2.21.0 (Apple Git-122)


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-10  0:35       ` Yuan Fu
@ 2019-10-10 21:54         ` Juri Linkov
  2019-10-11  1:38           ` Yuan Fu
  0 siblings, 1 reply; 15+ messages in thread
From: Juri Linkov @ 2019-10-10 21:54 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Emacs developers

> OTOH, here is an experiment I did earlier today. I optionally replace
> the buffer names and configurations with a function when saving window
> config. So instead of
>
>     (buffer "*scratch*"
>              (selected . t)             
>              ...
>              (dedicated)
>              (point . 290)
>              (start . 1))
>
> I save
>
>     (buffer lambda nil
>              (create-my-buffer "some useful info"))
>
> And when window-state-put finds out the data is not buffer name but a
> function, it simply calls the function to restore the buffer. This way
> we can store information about the buffer and how to restore it in a
> rather compact way. The change to existing code is pretty small, too.
>
> WDYT?

This is exactly what was needed for a long time.  Currently the desktop
saves window-states with buffer names.  But after restoring the desktop,
non-file buffers get lost, their windows are simply removed after restoring
by window-state-put.  This has even more adverse effect now since tabs
are saved in the desktop file and after restoring, clicking on a tab
displays an irrelevant buffer that replaces the saved non-file buffer.

What could be improved is to allow a non-file non-persistent mode
to provide a hook like ‘desktop-save-buffer’ that will return
a lambda that will be saved to the desktop like in your example above.
Then after loading from the desktop this lambda could restore the buffer.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-10 21:54         ` Juri Linkov
@ 2019-10-11  1:38           ` Yuan Fu
  2019-10-11  8:18             ` martin rudalics
  2019-10-12 20:58             ` Juri Linkov
  0 siblings, 2 replies; 15+ messages in thread
From: Yuan Fu @ 2019-10-11  1:38 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Emacs developers

> This is exactly what was needed for a long time.  Currently the desktop
> saves window-states with buffer names.  But after restoring the desktop,
> non-file buffers get lost, their windows are simply removed after restoring
> by window-state-put.  This has even more adverse effect now since tabs
> are saved in the desktop file and after restoring, clicking on a tab
> displays an irrelevant buffer that replaces the saved non-file buffer.
>
> What could be improved is to allow a non-file non-persistent mode
> to provide a hook like ‘desktop-save-buffer’ that will return
> a lambda that will be saved to the desktop like in your example above.
> Then after loading from the desktop this lambda could restore the buffer.

After thinking about your suggestion, I start to believe my experiment
isn’t the best approach (to solve the problem you mentioned above and
the problem I mentioned about gdb-mi). For your problem, since there are
tmp buffers that are not in any window, window.el clearly isn’t the
right place to handle them. I think desktop.el should handle them. And I
guess that’s what you meant. The creator of the tmp buffers could
provide a buffer local function that when called, returns a lambda form
that can be used to restore the tmp buffer. Or, if all you care about is
the missing windows resulted by missing tmp buffers, desktop.el can just
store the content of the tmp buffers (that are in a window when saving
desktop) in a cache file like other persistent mode do.

What’s more, above thought process reminded me that window-state-get/put
should probably stay away from buffer manipulation. And I think I can
achieve what I want to do without modifying window-state-get/put. To
recap, I want to save the window configuration and the type of the
function (register, breakpoint, etc) of each window, so that I can
restore that buffer later. I can do this: Before calling the state-get,
I go through each window and replace the buffers in them with
placeholder buffers and store the buffer type (breakpoint, register,
etc) in a window parameter. When later I restored the window
configuration, I go through each window and restore each buffer by the
window parameter I saved.

I think I can take back my request to modify window-state-get/put now.

A side note: Although I use “restore” in both problems, the stuff we are
trying to restore are different, your tmp buffer is just an ordinary
buffer and you want that exactly buffer back, and I’m not saving a
buffer but rather the type information. That took me a while to realize.

Yuan





^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-11  1:38           ` Yuan Fu
@ 2019-10-11  8:18             ` martin rudalics
  2019-10-12 16:25               ` Yuan Fu
  2019-10-12 20:58             ` Juri Linkov
  1 sibling, 1 reply; 15+ messages in thread
From: martin rudalics @ 2019-10-11  8:18 UTC (permalink / raw)
  To: Yuan Fu, Juri Linkov; +Cc: Emacs developers

 > After thinking about your suggestion, I start to believe my experiment
 > isn’t the best approach (to solve the problem you mentioned above and
 > the problem I mentioned about gdb-mi). For your problem, since there are
 > tmp buffers that are not in any window, window.el clearly isn’t the
 > right place to handle them. I think desktop.el should handle them.

If I'm not mistaken, there are occasions where window.el is the only
place to handle them.  Think of a state saved somewhere during a
session that contains references to dead temporary buffers.  To
resurrect such a state it might be nice to have a function that
restores these buffers from information stored by 'window-state-get'
or at least do something reasonable (whatever that is).

 > What’s more, above thought process reminded me that window-state-get/put
 > should probably stay away from buffer manipulation. And I think I can
 > achieve what I want to do without modifying window-state-get/put. To
 > recap, I want to save the window configuration and the type of the
 > function (register, breakpoint, etc) of each window, so that I can
 > restore that buffer later. I can do this: Before calling the state-get,
 > I go through each window and replace the buffers in them with
 > placeholder buffers

I suppose that, as a rule, placeholder buffers never get killed.  Right?

 > and store the buffer type (breakpoint, register,
 > etc) in a window parameter. When later I restored the window
 > configuration, I go through each window and restore each buffer by the
 > window parameter I saved.

Fine.  But, I still think that a solution built into the window state
functions would be more profitable.  And if it's an empty buffer name
advising 'window-state-put' to look up the associated window's
parameter list for instrcutions on how to populate that window.

martin




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-11  8:18             ` martin rudalics
@ 2019-10-12 16:25               ` Yuan Fu
  2019-10-13  8:17                 ` martin rudalics
  0 siblings, 1 reply; 15+ messages in thread
From: Yuan Fu @ 2019-10-12 16:25 UTC (permalink / raw)
  To: martin rudalics; +Cc: Emacs developers, Juri Linkov


> If I'm not mistaken, there are occasions where window.el is the only
> place to handle them.  Think of a state saved somewhere during a
> session that contains references to dead temporary buffers.  To
> resurrect such a state it might be nice to have a function that
> restores these buffers from information stored by 'window-state-get'
> or at least do something reasonable (whatever that is).

Restoring buffer could probably done by the caller of window-state-set. And the caller of window-state-get can save information into window-parameters for later restoration. Restoring buffers outside window-state-put also gives more flexibility, albeit less straightforward. I claim the caller is more flexible when restoring buffers is because it knows more and can keep track of things: what buffer has been displayed, what other windows are displaying, etc. 

> I suppose that, as a rule, placeholder buffers never get killed.  Right?

It is killed (only one placeholder buffer) after calls to window-state-get and window-state-put.

> Fine.  But, I still think that a solution built into the window state
> functions would be more profitable.  And if it's an empty buffer name
> advising 'window-state-put' to look up the associated window's
> parameter list for instrcutions on how to populate that window.

It certainly is nice to have such a feature. Although questioning the necessity, I have no objection to it. 

Yuan


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-11  1:38           ` Yuan Fu
  2019-10-11  8:18             ` martin rudalics
@ 2019-10-12 20:58             ` Juri Linkov
  2019-10-14  3:39               ` Yuan Fu
  1 sibling, 1 reply; 15+ messages in thread
From: Juri Linkov @ 2019-10-12 20:58 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Emacs developers

> After thinking about your suggestion, I start to believe my experiment
> isn’t the best approach (to solve the problem you mentioned above and
> the problem I mentioned about gdb-mi). For your problem, since there are
> tmp buffers that are not in any window, window.el clearly isn’t the
> right place to handle them. I think desktop.el should handle them. And I
> guess that’s what you meant.

Indeed, gdb-mi and desktop could work the same way:

1. before or after calling window-state-get
   save another data structure with buffer names from on all windows
   and information how to restore them;

2. before calling window-state-put create these buffers with the
   saved buffer names, so window-state-put will restore windows with the
   same buffer names.

> I go through each window and replace the buffers in them with
> placeholder buffers and store the buffer type (breakpoint, register,
> etc) in a window parameter.

By placeholder do you mean some default text contents to show when
tmp buffer is not restored?  Something like “tmp buffer was here”.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-12 16:25               ` Yuan Fu
@ 2019-10-13  8:17                 ` martin rudalics
  0 siblings, 0 replies; 15+ messages in thread
From: martin rudalics @ 2019-10-13  8:17 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Juri Linkov, Emacs developers

 > It certainly is nice to have such a feature. Although questioning
 > the necessity, I have no objection to it.

And I certainly won't insist on having such a feature ;-)

martin



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-12 20:58             ` Juri Linkov
@ 2019-10-14  3:39               ` Yuan Fu
  2019-10-15 18:14                 ` Juri Linkov
  0 siblings, 1 reply; 15+ messages in thread
From: Yuan Fu @ 2019-10-14  3:39 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Emacs developers


> 2. before calling window-state-put create these buffers with the
>   saved buffer names, so window-state-put will restore windows with the
>   same buffer names.

What I did is restore these buffer /after/ window-state-put. Because the information I needed is stored in window parameters.

> 
>> I go through each window and replace the buffers in them with
>> placeholder buffers and store the buffer type (breakpoint, register,
>> etc) in a window parameter.
> 
> By placeholder do you mean some default text contents to show when
> tmp buffer is not restored?  Something like “tmp buffer was here”.

I mean a dummy buffer for window-state-get to save. This buffer is not visible to the user in theory: I create it and put it in every window and call window-state-get, then swap back buffers and remove this placeholder. Then before window-state-put create this buffer, and window-state-put will put it in every window. Once I restored every windows’ buffer from their window parameter, I can kill the placeholder. The sole purpose of the placeholder is for window-state-get/put to have /something/ to save/display.

Yuan


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Customize ‘window-state-get/put’
  2019-10-14  3:39               ` Yuan Fu
@ 2019-10-15 18:14                 ` Juri Linkov
  0 siblings, 0 replies; 15+ messages in thread
From: Juri Linkov @ 2019-10-15 18:14 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Emacs developers

>> By placeholder do you mean some default text contents to show when
>> tmp buffer is not restored?  Something like “tmp buffer was here”.
>
> I mean a dummy buffer for window-state-get to save. This buffer is not
> visible to the user in theory: I create it and put it in every window and
> call window-state-get, then swap back buffers and remove this
> placeholder. Then before window-state-put create this buffer, and
> window-state-put will put it in every window. Once I restored every
> windows’ buffer from their window parameter, I can kill the
> placeholder. The sole purpose of the placeholder is for
> window-state-get/put to have /something/ to save/display.

Yes, this is a good solution for gdb-mi.

As for the desktop, we need to find a solution what to show in a saved
window when the file was deleted before restoring the saved file buffer.

Or maybe this problem is not specific to the desktop: even during the
same session, when a buffer (saved in the window configuration) was killed,
then restoring this window configuration just removes the window where
this buffer was before.  Often this has surprising effect.

What is the alternative?  Maybe to show an empty buffer in its previous
window with text like “killed buffer was here” and a button to restore it:
in case of file buffers it could call 'find-file'.



^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2019-10-15 18:14 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-07 16:19 Customize ‘window-state-get/put’ Yuan Fu
2019-10-07 22:01 ` Juri Linkov
2019-10-08  0:13   ` Yuan Fu
2019-10-09 22:31     ` Juri Linkov
2019-10-10  0:35       ` Yuan Fu
2019-10-10 21:54         ` Juri Linkov
2019-10-11  1:38           ` Yuan Fu
2019-10-11  8:18             ` martin rudalics
2019-10-12 16:25               ` Yuan Fu
2019-10-13  8:17                 ` martin rudalics
2019-10-12 20:58             ` Juri Linkov
2019-10-14  3:39               ` Yuan Fu
2019-10-15 18:14                 ` Juri Linkov
2019-10-08  8:05   ` Eli Zaretskii
2019-10-08  8:45 ` martin rudalics

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).