branch: elpa/adoc-mode
commit 717bce9c18039ced2a929ea4438267907714d2a5
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>
Add outline cycling commands
Add adoc-cycle (TAB), which rotates the visibility of the section
subtree at point between folded, child titles, and fully shown when
point is on a one-line title, and otherwise indents as usual; a prefix
argument cycles the whole buffer. Add adoc-cycle-buffer (S-TAB), which
rotates the buffer between overview, contents, and show-all.
Both are thin wrappers over the outline-cycle / outline-cycle-buffer
primitives, building on the outline-minor-mode integration.
---
CHANGELOG.md | 1 +
README.adoc | 2 +-
adoc-mode.el | 31 +++++++++++++++++++++++++++++++
test/adoc-mode-test.el | 43 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5343d29810..af2b323b0a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
### New features
+- Add outline cycling commands modelled on `org-mode` and `markdown-mode`:
`adoc-cycle` (`TAB`) rotates the visibility of the section subtree at point
(folded / child titles / fully shown) when point is on a one-line title, and
otherwise indents as usual; `adoc-cycle-buffer` (`S-TAB`) rotates the whole
buffer between overview, contents, and show-all. Both build on the
`outline-cycle` / `outline-cycle-buffer` primitives.
- Add list editing: `adoc-promote` (`M-left`) and `adoc-demote` (`M-right`)
now nest the list item at point one level deeper or shallower (for unordered
`*`/`-` and implicitly-numbered `.` lists) in addition to acting on section
titles, and the new `adoc-insert-list-item` (`M-RET`) inserts a sibling item
below the current one, keeping its indentation and marker and incrementing the
number/letter of explicitly-numbered items.
- Add `adoc-move-list-item-up` (`M-up`) and `adoc-move-list-item-down`
(`M-down`), which move the list item at point (together with its nested
sub-items) past its previous/next sibling, and `adoc-renumber-list`, which
renumbers a contiguous arabic (`1.`) or alphabetic (`a.`/`A.`)
explicitly-numbered list starting from its first item's value.
- Add heading navigation commands modelled on `markdown-mode` and `org-mode`:
`adoc-next-visible-heading` (`C-c C-n`), `adoc-previous-visible-heading` (`C-c
C-p`), `adoc-forward-same-level` (`C-c C-f`), `adoc-backward-same-level` (`C-c
C-b`), and `adoc-up-heading` (`C-c C-u`). They understand both one-line (`==
Title`) and two-line (underlined) titles and skip headings hidden by folding.
`outline-minor-mode` is now enabled by default so the folding commands are
available out of the box.
diff --git a/README.adoc b/README.adoc
index dfb469fb05..6d50179d91 100644
--- a/README.adoc
+++ b/README.adoc
@@ -44,7 +44,7 @@ Here are some of the main features of `adoc-mode`:
- list editing: `M-left` / `M-right` nest the list item at point deeper or
shallower, `M-RET` inserts a sibling item (incrementing the number for
explicitly-numbered lists), `M-up` / `M-down` move an item (with its sub-items)
past its siblings, and `M-x adoc-renumber-list` renumbers an
explicitly-numbered list
- navigate to anchors (`C-c C-a`) and follow URLs, `include::` macros, and
xrefs at point (`C-c C-o` / `M-.`)
- nested `imenu` index with hierarchical heading structure
-- `outline-minor-mode` enabled out of the box for folding (one-line title
style only)
+- outline folding built on `outline-minor-mode` (enabled out of the box):
`TAB` cycles the subtree at point, `S-TAB` cycles the whole buffer (overview /
contents / show all), one-line title style only
- integration with `flyspell-mode` (skips non-prose regions), comment commands
(`M-;`), and compilation mode
=== Demo
diff --git a/adoc-mode.el b/adoc-mode.el
index e7084b0578..5b6b1f4540 100644
--- a/adoc-mode.el
+++ b/adoc-mode.el
@@ -44,6 +44,7 @@
(require 'cl-lib)
(require 'compile)
+(require 'outline)
(require 'subr-x)
(require 'adoc-mode-image)
(require 'adoc-mode-tempo)
@@ -3556,6 +3557,31 @@ buffer stops the search. With a negative ARG, move
forward."
(goto-char orig)
(user-error "No parent section title"))))))
+;;;; Outline cycling
+
+(defun adoc-cycle (&optional arg)
+ "Cycle the visibility of the section subtree at point.
+On a section title, rotate its subtree between folded, child
+titles only, and fully shown (via `outline-cycle'). Off a title,
+indent or insert a tab as usual. With a prefix ARG, cycle the
+visibility of the whole buffer instead (see `adoc-cycle-buffer').
+
+Only one-line titles (e.g. `== Title') are recognised by the
+underlying `outline-minor-mode'."
+ (interactive "P")
+ (cond
+ (arg (adoc-cycle-buffer))
+ ((outline-on-heading-p) (outline-cycle))
+ (t (indent-for-tab-command))))
+
+(defun adoc-cycle-buffer ()
+ "Cycle the visibility of all section titles in the buffer.
+Rotate between an overview (top-level titles only), a table of
+contents (all titles, no bodies), and the fully expanded buffer
+\(via `outline-cycle-buffer')."
+ (interactive)
+ (outline-cycle-buffer))
+
(defvar sgml-char-names)
(defun adoc-make-unichar-alist ()
@@ -3746,6 +3772,8 @@ ITEMS is a list of (name pos . level)."
(define-key map (kbd "M-RET") 'adoc-insert-list-item)
(define-key map (kbd "M-<up>") 'adoc-move-list-item-up)
(define-key map (kbd "M-<down>") 'adoc-move-list-item-down)
+ (define-key map (kbd "TAB") 'adoc-cycle)
+ (define-key map (kbd "<backtab>") 'adoc-cycle-buffer)
(define-key map "\C-c\C-t" 'adoc-toggle-title-type)
(define-key map "\C-c\C-a" 'adoc-goto-ref-label)
(define-key map "\C-c\C-o" 'adoc-follow-thing-at-point)
@@ -3758,6 +3786,9 @@ ITEMS is a list of (name pos . level)."
["Backward (same level)" adoc-backward-same-level]
["Up to parent heading" adoc-up-heading]
"---"
+ ["Cycle subtree visibility" adoc-cycle]
+ ["Cycle buffer visibility" adoc-cycle-buffer]
+ "---"
["Promote (title / list item)" adoc-promote]
["Demote (title / list item)" adoc-demote]
["Insert list item" adoc-insert-list-item]
diff --git a/test/adoc-mode-test.el b/test/adoc-mode-test.el
index 565e3ca528..2923c3da64 100644
--- a/test/adoc-mode-test.el
+++ b/test/adoc-mode-test.el
@@ -1013,6 +1013,49 @@ on top of the `<mark>' default)."
(adoc-up-heading 1)
(should (looking-at-p "Doc Title$"))))
+;;;; Outline cycling
+
+(defun adoctest-cycle-buffer ()
+ "Set up a temp buffer with a small document for cycling tests."
+ (adoc-mode)
+ (insert "= Top\n\n== A\n\nbody a\n\n== B\n\nbody b\n")
+ (font-lock-ensure)
+ (goto-char (point-min)))
+
+(ert-deftest adoctest-test-cycle-subtree ()
+ (with-temp-buffer
+ (adoctest-cycle-buffer)
+ (let ((body (save-excursion (search-forward "body a") (point))))
+ (search-forward "== A") (beginning-of-line)
+ (should-not (outline-invisible-p body))
+ ;; on a heading, cycling folds the subtree, then reveals it again
+ (adoc-cycle)
+ (should (outline-invisible-p body))
+ (adoc-cycle)
+ (should-not (outline-invisible-p body)))))
+
+(ert-deftest adoctest-test-cycle-off-heading-does-not-fold ()
+ (with-temp-buffer
+ (adoctest-cycle-buffer)
+ (let ((body (save-excursion (search-forward "body a") (point))))
+ ;; point on an ordinary line: cycling must not fold anything
+ (goto-char body)
+ (adoc-cycle)
+ (should-not (outline-invisible-p body)))))
+
+(ert-deftest adoctest-test-cycle-buffer ()
+ (with-temp-buffer
+ (adoctest-cycle-buffer)
+ (let ((body (save-excursion (search-forward "body a") (point))))
+ (should-not (outline-invisible-p body))
+ ;; a prefix argument cycles the whole buffer: overview hides bodies
+ (adoc-cycle '(4))
+ (should (outline-invisible-p body))
+ ;; ... and the dedicated command eventually shows everything again
+ (adoc-cycle-buffer)
+ (adoc-cycle-buffer)
+ (should-not (outline-invisible-p body)))))
+
;;;; List editing
(ert-deftest adoctest-test-list-promote-demote-unordered ()