From d8fee4c307178fc2e0e7c206b8b8a42b2acda719 Mon Sep 17 00:00:00 2001 From: Matthias Meulien Date: Wed, 8 Dec 2021 22:35:42 +0100 Subject: [PATCH] Extend Outline mode with default visibility state * lisp/outline.el (outline-mode, outline-minor-mode): Ensure default visibility state is applied (outline-hide-sublevels): Add optional argument for function to call on each heading (outline-default-state): Define the default visibility state (outline-apply-default-state): Apply default visibility state --- lisp/outline.el | 50 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/lisp/outline.el b/lisp/outline.el index 2ede4e23ea..a3e5da4f5b 100644 --- a/lisp/outline.el +++ b/lisp/outline.el @@ -353,7 +353,8 @@ outline-mode '(outline-font-lock-keywords t nil nil backward-paragraph)) (setq-local imenu-generic-expression (list (list nil (concat "^\\(?:" outline-regexp "\\).*$") 0))) - (add-hook 'change-major-mode-hook #'outline-show-all nil t)) + (add-hook 'change-major-mode-hook #'outline-show-all nil t) + (outline-apply-default-state)) (defvar outline-minor-mode-map) @@ -436,7 +437,8 @@ outline-minor-mode nil t) (setq-local line-move-ignore-invisible t) ;; Cause use of ellipses for invisible text. - (add-to-invisibility-spec '(outline . t))) + (add-to-invisibility-spec '(outline . t)) + (outline-apply-default-state)) (when (or outline-minor-mode-cycle outline-minor-mode-highlight) (if font-lock-fontified (font-lock-remove-keywords nil outline-font-lock-keywords)) @@ -1058,13 +1060,16 @@ outline-show-heading (progn (outline-end-of-heading) (point)) nil)) -(defun outline-hide-sublevels (levels) +(defun outline-hide-sublevels (levels &optional fun) "Hide everything but the top LEVELS levels of headers, in whole buffer. This also unhides the top heading-less body, if any. Interactively, the prefix argument supplies the value of LEVELS. When invoked without a prefix argument, LEVELS defaults to the level -of the current heading, or to 1 if the current line is not a heading." +of the current heading, or to 1 if the current line is not a heading. + +When FUN is defined, sublevels aren't hidden but FUN is called +for each of them." (interactive (list (cond (current-prefix-arg (prefix-numeric-value current-prefix-arg)) @@ -1093,7 +1098,9 @@ outline-hide-sublevels (outline-map-region (lambda () (if (<= (funcall outline-level) levels) - (outline-show-heading))) + (if fun + (funcall fun) + (outline-show-heading)))) beg end) ;; Finally unhide any trailing newline. (goto-char (point-max)) @@ -1307,6 +1314,39 @@ outline-headers-as-kill (insert "\n\n")))))) (kill-new (buffer-string))))))) +(defcustom outline-default-state nil + "If non-nil, some headings are initially outlined. + +If equal to `only-headings', only heading are shown. + +If equal to a number, hide everything but the headings at that +level. + +If equal to a lambda function or function name, this function is +expected to toggle headings visibility, and will be called after +the mode is enabled." + :version "29.1" + :type '(choice (const :tag "Show all" nil) + (const :tag "Only headings" only-headings) + (natnum :tag "Outline level") + (function :tag "Custom function")) + :local t + :safe t) +;; TODO fix variable being set through file local variable + +(defun outline-apply-default-state () + "Apply the outline state defined by `outline-default-state'." + (interactive) + (cond + ((not outline-default-state) (outline-show-all)) + ((eq outline-default-state 'only-headings) + (outline-show-all) + (outline-hide-region-body (point-min) (point-max))) + ((integerp outline-default-state) + (outline-hide-sublevels outline-default-state)) + ((when (functionp outline-default-state) + (funcall outline-default-state))))) + (defun outline--cycle-state () "Return the cycle state of current heading. Return either 'hide-all, 'headings-only, or 'show-all." -- 2.30.2