branch: externals/bufferlo commit 67aa0d269eeb0ed0b19806a8d81a18eb11de2b96 Author: Florian Rommel <m...@florommel.de> Commit: Florian Rommel <m...@florommel.de>
Cleanup bufferlo--bookmark-frame-handler --- bufferlo.el | 246 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 142 insertions(+), 104 deletions(-) diff --git a/bufferlo.el b/bufferlo.el index 0650674345..5df2e4dc8c 100644 --- a/bufferlo.el +++ b/bufferlo.el @@ -2040,115 +2040,153 @@ 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. +This functions throws :noload when the user quits." + (if (not (eq bufferlo-bookmark-frame-load-policy 'prompt)) + bufferlo-bookmark-frame-load-policy + (pcase (let ((read-answer-short t)) + (with-local-quit + (read-answer + (concat + "Current frame already bookmarked: " + "load and retain Current, Replace with new, Merge with existing ") + '(("current" ?c "Replace frame, retain the current bookmark") + ("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"))))) + ("current" 'replace-frame-retain-current-bookmark) + ("replace" 'replace-frame-adopt-loaded-bookmark) + ("merge" 'merge) + (_ (throw :noload t))))) + (defun bufferlo--bookmark-frame-handler (bookmark &optional no-message) "Handle bufferlo frame bookmark. The argument BOOKMARK is the to-be restored frame bookmark created via `bufferlo--bookmark-frame-make'. The optional argument NO-MESSAGE inhibits the message after successfully restoring the bookmark." - (let ((new-frame) - (keep-new-frame)) - (unwind-protect - (catch :noload - (let ((bookmark-name (bookmark-name-from-full-record bookmark)) - (duplicate-policy bufferlo-bookmark-frame-duplicate-policy) - (msg)) - (if-let ((abm (assoc bookmark-name (bufferlo--active-bookmarks)))) - (progn - (when (eq duplicate-policy 'prompt) - (pcase (let ((read-answer-short t)) - (with-local-quit - (read-answer "Frame 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 frame with the existing 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)))) - (when (eq duplicate-policy 'raise) - (bufferlo--bookmark-raise abm) - (throw :noload t))) - (setq duplicate-policy nil)) ; signal not a duplicate - (when (and - bufferlo-bookmark-frame-load-make-frame - (not (consp current-prefix-arg)) ; user make-frame suppression - (not pop-up-frames)) ; make-frame implied by functions like `bookmark-jump-other-frame' - (with-temp-buffer - (setq new-frame (make-frame)))) - (let ((fbm (frame-parameter nil 'bufferlo-bookmark-frame-name)) - (load-policy bufferlo-bookmark-frame-load-policy)) - (if fbm - (progn - (when (eq load-policy 'prompt) - (pcase (let ((read-answer-short t)) - (with-local-quit - (read-answer "Current frame already bookmarked: load and retain Current, Replace with new, Merge with existing " - '(("current" ?c "Replace frame, retain the current bookmark") - ("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"))))) - ("current" (setq load-policy 'replace-frame-retain-current-bookmark)) - ("replace" (setq load-policy 'replace-frame-adopt-loaded-bookmark)) - ("merge" (setq load-policy 'merge)) - (_ (throw :noload t)))) - (pcase load-policy - ('disallow-replace - (when (not (equal fbm bookmark-name)) ; allow reloads of existing bookmark - (unless no-message (message "Frame already bookmarked as %s; not loaded." fbm)) - (throw :noload t))) - ('replace-frame-retain-current-bookmark - (setq msg (concat msg (format "; retained existing bookmark %s." fbm)))) - ('replace-frame-adopt-loaded-bookmark - (setq msg (concat msg (format "; adopted loaded bookmark %s." fbm))) - (setq fbm bookmark-name)) - ('merge - (setq msg (concat msg (format "; merged tabs from bookmark %s." bookmark-name)))))) - (setq fbm bookmark-name)) ; not already bookmarked - (with-selected-frame (or new-frame (selected-frame)) - (unless (eq load-policy 'merge) - (if (>= emacs-major-version 28) - (tab-bar-tabs-set nil) - (set-frame-parameter nil 'tabs nil))) - (let ((first (if (eq load-policy 'merge) nil t)) - (tab-bar-new-tab-choice t)) - (mapc - (lambda (tbm) - (if first - (setq first nil) - (tab-bar-new-tab-to)) - (bufferlo--bookmark-tab-handler tbm t 'embedded-tab) - (when-let (tab-name (alist-get 'tab-name tbm)) - (tab-bar-rename-tab tab-name))) - (alist-get 'tabs bookmark))) - (tab-bar-select-tab (alist-get 'current bookmark)) - (pcase duplicate-policy - ('allow) - ('clear - (setq fbm nil)) - ('clear-warn - (setq fbm nil) - (setq msg (concat msg "; cleared frame bookmark")))) - (set-frame-parameter nil 'bufferlo-bookmark-frame-name fbm))) - (when new-frame - (setq keep-new-frame t)) - (unless (or no-message bufferlo--bookmark-handler-no-message) - (message "Restored bufferlo frame bookmark%s%s" - (if bookmark-name (format ": %s" bookmark-name) "") - (if msg msg ""))))) - (if (and new-frame (not keep-new-frame)) - (delete-frame new-frame) - (let ((frame (or new-frame (selected-frame)))) - (when (and - (display-graphic-p frame) - (eq bufferlo-bookmark-frame-load-make-frame 'restore-geometry)) - (when-let ((fg (alist-get 'bufferlo--frame-geometry bookmark))) - (let-alist fg - (set-frame-position frame .left .top) - (set-frame-size frame .width .height 'pixelwise)))) - (raise-frame frame)))))) + (catch :noload + (let* ((bookmark-name (bookmark-name-from-full-record bookmark)) + (abm (assoc bookmark-name (bufferlo--active-bookmarks))) + (fbm (frame-parameter nil 'bufferlo-bookmark-frame-name)) + (new-frame-p (and bufferlo-bookmark-frame-load-make-frame + ;; User make-frame suppression + (not (consp current-prefix-arg)) + ;; make-frame implied by functions like + ;; `bookmark-jump-other-frame' + (not pop-up-frames))) + (duplicate-policy) + (load-policy) + (msg) + (msg-append (lambda (s) (setq msg (concat msg "; " s))))) + + ;; Bookmark already loaded in another frame? + (when abm + (setq duplicate-policy (bufferlo--bookmark-get-duplicate-policy + "frame" + bufferlo-bookmark-frame-duplicate-policy)) + (when (eq duplicate-policy 'raise) + (bufferlo--bookmark-raise abm) + (throw :noload t))) + + ;; No currently active bookmark in the frame? + (if (not fbm) + ;; Set active bookmark + (setq fbm bookmark-name) + ;; Handle existing bookmark according to the load policy + (setq load-policy (bufferlo--bookmark-frame-get-load-policy)) + (pcase load-policy + ('disallow-replace + (when (not (equal fbm bookmark-name)) ; allow reloads of existing bookmark + (unless no-message + (message "Frame already bookmarked as %s; not loaded." fbm)) + (throw :noload t))) + ('replace-frame-retain-current-bookmark + (funcall msg-append (format "retained existing bookmark %s." fbm))) + ('replace-frame-adopt-loaded-bookmark + (funcall msg-append (format "adopted loaded bookmark %s." fbm)) + (setq fbm bookmark-name)) + ('merge + (funcall msg-append (format "merged tabs from bookmark %s." + bookmark-name))))) + + ;; Do the rest with the target frame selected (current or newly created) + (with-selected-frame (if new-frame-p + (with-temp-buffer (make-frame)) + (selected-frame)) + ;; Clear existing tabs unless merging + (unless (eq load-policy 'merge) + (if (>= emacs-major-version 28) + (tab-bar-tabs-set nil) + (set-frame-parameter nil 'tabs nil))) + + ;; Load tabs + (let ((first (if (eq load-policy 'merge) nil t)) + (tab-bar-new-tab-choice t)) + (mapc + (lambda (tbm) + (if first + (setq first nil) + (tab-bar-new-tab-to)) + (bufferlo--bookmark-tab-handler tbm t 'embedded-tab) + (when-let (tab-name (alist-get 'tab-name tbm)) + (tab-bar-rename-tab tab-name))) + (alist-get 'tabs bookmark))) + (tab-bar-select-tab (alist-get 'current bookmark)) + + ;; Handle duplicate frame bookmark + (pcase duplicate-policy + ;; Do nothing for 'allow or nil + ('clear + (setq fbm nil)) + ('clear-warn + (setq fbm nil) + (funcall msg-append "cleared frame bookmark"))) + + (set-frame-parameter nil 'bufferlo-bookmark-frame-name fbm) + + ;; Restore geometry + (when (and new-frame-p + (display-graphic-p) + (eq bufferlo-bookmark-frame-load-make-frame 'restore-geometry)) + (when-let ((fg (alist-get 'bufferlo--frame-geometry bookmark))) + (let-alist fg + (set-frame-position nil .left .top) + (set-frame-size nil .width .height 'pixelwise)))) + + (raise-frame)) + + ;; Log message + (unless (or no-message bufferlo--bookmark-handler-no-message) + (message "Restored bufferlo frame bookmark%s%s" + (if bookmark-name (format ": %s" bookmark-name) "") + (or msg "")))))) (put #'bufferlo--bookmark-frame-handler 'bookmark-handler-type "B-Frame") ; short name here as bookmark-bmenu-list hard codes width of 8 chars