feature/evil: refactor folding & outline support

Code folding commands will now obey outline headers (if
outline-minor-mode is on and in outline-mode).
This commit is contained in:
Henrik Lissner 2018-09-20 22:23:33 -04:00
parent 9245e030bb
commit 6fce87bd06
4 changed files with 108 additions and 59 deletions

View file

@ -1,38 +1,34 @@
;;; feature/evil/autoload/folds.el -*- lexical-binding: t; -*-
(require 'evil-vimish-fold)
(require 'hideshow)
;; `hideshow' is a decent code folding implementation, but it won't let you
;; create custom folds. `evil-vimish-fold' offers custom folds, but essentially
;; create custom folds. `vimish-fold' offers custom folds, but essentially
;; ignores any other type of folding (indent or custom markers, which
;; hs-minor-mode gives you).
;; hs-minor-mode and `outline-mode' give you).
;;
;; So this is my effort to combine them.
(defun +evil--vimish-fold-p ()
(cl-some #'vimish-fold--vimish-overlay-p (overlays-at (point))))
(and (featurep 'vimish-fold)
(cl-some #'vimish-fold--vimish-overlay-p
(overlays-at (point)))))
(defun +evil--ensure-modes (&rest _)
"Ensure hs-minor-mode is enabled."
(unless (bound-and-true-p hs-minor-mode)
(hs-minor-mode +1)))
(defun +evil--outline-fold-p ()
(and (or (bound-and-true-p outline-minor-mode)
(derived-mode-p 'outline-mode))
(outline-on-heading-p)))
(advice-add #'hs-toggle-hiding :before #'+evil--ensure-modes)
(advice-add #'hs-hide-block :before #'+evil--ensure-modes)
(advice-add #'hs-hide-level :before #'+evil--ensure-modes)
(advice-add #'hs-show-all :before #'+evil--ensure-modes)
(advice-add #'hs-hide-all :before #'+evil--ensure-modes)
(defun +evil--hideshow-fold-p ()
(hs-minor-mode +1)
(save-excursion
(ignore-errors
(or (hs-looking-at-block-start-p)
(hs-find-block-beginning)))))
;; --- fold commands ----------------------
;;;###autoload
(defun +evil-fold-p ()
(or (+evil--vimish-fold-p)
(ignore-errors
(+evil--ensure-modes)
(hs-already-hidden-p))))
;;
;; Code folding
(defmacro +evil-from-eol (&rest body)
"Perform action after moving to the end of the line."
@ -40,47 +36,87 @@
(end-of-line)
,@body))
;;;###autoload (autoload '+evil:fold-toggle "feature/evil/autoload/folds" nil t)
(evil-define-command +evil:fold-toggle ()
;;;###autoload
(defun +evil/fold-toggle ()
(interactive)
(if (+evil--vimish-fold-p)
(vimish-fold-toggle)
(+evil-from-eol (hs-toggle-hiding))))
(save-excursion
(cond ((+evil--vimish-fold-p) (vimish-fold-toggle))
((+evil--hideshow-fold-p) (+evil-from-eol (hs-toggle-hiding)))
((+evil--outline-fold-p) (outline-toggle-children)))))
;;;###autoload (autoload '+evil:fold-open "feature/evil/autoload/folds" nil t)
(evil-define-command +evil:fold-open ()
;;;###autoload
(defun +evil/fold-open ()
(interactive)
(if (+evil--vimish-fold-p)
(vimish-fold-unfold)
(+evil-from-eol (hs-show-block))))
(save-excursion
(cond ((+evil--vimish-fold-p) (vimish-fold-unfold))
((+evil--hideshow-fold-p) (+evil-from-eol (hs-show-block)))
((+evil--outline-fold-p)
(outline-show-children)
(outline-show-entry)))))
;;;###autoload (autoload '+evil:fold-close "feature/evil/autoload/folds" nil t)
(evil-define-command +evil:fold-close ()
;;;###autoload
(defun +evil/fold-close ()
(interactive)
(if (+evil--vimish-fold-p)
(vimish-fold-refold)
(+evil-from-eol (hs-hide-block))))
(save-excursion
(cond ((+evil--vimish-fold-p) (vimish-fold-refold))
((+evil--hideshow-fold-p) (+evil-from-eol (hs-hide-block)))
((+evil--outline-fold-p) (outline-hide-subtree)))))
;;;###autoload (autoload '+evil:fold-open-all "feature/evil/autoload/folds" nil t)
(evil-define-command +evil:fold-open-all (&optional level)
;;;###autoload
(defun +evil/fold-open-all (&optional level)
"Open folds at LEVEL (or all folds if LEVEL is nil)."
(interactive "<c>")
(vimish-fold-unfold-all)
(if (integerp level)
(hs-hide-level (1- level))
(hs-show-all)))
(interactive
(list (if current-prefix-arg (prefix-numeric-value current-prefix-arg))))
(when (featurep 'vimish-fold)
(vimish-fold-unfold-all))
(save-excursion
(if (integerp level)
(progn
(outline-hide-sublevels (max 1 (1- level)))
(hs-life-goes-on
(hs-hide-level-recursive (1- level) (point-min) (point-max))))
(hs-show-all)
(when (fboundp 'outline-show-all)
(outline-show-all)))))
;;;###autoload (autoload '+evil:fold-close-all "feature/evil/autoload/folds" nil t)
(evil-define-command +evil:fold-close-all (&optional level)
;;;###autoload
(defun +evil/fold-close-all (&optional level)
"Close folds at LEVEL (or all folds if LEVEL is nil)."
(interactive "<c>")
(vimish-fold-refold-all)
(if (integerp level)
(hs-hide-level (1- level))
(hs-hide-all)))
(interactive
(list (if current-prefix-arg (prefix-numeric-value current-prefix-arg))))
(save-excursion
(when (featurep 'vimish-fold)
(vimish-fold-refold-all))
(if (integerp level)
(progn
(when (fboundp 'outline-hide-sublevels)
(outline-hide-sublevels (max 1 (1- level))))
(hs-life-goes-on
(hs-hide-level-recursive (1- level) (point-min) (point-max))))
(when (fboundp 'outline-hide-sublevels)
(outline-hide-sublevels 1))
(hs-hide-all))))
(defun +evil--invisible-points (count)
(let (points)
(save-excursion
(catch 'abort
(if (< count 0) (beginning-of-line))
(while (re-search-forward hs-block-start-regexp nil t
(if (> count 0) 1 -1))
(unless (invisible-p (point))
(end-of-line)
(when (hs-already-hidden-p)
(push (point) points)
(when (>= (length points) count)
(throw 'abort nil))))
(forward-line (if (> count 0) 1 -1)))))
points))
;; --- misc -------------------------------
;;
;; Misc
;;;###autoload
(defun +evil/matchit-or-toggle-fold ()