How to achieve code folding effects in Emacs?

大兔子大兔子 提交于 2019-11-27 05:47:22
jrockway

Folding is generally unnecessary with emacs, as it has tools that explicitly implement the actions people do manually when folding code.

Most people have good success with simple incremental searches. See "foo" mentioned somewhere? Type C-sfoo, find the definition, press enter, read it, and then press C-x C-x to go back to where you were. Simple and very useful.

Most modes support imenu. M-ximenu will let you jump to a function definition (etc.) by name. You can also bind it to a mouse click to get a menu of functions (or add it to the menubar; see the Info page for more detail). It provides data for which-function-mode, which will let you see which function you are currently inside in the modeline. (Why are your functions this long, though?)

There is also speedbar, which displays the imenu information (and other things) graphically.

If you want to get an overview of your file, try M-xoccur". Given a regex, it will create a new buffer with each match in the current buffer. You can search for "(defun" to get an overview of the functions the current file implements. Clicking on the result will move you to that position in the file.

So anyway, think about what you really want to achieve, and Emacs probably implements that. Don't fight with imperfect tools that make you fold and unfold things constantly.

dmckee

hide-show mode (hs-minor-mode) with default keybinding C-c @ C-M-h to trigger the folding (hs-hide-all)

Another way to skin the cat:

As it happens, you don’t need any package or extra configuration for that. Just go to any source file, type

M-1 C-x $ and magic happens!

As usual, it’s white magic: C-x $ will bring your code back.

We can use Emacs’ help system to discover what’s going on: C-h k C-x $ tells us that the above key combination is calling set-selective-display, a function that takes one numerical argument (the M-1 prefix passes 1 as the value of that argument) and, unsurprisingly, sets the variable selective-display to the value of that argument.

from minor emacs wizardry blog

Just for completeness: M-3 C-x $ would show deeper nested code and so on.

FWIW I made a tiny helper today based on smth. found here so that F5 toggles code folding based on the current cursor position:

(global-set-key (kbd "<f5>") 'set-selective-display-dlw)

(defun set-selective-display-dlw (&optional level)
"Fold text indented same of more than the cursor.
If level is set, set the indent level to LEVEL.
If 'selective-display' is already set to LEVEL, clicking
F5 again will unset 'selective-display' by setting it to 0."
  (interactive "P")
  (if (eq selective-display (1+ (current-column)))
      (set-selective-display 0)
    (set-selective-display (or level (1+ (current-column))))))

I use the outline minor mode to fold my python code. Instead of needing to place {{{ and }}} as in folding mode, it uses where the block is defined.

http://www.gnu.org/software/emacs/manual/html_node/emacs/Outline-Mode.html http://www.emacswiki.org/emacs/OutlineMinorMode

I am pretty sure that it comes with emacs. I then add this to my .emacs

;;======= Code folding =======
(add-hook 'python-mode-hook 'my-python-outline-hook)
; this gets called by outline to deteremine the level. Just use the length of the whitespace
(defun py-outline-level ()
  (let (buffer-invisibility-spec)
    (save-excursion
      (skip-chars-forward "    ")
      (current-column))))
; this get called after python mode is enabled
(defun my-python-outline-hook ()
  ; outline uses this regexp to find headers. I match lines with no indent and indented "class"
  ; and "def" lines.
  (setq outline-regexp "[^ \t]\\|[ \t]*\\(def\\|class\\) ")
  ; enable our level computation
  (setq outline-level 'py-outline-level)
  ; do not use their \C-c@ prefix, too hard to type. Note this overides some bindings.
  (setq outline-minor-mode-prefix "\C-t")
  ; turn on outline mode
  (outline-minor-mode t)
  ; initially hide all but the headers
  ;(hide-body)
  ; make paren matches visible
  (show-paren-mode 1)
)

You can also get code folding by using CEDET with following code in init file:

(global-semantic-folding-mode t)

After evaluation of this code, the small triangle will appear in fringle area, so you will able to fold & unfold code using it. This method is more precise, as it uses syntactic information, extracted from source code

hs-minor-mode works beautifully.

It works even more beautifully when paired with fold-dwim (do what I mean). Then there's fold-dwim-org, which provides org-mode like key-bindings for code folding! Both can be installed via marmalade (and I think elpa).

Apparently there is no perfect solution, but I think the best one is this:

http://www.emacswiki.org/emacs/FoldingMode

vimish-fold is also a nice and easy solution.

https://github.com/mrkkrp/vimish-fold.

From the homepage:

This is a package to perform text folding like in Vim. It has the following features:

  • folding of active regions;
  • good visual feedback: it's obvious which part of text is folded;
  • persistence by default: when you close file your folds don't disappear;
  • persistence scales well, you can work on hundreds of files with lots of folds without adverse effects;
  • it doesn't break indentation or something;
  • folds can be toggled from folded state to unfolded and back very easily;
  • quick navigation between existing folds;
  • you can use mouse to unfold folds (good for beginners and not only for them);
  • for fans of avy package: you can use avy to fold text with minimal number of key strokes!

Using the excellent use-package I install and activate it using this snippet in my config:

(use-package vimish-fold
  :ensure t
  :config (vimish-fold-global-mode t))

emacs comes with hs-minor-mode which fascilitates code folding between balanced expressions http://www.emacswiki.org/emacs/HideShow

I believe that your comparison of your "project" to folding is not quite good, because folding is about changing the appearance while keeping the buffer contents intact (the text). Your project would involve showing extra text while keeping the buffer contents intact, AFAIU. So. it's not implementable as a composition of text-insertion and folding (then, the buffer contents would be changed).

But perhaps, it's indeed possible with the same mechanism as folding is done with -- "overlays"... Consider the "before-string" and "after-string" overlay properties; perhaps, you could put your function definitions into these strings belonging to a zero-length overlay at the point. Look at outline-flag-region function to see how overlays are used in the outline mode.

If you use hs-minor-mode, it might be a good idea to also set a more convenient shortcut, e.g.:

(eval-after-load 'hideshow
 '(progn
   (global-set-key (kbd "C-+") 'hs-toggle-hiding)))

With inspiration from einSelbst's answer:

(advice-add 'set-selective-display
            :filter-args (lambda (args)
                           (if (or (car args) selective-display)
                               args
                             (list (1+ (current-column)))))
            '((name . set-selective-display-from-cursor-column)))

Voila, C-x $ suddenly became useful even without any C-u nor M-4 business.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!