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

Posted

技术标签:

【中文标题】Emacs中如何实现代码折叠效果?【英文标题】:How to achieve code folding effects in Emacs? 【发布时间】:2010-11-08 06:46:15 【问题描述】:

实现代码折叠或 org-mode 使用的循环类型之类的最佳方法是什么。在 elisp 中创建此类行为的最佳解决方案是什么?

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

就折叠而言,我只使用内置的 set-selective-display

编辑 2 号:

感谢您的回答,但我认为我问错了问题,所以让我试着更清楚地了解我想要做什么。我想创建以下内容

当你把你的观点放在一个函数上并调用这个 elisp 函数时,它将把函数定义从它所在的任何地方(我正在考虑只使用 find-tag )并将它展开到当前缓冲区中。这个想法是,如果您必须跳转到不同的缓冲区来读取函数定义,我觉得这是到另一个文件的上下文切换。所以我希望它表现得像代码折叠一样,只是它从缓冲区外部提取代码。这会带来一些问题,因为它实际上无法将代码粘贴到缓冲区中,或者如果有人保存它将保存拉入的代码。所以我想知道是否有一种方法可以在缓冲区内创建一个也不属于缓冲区的区域。我认为这是有道理的。

【问题讨论】:

您正在寻找一些东西,当您在函数 CALL 中使用点调用它时,它会跳转到函数定义?有点像获得有关 elisp 函数的帮助会让您跳转到 elisp 代码?如果没有“项目”的一些概念,我认为您无法做到这一点,例如,您如何知道要跳转到哪个“交换”功能? 另请参阅:***.com/questions/382781/… 对选择性显示进行了一些调整,以获得一些类似折叠的效果。 我建议你删除你的EDIT NB 2 并为它提出一个新问题。 【参考方案1】:

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

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

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

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

如果您想了解您的文件,请尝试 Mxoccur"。给定一个正则表达式,它将为当前缓冲区中的每个匹配项创建一个新缓冲区。您可以搜索"(defun" 获取当前文件实现的功能的概述。单击结果会将您移动到文件中的该位置。

所以无论如何,想想你真正想要实现的目标,Emacs 可能会实现它。不要与不完美的工具作斗争,这些工具会让你不断地折叠和展开事物。

【讨论】:

Vim 还以一种或另一种形式提供了所有这些功能,但我仍然发现它的代码折叠功能非常宝贵。 我对第一句话投了反对票(“折叠对于 emacs 来说通常是不必要的,因为...”)。我经常使用简单的折叠(基于缩进级别)来扫描不熟悉代码的结构。 M-s o 是 M-x 发生的快捷方式 我投了赞成票,因为答案中有许多有用的快捷方式,但也赞成@SimonMichael 评论,因为折叠/展开有时仍然有用! 答案是经过深思熟虑的,而且信息量很大。但是,OP 询问如何进行代码折叠。 OP 没有问每个人最喜欢的避免代码折叠的方式是什么。投反对票。【参考方案2】:

您可以使用隐藏显示模式 (hs-minor-mode)。要仅为当前缓冲区动态激活此模式,请键入 M-x hs-minor-mode RET

假设你有默认的键绑定:

C-c @ C-M-h 全部折叠 (hs-hide-all)。 C-c @ C-h 隐藏当前块 (hs-hide-block)。点(光标)必须在块内。 C-c @ C-s 显示当前区块 (hs-show-block)。该点必须位于隐藏代码的... 标记中。

【讨论】:

这很好用。而对于 evil-mode,这是由普通的 vim 命令触发的:zRzMzozc【参考方案3】:

另一种给猫剥皮的方法:

事实上,您不需要任何软件包或额外配置 那。只需转到任何源文件,键入

M-1 C-x $,奇迹发生了!

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

我们可以使用 Emacs 的帮助系统来发现发生了什么: C-h k C-x $ 告诉我们上面的组合键正在调用 set-selective-display,一个接受一个数值参数的函数 (M-1 前缀传递 1 作为该参数的值)并且, 不出所料,将变量选择性显示设置为 那个论点。

来自minor emacs wizardry blog

为了完整性:M-3 C-x $ 会显示更深的嵌套代码等等。

FWIW 我今天基于 smth 做了一个小帮手。找到here,以便 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))))))

【讨论】:

这个很完美,set-selective-display-dlw很好用。谢谢【参考方案4】:

我使用大纲次要模式来折叠我的 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)
)

【讨论】:

看起来 outline-mode 在 emacs 24 中支持 python 开箱即用 - 不需要自定义 outline-level 函数。这就是我需要添加到我的user.el:(add-hook 'python-mode-hook 'outline-minor-mode) 哦,你肯定想覆盖outline-minor-mode-prefix - 默认键绑定很糟糕 - 我使用(setq outline-minor-mode-prefix (kbd "C-;"))【参考方案5】:

您还可以通过使用 CEDET 在 init 文件中使用以下代码来获得代码折叠:

(global-semantic-folding-mode t)

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

【讨论】:

如果遇到一些错误,看看这个问题:***.com/questions/15307113/…【参考方案6】:

hs-minor-mode 效果很好。

与 fold-dwim 搭配使用时效果更佳(按我的意思做)。然后是 fold-dwim-org,它为代码折叠提供了类似 org-mode 的键绑定!两者都可以通过橘子酱安装(我认为是 elpa)。

【讨论】:

【参考方案7】:

显然没有完美的解决方案,但我认为最好的解决方案是:

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

【讨论】:

【参考方案8】:

vimish-fold 也是一个不错且简单的解决方案。

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

来自主页:

这是一个像在 Vim 中一样执行文本折叠的包。它具有以下特点:

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

使用出色的 use-package 我在我的配置中使用这个 sn-p 安装并激活它:

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

【讨论】:

【参考方案9】:

我很惊讶没有人提到收窄。它非常棒,它还与 emacs 捆绑在一起。只需选择您要关注的代码并按C-x n n,返回全视图模式只需执行C-x n w。我总是更喜欢使用内置的 emacs 功能,而不是用另一个包来混乱我的用户空间。如果 emacs 可以通过内置功能做到这一点,那么我会更喜欢它而不是一些第三方包,但这只是我,并不意味着或暗示任何其他东西,除了我喜欢简单的东西而不是复杂的长配置。

【讨论】:

【参考方案10】:

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

但也许,确实有可能使用与折叠相同的机制——“覆盖”...考虑“前字符串”和“后字符串”overlay properties;也许,您可以将您的函数定义放入这些属于零长度覆盖的字符串中。查看outline-flag-region 函数,了解在大纲模式下如何使用叠加层。

【讨论】:

【参考方案11】:

emacs 带有 hs-minor-mode,它促进平衡表达式之间的代码折叠 http://www.emacswiki.org/emacs/HideShow

【讨论】:

【参考方案12】:

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

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

【讨论】:

【参考方案13】:

灵感来自einSelbst's answer:

(advice-add '设置选择性显示 :filter-args (lambda (args) (如果(或(汽车参数)选择性显示) 参数 (列表(1+(当前列))))) '(((name.set-selective-display-from-cursor-column)))

瞧,C-x $ 突然变得有用,即使没有任何 C-uM-4 业务。

【讨论】:

【参考方案14】:

如果你正在做一些 javascript 并使用js2-mode.el,你可以:

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

C-c C-e: 隐藏元素

C-c C-s: 显示元素

【讨论】:

以上是关于Emacs中如何实现代码折叠效果?的主要内容,如果未能解决你的问题,请参考以下文章

emacs模块——hideshow 代码折叠

markdown 实现代码折叠效果

Mediawiki导航栏的折叠效果

emacs nxml-mode中的折叠标签

winform, ListView Groups 下面的项目如何实现折叠,展开(默认都是展开) 类似treeview的效果

8102 年,如何实现带动画的折叠面板