From: Juri Linkov Date: Mon, 19 Sep 2022 19:35:51 +0000 (+0300) Subject: * lisp/outline.el (outline-minor-mode-use-margins): New user option. X-Git-Tag: emacs-29.0.90~1856^2~371 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=0a15956f495338b4f2260c7676a6040436a90645;p=emacs.git * lisp/outline.el (outline-minor-mode-use-margins): New user option. (outline--use-margins, outline--use-buttons, outline--use-rtl): New buffer-local internal variables. (outline-open, outline-close): Move :ascent center to default of define-icon. Use ASCII-art for text. Fix docstring and help-echo. (outline-close-rtl, outline-open-in-margins) (outline-close-in-margins, outline-close-rtl-in-margins): New icon definitions. (outline-minor-mode-highlight-buffer): Remove outline--insert-open-button since initial outline--fix-up-all-buttons is added now to outline-minor-mode. (outline-minor-mode): Set buffer-local outline--use-buttons, outline--use-margins and outline--use-rtl. Show/hide margins for outline--use-margins. Add hook after-change-functions for editable buffers. Move outline--fix-up-all-buttons for both cases: font-lock and non-font-lock. (outline--use-buttons-p): Remove function. (outline--make-button-overlay): Use outline--use-rtl icon outline-close-rtl. (outline--make-margin-overlay): New function. (outline--insert-open-button, outline--insert-close-button): Add optional arg 'use-margins'. (outline--fix-up-all-buttons): Call outline--insert-close-button and outline--insert-open-button with arg outline--use-margins. (outline-cycle-buffer): Remove outline--fix-up-all-buttons that is already called from outline-flag-region. * lisp/emacs-lisp/icons.el (icons--create): Handle keywords :rotation and :ascent with the default value 'center (bug#57813). * doc/emacs/text.texi (Outline Mode): Mention outline-minor-mode-use-margins. --- diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index fa8eaf09245..35dce18d022 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -1003,6 +1003,11 @@ addition to ellipsis to show that a section is hidden. Using @kbd{RET} (or clicking on the button with a mouse) will toggle displaying the section. +@vindex outline-minor-mode-use-margins + If @code{outline-minor-mode-use-margins} is non-@code{nil}, Outline +minor mode will use the window margins in addition to ellipsis to show +that a section is hidden. + @vindex outline-minor-mode-cycle If the @code{outline-minor-mode-cycle} user option is non-@code{nil}, the @kbd{TAB} and @kbd{S-@key{TAB}} keys are enabled on the diff --git a/etc/NEWS b/etc/NEWS index ee333a84e45..821da805ca2 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -962,7 +962,14 @@ or is itself too long. *** New user option 'outline-minor-mode-use-buttons'. If non-nil, Outline Minor Mode will use buttons to hide/show outlines in addition to the ellipsis. The default is nil in editing modes, but -non-nil in 'special-mode' and its derivatives. +non-nil in 'help-mode' and its derivatives. + ++++ +*** New user option 'outline-minor-mode-use-margins'. +If non-nil, Outline Minor Mode will use the window margins to +hide/show outlines in addition to the ellipsis. The default is +non-nil in 'special-mode' and its derivatives, and it can be used in +editing modes. ** Windows @@ -1489,8 +1496,8 @@ characters instead of just 'SPC' and 'TAB'. This mode adds some highlighting, fixes the 'M-q' command, and has commands for doing maintenance of the Emacs NEWS files. In addition, this mode turns on 'outline-minor-mode', and thus displays -customizable icons (see 'icon-preference') on heading lines. To -disable these icons, customize 'outline-minor-mode-use-buttons' to a +customizable icons (see 'icon-preference') in the margins. To +disable these icons, customize 'outline-minor-mode-use-margins' to a nil value. --- diff --git a/lisp/emacs-lisp/icons.el b/lisp/emacs-lisp/icons.el index ff4f20c2071..ccc36577932 100644 --- a/lisp/emacs-lisp/icons.el +++ b/lisp/emacs-lisp/icons.el @@ -202,7 +202,11 @@ present if the icon is represented by an image." :height (if (eq height 'line) (window-default-line-height) height) - :scale 1 :ascent 'center) + :scale 1 + :rotation (plist-get keywords :rotation) + :ascent (if (plist-member keywords :ascent) + (plist-get keywords :ascent) + 'center)) (create-image file)))))) (cl-defmethod icons--create ((_type (eql 'emoji)) icon _keywords) diff --git a/lisp/outline.el b/lisp/outline.el index e3fbd8b3272..ab37e398e98 100644 --- a/lisp/outline.el +++ b/lisp/outline.el @@ -292,25 +292,65 @@ buffers (yet) -- that will be amended in a future version." :safe #'booleanp :version "29.1") +(defvar-local outline--use-buttons nil + "Non-nil when buffer displays clickable buttons on the headings.") + +(defvar-local outline--use-rtl nil + "Non-nil when direction of clickable buttons is right-to-left.") + +(defcustom outline-minor-mode-use-margins '(derived-mode . special-mode) + "Whether to display clickable buttons in the margins. +The value should be a `buffer-match-p' condition. + +These buttons can be used to hide and show the body under the heading. +Note that this feature is meant to be used in editing buffers." + :type 'buffer-predicate + :safe #'booleanp + :version "29.1") + +(defvar-local outline--use-margins nil + "Non-nil when buffer displays clickable buttons in the margins.") + (define-icon outline-open nil - '((image "outline-open.svg" "outline-open.pbm" - :height 15 :ascent center) + '((image "outline-open.svg" "outline-open.pbm" :height 15) (emoji "🔽") (symbol " ▼ ") - (text " open ")) - "Icon used for buttons for opening a section in outline buffers." + (text " v ")) + "Icon used for buttons for opened sections in outline buffers." :version "29.1" - :help-echo "Open this section") + :help-echo "Close this section") (define-icon outline-close nil - '((image "outline-close.svg" "outline-close.pbm" - :height 15 :ascent center) + '((image "outline-close.svg" "outline-close.pbm" :height 15) (emoji "▶️") (symbol " ▶ ") - (text " close ")) - "Icon used for buttons for closing a section in outline buffers." + (text " > ")) + "Icon used for buttons for closed sections in outline buffers." :version "29.1" - :help-echo "Close this section") + :help-echo "Open this section") + +(define-icon outline-close-rtl outline-close + '((image "outline-close.svg" "outline-close.pbm" :height 15 :rotation 180) + (emoji "◀️") + (symbol " ◀ ") + (text " < ")) + "Right-to-left icon used for buttons in closed outline sections." + :version "29.1") + +(define-icon outline-open-in-margins outline-open + '((image "outline-open.svg" "outline-open.pbm" :height 10)) + "Icon used for buttons for opened sections in margins." + :version "29.1") + +(define-icon outline-close-in-margins outline-close + '((image "outline-open.svg" "outline-open.pbm" :height 10 :rotation -90)) + "Icon used for buttons for closed sections in margins." + :version "29.1") + +(define-icon outline-close-rtl-in-margins outline-close-rtl + '((image "outline-open.svg" "outline-open.pbm" :height 10 :rotation 90)) + "Right-to-left icon used for closed sections in margins." + :version "29.1") (defvar outline-level #'outline-level @@ -439,9 +479,7 @@ outline font-lock faces to those of major mode." (when (or (memq outline-minor-mode-highlight '(append override)) (and (eq outline-minor-mode-highlight t) (not (get-text-property (match-beginning 0) 'face)))) - (overlay-put overlay 'face (outline-font-lock-face))) - (when (outline--use-buttons-p) - (outline--insert-open-button))) + (overlay-put overlay 'face (outline-font-lock-face)))) (goto-char (match-end 0)))))) ;;;###autoload @@ -456,13 +494,37 @@ See the command `outline-mode' for more information on this mode." (key-description outline-minor-mode-prefix) outline-mode-prefix-map) (if outline-minor-mode (progn + (cond + ((buffer-match-p outline-minor-mode-use-margins (current-buffer)) + (setq-local outline--use-margins t)) + ((buffer-match-p outline-minor-mode-use-buttons (current-buffer)) + (setq-local outline--use-buttons t))) + (when (and (or outline--use-buttons outline--use-margins) + (eq (current-bidi-paragraph-direction) 'right-to-left)) + (setq-local outline--use-rtl t)) + (when outline--use-margins + (if outline--use-rtl + (setq-local right-margin-width (1+ right-margin-width)) + (setq-local left-margin-width (1+ left-margin-width))) + (setq-local fringes-outside-margins t) + ;; Force display of margins + (set-window-buffer nil (window-buffer))) + (when (or outline--use-buttons outline--use-margins) + (add-hook 'after-change-functions + (lambda (beg end _len) + (when outline--use-buttons + (remove-overlays beg end 'outline-button t)) + (when outline--use-margins + (remove-overlays beg end 'outline-margin t)) + (outline--fix-up-all-buttons beg end)) + nil t)) (when outline-minor-mode-highlight (if (and global-font-lock-mode (font-lock-specified-p major-mode)) (progn (font-lock-add-keywords nil outline-font-lock-keywords t) - (font-lock-flush) - (outline--fix-up-all-buttons)) + (font-lock-flush)) (outline-minor-mode-highlight-buffer))) + (outline--fix-up-all-buttons) ;; Turn off this mode if we change major modes. (add-hook 'change-major-mode-hook (lambda () (outline-minor-mode -1)) @@ -476,16 +538,19 @@ See the command `outline-mode' for more information on this mode." (font-lock-remove-keywords nil outline-font-lock-keywords)) (remove-overlays nil nil 'outline-overlay t) (font-lock-flush)) + (when outline--use-margins + (if outline--use-rtl + (setq-local right-margin-width (1- right-margin-width)) + (setq-local left-margin-width (1- left-margin-width))) + (setq-local fringes-outside-margins nil) + ;; Force removal of margins + (set-window-buffer nil (window-buffer))) (setq line-move-ignore-invisible nil) ;; Cause use of ellipses for invisible text. (remove-from-invisibility-spec '(outline . t)) ;; When turning off outline mode, get rid of any outline hiding. (outline-show-all))) -(defun outline--use-buttons-p () - (and outline-minor-mode - (buffer-match-p outline-minor-mode-use-buttons (current-buffer)))) - (defvar-local outline-heading-alist () "Alist associating a heading for every possible level. Each entry is of the form (HEADING . LEVEL). @@ -1000,8 +1065,11 @@ If non-nil, EVENT should be a mouse event." (overlay-put o 'follow-link 'mouse-face) (overlay-put o 'mouse-face 'highlight) (overlay-put o 'outline-button t)) - (let ((icon - (icon-elements (if (eq type 'close) 'outline-close 'outline-open))) + (let ((icon (icon-elements (if (eq type 'close) + (if outline--use-rtl + 'outline-close-rtl + 'outline-close) + 'outline-open))) (inhibit-read-only t)) ;; In editing buffers we use overlays only, but in other buffers ;; we use a mix of text properties, text and overlays to make @@ -1015,10 +1083,40 @@ If non-nil, EVENT should be a mouse event." (overlay-put o 'face (plist-get icon 'face)))) o)) -(defun outline--insert-open-button () +(defun outline--make-margin-overlay (type) + (let ((o (seq-find (lambda (o) + (overlay-get o 'outline-margin)) + (overlays-at (point))))) + (unless o + (setq o (make-overlay (point) (1+ (point)))) + (overlay-put o 'follow-link 'mouse-face) + (overlay-put o 'mouse-face 'highlight) + (overlay-put o 'outline-margin t)) + (let ((icon (icon-elements (if (eq type 'close) + (if outline--use-rtl + 'outline-close-rtl-in-margins + 'outline-close-in-margins) + 'outline-open-in-margins))) + (inhibit-read-only t)) + (overlay-put + o 'before-string + (propertize " " 'display + `((margin ,(if outline--use-rtl + 'right-margin 'left-margin)) + ,(or (plist-get icon 'image) + (plist-get icon 'string)))))) + o)) + +(defun outline--insert-open-button (&optional use-margins) (with-silent-modifications (save-excursion - (beginning-of-line) + (beginning-of-line) + (if use-margins + (let ((o (outline--make-margin-overlay 'open))) + (overlay-put o 'help-echo "Click to hide") + (overlay-put o 'keymap + (define-keymap + "" #'outline-hide-subtree))) (when (derived-mode-p 'special-mode) (let ((inhibit-read-only t)) (insert " ") @@ -1028,12 +1126,19 @@ If non-nil, EVENT should be a mouse event." (overlay-put o 'keymap (define-keymap "RET" #'outline-hide-subtree - "" #'outline-hide-subtree)))))) + "" #'outline-hide-subtree + " " #'outline-hide-subtree))))))) -(defun outline--insert-close-button () +(defun outline--insert-close-button (&optional use-margins) (with-silent-modifications (save-excursion - (beginning-of-line) + (beginning-of-line) + (if use-margins + (let ((o (outline--make-margin-overlay 'close))) + (overlay-put o 'help-echo "Click to show") + (overlay-put o 'keymap + (define-keymap + "" #'outline-show-subtree))) (when (derived-mode-p 'special-mode) (let ((inhibit-read-only t)) (insert " ") @@ -1043,10 +1148,11 @@ If non-nil, EVENT should be a mouse event." (overlay-put o 'keymap (define-keymap "RET" #'outline-show-subtree - "" #'outline-show-subtree)))))) + "" #'outline-show-subtree + " " #'outline-show-subtree))))))) (defun outline--fix-up-all-buttons (&optional from to) - (when (outline--use-buttons-p) + (when (or outline--use-buttons outline--use-margins) (when from (save-excursion (goto-char from) @@ -1057,8 +1163,8 @@ If non-nil, EVENT should be a mouse event." (outline-end-of-heading) (seq-some (lambda (o) (eq (overlay-get o 'invisible) 'outline)) (overlays-at (point)))) - (outline--insert-close-button) - (outline--insert-open-button))) + (outline--insert-close-button outline--use-margins) + (outline--insert-open-button outline--use-margins))) (or from (point-min)) (or to (point-max))))) (define-obsolete-function-alias 'hide-subtree #'outline-hide-subtree "25.1") @@ -1627,8 +1733,7 @@ With a prefix argument, show headings up to that LEVEL." (t (outline-show-all) (setq outline--cycle-buffer-state 'show-all) - (message "Show all"))) - (outline--fix-up-all-buttons))) + (message "Show all"))))) (defvar-keymap outline-navigation-repeat-map