diff --git a/modules/editor/fold/autoload/evil.el b/modules/editor/fold/autoload/evil.el deleted file mode 100644 index 7ae386f3d..000000000 --- a/modules/editor/fold/autoload/evil.el +++ /dev/null @@ -1,150 +0,0 @@ -;;; editor/fold/autoload/evil.el -*- lexical-binding: t; -*- -;;;###if (featurep! :editor evil) - -(require 'hideshow) - -;; `hideshow' is a decent code folding implementation, but it won't let you -;; create custom folds. `vimish-fold' offers custom folds, but essentially -;; ignores any other type of folding (indent or custom markers, which -;; hs-minor-mode and `outline-mode' give you). -;; -;; So this is my effort to combine them. - -(defun +fold--vimish-fold-p () - (and (featurep 'vimish-fold) - (cl-some #'vimish-fold--vimish-overlay-p - (overlays-at (point))))) - -(defun +fold--outline-fold-p () - (and (or (bound-and-true-p outline-minor-mode) - (derived-mode-p 'outline-mode)) - (outline-on-heading-p))) - -(defun +fold--hideshow-fold-p () - (hs-minor-mode +1) - (save-excursion - (ignore-errors - (or (hs-looking-at-block-start-p) - (hs-find-block-beginning))))) - - -;; -;; Code folding - -(defmacro +fold-from-eol (&rest body) - "Perform action after moving to the end of the line." - `(save-excursion - (end-of-line) - ,@body)) - -;;;###autoload -(defun +fold/toggle () - "Toggle the fold at point. - -Targets `vimmish-fold', `hideshow' and `outline' folds." - (interactive) - (save-excursion - (cond ((+fold--vimish-fold-p) (vimish-fold-toggle)) - ((+fold--outline-fold-p) - (cl-letf (((symbol-function #'outline-hide-subtree) - (symbol-function #'outline-hide-entry))) - (outline-toggle-children))) - ((+fold--hideshow-fold-p) (+fold-from-eol (hs-toggle-hiding)))))) - -;;;###autoload -(defun +fold/open () - "Open the folded region at point. - -Targets `vimmish-fold', `hideshow' and `outline' folds." - (interactive) - (save-excursion - (cond ((+fold--vimish-fold-p) (vimish-fold-unfold)) - ((+fold--outline-fold-p) - (outline-show-children) - (outline-show-entry)) - ((+fold--hideshow-fold-p) (+fold-from-eol (hs-show-block)))))) - -;;;###autoload -(defun +fold/close () - "Close the folded region at point. - -Targets `vimmish-fold', `hideshow' and `outline' folds." - (interactive) - (save-excursion - (cond ((+fold--vimish-fold-p) (vimish-fold-refold)) - ((+fold--hideshow-fold-p) (+fold-from-eol (hs-hide-block))) - ((+fold--outline-fold-p) (outline-hide-subtree))))) - -;;;###autoload -(defun +fold/open-all (&optional level) - "Open folds at LEVEL (or all folds if LEVEL is nil)." - (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 -(defun +fold/close-all (&optional level) - "Close folds at LEVEL (or all folds if LEVEL is nil)." - (interactive - (list (if current-prefix-arg (prefix-numeric-value current-prefix-arg)))) - (save-excursion - (when (featurep 'vimish-fold) - (vimish-fold-refold-all)) - (hs-life-goes-on - (if (integerp level) - (hs-hide-level-recursive (1- level) (point-min) (point-max)) - (hs-hide-all))))) - -(defun +fold--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)) - -;;;###autoload -(defun +fold/next (count) - "Jump to the next vimish fold, outline heading or folded region." - (interactive "p") - (cl-loop with orig-pt = (point) - for fn - in (list (lambda () - (when hs-block-start-regexp - (car (+fold--invisible-points count)))) - (lambda () - (if (> count 0) - (evil-vimish-fold/next-fold count) - (evil-vimish-fold/previous-fold (- count))) - (if (/= (point) orig-pt) (point)))) - if (save-excursion (funcall fn)) - collect it into points - finally do - (if-let* ((pt (car (sort points (if (> count 0) #'< #'>))))) - (goto-char pt) - (message "No more folds %s point" (if (> count 0) "after" "before")) - (goto-char orig-pt)))) - -;;;###autoload -(defun +fold/previous (count) - "Jump to the previous vimish fold, outline heading or folded region." - (interactive "p") - (+fold/next (- count))) diff --git a/modules/editor/fold/autoload/fold.el b/modules/editor/fold/autoload/fold.el index ac1d9e2a6..da1d95184 100644 --- a/modules/editor/fold/autoload/fold.el +++ b/modules/editor/fold/autoload/fold.el @@ -1,89 +1,155 @@ ;;; editor/fold/autoload/fold.el -*- lexical-binding: t; -*- -(defface +fold-hideshow-folded-face - `((t (:inherit font-lock-comment-face :weight light))) - "Face to hightlight `hideshow' overlays." - :group 'doom-themes) +;; `hideshow' is a decent code folding implementation, but it won't let you +;; create custom folds. `vimish-fold' offers custom folds, but essentially +;; ignores any other type of folding (indent or custom markers, which hideshow +;; and `outline-mode' give you). This is my effort to combine them. -;;;###autoload -(defun +fold-hideshow*ensure-mode (&rest _) - "Ensure hs-minor-mode is enabled." +;; +;;; Helpers + +(defun +fold--ensure-hideshow-mode () (unless (bound-and-true-p hs-minor-mode) (hs-minor-mode +1))) -;;;###autoload -(defun +fold-hideshow-haml-forward-sexp (arg) - (haml-forward-sexp arg) - (move-beginning-of-line 1)) +(defun +fold--vimish-fold-p () + (and (featurep 'vimish-fold) + (cl-some #'vimish-fold--vimish-overlay-p + (overlays-at (point))))) -;;;###autoload -(defun +fold-hideshow-forward-block-by-indent (_arg) - (let ((start (current-indentation))) - (forward-line) - (unless (= start (current-indentation)) - (let ((range (+fold-hideshow-indent-range))) - (goto-char (cadr range)) - (end-of-line))))) +(defun +fold--outline-fold-p () + (and (or (bound-and-true-p outline-minor-mode) + (derived-mode-p 'outline-mode)) + (outline-on-heading-p))) -;;;###autoload -(defun +fold-hideshow-set-up-overlay (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 '+fold-hideshow-folded-face)))) +(defun +fold--hideshow-fold-p () + (+fold--ensure-hideshow-mode) + (save-excursion + (ignore-errors + (or (hs-looking-at-block-start-p) + (hs-find-block-beginning))))) + +(defun +fold--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)) + +(defmacro +fold-from-eol (&rest body) + "Perform action after moving to the end of the line." + `(save-excursion + (end-of-line) + ,@body)) ;; -;; Indentation detection +;;; Commands -(defun +fold--hideshow-empty-line-p (_) - (string= "" (string-trim (thing-at-point 'line)))) +;;;###autoload +(defun +fold/toggle () + "Toggle the fold at point. -(defun +fold--hideshow-geq-or-empty-p (base-indent) - (or (+fold--hideshow-empty-line-p base-indent) - (>= (current-indentation) base-indent))) - -(defun +fold--hideshow-g-or-empty-p (base-indent) - (or (+fold--hideshow-empty-line-p base-indent) - (> (current-indentation) base-indent))) - -(defun +fold--hideshow-seek (start direction before skip predicate base-indent) - "Seeks forward (if direction is 1) or backward (if direction is -1) from start, until predicate -fails. If before is nil, it will return the first line where predicate fails, otherwise it returns -the last line where predicate holds." +Targets `vimmish-fold', `hideshow' and `outline' folds." + (interactive) (save-excursion - (goto-char start) - (goto-char (point-at-bol)) - (let ((bnd (if (> 0 direction) - (point-min) - (point-max))) - (pt (point))) - (when skip (forward-line direction)) - (cl-loop while (and (/= (point) bnd) (funcall predicate base-indent)) - do (progn - (when before (setq pt (point-at-bol))) - (forward-line direction) - (unless before (setq pt (point-at-bol))))) - pt))) + (cond ((+fold--vimish-fold-p) (vimish-fold-toggle)) + ((+fold--outline-fold-p) + (cl-letf (((symbol-function #'outline-hide-subtree) + (symbol-function #'outline-hide-entry))) + (outline-toggle-children))) + ((+fold--hideshow-fold-p) (+fold-from-eol (hs-toggle-hiding)))))) -(defun +fold-hideshow-indent-range (&optional point) - "Return the point at the begin and end of the text block with the same (or -greater) indentation. If `point' is supplied and non-nil it will return the -begin and end of the block surrounding point." +;;;###autoload +(defun +fold/open () + "Open the folded region at point. + +Targets `vimmish-fold', `hideshow' and `outline' folds." + (interactive) (save-excursion - (when point - (goto-char point)) - (let ((base-indent (current-indentation)) - (begin (point)) - (end (point))) - (setq begin (+fold--hideshow-seek begin -1 t nil #'+fold--hideshow-geq-or-empty-p base-indent) - begin (+fold--hideshow-seek begin 1 nil nil #'+fold--hideshow-g-or-empty-p base-indent) - end (+fold--hideshow-seek end 1 t nil #'+fold--hideshow-geq-or-empty-p base-indent) - end (+fold--hideshow-seek end -1 nil nil #'+fold--hideshow-empty-line-p base-indent)) - (list begin end base-indent)))) + (cond ((+fold--vimish-fold-p) (vimish-fold-unfold)) + ((+fold--outline-fold-p) + (outline-show-children) + (outline-show-entry)) + ((+fold--hideshow-fold-p) (+fold-from-eol (hs-show-block)))))) + +;;;###autoload +(defun +fold/close () + "Close the folded region at point. + +Targets `vimmish-fold', `hideshow' and `outline' folds." + (interactive) + (save-excursion + (cond ((+fold--vimish-fold-p) (vimish-fold-refold)) + ((+fold--hideshow-fold-p) (+fold-from-eol (hs-hide-block))) + ((+fold--outline-fold-p) (outline-hide-subtree))))) + +;;;###autoload +(defun +fold/open-all (&optional level) + "Open folds at LEVEL (or all folds if LEVEL is nil)." + (interactive + (list (if current-prefix-arg (prefix-numeric-value current-prefix-arg)))) + (when (featurep 'vimish-fold) + (vimish-fold-unfold-all)) + (save-excursion + (+fold--ensure-hideshow-mode) + (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 +(defun +fold/close-all (&optional level) + "Close folds at LEVEL (or all folds if LEVEL is nil)." + (interactive + (list (if current-prefix-arg (prefix-numeric-value current-prefix-arg)))) + (save-excursion + (when (featurep 'vimish-fold) + (vimish-fold-refold-all)) + (+fold--ensure-hideshow-mode) + (hs-life-goes-on + (if (integerp level) + (hs-hide-level-recursive (1- level) (point-min) (point-max)) + (hs-hide-all))))) + +;;;###autoload +(defun +fold/next (count) + "Jump to the next vimish fold, outline heading or folded region." + (interactive "p") + (cl-loop with orig-pt = (point) + for fn + in (list (lambda () + (when hs-block-start-regexp + (car (+fold--invisible-points count)))) + (lambda () + (when (featurep 'vimish-fold) + (if (> count 0) + (evil-vimish-fold/next-fold count) + (evil-vimish-fold/previous-fold (- count)))) + (if (/= (point) orig-pt) (point)))) + if (save-excursion (funcall fn)) + collect it into points + finally do + (if-let* ((pt (car (sort points (if (> count 0) #'< #'>))))) + (goto-char pt) + (message "No more folds %s point" (if (> count 0) "after" "before")) + (goto-char orig-pt)))) + +;;;###autoload +(defun +fold/previous (count) + "Jump to the previous vimish fold, outline heading or folded region." + (interactive "p") + (+fold/next (- count))) diff --git a/modules/editor/fold/autoload/hideshow.el b/modules/editor/fold/autoload/hideshow.el new file mode 100644 index 000000000..d28dba48d --- /dev/null +++ b/modules/editor/fold/autoload/hideshow.el @@ -0,0 +1,83 @@ +;;; editor/fold/autoload/hideshow.el -*- lexical-binding: t; -*- + +(defface +fold-hideshow-folded-face + `((t (:inherit font-lock-comment-face :weight light))) + "Face to hightlight `hideshow' overlays." + :group 'doom-themes) + +;;;###autoload +(defun +fold-hideshow-haml-forward-sexp (arg) + (haml-forward-sexp arg) + (move-beginning-of-line 1)) + +;;;###autoload +(defun +fold-hideshow-forward-block-by-indent (_arg) + (let ((start (current-indentation))) + (forward-line) + (unless (= start (current-indentation)) + (let ((range (+fold-hideshow-indent-range))) + (goto-char (cadr range)) + (end-of-line))))) + +;;;###autoload +(defun +fold-hideshow-set-up-overlay (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 '+fold-hideshow-folded-face)))) + + +;; +;;; Indentation detection + +(defun +fold--hideshow-empty-line-p (_) + (string= "" (string-trim (thing-at-point 'line)))) + +(defun +fold--hideshow-geq-or-empty-p (base-indent) + (or (+fold--hideshow-empty-line-p base-indent) + (>= (current-indentation) base-indent))) + +(defun +fold--hideshow-g-or-empty-p (base-indent) + (or (+fold--hideshow-empty-line-p base-indent) + (> (current-indentation) base-indent))) + +(defun +fold--hideshow-seek (start direction before skip predicate base-indent) + "Seeks forward (if direction is 1) or backward (if direction is -1) from start, until predicate +fails. If before is nil, it will return the first line where predicate fails, otherwise it returns +the last line where predicate holds." + (save-excursion + (goto-char start) + (goto-char (point-at-bol)) + (let ((bnd (if (> 0 direction) + (point-min) + (point-max))) + (pt (point))) + (when skip (forward-line direction)) + (cl-loop while (and (/= (point) bnd) (funcall predicate base-indent)) + do (progn + (when before (setq pt (point-at-bol))) + (forward-line direction) + (unless before (setq pt (point-at-bol))))) + pt))) + +(defun +fold-hideshow-indent-range (&optional point) + "Return the point at the begin and end of the text block with the same (or +greater) indentation. If `point' is supplied and non-nil it will return the +begin and end of the block surrounding point." + (save-excursion + (when point + (goto-char point)) + (let ((base-indent (current-indentation)) + (begin (point)) + (end (point))) + (setq begin (+fold--hideshow-seek begin -1 t nil #'+fold--hideshow-geq-or-empty-p base-indent) + begin (+fold--hideshow-seek begin 1 nil nil #'+fold--hideshow-g-or-empty-p base-indent) + end (+fold--hideshow-seek end 1 t nil #'+fold--hideshow-geq-or-empty-p base-indent) + end (+fold--hideshow-seek end -1 nil nil #'+fold--hideshow-empty-line-p base-indent)) + (list begin end base-indent)))) diff --git a/modules/editor/fold/config.el b/modules/editor/fold/config.el index 74391f181..5c399b210 100644 --- a/modules/editor/fold/config.el +++ b/modules/editor/fold/config.el @@ -18,19 +18,21 @@ ;; Packages (def-package! hideshow ; built-in - :defer t - :init - ;; Ensure `hs-minor-mode' is active when triggering these commands - (advice-add #'hs-toggle-hiding :before #'+fold-hideshow*ensure-mode) - (advice-add #'hs-hide-block :before #'+fold-hideshow*ensure-mode) - (advice-add #'hs-hide-level :before #'+fold-hideshow*ensure-mode) - (advice-add #'hs-show-all :before #'+fold-hideshow*ensure-mode) - (advice-add #'hs-hide-all :before #'+fold-hideshow*ensure-mode) + :commands (hs-toggle-hiding hs-hide-block hs-hide-level hs-show-all hs-hide-all) :config (setq hs-hide-comments-when-hiding-all nil ;; Nicer code-folding overlays (with fringe indicators) hs-set-up-overlay #'+fold-hideshow-set-up-overlay) + (defun +fold-hideshow*ensure-mode (&rest _) + "Ensure `hs-minor-mode' is enabled." + (unless (bound-and-true-p hs-minor-mode) + (hs-minor-mode +1))) + (advice-add! '(hs-toggle-hiding + hs-hide-block hs-hide-level + hs-show-all hs-hide-all) + :before #'+fold-hideshow*ensure-mode) + ;; extra folding support for more languages (unless (assq 't hs-special-modes-alist) (setq hs-special-modes-alist