Emacs中有类似Sublime Text 2的“Goto Anything”(或即时搜索)功能吗?

25

最近我尝试过Sublime Text 2,我发现其中的Goto Anything功能非常有用,可以很好地浏览源代码(Ctrl-P file@ symbol似乎效果很好)。那么Emacs有没有类似的功能呢?最好是一些只需简单配置就能使用的,而不需要大量的自定义elisp。

到目前为止,我尝试过:

  1. 我看到了HelmAnything,但据我所知,它们都不能进行实际的“即时”搜索(见下面的编辑)。

  2. 我使用过multi-occur-in-matching-buffers,但它也似乎无法满足“即时”搜索的标准。

  3. imenu/idomenu对于单个文件很有效,但不能跨文件使用。

我目前将#2和#3组合在一起,作为Goto Anything的替代品。

如果没有Goto Anything的确切克隆版本,那么我可以使用简单的即时搜索解决方案(在所有打开的缓冲区中搜索给定的字符串,并动态显示结果)。因此,这也是可以接受的。

我使用的是Emacs 24.2,所以任何仅适用于v24的elisp都可以。

编辑:按照event_jr的建议,我再次尝试了Helm,并发现它支持跨所有打开的缓冲区进行即时搜索。 helm-multi-occur+helm-follow-mode非常接近满足我的需求,唯一的小问题是(不想听起来太挑剔):

  • 我还没有找到一种方法可以在运行helm-multi-occur时自动打开helm-follow-mode。 我必须使用C-c C-f手动调用它。 有人能否提供一段elisp代码片段?

  • 它不像ST2的Goto Anything那样“智能”(即它不理解源代码中的“符号”,如同Goto Anything那样)。

编辑#2:现在我已经拥有了大部分的Goto Anything功能,感谢event_jr下方的答案(当然还要感谢Helm的创建者Thierry Volpi

;; instant recursive grep on a directory with helm
(defun instant-rgrep-using-helm ()
  "Recursive grep in a directory."
  (interactive)
  (let ((helm-after-initialize-hook #'helm-follow-mode))
    (helm-do-grep)))


;; instant search across all buffers with helm
(defun instant-search-using-helm ()
  "Multi-occur in all buffers backed by files."
  (interactive)
  (let ((helm-after-initialize-hook #'helm-follow-mode))
    (helm-multi-occur
     (delq nil
           (mapcar (lambda (b)
                     (when (buffer-file-name b) (buffer-name b)))
                   (buffer-list))))))

;; set keybindings
(global-set-key (kbd "C-M-s") 'instant-search-using-helm)
(global-set-key (kbd "C-M-S-s") 'helm-resume)
(global-set-key (kbd "C-M-g") 'instant-rgrep-using-helm)

1
这可能是一个更适合superuser.com的问题。 - Tim Radcliffe
10
不,关于编程背景下的Emacs的问题是完全在SO范围内的。 - Mirzhan Irkegulov
6
我不会因为Sublime Text没有"跳转到任何地方"功能就从Emacs转换,如果这样做,我将得到一件事情,失去一百万件。 :) - Vicky Chijwani
3
@event_jr ,这并不是指 Emacs 有特定的“杀手级功能”。实际上,Emacs 没有一个固定的“功能”集。关键在于编辑器本身。我喜欢修改每一个 Emacs 的细节之处是如此容易。无限的可定制性不断增加并得到回报。我所做的每一个小修改都让 Emacs 更接近我心目中“理想”的编辑器。从某种意义上说,这才是 Emacs 真正的杀手级功能。另一方面,如果我使用 ST2,我的生产力会很快饱和到最大水平。 - Vicky Chijwani
是的,如果可能的话,还有那些定义,也许还有其他的定义(常量等)。 - Vicky Chijwani
显示剩余6条评论
5个回答

19

只需使用helm。

或许它的配置比你要求的要多,但一旦你把它配置成你喜欢的样子,它就应该非常舒适。非常像Emacs ;)

而且你应该向Thierry报告一些更适合新手的默认设置的bug。他对问题非常敏感。

helm-multi-occur

主要通过helm-multi-occur提供了多缓冲交互式"出现"。如果你执行该命令,你会注意到你需要先选择一些缓冲区(使用C-SPC从列表中选择,M-SPC选择全部)。然后在下一个提示中输入查询内容。很容易制作自己的跳过缓冲区选择的版本,例如:

(eval-after-load "helm-regexp"
    '(setq helm-source-moccur
           (helm-make-source "Moccur"
               'helm-source-multi-occur :follow 1)))

(defun my-helm-multi-all ()
  "multi-occur in all buffers backed by files."
  (interactive)
  (helm-multi-occur
   (delq nil
         (mapcar (lambda (b)
                   (when (buffer-file-name b) (buffer-name b)))
                 (buffer-list)))))

helm-buffers-list

通常你不关心查询字符串的确切出现位置,而是想要一个包含它的所有缓冲区列表。

helm-buffers-list 有一些技巧。你指定的第一个符号是按主模式过滤,你可以使用 "@" 前缀来缩小列表到包含某个字符串的缓冲区。

例如,"ruby @prompt" 将显示包含 "ruby" 主模式和内容中包含 "prompt" 的缓冲区列表。或者只使用 "@prompt" 来显示包含 "prompt" 的所有缓冲区。


一旦你习惯了它,它就变得功能强大且舒适。


编辑 修改了 my-helm-multi-all 以启用 helm-follow-mode。

编辑 2 更新了 helm-follow-mode 代码以反映 helm 的更改。

编辑 3 再次更新以反映helm 的更改


我编辑了我的答案,展示如何使用提供的钩子解决问题。defadvice 类似于链锯,很少需要用到它来解决问题。 - event_jr
2
嗨。我尝试了这个,但是出现了“Wrong type argument: number-or-marker-p, nil”的错误。我正在使用Emacs 24。 - Gonçalo Marrafa
感谢提供如此优质的信息。我是 Source Insight 的忠实粉丝,使用 Helm + GTags 快速浏览源代码非常有帮助。 - sudurais
1
似乎最近helm的更新再次导致了这个问题。 - nispio
1
确实。@nispio,我已根据您拒绝的编辑修复了代码。 - event_jr
显示剩余5条评论

7

Emacs有Projectile满足您的需求:

  • 在项目中跳转到文件
  • 在项目缓冲区中进行多次出现

它还可以跳转到测试和项目缓冲区,在项目中进行grep、替换、重新生成etags表等其他酷炫的功能。Projectile还具有helm后端。 - Bozhidar Batsov
正如我在问题中所说的那样,我已经使用过multi-occur,但它无法进行即时搜索(“即时”是指“谷歌即时”)。使用multi-occur,您必须输入整个查询,按下RET,然后才能查看结果。此外,如果您需要更改搜索查询,则必须再次运行multi-occur并使用新的搜索词条。这不是我要找的。 - Vicky Chijwani
Vicky:就我个人而言,在你提到“Google Instant”并且我搜索了“Google Instant”这个短语之前,我根本不知道“即时搜索”是什么意思。除非你已经知道Google的定义,否则“即时搜索”这个表达方式非常模糊。我建议使用“动态搜索结果”这样更清晰的描述。 - phils
@phils 这就是为什么我在我的问题中链接到演示该功能的视频的原因:https://www.youtube.com/watch?v=36NIIgcrYzE 和 https://www.youtube.com/watch?v=Q0OtfjgnoLA#t=1m00s - Vicky Chijwani

1
  1. Heml距离ST3的模糊搜索相距甚远。

  2. Fiplr看起来很有前途,但在我的笔记本电脑上无法运行(请参见github上的第一个问题)。

  3. Simp.el看起来像Fiplr,但在我的电脑上也无法正常工作。

  4. Projectile适合我!这是你的解决方案!

我还使用ido-mode和flx-ido进行模糊搜索,

而对于垂直显示结果的方式,我在我的.emacs文件中使用以下内容:

;; Display ido results vertically, rather than horizontally
(setq ido-decorations (quote ("\n-> " "" "\n   " "\n   ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]")))
(defun ido-disable-line-truncation () (set (make-local-variable 'truncate-lines) nil))
(add-hook 'ido-minibuffer-setup-hook 'ido-disable-line-truncation)
(defun ido-define-keys () ;; C-n/p is more intuitive in vertical layout
  (define-key ido-completion-map (kbd "C-n") 'ido-next-match)
  (define-key ido-completion-map (kbd "C-p") 'ido-prev-match))
(add-hook 'ido-setup-hook 'ido-define-keys)

2
这并没有提供问题的答案。如果您想对作者进行批评或请求澄清,请在他们的帖子下留言。 - Dave Cousineau
我提供了一些对我自己无效但可能对其他人有效的答案。 - David 天宇 Wong
我猜你在Projectile中使用flx进行模糊搜索? - event_jr
更像是 ido + flx-ido。 - David 天宇 Wong

0

对于Emacs,我定制并修改了这个解决方案(用于安装helm):

(defun helm-occur-from-point (initial-value)
  "Invoke `helm-occur' from point."
  (interactive)
  (let ((input initial-value)
        (bufs (list (buffer-name (current-buffer)))))
    ;; (isearch-exit)
    (helm-occur-init-source)
    (helm-attrset 'moccur-buffers bufs helm-source-occur)
    (helm-set-local-variable 'helm-multi-occur-buffer-list bufs)
    (helm-set-local-variable
     'helm-multi-occur-buffer-tick
     (cl-loop for b in bufs
              collect (buffer-chars-modified-tick (get-buffer b))))
    (helm :sources 'helm-source-occur
          :buffer "*helm occur*"
          :history 'helm-grep-history
          :input input
          :truncate-lines t)))

(defun get-point-text ()
    "Get 'interesting' text at point; either word, or region"
    (if mark-active
        (buffer-substring (mark) (point))
      (thing-at-point 'symbol)))
  (defun helm-occur-1 (initial-value)
    "Preconfigured helm for Occur with initial input."
    (helm-occur-from-point initial-value))
  (defun bk-helm-occur ()
    "Invoke helm-occur with initial input configured from text at point"
    (interactive)
    (helm-occur-1 (get-point-text)))
  (global-set-key (kbd "M-s-o") 'bk-helm-occur)

主要是基于@see https://news.ycombinator.com/item?id=6872508,但在最新的helm版本中不起作用,但通过我的更改进行了修复(只需从一些内部helm模块中复制/粘贴)


0

冰柱提供了一些与您似乎正在寻找的功能类似的功能。

  1. C-x bC-x C-f用于选择缓冲区或文件时,允许多重完成:您可以键入一个模式以匹配缓冲区/文件名称和/或匹配内容缓冲区/文件中。当您输入时,候选项会按照增量方式逐步筛选(您称之为“即时”是 Emacs 称之为“增量”的意思)。您可以逐步改进搜索模式,以不同的方式缩小选择范围。您可以同时访问任意数量的与之匹配的缓冲区/文件。您也可以使用相同的方法在 Dired 中搜索标记文件:C-F

  2. C-c`(icicle-search)可增量搜索多个缓冲区或文件。同样,支持逐步改进等功能。

#1和#2的主要区别在于:

  • 对于#1,你只想找到匹配的缓冲区或文件。你并不关心找到特定的出现次数,任何匹配都足够。

  • 对于#2,你提供要搜索的缓冲区或文件,并希望在搜索命中之间导航。

你也可以使用#1来定位你想要的缓冲区和文件,然后搜索它们的内容:你上次使用的内容匹配模式可用作Isearch(C-s)的搜索模式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接