[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/popper cd975ac5b8 047/102: Updated README with new feat
From: |
ELPA Syncer |
Subject: |
[elpa] externals/popper cd975ac5b8 047/102: Updated README with new features, popups by predicate |
Date: |
Fri, 8 Sep 2023 15:58:53 -0400 (EDT) |
branch: externals/popper
commit cd975ac5b82790a1b5e0a94c4c18867110790da4
Author: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
Commit: Karthik Chikmagalur <karthikchikmagalur@gmail.com>
Updated README with new features, popups by predicate
- Buffer hiding/suppression integrated into customization etc.
- Readme updated with new features.
- Specify popups and popups to suppress by predicate in addition to name
regexps
and major modes.
---
README.org | 60 ++++++++++++++++++++---
popper.el | 162 +++++++++++++++++++++++++++++++++----------------------------
2 files changed, 143 insertions(+), 79 deletions(-)
diff --git a/README.org b/README.org
index 3ba03c4fb5..821ad3a854 100644
--- a/README.org
+++ b/README.org
@@ -1,5 +1,7 @@
#+title: Popper.el
+/New in v0.40: Auto-hide or suppress popup buffers, assign popups by predicate/
+
Popper is a minor-mode to tame the flood of ephemeral windows Emacs produces,
while still keeping them within arm's reach. Designate any buffer to "popup"
status, and it will stay out of your way. Disimss or summon it easily with one
@@ -86,19 +88,36 @@ See [[*Customization][Customization]] for details on
specifying buffer types as
:END:
To get started, customize this variable:
-- =popper-reference-buffers=: List of buffers to treat as popups. Each entry
in the list can be a regexp (string) to match buffer names against, or a
major-mode (symbol) to match buffer major-modes against.
+- =popper-reference-buffers=: List of buffers to treat as popups. Each entry
in the list can be a regexp (string) to match buffer names against, a
major-mode (symbol) to match buffer major-modes against, or an arbitrary
predicate (function) that is called with the buffer as argument.
Example:
#+BEGIN_SRC emacs-lisp
- '("\\*Messages\\*"
- "Output\\*$"
- help-mode
- compilation-mode)
+ (setq popper-reference-buffers
+ '("\\*Messages\\*"
+ "Output\\*$"
+ help-mode
+ compilation-mode))
#+END_SRC
Will treat the following as popups: The Messages buffer, any buffer ending
in "Output*", and all help and compilation buffers.
+ Example with predicate:
+
+ #+BEGIN_SRC emacs-lisp
+ (setq popper-reference-buffers
+ '("\\*Messages\\*"
+ help-mode
+ (lambda (buf) (with-current-buffer buf
+ (and (derived-mode-p 'fundamental-mode)
+ (< (count-lines (point-min) (point-max))
+ 10)))))))
+ #+END_SRC
+
+ In addition to the Messages and all help buffers, any buffer derived from
the major mode =fundamental-mode= that has fewer than 10 lines will be
considered a popup.
+
+ Note that for performance reasons, each predicate is run once on each newly
created buffer to classify it as a popup. So the predicate can only access the
state of the buffer when it is created, and thus dynamically changing a
buffer's popup status based on its changing contents is not possible.
+
There are other customization options, check the =popper= group.
** Grouping popups by context
@@ -131,7 +150,7 @@ You can also provide a custom function that takes no
arguments, is executed in t
(setq popper-group-function #'popper-group-by-my-rule)
#+END_SRC
-** Managing popup placement
+** Managing popup placement
In keeping with the principle of least surprise, all popups are shown in the
same location: At the bottom of the frame. You can customize
=popper-display-function= to change how popups are displayed.
However this means you can't have more than one popup open at a time. You may
also want more control over where individual popups appear. For example, you
may want an IDE-like set-up, with all help windows open on the right, REPLs on
top and compilation windows at the bottom. This is best done by customizing
Emacs' =display-buffer-alist=. Since this is a
[[https://www.gnu.org/software/emacs/manual/html_node/elisp/The-Zen-of-Buffer-Display.html#The-Zen-of-Buffer-Display][singularly
confus [...]
@@ -163,6 +182,35 @@ If you already have rules in place for how various buffers
should be displayed,
(setq popper-display-control nil))
#+end_src
+** Suppressing popups
+Popper can suppress popups when they are first created. The buffer will be
registered in the list of popups but will not show up on your screen. Instead,
a message ("Popup suppressed: $buffer-name") will be printed to the echo area.
You can then raise it using =popper-toggle-latest= or =popper-cycle= at your
convenience. It will behave like regular popups from that point on.
+
+To specify popups to auto-hide, use a cons cell with the =hide= symbol when
specifying =popup-reference-buffers=:
+
+#+begin_src emacs-lisp
+ (setq popper-reference-buffers
+ '("\\*Messages\\*"
+ ("\\*Async Shell Command\\*" . hide)
+ (completion-list-mode . hide)
+ occur-mode))
+#+end_src
+
+This assignment will suppress async shell command output and the Completions
buffer. The other entries are treated as normal popups.
+
+You can combine the hiding feature with predicates for classifying buffers as
popups:
+
+#+BEGIN_SRC emacs-lisp
+ (defun popper-shell-output-empty-p (buf)
+ (and (string-match-p "\\*Async Shell Command\\*" (buffer-name buf))
+ (= (buffer-size buf) 0)))
+
+ (setq popper-reference-buffers
+ '("\\*Messages\\*"
+ (popper-shell-output-empty-p . hide)))
+#+END_SRC
+
+This assignment will suppress display of the async shell command output buffer
only when there is no output (stdout). Once it is hidden it will be treated as
a popup on par with the Messages buffer.
+
* Technical notes
=popper= uses a buffer local variable (=popper-popup-status=) to identify if a
given buffer should be treated as a popup. Matching is always by buffer and not
window, so having two windows of a buffer, one treated as a popup and one as a
regular window, isn't possible (although you can do this with indirect clones).
In addition, it maintains an alist of popup windows/buffers for cycling through.
diff --git a/popper.el b/popper.el
index 6d1b73e13d..bbcc144fab 100644
--- a/popper.el
+++ b/popper.el
@@ -85,7 +85,7 @@
"List of buffers to treat as popups.
Each entry in the list can be a regexp (string) to match buffer
names against, or a `major-mode' (symbol) to match buffer
-major-modes against.
+major-modes against, or a predicate of one argument (a buffer).
Example:
@@ -95,8 +95,20 @@ Example:
compilation-mode)
Will match against the Messages buffer, any buffer ending in
-Output*, and all help and compilation buffers."
- :type '(restricted-sexp :match-alternatives (stringp symbolp))
+Output*, and all help and compilation buffers.
+
+'(\"\\*Messages\\*\"
+ help-mode
+ (lambda (buf) (with-current-buffer buf
+ (and (derived-mode-p 'fundamental-mode)
+ (< (count-lines (point-min) (point-max))
+ 10)))))
+
+will match against the Messages buffer, all help buffers and any
+buffer with major-mode derived from fundamental mode that has
+fewer than 10 lines at time of creation.
+"
+ :type '(restricted-sexp :match-alternatives (stringp symbolp functionp
consp))
:group 'popper)
(defcustom popper-mode-line '(:eval (propertize " POP" 'face
'mode-line-emphasis))
@@ -164,7 +176,7 @@ Built-in choices include
(function :tag "Custom function")))
(defcustom popper-window-height #'popper--fit-window-height
- "Specify the height of the popup window.
+ "Specify the height of the popup window.
This can be a number representing the height in chars or a
function that optionally takes one argument (the popup window)
@@ -178,38 +190,34 @@ Examples:
;; The default, scale window height with buffer size up to 33% of
the frame height.
-(lambda (win)
+ (lambda (win)
(fit-window-to-buffer
- win
- (floor (frame-height) 3)))
-"
+ win
+ (floor (frame-height) 3)))"
:group 'popper
:type '(choice (integer :tag "Height in chars")
(function :tag "Height function")))
-(defvar popper-reference-names nil
+(defvar popper--reference-names nil
"List of buffer names whose windows are treated as popups.")
-(defvar popper-reference-modes nil
+(defvar popper--reference-modes nil
"List of buffer major-modes whose buffers are treated as popups.")
-(defvar popper-reference-predicates nil
+(defvar popper--reference-predicates nil
"List of predicates to test if a buffer is treated as a popup.
Each predicate takes a buffer as an argument and returns t if it
should be considered a popup")
-(defvar popper-suppressed-names nil
- "List of buffer names whose windows are treated as suppressed
- popups.")
+(defvar popper--suppressed-names nil
+ "Buffer name list matching suppressed popup buffers.")
-(defvar popper-suppressed-modes nil
- "List of buffer major-modes whose windows are treated as
- suppressed popups.")
+(defvar popper--suppressed-modes nil
+ "Major mode list matching suppressed popup buffers.")
-(defvar popper-suppressed-predicates nil
- "List of predicates for which matching buffers are treated as
- suppressed popups.")
+(defvar popper--suppressed-predicates nil
+ "Predicate list matching suppressed popup buffers.")
(defvar popper-open-popup-alist nil
"Alist of currently live (window . buffer)s that are treated as popups.")
@@ -229,10 +237,11 @@ grouped by the predicate `popper-group-function'.")
'user-popup: This is a regular buffer lowered to popup status by the user.")
(defun popper--fit-window-height (win)
- "Determine the popper window height by fitting it to the buffer's content."
+ "Determine the height of popup window WIN by fitting it to the buffer's
content."
(fit-window-to-buffer
win
- (floor (frame-height) 3)))
+ (floor (frame-height) 3)
+ (floor (frame-height) 6)))
(defun popper-select-popup-at-bottom (buffer &optional _alist)
"Display and switch to popup-buffer BUFFER at the bottom of the screen."
@@ -247,9 +256,9 @@ grouped by the predicate `popper-group-function'.")
"Predicate to test if buffer BUF meets the criteria listed in
`popper-reference-buffers'."
(or (seq-some (lambda (buf-regexp)
(string-match-p buf-regexp (buffer-name buf)))
- popper-reference-names)
- (member (buffer-local-value 'major-mode buf) popper-reference-modes)
- (seq-some (lambda (pred) (funcall pred buf))
popper-reference-predicates)))
+ popper--reference-names)
+ (member (buffer-local-value 'major-mode buf) popper--reference-modes)
+ (seq-some (lambda (pred) (funcall pred buf))
popper--reference-predicates)))
(defun popper-display-control-p (buf &optional _act)
"Predicate to test if display of buffer BUF needs to be handled by popper.
@@ -328,36 +337,24 @@ Each element of the alist is a cons cell of the form
(window . buffer)."
(let* ((open-buffers (mapcar #'window-buffer (window-list)))
(open-popups (popper-find-popups open-buffers))
(closed-popups (cl-remove-if-not
- (lambda (arg)
- (memq (buffer-local-value 'popper-popup-status (cdr
arg))
+ (lambda (win-buf)
+ (memq (buffer-local-value 'popper-popup-status (cdr
win-buf))
'(popup user-popup)))
- (cl-set-difference popper-open-popup-alist
- open-popups
- :key #'cdr))))
+ (cl-set-difference popper-open-popup-alist
open-popups :key #'cdr))))
(setq popper-open-popup-alist (nreverse open-popups))
(if popper-group-function
(cl-loop for (win . buf) in closed-popups do
- (let ((identifier-popups
- (cdr (assoc
- (with-current-buffer buf
- (funcall popper-group-function))
- popper-buried-popup-alist
- 'equal))))
- (setf
- (alist-get
- (with-current-buffer buf
- (funcall popper-group-function))
- popper-buried-popup-alist
- nil nil 'equal)
- (append (list (cons win buf))
- (cl-remove (cons win buf)
- identifier-popups
- :key 'cdr)))))
- (setf (alist-get nil popper-buried-popup-alist)
- (append closed-popups
- (cl-set-difference (cdr (assoc nil
popper-buried-popup-alist))
- closed-popups
- :key #'cdr)))))
+ (let* ((group-name (with-current-buffer buf (funcall
popper-group-function)))
+ (group-popups (cdr (assoc group-name
popper-buried-popup-alist 'equal)))
+ (newpop (cons win buf)))
+ (setf (alist-get group-name popper-buried-popup-alist
+ nil nil 'equal)
+ (append (list newpop)
+ (cl-remove newpop group-popups :key
'cdr)))))
+ (let ((old-popups (alist-get nil popper-buried-popup-alist)))
+ (setf (alist-get nil popper-buried-popup-alist)
+ (append closed-popups
+ (cl-set-difference old-popups closed-popups :key
#'cdr))))))
;; Mode line update
(cl-loop for (_ . buf) in popper-open-popup-alist do
(with-current-buffer buf
@@ -423,7 +420,7 @@ a popup buffer to open."
nil 'remove 'equal)))
(buf (cdr new-popup)))
(if (buffer-live-p buf)
- (progn (display-buffer buf))
+ (display-buffer buf)
(popper-open-latest))
(message no-popup-msg)))))
@@ -564,12 +561,14 @@ If BUFFER is not specified act on the current buffer
instead."
"Predicate to check if popup-buffer BUF needs to be suppressed."
(or (seq-some (lambda (buf-regexp)
(string-match-p buf-regexp (buffer-name buf)))
- popper-suppressed-names)
- (member (buffer-local-value 'major-mode buf) popper-suppressed-modes)
- (seq-some (lambda (pred) (funcall pred buf))
popper-suppressed-predicates)))
+ popper--suppressed-names)
+ (member (buffer-local-value 'major-mode buf) popper--suppressed-modes)
+ (seq-some (lambda (pred) (funcall pred buf))
popper--suppressed-predicates)))
(defun popper-suppress-popups ()
- "TODO: Suppress open popups in the user-defined
+ "TODO.
+
+ Suppress open popups in the user-defined
`popper-suppress-buffers' list. This should run after
`popper-update-popups' in `window-configuration-change-hook'."
@@ -592,24 +591,39 @@ If BUFFER is not specified act on the current buffer
instead."
(when configuration-changed-p
(popper-update-popups))))
+(declare-function popper--classify-type "popper")
+(declare-function popper--insert-type "popper")
+
(defun popper--set-reference-vars ()
"Unpack `popper-reference-buffers' to`set the values of various
- popper-reference- variables."
- (defun popper--insert-element-type (elm)
+ popper--reference- variables."
+ (defun popper--classify-type (elm)
(pcase elm
- ((pred stringp) (cl-pushnew elm popper-reference-names))
- ((pred symbolp) (cl-pushnew elm popper-reference-modes))
- ;; ((pred functionp) (push elm predlist)) ;; TODO
- ((pred consp)
- (progn (when (eq (cdr elm) 'hide)
- (pcase (car elm)
- ((pred stringp) (cl-pushnew (car elm)
popper-suppressed-names))
- ((pred symbolp) (cl-pushnew (car elm)
popper-suppressed-modes))))
- (popper--insert-element-type
- (car elm))))))
+ ((pred stringp) 'name)
+ ((and (pred symbolp)
+ (guard (or (get elm 'derived-mode-parent)
+ (get elm 'mode-class)
+ (not (boundp elm))
+ (not (fboundp elm))
+ (commandp elm))))
+ 'mode)
+ ((pred functionp) 'pred)
+ ((pred consp) 'cons)))
+
+ (defun popper--insert-type (elm)
+ (pcase (popper--classify-type elm)
+ ('name (cl-pushnew elm popper--reference-names))
+ ('mode (cl-pushnew elm popper--reference-modes))
+ ('pred (cl-pushnew elm popper--reference-predicates))
+ ('cons (when (eq (cdr elm) 'hide)
+ (pcase (popper--classify-type (car elm))
+ ('name (cl-pushnew (car elm) popper--suppressed-names))
+ ('mode (cl-pushnew (car elm) popper--suppressed-modes))
+ ('pred (cl-pushnew (car elm) popper--suppressed-modes))))
+ (popper--insert-type (car elm)))))
(dolist (entry popper-reference-buffers nil)
- (popper--insert-element-type entry)))
+ (popper--insert-type entry)))
;;;###autoload
(define-minor-mode popper-mode
@@ -646,10 +660,12 @@ details on how to designate buffer types as popups."
;; TODO: Clean this up
(setq popper-buried-popup-alist nil
popper-open-popup-alist nil
- popper-reference-names nil
- popper-reference-modes nil
- popper-suppressed-names nil
- popper-suppressed-modes nil)
+ popper--reference-names nil
+ popper--reference-modes nil
+ popper--reference-predicates nil
+ popper--suppressed-names nil
+ popper--suppressed-modes nil
+ popper--suppressed-predicates nil)
(setq display-buffer-alist
(cl-remove 'popper-display-control-p
display-buffer-alist
- [elpa] externals/popper 500d1d477c 021/102: Fixed duplication bug, (continued)
- [elpa] externals/popper 500d1d477c 021/102: Fixed duplication bug, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 03dc41c315 019/102: More robust minor mode definition, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 1a059a5973 009/102: Reduced surface area of package, ELPA Syncer, 2023/09/08
- [elpa] externals/popper a27500408c 023/102: Enhancements, see details, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 3584603390 013/102: Setting up project awareness, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 9eb1a8cbd8 006/102: Merge pull request #1 from syohex/fix-minimum-version, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 35e266d984 031/102: Add support for fullscreen popups, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 598571f025 041/102: Started work on buffer-hiding feature, ELPA Syncer, 2023/09/08
- [elpa] externals/popper b120c6836c 042/102: extract window height determining function, ELPA Syncer, 2023/09/08
- [elpa] externals/popper c96915cb77 043/102: Merge commit 'b120c68' into feature, ELPA Syncer, 2023/09/08
- [elpa] externals/popper cd975ac5b8 047/102: Updated README with new features, popups by predicate,
ELPA Syncer <=
- [elpa] externals/popper 1312c0f0f6 053/102: Added video demo of buffer hiding, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 851d838821 065/102: Extracted popper-echo into a separate library, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 7afd502b3b 068/102: Fixed popper-echo display when the group is a symbol, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 667dcdd063 069/102: Added badge, ELPA Syncer, 2023/09/08
- [elpa] externals/popper 4d58a6dbba 076/102: Handle unbound dispatch keys in popper-echo, ELPA Syncer, 2023/09/08
- [elpa] externals/popper d5ab9b2c41 077/102: Popup without selecting (#17), ELPA Syncer, 2023/09/08
- [elpa] externals/popper a93ff38ab6 098/102: popper: Assign copyright to FSF, ELPA Syncer, 2023/09/08
- [elpa] externals/popper fd39948875 024/102: Removed redundant info from documentation, ELPA Syncer, 2023/09/08
- [elpa] externals/popper b32abcba49 030/102: Fixed popup display of newly created popup buffers, ELPA Syncer, 2023/09/08
- [elpa] externals/popper c465e0de24 007/102: Added technical notes to README, ELPA Syncer, 2023/09/08