ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

编辑编号 2:

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

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

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

B
Bleeding Fingers

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

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

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

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

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

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


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

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

假设您有默认的键绑定:

抄送@CMh 全部折叠(hs-hide-all)。

Cc @Ch 隐藏当前块(hs-hide-block)。点(光标)必须在块内。

Cc @Cs 显示当前块(hs-show-block)。该点必须位于隐藏代码的 {...} 标记中。


这很好用。而对于 evil-mode,这是由普通的 vim 命令触发的:zRzMzozc
e
einSelbst

另一种给猫剥皮的方法:

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

M-1 Cx $ 奇迹发生了!

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

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

来自minor emacs wizardry blog

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

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 很不错。谢谢
N
Nikwin

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

您还可以通过在初始化文件中使用带有以下代码的 CEDET 来获得代码折叠:

(global-semantic-folding-mode t)

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


如果遇到一些错误,请查看以下问题:stackoverflow.com/questions/15307113/…
J
Jones

hs-minor-mode 效果很好。

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


f
freitass

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

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


H
Horus

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

K
Kirk Walla

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


i
imz -- Ivan Zakharyaschev

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

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


e
eunikorn

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


q
quazgar

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

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

D
DomQ

来自 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)))

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


r
roboli

如果您正在执行一些 JavaScript 并使用 js2-mode.el,您可以:

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

C-c C-e:隐藏元素

C-c C-s:显示元素