如何在emacs中将正则表达式绑定到组合键?

时间:2020-03-05 18:39:26  来源:igfitidea点击:

就上下文而言,我是emacs新手。我已经使用了很长时间,但是已经越来越多地使用了(我非常喜欢)。我对lisp也很满意,但是对elisp不太熟悉。

我需要做的是将正则表达式绑定到键盘组合,因为我经常使用此特定的正则表达式。

我一直在做什么:

M-C-s ^.*Table\(\(.*\n\)*?GO\)

注意,我在上面使用换行符,但是我发现对于isearch-forward-regexp,我们确实需要用C-q Q-j的结果替换正则表达式中的\ n。这将插入文字换行符(不结束命令),使我可以将换行符放入表达式中并跨行匹配。

如何将其绑定到组合键?

我隐约地理解我需要创建一个elisp函数,该函数执行带有表达式的" isearch-forward-regexp",但是我对此细节感到困惑。我搜索了google,发现大多数文档有点令人困惑。

如何在emacs中将正则表达式绑定到组合键?

到目前为止,迈克·斯通(Mike Stone)的答案是最好的-不完全是我要找的东西,但是它可以满足我的需求

编辑这种工作方式,但是在存储了宏之后,当我稍后再使用它时,我无法将其与C-x e一起使用。 (即,如果我重新引导emacs,然后键入" M-x宏名",然后键入" C-x e",那么我会在小型缓冲区中收到一条消息,例如" no last kbd macro"或者类似内容)

@Mike Stone感谢我们提供的信息。我试着像这样创建一个宏:

C-x( M-C-s ^.*Table\(\(.*C-q C-J\)*?GO\) C-x)

这创建了我的宏,但是当我执行我的宏时,我没有像使用" isearch-forward-regexp"时得到的那样突出显示。相反,它只是跳到表达式的下一个匹配项的末尾。因此,这对于我需要的并不是真正的工作。有任何想法吗?

编辑:看起来我可以使用宏来做我想要的事情,我只需要在isearch-forward-regexp框外思考。我会尝试你的建议。

解决方案

回答

我们可以使用宏,只需执行C-x(然后对宏进行所有操作,然后对C-x进行处理)即可结束宏,然后执行C-x e将执行最后定义的宏。然后,我们可以使用" Mx name-last-kbd-macro"为它命名,这可以为它分配一个名称,然后可以使用" Mx TESTIT"调用它,然后使用" Mx insert-kbd-macro"存储定义。这会将宏放入我们当前的缓冲区中,然后我们可以将其存储在.emacs文件中。

例子:

C-x( abc *return* C-x)

将定义一个宏以键入" abc",然后按回车键。

C-xeee

立即执行上述宏3次(首先执行e,然后执行2 e将再次执行两次)。

M-x name-last-kbd-macro testit

将该宏命名为" testit"

M-x testit

执行刚刚命名的宏(打印" abc"然后返回)。

M-x insert-kbd-macro

将以下内容放入当前缓冲区:

(fset 'testit
   [?a ?b ?c return])

然后可以将其保存在.emacs文件中,以在重新启动emacs之后一遍又一遍地使用命名的宏。

回答

@贾斯汀:

执行宏时,这有点不同...增量搜索将只执行一次,如果要再次搜索,则必须再次执行宏。但是,我们可以执行更强大和复杂的操作,例如搜索关键字,跳转到行的开头,标记,转到行的末尾,Mw(要复制),然后跳转到另一个缓冲区,然后是Cy(粘贴) ),然后跳回到另一个缓冲区并结束宏。然后,每次执行宏时,我们都会将一行复制到下一个缓冲区。

关于emacs宏的真正酷的事情是,它会在看到响声时停止运行……这发生在我们无法匹配增量搜索(以及其他情况)时。因此,在上面的宏中,我们可以执行C-u 1000 C-x e,该宏将执行该宏1000次...但是由于我们进行了搜索,因此它只会复制1000行,或者直到搜索失败!这意味着如果有100个匹配项,它将仅执行宏100次。

编辑:签出C-hf Highlight-lines-matching-regexp,它将显示一个命令,该命令将突出显示与正则表达式匹配的所有内容...我不知道如何撤消突出显示,但是...无论如何,我们都可以使用存储的宏以突出显示所有匹配的正则表达式,然后另一个宏以查找下一个...?

进一步编辑:M-x unhighlight-regexp将取消突出显示,尽管我们必须输入最后一个正则表达式(但默认为我们以前突出显示的正则表达式)

回答

通常,要在Emacs中定义自定义键绑定,我们需要编写

(define-key global-map (kbd "C-c C-f") 'function-name)

毫无疑问,"定义键"是定义新键的功能。 " global-map"是全局按键图,与每种模式下的单独映射相反。 (kbd" C-c C-f")返回一个表示密钥序列C-c C-f的字符串。还有其他方法可以做到这一点,包括直接输入字符串,但这通常是最直接的,因为它采用了正常的书面表示形式。函数名称是函数名称。

现在,除非已经定义了函数,否则我们将需要在使用它之前对其进行定义。为此,请写

(defun function-name (args)
  (interactive)
  stuff
  ...)

defun定义了一个函数,使用C-h f defun来获取更具体的信息。 (interactive)并没有真正的函数调用。它告诉编译器可以由用户使用" M-x函数名称"并通过键绑定来调用该函数。

现在,特别是对于交互式搜索,这很棘手。实际上," isearch"模块并未针对我们要执行的操作进行设置。但是我们可以使用它来执行类似的操作。

回答

我从字面上解决问题开始,

(defun search-maker (s)
  `(lambda ()
     (interactive)
     (let ((regexp-search-ring (cons ,s regexp-search-ring)) ;add regexp to history
           (isearch-mode-map (copy-keymap isearch-mode-map)))
       (define-key isearch-mode-map (vector last-command-event) 'isearch-repeat-forward) ;make last key repeat
       (isearch-forward-regexp)))) ;`

(global-set-key (kbd "C-. t") (search-maker "^.*Table\(\(.*\n\)*?GO\)"))
(global-set-key (kbd "<f6>") (search-maker "HELLO WORLD"))

键盘序列从((kbd ...)开始新的空白搜索。要实际搜索字符串,请根据需要再次按最后一个键。所以C-。 t t t或者<f6> <f6> <f6>`。该解决方案基本上是一种hack,但是如果我们想尝试一下,我会把它留在这里。

以下内容可能是我们所需要的最接近的内容,

(defmacro define-isearch-yank (key string)
  `(define-key isearch-mode-map ,key 
     (lambda ()
       (interactive) 
       (isearch-yank-string ,string)))) ;`

(define-isearch-yank (kbd "C-. t") "^.*Table\(\(.*\n\)*?GO\)")
(define-isearch-yank (kbd "<f6>") "HELLO WORLD")

按键组合现在仅适用于isearch模式。我们可以正常开始搜索,然后按组合键插入预定义的字符串。