From f49a507ec802f7ec198be8a2dd93d18084781d30 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Mon, 15 May 2017 20:20:06 +0200 Subject: [PATCH] feature/evil: new code-folding system --- core/core-ui.el | 8 --- modules/feature/evil/autoload/evil.el | 37 ----------- modules/feature/evil/autoload/folds.el | 89 ++++++++++++++++++++++++++ modules/feature/evil/config.el | 7 ++ modules/feature/evil/packages.el | 1 + modules/ui/doom/config.el | 7 ++ 6 files changed, 104 insertions(+), 45 deletions(-) create mode 100644 modules/feature/evil/autoload/folds.el diff --git a/core/core-ui.el b/core/core-ui.el index d28d221ec..e7faf0809 100644 --- a/core/core-ui.el +++ b/core/core-ui.el @@ -116,16 +116,8 @@ local value, whether or not it's permanent-local. Therefore, we cycle ;; Plugins ;; -;; I modified the built-in `hideshow' package to enable itself when needed. A -;; better, more vim-like code-folding plugin would be the `origami' plugin, but -;; until certain breaking bugs are fixed in it, I won't switch over. (def-package! hideshow ; built-in :commands (hs-minor-mode hs-toggle-hiding hs-already-hidden-p) - :init - (defun doom*autoload-hideshow () - (unless (bound-and-true-p hs-minor-mode) - (hs-minor-mode 1))) - (advice-add #'evil-toggle-fold :before #'doom*autoload-hideshow) :config (setq hs-hide-comments-when-hiding-all nil)) diff --git a/modules/feature/evil/autoload/evil.el b/modules/feature/evil/autoload/evil.el index 7048d342f..94c9f625b 100644 --- a/modules/feature/evil/autoload/evil.el +++ b/modules/feature/evil/autoload/evil.el @@ -169,43 +169,6 @@ evil-window-move-* (e.g. `evil-window-move-far-left')" (doom-narrow-buffer beg end bang)) -;; --- code folding ----------------------- - -;; I wrote these for two reasons: -;; 1. To facilitate lazy-loading of hideshow.el (otherwise, evil wouldn't know what mode to use) -;; 2. To allow level-based folding (parity with vim), e.g. 2zr will open all -;; folds up to 2nd level folds. - -;;;###autoload (autoload '+evil:open-folds-recursively "feature/evil/autoload/evil" nil t) -(evil-define-command +evil:open-folds-recursively (level) - "Opens all folds recursively, up to LEVEL." - (interactive "") - (unless (bound-and-true-p hs-minor-mode) - (hs-minor-mode 1)) - (if level (hs-hide-level level) (evil-open-folds))) - -;;;###autoload (autoload '+evil:close-folds-recursively "feature/evil/autoload/evil" nil t) -(evil-define-command +evil:close-folds-recursively (level) - "Closes all folds recursively, up to LEVEL." - (interactive "") - (unless (bound-and-true-p hs-minor-mode) - (hs-minor-mode 1)) - (if level (hs-hide-level level) (evil-close-folds))) - -;;;###autoload -(defun +evil/matchit-or-toggle-fold () - "Do what I mean. If on a fold-able element, toggle the fold with -`hs-toggle-hiding'. Otherwise, if on a delimiter, jump to the matching one with -`evilmi-jump-items'. If in a magit-status buffer, use `magit-section-toggle'." - (interactive) - (cond ((eq major-mode 'magit-status-mode) - (call-interactively 'magit-section-toggle)) - ((ignore-errors (hs-already-hidden-p)) - (hs-toggle-hiding)) - (t - (call-interactively 'evilmi-jump-items)))) - - ;; --- custom arg handlers ---------------- (defvar +evil--buffer-match-global evil-ex-substitute-global "") diff --git a/modules/feature/evil/autoload/folds.el b/modules/feature/evil/autoload/folds.el new file mode 100644 index 000000000..dcdceed6e --- /dev/null +++ b/modules/feature/evil/autoload/folds.el @@ -0,0 +1,89 @@ +;;; feature/evil/autoload/folds.el + +;; It's frustrating how hideshow is a decent code folding implementation, but it +;; won't let you create custom folds. Meanwhile, evil-vimish-fold offers custom +;; folds, but essentially ignores any other type of folding (indent or custom +;; markers, which hs-minor-mode gives you). +;; +;; So this is my effort to combine them. + +;; Initialize the two modes +(evil-vimish-fold-mode +1) + +(defun +evil*fold-hs-minor-mode (&rest args) + "Lazily activate buffer-local hs-minor-mode." + (unless (bound-and-true-p hs-minor-mode) + (hs-minor-mode +1))) +(advice-add #'evil-fold-action :before #'+evil*fold-hs-minor-mode) + +(add-to-list + 'evil-fold-list + '((evil-vimish-mode hs-minor-mode) + :delete vimish-fold-delete + :open-all +evil/fold-open-all + :close-all +evil/fold-close-all + :toggle +evil/fold-toggle + :open +evil/fold-open + :open-rec nil + :close +evil/fold-close)) + + +;; --- fold functions --------------------- + +(defun +evil--vimish-fold-p () + (cl-some #'vimish-fold--vimish-overlay-p (overlays-at (point)))) + +;;;###autoload +(defun +evil-fold-p () + (or (+evil--vimish-fold-p) + (hs-already-hidden-p))) + +;;;###autoload (autoload '+evil/fold-toggle "feature/evil/autoload/folds" nil t) +(evil-define-command +evil/fold-toggle () + (interactive) + (if (+evil--vimish-fold-p) + (vimish-fold-toggle) + (hs-toggle-hiding))) + +;;;###autoload (autoload '+evil/fold-open "feature/evil/autoload/folds" nil t) +(evil-define-command +evil/fold-open () + (interactive) + (if (+evil--vimish-fold-p) + (vimish-fold-unfold) + (hs-hide-block))) + +;;;###autoload (autoload '+evil/fold-close "feature/evil/autoload/folds" nil t) +(evil-define-command +evil/fold-close () + (interactive) + (if (+evil--vimish-fold-p) + (vimish-fold-refold) + (hs-hide-block))) + +;;;###autoload (autoload '+evil/fold-open-all "feature/evil/autoload/folds" nil t) +(evil-define-command +evil/fold-open-all (&optional level) + (interactive "") + (vimish-fold-unfold-all) + (if level (hs-hide-level level) (hs-show-all))) + +;;;###autoload (autoload '+evil/fold-close-all "feature/evil/autoload/folds" nil nil) +(evil-define-command +evil/fold-close-all (&optional level) + (interactive "") + (vimish-fold-refold-all) + (if level (hs-hide-level level) (hs-hide-all))) + + +;; --- misc ------------------------------- + +;;;###autoload +(defun +evil/matchit-or-toggle-fold () + "Do what I mean. If on a fold-able element, toggle the fold with +`hs-toggle-hiding'. Otherwise, if on a delimiter, jump to the matching one with +`evilmi-jump-items'. If in a magit-status buffer, use `magit-section-toggle'." + (interactive) + (call-interactively + (cond ((eq major-mode 'magit-status-mode) + #'magit-section-toggle) + ((+evil-fold-p) + #'+evil/fold-toggle) + (t + #'evilmi-jump-items)))) diff --git a/modules/feature/evil/config.el b/modules/feature/evil/config.el index f416ae7e6..3f5be11a1 100644 --- a/modules/feature/evil/config.el +++ b/modules/feature/evil/config.el @@ -388,6 +388,13 @@ the new algorithm is confusing, like in python or ruby." :config (global-evil-surround-mode 1)) +(def-package! evil-vimish-fold + :commands evil-vimish-fold-mode + :init + (setq vimish-fold-dir (concat doom-cache-dir "vimish-fold/") + vimish-fold-indication-mode 'right-fringe)) + + ;; Without `evil-visualstar', * and # grab the word at point and search, no ;; matter what mode you're in. I want to be able to visually select a region and ;; search for other occurrences of it. diff --git a/modules/feature/evil/packages.el b/modules/feature/evil/packages.el index ebc1c502d..95528f74e 100644 --- a/modules/feature/evil/packages.el +++ b/modules/feature/evil/packages.el @@ -16,5 +16,6 @@ (package! evil-textobj-anyblock) (package! evil-snipe) (package! evil-surround) +(package! evil-vimish-fold) (package! evil-visualstar) (package! neotree) diff --git a/modules/ui/doom/config.el b/modules/ui/doom/config.el index 6d56d56c2..ccfd2e2e5 100644 --- a/modules/ui/doom/config.el +++ b/modules/ui/doom/config.el @@ -128,6 +128,13 @@ (setq hs-set-up-overlay (lambda (ov) (when (eq 'code (overlay-get ov 'hs)) + (when (featurep 'vimish-fold) + (overlay-put + ov 'before-string + (propertize "…" 'display + (list vimish-fold-indication-mode + 'empty-line + 'vimish-fold-fringe)))) (overlay-put ov 'display (propertize " [...] " 'face '+doom-folded-face))))))