jrblevin / markdown-mode

Emacs Markdown Mode
http://jblevins.org/projects/markdown-mode/
GNU General Public License v3.0
886 stars 162 forks source link

Feature request: `Tab` to toggle `fold/unfold` of code block #597

Open snowman opened 3 years ago

snowman commented 3 years ago

Expected Behavior

The █ is an indicator of the point.

sample code block:

```elisp█
(use-package ivy
  :ensure t
  :diminish ivy-mode
  :hook (after-init . ivy-mode))
```█

When the point █ is at the beginning or end of the code block, by pressing tab, it should fold the code block above into:

sample code block:

```elisp...

Press tab again to unfold them.


It's like org-cycle does for Structure Templates of org-mode:

#+BEGIN_SRC elisp
(use-package ivy
  :ensure t
  :diminish ivy-mode
  :hook (after-init . ivy-mode))
#+END_SRC

becomes

#+BEGIN_SRC elisp...

eeowaa commented 1 year ago

This is not a generic solution, but for those using Doom Emacs and don't mind a hideshow-based solution, this is how I have implemented folding of GFM code blocks in markdown-mode:

(setq-hook! 'markdown-mode-hook hs-allow-nesting nil)

(after! markdown-mode
  (let* ((start `(,markdown-regex-gfm-code-block-open 5))
         (end markdown-regex-gfm-code-block-close)
         (comment-start nil)
         (forward-sexp-func (lambda (&rest _)
                              (re-search-forward markdown-regex-gfm-code-block-close
                                                 (point-max)
                                                 'ignore)))
         (adjust-beg-func nil)
         (hs-spec `(,start ,end ,comment-start ,forward-sexp-func ,adjust-beg-func)))
    (dolist (mode '(markdown-mode gfm-mode))
      (add-to-list 'hs-special-modes-alist (cons mode hs-spec))))

  (defadvice! my/markdown-looking-at-block-start-a ()
    :before-while #'hs-looking-at-block-start-p
    (or (not (eq major-mode 'markdown-mode))
        (when-let ((bounds (markdown-code-block-at-point))
                   (start (car bounds)))
          (= (line-number-at-pos)
             (line-number-at-pos start)))))

  (defun my/markdown-find-block-start ()
    (when-let ((bounds (markdown-code-block-at-point))
               (start (car bounds)))
      (goto-char start)))

  (defadvice! my/markdown-find-block-start-a (&rest _)
    :before-while #'hs-find-block-beginning
    :after (if (modulep! :editor fold)
               '(+fold/close +fold/open +fold/toggle)
             '(hs-hide-block hs-show-block))
    (or (not (eq major-mode 'markdown-mode))
        (my/markdown-find-block-start)))

  (when (modulep! :editor fold)
    (defadvice! my/+fold-from-eol-a (&rest body)
      :override #'+fold-from-eol
      (macroexp-progn body))))