branch: externals/ement commit 7140d7c8ca8e8a1f609fbee9db2d6a5e27c604c7 Merge: 570318221b db2952d322 Author: Adam Porter <a...@alphapapa.net> Commit: Adam Porter <a...@alphapapa.net>
Merge: Improvements and fixes for compose buffer enhancements (pt 2) --- ement-room.el | 154 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 93 insertions(+), 61 deletions(-) diff --git a/ement-room.el b/ement-room.el index 28de04ce24..73877154e6 100644 --- a/ement-room.el +++ b/ement-room.el @@ -500,8 +500,8 @@ sends the composed message directly." (reusable-frames . nil))) "`display-buffer' action for displaying compose buffers. -See also `ement-room-compose-buffer-window-auto-height' and -`ement-room-compose-buffer-window-dedicated'." +See also option `ement-room-compose-buffer-window-auto-height' +and `ement-room-compose-buffer-window-dedicated'." :type display-buffer--action-custom-type :risky t) @@ -523,9 +523,15 @@ the option `ement-room-compose-buffer-window-auto-height' is enabled (this option generally keeps the windows too small to usefully display other buffers). -See also `set-window-dedicated-p'." +The value `delete' means that windows will not be dedicated, but +they will still be deleted once the message is sent or aborted +\(even when they have also been used to display other buffers). + +See also `set-window-dedicated-p' and +`switch-to-buffer-in-dedicated-window'." :type '(radio (const :tag "Always" t) (const :tag "Never" nil) + (const :tag "Never (but always delete window)" delete) (const :tag "Newly-created windows" created) (const :tag "When auto-height enabled" auto-height))) @@ -547,21 +553,19 @@ See also `ement-room-compose-buffer-window-auto-height-max' and ;; get the correct result in the majority of situations, and it is simple. (defvar ement-room-compose-buffer-window-auto-height-resizing-p) -(defvar ement-room-compose-buffer-window-auto-height-cache) - (defcustom ement-room-compose-buffer-window-auto-height-min nil "If non-nil, limits the body height of the compose buffer window. -See also `ement-room-compose-buffer-window-auto-height' and -`ement-room-compose-buffer-window-auto-height-max'." +See also option `ement-room-compose-buffer-window-auto-height' +and `ement-room-compose-buffer-window-auto-height-max'." :type '(choice (const :tag "Default" nil) (natnum :tag "Lines"))) (defcustom ement-room-compose-buffer-window-auto-height-max nil "If non-nil, limits the body height of the compose buffer window. -See also `ement-room-compose-buffer-window-auto-height' and -`ement-room-compose-buffer-window-auto-height-min'." +See also option `ement-room-compose-buffer-window-auto-height' +and `ement-room-compose-buffer-window-auto-height-min'." :type '(choice (const :tag "Default" nil) (natnum :tag "Lines"))) @@ -4436,8 +4440,8 @@ a copy of the local keymap, and sets `header-line-format'." (defun ement-room-compose-buffer-window-auto-height () "Ensure that the compose buffer displays the whole message. -Called via `post-command-hook' if `ement-room-compose-buffer-window-auto-height' -is non-nil." +Called via `post-command-hook' if option +`ement-room-compose-buffer-window-auto-height' is non-nil." ;; We use `post-command-hook' (rather than, say, `after-change-functions'), ;; because the required window height might change for reasons other than text ;; editing (e.g. changes to the window's width or the font size). @@ -4449,8 +4453,35 @@ is non-nil." ;; The following may also clear the cache in order to force a recalculation: ;; - `ement-room-compose-buffer-window-state-change-handler' ;; - `ement-room-compose-buffer-window-buffer-change-handler' + ;; + ;; Global mutex `ement-room-compose-buffer-window-auto-height-resizing-p' + ;; ensures that we cannot run recursively. We also resize only the selected + ;; window, even if there are compose buffers displayed in other windows which + ;; might also be affected. This conservative approach can prevent desirable + ;; resizing in some cases, but restricting our behaviour this way keeps things + ;; simple so that we needn't consider potential issues such as endless cycles + ;; of conflicting resizes. + ;; + ;; Perfection would in any case be non-trivial -- consider two compose windows + ;; side-by-side in a horizontal split, each showing a different compose buffer + ;; with a different desired height. We cannot have the "correct" size for + ;; both simultaneously. The best thing to do would be to maintain the tallest + ;; height amongst all conflicting windows at all times -- but that is, again, + ;; considerably more complex. + ;; + ;; Most of the time the window arrangements are expected to be very simple and + ;; so a more comprehensive solution, while possible, is not worth the added + ;; complexity -- our relatively simplistic approach is good enough for the + ;; vast majority of situations. + + ;; Skip resizing if we are being called recursively... (unless (or (bound-and-true-p ement-room-compose-buffer-window-auto-height-resizing-p) - (window-full-height-p)) + ;; ...or there are no other windows to resize... + (window-full-height-p) + ;; ...or we have just switched to this buffer from another buffer + ;; (we may be cycling window buffers, and about to switch again). + (and (window-old-buffer) + (not (eq (window-old-buffer) (current-buffer))))) ;; Manipulate the window body height. (let* ((pixelwise (and ement-room-compose-buffer-window-auto-height-pixelwise (display-graphic-p))) @@ -4458,12 +4489,14 @@ is non-nil." (buflines (max 1 (count-screen-lines nil nil t))) (cache (if pixelwise (* buflines lineheight) - buflines))) + buflines)) + (wcache (window-parameter + nil 'ement-room-compose-buffer-window-auto-height-cache))) ;; Do nothing if the desired height has not changed. - (unless (and (boundp 'ement-room-compose-buffer-window-auto-height-cache) - (eql cache ement-room-compose-buffer-window-auto-height-cache)) + (unless (and wcache (eql cache wcache)) ;; Otherwise resize the window... - (setq-local ement-room-compose-buffer-window-auto-height-cache cache) + (set-window-parameter + nil 'ement-room-compose-buffer-window-auto-height-cache cache) (let* ((ement-room-compose-buffer-window-auto-height-resizing-p t) (minheight (if ement-room-compose-buffer-window-auto-height-min (max 1 ement-room-compose-buffer-window-auto-height-min) @@ -4517,26 +4550,25 @@ selected or deselected. This prevents a compose buffer window being stuck at the wrong height (until the number of lines changes again) if something other than the auto-height feature resizes the window. We simply -flush the height cache for these state changes, thus ensuring the -required height is recalculated on the next cycle). +flush the auto-height cache, thus ensuring the required height is +recalculated on the next cycle). See also `ement-room-compose-buffer-window-buffer-change-handler'." + ;; Ignore the window state changes triggered by our auto-height resizing. + ;; + ;; Also do nothing if the state change is for the selected window, as + ;; the buffer-local `post-command-hook' is already dealing with that + ;; case. We only care about window state changes which are triggered + ;; from elsewhere. This means we skip the case whereby the selected + ;; window has just switched to the compose buffer, and so we use + ;; `window-buffer-change-functions' as well to capture that case. + ;; (See `ement-room-compose-buffer-window-buffer-change-handler'.) (when ement-room-compose-buffer-window-auto-height - ;; Ignore the window state changes triggered by our auto-height resizing. - (unless (bound-and-true-p ement-room-compose-buffer-window-auto-height-resizing-p) - (let ((buf (current-buffer))) - ;; Do nothing if the state change happened while the compose buffer was - ;; current, as the buffer-local `post-command-hook' is already dealing - ;; with that case. We only care about window state changes which are - ;; triggered from elsewhere. This means that we skip the case whereby - ;; the selected window has just switched to the compose buffer, and so - ;; we use `window-buffer-change-functions' as well to capture that case. - ;; (See `ement-room-compose-buffer-window-buffer-change-handler'.) - (with-selected-window win - (unless (eq (current-buffer) buf) - ;; Clear the height cache for this compose buffer. - (when (bound-and-true-p ement-room-compose-buffer-window-auto-height-cache) - (setq-local ement-room-compose-buffer-window-auto-height-cache nil)))))))) + (unless (or (bound-and-true-p ement-room-compose-buffer-window-auto-height-resizing-p) + (eq win (selected-window))) + ;; Clear the auto-height cache for this window. + (set-window-parameter + win 'ement-room-compose-buffer-window-auto-height-cache nil)))) (defun ement-room-compose-buffer-window-buffer-change-handler (win) "Called via buffer-local `window-buffer-change-functions' in compose buffers. @@ -4544,41 +4576,38 @@ See also `ement-room-compose-buffer-window-buffer-change-handler'." Called for any window WIN showing a compose buffer if that window has just been created or assigned that buffer. -Like `ement-room-compose-buffer-window-state-change-handler' (see -which) in purpose, but handling the case where WIN has just -switched to displaying the compose buffer (which the other -handler ignores as a side-effect of its conditional logic). +Flush the auto-height cache for any window which switches to +displaying a compose buffer, to ensure the required height is +recalculated on the next cycle. + +Also detect whether a composer buffer's window was created for +that purpose, as this information affects the behaviour of +`ement-room-compose-buffer-quit-restore-window'. -This function also determines whether the composer buffer's -window has been newly created, which affects the behaviour of -`ement-room-compose-buffer-quit-restore-window'." +See also `ement-room-compose-buffer-window-state-change-handler'." (with-selected-window win - ;; Clear the height cache for this compose buffer. (when ement-room-compose-buffer-window-auto-height - (when (bound-and-true-p ement-room-compose-buffer-window-auto-height-cache) - (setq-local ement-room-compose-buffer-window-auto-height-cache nil) - ;; `window-buffer-change-functions' runs /after/ `post-command-hook', - ;; so after flushing the cache we need to invoke the resize handler, as - ;; otherwise it wouldn't update until after the /subsequent/ command. - ;; We don't want to do this while this hook is still running though - ;; (the result is inaccurate), so defer it with a timer. - (unless (bound-and-true-p ement-room-compose-buffer-window-auto-height-resizing-p) - (run-with-timer 0 nil (lambda (win) - (with-selected-window win - (ement-room-compose-buffer-window-auto-height))) - win)))) - ;; Process `ement-room-compose-buffer-window-dedicated' when the compose - ;; buffer is first displayed, to decide whether the window should be - ;; dedicated to the buffer. + ;; Clear the auto-height cache for this window. + (set-window-parameter + win 'ement-room-compose-buffer-window-auto-height-cache nil)) + ;; Establish whether we've processed this window before, and whether it was + ;; created to display a compose buffer. We set a window property the first + ;; time that we see the window, so if it's set at all, we've seen it before. (unless (assq 'ement-room-compose-buffer-window-created-p (window-parameters win)) - (let ((createdp (not (window-prev-buffers)))) - (set-window-parameter win 'ement-room-compose-buffer-window-created-p - createdp) + ;; If the window has never shown any other buffer, then it was created + ;; specifically to display a compose buffer. + (let ((created-for-compose-p (set-window-parameter + win 'ement-room-compose-buffer-window-created-p + (not (window-prev-buffers win))))) + ;; Process `ement-room-compose-buffer-window-dedicated' when the compose + ;; buffer is first displayed in this window, to decide whether the + ;; window should be dedicated to the buffer. (when (cl-case ement-room-compose-buffer-window-dedicated - (created createdp) + (created created-for-compose-p) (auto-height ement-room-compose-buffer-window-auto-height) + (delete nil) (t ement-room-compose-buffer-window-dedicated)) - (set-window-dedicated-p nil t)))))) + (set-window-dedicated-p win t)))))) (defun ement-room-compose-buffer-quit-restore-window () "Kill the current compose buffer and deal appropriately with its window. @@ -4591,6 +4620,9 @@ A non-dedicated window which has displayed another buffer at any point will not be deleted." ;; N.b. This function exists primarily for documentation purposes, ;; to clarify the side-effect of using a dedicated window. + (when (eq ement-room-compose-buffer-window-dedicated 'delete) + ;; `quit-restore-window' always deletes a dedicated window. + (set-window-dedicated-p nil t)) (quit-restore-window nil 'kill)) (declare-function dabbrev--select-buffers "dabbrev")