如何在Emacs中实现代码折叠效果?


123

什么是实现诸如代码折叠或组织模式使用的循环类型之类的最佳方法?elisp创建此类行为的最佳解决方案是什么?

编辑:对不起,我不清楚。我想用elisp编写某种与代码折叠非常相似的东西,或者实际上最像具有可扩展层次结构的org-mode。我想知道实现这种影响的最佳方法。我想我听说emacs叠加是一个很好的解决方案,但我不知道。

至于折叠,我只使用内置的set-selective-display

编辑编号2:

感谢您的回答,但我想我问的是错误的问题,因此让我尝试更清楚地了解我要做什么。我想创建以下内容

当您将观点放在一个函数上并调用此elisp函数时,它将把函数定义从任何位置放到哪里(我正在考虑为此使用find-tag)并将其展开到当前缓冲区中。我的想法是,如果您必须跳转到其他缓冲区以读取函数定义,我想将其上下文切换到另一个文件。因此,我希望它的行为就像代码折叠一样,只不过它从缓冲区外部提取代码。这带来了一些问题,因为它无法将代码手动粘贴到缓冲区中,或者如果有人将其保存,则会保存提取的代码。所以我想知道是否有一种方法可以在缓冲区内创建一个区域,该区域也不是缓冲区的一部分。我认为这是有道理的。


您正在寻找某种东西,当您在函数CALL中使用point调用它时,它会跳转到函数定义吗?有点像获得有关elisp函数的帮助将使您跳至elisp代码?我认为没有“项目”的概念就无法做到这一点,例如,您如何知道要跳转到哪个“交换”功能?
布赖恩·波斯托

1
另请参阅:stackoverflow.com/questions/382781/…,其中对选择性显示进行了一些调整,以实现类似折叠的效果。
Michael Paulukonis 2010年

我建议您删除EDIT NB 2并提出一个新问题。
Stefan

Answers:


151

emacs通常不需要折叠,因为它具有可明确实现人们在折叠代码时手动执行的操作的工具。

通过简单的增量搜索,大多数人都取得了成功。看到某处提到的“ foo”吗?键入C-sfoo,找到定义,按Enter键,阅读它,然后按C-x C-x返回到原来的位置。简单且非常有用。

大多数模式都支持imenuM-ximenu将让您按名称跳转到函数定义(等)。您还可以将其绑定到鼠标上以获取功能菜单(或将其添加到菜单栏;有关更多详细信息,请参见“信息”页面)。它提供了哪个功能模式的数据,这将使您看到当前在modeline中的哪个功能。(为什么您的功能这么长?)

还有speedbar,它以图形方式显示imenu信息(和其他内容)。

如果要获取文件概述,请尝试 M-xoccur “。给定一个正则表达式,它将创建一个新缓冲区,当前缓冲区中的每个匹配项都可以。您可以搜索“(defun”)以获取当前文件功能的概述。单击结果将带您到文件中的该位置。

因此,无论如何,请考虑您真正想要实现的目标,Emacs可能会实现该目标。不要与不完善的工具作斗争,这些工具会使您不断折叠和展开东西。


13
Vim还以一种或另一种形式提供所有这些功能,但我仍然发现其代码折叠功能非常宝贵。
直觉

115
我否决了第一句话(“对于emacs,通常不需要折叠,因为...”)。我经常使用简单的折叠(基于缩进级别)来扫描不熟悉的代码的结构。
西蒙·迈克尔

4
O女士是Mx发生的捷径
Joshua Olson 2013年

3
我赞成投票,因为答案中有许多有用的快捷方式,但也赞成@SimonMichael评论,因为有时折叠/展开仍然有用!
Adrien Coquio

56
答案经过深思熟虑,非常有用。但是,OP询问如何进行代码折叠。OP并未询问每个人最喜欢避免代码折叠的方式是什么。下投。
wkschwartz


39

换猫的另一种方法:

碰巧的是,您不需要任何软件包或额外的配置。只需转到任何源文件,键入

M-1 Cx $和魔术发生了!

像往常一样,这是一个白魔法:Cx $将带回您的代码。

我们可以使用Emacs的帮助系统来发现正在发生的事情:Ch k Cx $告诉我们上述按键组合正在调用 set-selective-display,该函数采用一个数值参数(M-1前缀将1传递为值毫不奇怪,将变量selective-display设置为该参数的值。

来自次要的emacs向导博客

仅出于完整性考虑:M-3 Cx $将显示更深层的嵌套代码,依此类推。

FWIW我今天基于smth做了一个小帮手。在这里找到以便F5根据当前光标位置切换代码折叠:

(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))))))

22

我使用大纲次要模式来折叠我的python代码。不需要像折叠模式那样放置{{{和}}},它使用定义块的位置。

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

我很确定emacs附带了它。然后将其添加到我的.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)
)

8
看起来像outline-mode在emacs 24中支持python即用型-不需要自定义outline-level功能。这就是我需要添加的全部内容user.el(add-hook 'python-mode-hook 'outline-minor-mode)
scytale,2012年

1
哦,您一定要重写outline-minor-mode-prefix-默认的键绑定太糟糕了-我使用(setq outline-minor-mode-prefix (kbd "C-;"))
scytale,2012年

13

您还可以通过将CEDET与init文件中的以下代码结合使用来折叠代码:

(global-semantic-folding-mode t)

评估此代码后,小三角形将出现在边缘区域,因此您可以使用它折叠和展开代码。此方法更精确,因为它使用从源代码中提取的语法信息


1
如果面对的一些bug,对这个问题看:stackoverflow.com/questions/15307113/...
AdrieanKhisbe

9

hs-minor-mode工作精美。

与fold-dwim搭配使用时,效果更佳(按我的意思)。然后是fold-dwim-org,它提供了像键盘绑定这样的组织模式来进行代码折叠!两者都可以通过果酱安装(我认为是elpa)。



5

vimish-fold 也是一个很好的解决方案。

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

从首页:

这个软件包可以像Vim一样执行文本折叠。它具有以下功能:

  • 折叠活动区域;
  • 良好的视觉反馈:很明显,文本的哪一部分被折叠;
  • 默认情况下是持久性的:关闭文件时,褶皱不会消失;
  • 持久性很好地扩展,您可以处理数百个具有很多折痕的文件,而不会产生不利影响;
  • 它不会破坏缩进或其他东西;
  • 折痕可以很容易地从折起状态切换到展开和返回;
  • 现有折页之间的快速导航;
  • 您可以使用鼠标展开折痕(不仅对初学者有益,而且对初学者也有利);
  • 对于avy包的粉丝:您可以使用avy折叠带有最少按键次数的文本!

使用出色的软件,use-package我可以在配置中使用以下代码片段安装并激活它:

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

3

我很惊讶没有人提到缩小范围。它很棒,它也与emacs捆绑在一起。只需选择您要关注的代码,然后按C-x n n即可返回全屏模式C-x n w。我总是更喜欢使用内置的emacs功能,而不是将我的用户空间与另一个软件包混淆在一起。如果emacs可以使用内置功能做到这一点,那么我将优先于某些第三方软件包,但这仅是我个人,并不意味着或暗示任何其他事情,除了我喜欢复杂的长配置上的简单内容之外。



2

我相信您对“项目”与折叠的比较不是很好,因为折叠是在更改外观的同时保持缓冲区内容(文本)完整。您的项目将涉及显示额外的文本,同时保持缓冲区内容完整无缺,即AFAIU。所以。它不能实现为文本插入和折叠的组合(然后,缓冲区内容将被更改)。

但是也许,确实有可能采用与完成折叠相同的机制-“ overlays” ...考虑“ before-string”和“ string-string” 覆盖属性;也许,您可以将函数定义放入这些字符串,这些字符串属于零长度覆盖点。查看outline-flag-region函数,以查看大纲模式下如何使用叠加层。


2

如果使用hs-minor-mode,最好设置一个更方便的快捷方式,例如:

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

0

einSelbst的回答中得到启发:

(建议添加“设置选择显示”
            :filter-args(lambda(args)
                           (如果(或(汽车参数)选择性显示)
                               args
                             (清单(1+(当前栏))))
            '(((名称。set-selective-display-from-cursor-column)))

瞧,C-x $突然间,即使没有任何生意C-u也变得有用M-4


0

如果您正在使用JavaScript并使用js2-mode.el,则可以:

C-c C-f:切换隐藏/全部显示

C-c C-e:隐藏元素

C-c C-s:显示元素

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.