branch: externals/bufferlo commit eb2303fe5d21132ecc0feea22ce25f0175700a0c Author: Florian Rommel <m...@florommel.de> Commit: Florian Rommel <m...@florommel.de>
Cleanup bufferlo--bookmark-tab-handler --- bufferlo.el | 257 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 137 insertions(+), 120 deletions(-) diff --git a/bufferlo.el b/bufferlo.el index 5df2e4dc8c..c773b15410 100644 --- a/bufferlo.el +++ b/bufferlo.el @@ -1899,6 +1899,66 @@ FRAME specifies the frame; the default value of nil selects the current frame." (when-let (replace (assoc (cadr bc) replace-alist)) (setf (cadr bc) (cdr replace))))))))) +(defun bufferlo--bookmark-get-duplicate-policy (thing default-policy) + "Get the duplicate policy for THING bookmarks. +THING should be either \"frame\" or \"tab\". +Ask the user if DEFAULT-POLICY is set to \\='prompt. +This functions throws :noload when the user quits." + (if (not (eq default-policy 'prompt)) + default-policy + (pcase (let ((read-answer-short t)) + (with-local-quit + (read-answer + (concat + (format "%s bookmark name already active: " (capitalize thing)) + "Allow, Clear bookmark after loading, Raise existing ") + '(("allow" ?a "Allow duplicate") + ("clear" ?c "Clear the bookmark after loading") + ("raise" ?r (format "Raise the %s with the existing bookmark" + thing)) + ("help" ?h "Help") + ("quit" ?q "Quit and abort bookmark loading"))))) + ("allow" 'allow) + ("clear" 'clear) + ("raise" 'raise) + (_ (throw :noload t))))) + +(defun bufferlo--bookmark-tab-get-replace-policy () + "Get the replace policy for tab bookmarks. +Ask the user if `bufferlo-bookmark-tab-replace-policy' is set to \\='prompt. +This functions throws :noload when the user quits." + (if (not (eq bufferlo-bookmark-tab-replace-policy 'prompt)) + bufferlo-bookmark-frame-load-policy + (pcase (let ((read-answer-short t)) + (with-local-quit + (read-answer "Replace current tab, New tab " + '(("replace" ?o "Replace tab") + ("new" ?n "New tab") + ("help" ?h "Help") + ("quit" ?q "Quit and abort bookmark loading"))))) + ("replace" 'replace) + ("new" 'new) + (_ (throw :noload t))))) + +(defun bufferlo--bookmark-tab-get-clear-policy () + "Get the clear policy for tab bookmarks. +Ask the user if `bufferlo-bookmark-tab-in-bookmarked-frame-policy' is +set to \\='prompt. This functions throws :noload when the user quits." + (if (not (eq bufferlo-bookmark-tab-in-bookmarked-frame-policy 'prompt)) + bufferlo-bookmark-frame-load-policy + (pcase (let ((read-answer-short t)) + (with-local-quit + (read-answer + (concat "Tab bookmark conflicts with frame bookmark: " + "Allow tab bookmark, Clear tab bookmark ") + '(("allow" ?a "Allow tab bookmark") + ("clear" ?c "Clear tab bookmark") + ("help" ?h "Help") + ("quit" ?q "Quit and abort bookmark loading"))))) + ("allow" 'allow) + ("clear" 'clear) + (_ (throw :noload t))))) + (defvar bufferlo--bookmark-handler-no-message nil) (defun bufferlo--bookmark-tab-handler (bookmark &optional no-message embedded-tab) @@ -1909,78 +1969,77 @@ NO-MESSAGE is non-nil, inhibit the message after successfully restoring the bookmark. If EMBEDDED-TAB is non-nil, indicate that this bookmark is embedded in a frame bookmark." (catch :noload - (let ((bookmark-name (if (null embedded-tab) - (bookmark-name-from-full-record bookmark) - nil)) - (msg)) - (when-let ((abm (assoc bookmark-name (bufferlo--active-bookmarks))) - (duplicate-policy bufferlo-bookmark-tab-duplicate-policy)) - (when (eq duplicate-policy 'prompt) - (pcase (let ((read-answer-short t)) - (with-local-quit - (read-answer "Tab bookmark name already active: Allow, Clear bookmark after loading, Raise existing " - '(("allow" ?a "Allow duplicate") - ("clear" ?c "Clear the bookmark after loading") - ("raise" ?r "Raise the existing tab bookmark") - ("help" ?h "Help") - ("quit" ?q "Quit with no changes"))))) - ("allow" (setq duplicate-policy 'allow)) - ("clear" (setq duplicate-policy 'clear)) - ("raise" (setq duplicate-policy 'raise)) - (_ (throw :noload t)))) - (pcase duplicate-policy - ('allow) - ('clear - (setq bookmark-name nil)) - ('clear-warn - (setq bookmark-name nil) - (setq msg (concat msg "; cleared tab bookmark"))) - ('raise - (bufferlo--bookmark-raise abm) - (throw :noload t)))) + (let* ((bookmark-name (if (not embedded-tab) + (bookmark-name-from-full-record bookmark) + nil)) + (abm (assoc bookmark-name (bufferlo--active-bookmarks))) + (disconnect-tbm-p) + (msg) + (msg-append (lambda (s) (setq msg (concat msg "; " s))))) + + ;; Bookmark already loaded in another tab? + (when abm + (let ((duplicate-policy (bufferlo--bookmark-get-duplicate-policy + "tab" + bufferlo-bookmark-tab-duplicate-policy))) + (pcase duplicate-policy + ('allow) + ('clear + (setq bookmark-name nil)) + ('clear-warn + (setq bookmark-name nil) + (funcall msg-append "cleared tab bookmark")) + ('raise + (bufferlo--bookmark-raise abm) + (throw :noload t))))) + + ;; Bookmark not loaded as part of a frame bookmark? (unless embedded-tab - (let ((replace-policy bufferlo-bookmark-tab-replace-policy)) - (when (eq replace-policy 'prompt) - (pcase (let ((read-answer-short t)) - (with-local-quit - (read-answer "Replace current tab, New tab " - '(("replace" ?o "Replace tab") - ("new" ?n "New tab") - ("help" ?h "Help") - ("quit" ?q "Quit with no changes"))))) - ("replace" (setq replace-policy 'replace)) - ("new" (setq replace-policy 'new)) - (_ (throw :noload t)))) + + ;; Replace current tab or create new tab? + (let ((replace-policy (bufferlo--bookmark-tab-get-replace-policy))) (pcase replace-policy ('replace) ('new (unless (consp current-prefix-arg) ; user new tab suppression - (tab-bar-new-tab-to)))))) + (tab-bar-new-tab-to))))) + + ;; Handle an independent tab bookmark inside a frame bookmark + (when (and bookmark-name + (frame-parameter nil 'bufferlo-bookmark-frame-name)) + (let ((clear-policy (bufferlo--bookmark-tab-get-clear-policy))) + (pcase clear-policy + ('clear + (setq disconnect-tbm-p t)) + ('clear-warn + (setq disconnect-tbm-p t) + (funcall msg-append "cleared tab bookmark")))))) + + ;; Do the real work: restore the tab + ;; NOTE: No :noload throws after this point (let* ((ws (copy-tree (alist-get 'window bookmark))) - (dummy (generate-new-buffer " *bufferlo dummy buffer*")) ; TODO: needs unwind-protect or make-finalizer or with-temp-buffer? - (renamed - (mapcar - (lambda (bm) - (let ((orig-name (car bm)) - (record (cadr bm))) - (set-buffer dummy) - (condition-case err - (progn (funcall (or (bookmark-get-handler record) - 'bookmark-default-handler) - record) - (run-hooks 'bookmark-after-jump-hook)) - (error - (ignore err) - (message "Bufferlo tab: Could not restore %s (error %s)" orig-name err))) - (unless (eq (current-buffer) dummy) - (unless (string-equal orig-name (buffer-name)) - (cons orig-name (buffer-name)))))) - (alist-get 'buffer-bookmarks bookmark))) - (bl (mapcar (lambda (b) - (if-let (replace (assoc b renamed)) - (cdr replace) - b)) - (alist-get 'buffer-list bookmark))) + (dummy (generate-new-buffer " *bufferlo dummy buffer*")); + (restore (lambda (bm) + (let ((orig-name (car bm)) + (record (cadr bm))) + (set-buffer dummy) + (condition-case err + (progn (funcall (or (bookmark-get-handler record) + 'bookmark-default-handler) + record) + (run-hooks 'bookmark-after-jump-hook)) + (error + (message "Bufferlo tab: Could not restore %s (error %s)" + orig-name err))) + (unless (eq (current-buffer) dummy) + (unless (string-equal orig-name (buffer-name)) + (cons orig-name (buffer-name))))))) + (renamed (mapcar restore (alist-get 'buffer-bookmarks bookmark))) + (replace-renamed (lambda (b) + (if-let (replace + (assoc b renamed)) + (cdr replace) b))) + (bl (mapcar replace-renamed (alist-get 'buffer-list bookmark))) (bl (seq-filter #'get-buffer bl)) (bl (mapcar #'get-buffer bl))) (kill-buffer dummy) @@ -1988,34 +2047,15 @@ this bookmark is embedded in a frame bookmark." (window-state-put ws (frame-root-window) 'safe) (set-frame-parameter nil 'buffer-list bl) (set-frame-parameter nil 'buried-buffer-list nil) - (let ((tbm bookmark-name)) - (when (and (not embedded-tab) - bookmark-name - (frame-parameter nil 'bufferlo-bookmark-frame-name)) - (let ((clear-policy bufferlo-bookmark-tab-in-bookmarked-frame-policy)) - (when (eq clear-policy 'prompt) - (pcase (let ((read-answer-short t)) - (with-local-quit - (read-answer "Tab bookmark conflicts with frame bookmark: Allow tab bookmark, Clear tab bookmark " - '(("allow" ?a "Allow tab bookmark") - ("clear" ?c "Clear tab bookmark") - ("help" ?h "Help") - ("quit" ?q "Quit--retains the bookmark"))))) - ("clear" (setq clear-policy 'clear)) - (_ (setq clear-policy 'allow)))) ; allow, quit cases - (pcase clear-policy - ('clear - (setq tbm nil)) - ('clear-warn - (setq tbm nil) - (setq msg (concat msg "; cleared tab bookmark"))) - ('allow)))) - (setf (alist-get 'bufferlo-bookmark-tab-name - (cdr (bufferlo--current-tab))) - tbm)) - (unless (or no-message bufferlo--bookmark-handler-no-message) - (message "Restored bufferlo tab bookmark%s%s" - (if bookmark-name (format ": %s" bookmark-name) "") (if msg msg ""))))))) + (setf (alist-get 'bufferlo-bookmark-tab-name + (cdr (bufferlo--current-tab))) + (unless disconnect-tbm-p bookmark-name))) + + ;; Log message + (unless (or no-message bufferlo--bookmark-handler-no-message) + (message "Restored bufferlo tab bookmark%s%s" + (if bookmark-name (format ": %s" bookmark-name) "") + (or msg "")))))) (put #'bufferlo--bookmark-tab-handler 'bookmark-handler-type "B-Tab") ; short name here as bookmark-bmenu-list hard codes width of 8 chars @@ -2040,30 +2080,6 @@ FRAME specifies the frame; the default value of nil selects the current frame." (bufferlo--frame-geometry . ,(funcall bufferlo-frame-geometry-function (or frame (selected-frame)))) (handler . ,#'bufferlo--bookmark-frame-handler)))) -(defun bufferlo--bookmark-get-duplicate-policy (thing default-policy) - "Get the duplicate policy for THING bookmarks. -THING should be either \"frame\" or \"tab\". -Ask the user if DEFAULT-POLICY is set to \\='prompt. -This functions throws :noload when the user quits." - (if (not (eq default-policy 'prompt)) - default-policy - (pcase (let ((read-answer-short t)) - (with-local-quit - (read-answer - (concat - (format "%s bookmark name already active: " (capitalize thing)) - "Allow, Clear bookmark after loading, Raise existing ") - '(("allow" ?a "Allow duplicate") - ("clear" ?c "Clear the bookmark after loading") - ("raise" ?r (format "Raise the %s with the existing bookmark" - thing)) - ("help" ?h "Help") - ("quit" ?q "Quit with no changes"))))) - ("allow" 'allow) - ("clear" 'clear) - ("raise" 'raise) - (_ (throw :noload t))))) - (defun bufferlo--bookmark-frame-get-load-policy () "Get the load policy for frame bookmarks. Ask the user if `bufferlo-bookmark-frame-load-policy' is set to \\='prompt. @@ -2080,7 +2096,7 @@ This functions throws :noload when the user quits." ("replace" ?r "Replace frame, adopt the loaded bookmark") ("merge" ?m "Merge the new tab content with the existing bookmark") ("help" ?h "Help") - ("quit" ?q "Quit with no changes"))))) + ("quit" ?q "Quit and abort bookmark loading"))))) ("current" 'replace-frame-retain-current-bookmark) ("replace" 'replace-frame-adopt-loaded-bookmark) ("merge" 'merge) @@ -2136,7 +2152,8 @@ the message after successfully restoring the bookmark." (funcall msg-append (format "merged tabs from bookmark %s." bookmark-name))))) - ;; Do the rest with the target frame selected (current or newly created) + ;; Do the real work with the target frame selected (current or newly created) + ;; NOTE: No :noload throws after this point (with-selected-frame (if new-frame-p (with-temp-buffer (make-frame)) (selected-frame))