From 4f8c824f292a11c83cccdffa8a7e2107aa40ad01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Pastor=20P=C3=A9rez?= Date: Sun, 31 Mar 2024 18:10:48 +0200 Subject: [PATCH 1/6] feat: allow run time configuration of `popper-display-function' --- popper.el | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/popper.el b/popper.el index 2b16e26..e40d807 100644 --- a/popper.el +++ b/popper.el @@ -262,16 +262,40 @@ Valid values are \\='popup, \\='raised, \\='user-popup or nil. (floor (frame-height) 3) (floor (frame-height) 6))) +(defun popper-select-popup-at-top (buffer &optional alist) + "Display and switch to popup-buffer BUFFER at the top of the screen. +ALIST is an association list of action symbols and values. See +Info node `(elisp) Buffer Display Action Alists' for details of +such alists." + (let ((window (popper-display-popup-at-dir buffer 'top alist))) + (select-window window))) + (defun popper-select-popup-at-bottom (buffer &optional alist) "Display and switch to popup-buffer BUFFER at the bottom of the screen. ALIST is an association list of action symbols and values. See Info node `(elisp) Buffer Display Action Alists' for details of such alists." - (let ((window (popper-display-popup-at-bottom buffer alist))) + (let ((window (popper-display-popup-at-dir buffer 'bottom alist))) + (select-window window))) + +(defun popper-select-popup-at-left (buffer &optional alist) + "Display and switch to popup-buffer BUFFER at the left of the screen. +ALIST is an association list of action symbols and values. See +Info node `(elisp) Buffer Display Action Alists' for details of +such alists." + (let ((window (popper-display-popup-at-dir buffer 'left alist))) + (select-window window))) + +(defun popper-select-popup-at-right (buffer &optional alist) + "Display and switch to popup-buffer BUFFER at the right of the screen. +ALIST is an association list of action symbols and values. See +Info node `(elisp) Buffer Display Action Alists' for details of +such alists." + (let ((window (popper-display-popup-at-dir buffer 'right alist))) (select-window window))) -(defun popper-display-popup-at-bottom (buffer &optional alist) - "Display popup-buffer BUFFER at the bottom of the screen. +(defun popper-display-popup-at-dir (buffer dir &optional alist) + "Display popup-buffer BUFFER as a side window in DIR. ALIST is an association list of action symbols and values. See Info node `(elisp) Buffer Display Action Alists' for details of such alists." @@ -279,8 +303,13 @@ such alists." buffer (append alist `((window-height . ,popper-window-height) - (side . bottom) - (slot . 0))))) + (side . ,dir) + (slot . 1))))) + +(defun popper-select-popup (buffer &optional alist) + "Invoke the popper-select function configured in `popper-display-function'. +For the meaning of BUFFER and ALIST read `popper-select-popup-at-bottom'." + (funcall popper-display-function buffer alist)) (defun popper-popup-p (buf) "Predicate to test if buffer BUF qualifies for popper handling. @@ -706,8 +735,7 @@ types as popups." (add-hook 'window-configuration-change-hook #'popper--update-popups) (add-hook 'select-frame-hook #'popper--update-popups) (add-to-list 'display-buffer-alist - `(popper-display-control-p - (,popper-display-function)))) + '(popper-display-control-p popper-select-popup))) ;; Turning the mode OFF (remove-hook 'window-configuration-change-hook #'popper--update-popups) (remove-hook 'window-configuration-change-hook #'popper--suppress-popups) From 5265b67736ca1c5862c7ab4e465b94ffdaa876aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Pastor=20P=C3=A9rez?= Date: Wed, 3 Apr 2024 13:21:56 +0200 Subject: [PATCH 2/6] fix: `popper-select-popup' not using buffer-local value of `popper-display-function' --- popper.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/popper.el b/popper.el index e40d807..f9a703e 100644 --- a/popper.el +++ b/popper.el @@ -307,9 +307,10 @@ such alists." (slot . 1))))) (defun popper-select-popup (buffer &optional alist) - "Invoke the popper-select function configured in `popper-display-function'. + "Invoke `popper-display-function' locally bound in BUFFER. For the meaning of BUFFER and ALIST read `popper-select-popup-at-bottom'." - (funcall popper-display-function buffer alist)) + (with-current-buffer buffer + (funcall popper-display-function buffer alist))) (defun popper-popup-p (buf) "Predicate to test if buffer BUF qualifies for popper handling. From 4e8271ffbc5002b10e2ea49ec0f9f5a5b6c786f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Pastor=20P=C3=A9rez?= Date: Wed, 3 Apr 2024 17:24:27 +0200 Subject: [PATCH 3/6] feat: allow the user to configure a custom display action for popup buffers --- popper.el | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/popper.el b/popper.el index f9a703e..a483afc 100644 --- a/popper.el +++ b/popper.el @@ -163,6 +163,15 @@ action alist and displays the buffer. See (info \"(elisp) Buffer Display Action Alists\") for details on the alist." :type 'function) +(defcustom popper-display-action '() + "Action to use to display popper. + + Note that this is only used when +`popper-display-control' is non-nil. + +See (info \"(elisp) Buffer Display Action Alists\") for details on the alist." + :type 'list) + (defcustom popper-group-function nil "Function that returns a popup context. @@ -736,7 +745,8 @@ types as popups." (add-hook 'window-configuration-change-hook #'popper--update-popups) (add-hook 'select-frame-hook #'popper--update-popups) (add-to-list 'display-buffer-alist - '(popper-display-control-p popper-select-popup))) + `(popper-display-control-p popper-select-popup + ,@popper-display-action))) ;; Turning the mode OFF (remove-hook 'window-configuration-change-hook #'popper--update-popups) (remove-hook 'window-configuration-change-hook #'popper--suppress-popups) From 89e3608c564c7bd7e46409b4f7fa61625b838179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Pastor=20P=C3=A9rez?= Date: Fri, 5 Apr 2024 10:41:04 +0200 Subject: [PATCH 4/6] feat: try to fit popups in free side window slots --- popper.el | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/popper.el b/popper.el index a483afc..c7d6aaa 100644 --- a/popper.el +++ b/popper.el @@ -276,7 +276,7 @@ Valid values are \\='popup, \\='raised, \\='user-popup or nil. ALIST is an association list of action symbols and values. See Info node `(elisp) Buffer Display Action Alists' for details of such alists." - (let ((window (popper-display-popup-at-dir buffer 'top alist))) + (let ((window (popper-display-popup-at-side buffer 'top alist))) (select-window window))) (defun popper-select-popup-at-bottom (buffer &optional alist) @@ -284,7 +284,7 @@ such alists." ALIST is an association list of action symbols and values. See Info node `(elisp) Buffer Display Action Alists' for details of such alists." - (let ((window (popper-display-popup-at-dir buffer 'bottom alist))) + (let ((window (popper-display-popup-at-side buffer 'bottom alist))) (select-window window))) (defun popper-select-popup-at-left (buffer &optional alist) @@ -292,7 +292,7 @@ such alists." ALIST is an association list of action symbols and values. See Info node `(elisp) Buffer Display Action Alists' for details of such alists." - (let ((window (popper-display-popup-at-dir buffer 'left alist))) + (let ((window (popper-display-popup-at-side buffer 'left alist))) (select-window window))) (defun popper-select-popup-at-right (buffer &optional alist) @@ -300,20 +300,41 @@ such alists." ALIST is an association list of action symbols and values. See Info node `(elisp) Buffer Display Action Alists' for details of such alists." - (let ((window (popper-display-popup-at-dir buffer 'right alist))) + (let ((window (popper-display-popup-at-side buffer 'right alist))) (select-window window))) -(defun popper-display-popup-at-dir (buffer dir &optional alist) - "Display popup-buffer BUFFER as a side window in DIR. +(defun popper-display-popup-at-side (buffer side &optional alist) + "Display popup-buffer BUFFER as a side window in SIDE. +Try to fit the window in a new slot. ALIST is an association list of action symbols and values. See Info node `(elisp) Buffer Display Action Alists' for details of such alists." - (display-buffer-in-side-window - buffer - (append alist - `((window-height . ,popper-window-height) - (side . ,dir) - (slot . 1))))) + (let* ((side-windows (seq-filter #'(lambda (win) + (equal (window-parameter win 'window-side) + side)) + (window-list))) + (used-slots (sort (mapcar #'(lambda (win) + (window-parameter win 'window-slot)) + side-windows) + #'<)) + (free-slot (if-let ((slot (car used-slots))) + (progn + (while (member slot used-slots) + (setq slot (1+ slot))) ; Find a free slot. + (when-let (max-side-slots (nth (cond ((eq side 'left) 0) + ((eq side 'top) 1) + ((eq side 'right) 2) + ((eq side 'bottom) 3)) + window-sides-slots)) + (setq slot (min slot max-side-slots))) + slot) + 0))) + (display-buffer-in-side-window + buffer + (append alist + `((window-height . ,popper-window-height) + (side . ,side) + (slot . ,free-slot)))))) (defun popper-select-popup (buffer &optional alist) "Invoke `popper-display-function' locally bound in BUFFER. From 884c51091598eb530110ff7fea88a1cb240df8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Pastor=20P=C3=A9rez?= Date: Sun, 7 Apr 2024 17:40:53 +0200 Subject: [PATCH 5/6] feat: add transient to interactively select popup side --- popper.el | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/popper.el b/popper.el index c7d6aaa..5bc498f 100644 --- a/popper.el +++ b/popper.el @@ -4,7 +4,7 @@ ;; Author: Karthik Chikmagalur ;; Version: 0.4.6 -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "28.1")) ;; Keywords: convenience ;; URL: https://github.com/karthink/popper @@ -76,6 +76,7 @@ (require 'subr-x)) (require 'cl-lib) (require 'seq) +(require 'transient) (declare-function project-root "project") (declare-function project-current "project") @@ -676,6 +677,36 @@ If BUFFER is not specified act on the current buffer instead." ((or 'popup 'user-popup) (popper-raise-popup buf)) (_ (popper-lower-to-popup buf))))) +(defun popper--toggle-type-selector (fn) + "Invoke `popper-toggle-type' with FN as `popper-display-function'." + (setq-local popper-display-function fn) + (popper-toggle-type)) + +(transient-define-prefix popper-toggle-type-transient () + "Popper toggle type transient." + [[("k" "top" (lambda () + (interactive) + (popper--toggle-type-selector #'popper-select-popup-at-top)))] + [("j" "bottom" (lambda () + (interactive) + (popper--toggle-type-selector #'popper-select-popup-at-bottom)))] + [("h" "left" (lambda () + (interactive) + (popper--toggle-type-selector #'popper-select-popup-at-left)))] + [("l" "right" (lambda () + (interactive) + (popper--toggle-type-selector #'popper-select-popup-at-right)))]]) + +(defun popper-toggle-type-with-transient (&optional buffer) + "Like `popper-toggle-type' but asking for direction. +If BUFFER is not specified act on the current buffer instead." + (interactive) + (let* ((buf (get-buffer (or buffer (current-buffer)))) + (popup-status (buffer-local-value 'popper-popup-status buf))) + (pcase popup-status + ((or 'popup 'user-popup) (popper-raise-popup buf)) + (_ (popper-toggle-type-transient))))) + (defun popper-kill-latest-popup () "Kill the latest popup-buffer and delete its window." (interactive) From 44d112367d32f771ab60f336548038d837f54f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Pastor=20P=C3=A9rez?= Date: Fri, 6 Dec 2024 13:15:59 +0100 Subject: [PATCH 6/6] fix: popup buffers getting duplicated when switching to them --- popper.el | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/popper.el b/popper.el index 5bc498f..7d00c70 100644 --- a/popper.el +++ b/popper.el @@ -312,30 +312,34 @@ Info node `(elisp) Buffer Display Action Alists' for details of such alists." (let* ((side-windows (seq-filter #'(lambda (win) (equal (window-parameter win 'window-side) - side)) + side)) (window-list))) - (used-slots (sort (mapcar #'(lambda (win) - (window-parameter win 'window-slot)) - side-windows) - #'<)) - (free-slot (if-let ((slot (car used-slots))) - (progn - (while (member slot used-slots) - (setq slot (1+ slot))) ; Find a free slot. - (when-let (max-side-slots (nth (cond ((eq side 'left) 0) - ((eq side 'top) 1) - ((eq side 'right) 2) - ((eq side 'bottom) 3)) - window-sides-slots)) - (setq slot (min slot max-side-slots))) - slot) - 0))) + (displayed-win (seq-find #'(lambda (win) + (eq (window-buffer win) buffer)) + side-windows)) + (target-slot (if displayed-win + (window-parameter displayed-win 'window-slot) + (let* ((used-slots (sort (mapcar #'(lambda (win) + (window-parameter win 'window-slot)) + side-windows) + #'<)) + (free-slot 0)) + (while (member free-slot used-slots) + (setq free-slot (1+ free-slot))) + (when-let ((max-side-slots (nth (cond + ((eq side 'left) 0) + ((eq side 'top) 1) + ((eq side 'right) 2) + ((eq side 'bottom) 3)) + window-sides-slots))) + (setq free-slot (min free-slot max-side-slots))) + free-slot)))) (display-buffer-in-side-window buffer (append alist `((window-height . ,popper-window-height) (side . ,side) - (slot . ,free-slot)))))) + (slot . ,target-slot)))))) (defun popper-select-popup (buffer &optional alist) "Invoke `popper-display-function' locally bound in BUFFER.