Emacs Lisp和不确定性正则表达式

5

最近我花了太多时间来调试Emacs中的自动完成模式功能,这个函数似乎是不确定性的,让我彻底困惑了。

 (re-search-backward "\\(\\sw\\|\\s_\\|\\s\\.\\|\\s\\\\|[#@|]\\)\\=")

命令在while循环中调用,向后搜索以找到应该自动完成的完整“单词”。供参考,实际代码

一些背景和我的调查

我一直在尝试使用slime连接到Node.js后端来设置Javascript的自动完成。

在连接到Node.js后端的Slime REPL中进行自动完成非常完美,

enter image description here

在js2-mode缓冲区内使用自动完成功能,与Slime连接后无法查找来自slime的补全。在这张图片中,您可以看到它退回到已经存在于缓冲区中的单词。

enter image description here

我已经追踪到这个问题是由Slime的slime-beginning-of-symbol函数引起的。

假设我正在尝试完成fs.ch,其中fs已经被要求并且已经在范围内,在字符h之后找到该点。

在slime repl缓冲区中,beginning函数将点向后移动,直到它遇到空格并匹配fs.ch

在js2-mode缓冲区中,beginning函数仅将点移动到点字符,并仅匹配ch

重现问题

我一直在各种缓冲区中通过eval (re-search-backward "\\(\\sw\\|\\s_\\|\\s\\.\\|\\s\\\\|[#@|]\\)\\=")来反复测试。对于所有示例,点都从行末开始向后移动,直到搜索失败。

  • 在scratch缓冲区fs.ch中,光标停在c上。
  • 在slime repl fs.ch中,光标停在f上。
  • 在js2-mode缓冲区fs.ch中,光标停在c上。
  • 在emacs-lisp-mode缓冲区fs.ch中,光标停在f上。

我不知道为什么会发生这种情况

我猜测这些模式中有些东西设置或取消了全局正则表达式变量,然后产生了这个效果,但到目前为止,我一直无法找到或证明任何东西。

我甚至追踪到了emacs c code,但那时我意识到我已经完全超出了自己的能力范围,决定寻求帮助。

能帮忙吗?


在Emacs正则表达式中,\sCODE匹配任何语法为CODE的字符。语法表可以在缓冲区之间变化(语法表通常由主模式建立)。请参阅C-h i g (elisp) Regexp Backslash RET - phils
我认为你的问题在于这些缓冲区中“.”有不同的语法。你可以在相应的缓冲区中使用“M-x describe-syntax”进行检查。也许,你需要使用“modify-syntax-entry”来纠正这个问题。也许,你需要创建一个临时的语法表,使用“make-syntax-table”,它继承了主模式的标准。 - Tobias
就是这样。我在 #emacs 中提出了这个问题,他们也说了同样的话。我之前不知道语法表。 - Dan Midwood
2个回答

1

你应该在正则表达式中将 \\s\\. 替换为 \\s.


0

我通过重新定义加入到自动完成的ac-sources中的源来“修复”了问题。

我还在学习elisp的路上,所以这可能是实现我所需最像黑客方式的方式,但它有效。

我将正则表达式从以下内容更改:

\\(\\sw\\|\\s_\\|\\s\\.\\|\\s\\\\|[#@|]\\)\\=

\\(\\sw\\|\\s_\\|\\s.\\|\\s\\\\|[#@|]\\)\\=

(注意将\\s\\.\\更改为\\s.\\)。

然后在我的init.el中覆盖了自动完成设置。(当我真正了解elisp时,我可能会找到一百种完善它的方法)。

(defun js-slime-beginning-of-symbol ()
  "Move to the beginning of the CL-style symbol at point."
  (while (re-search-backward "\\(\\sw\\|\\s_\\|\\s.\\|\\s\\\\|[#@|]\\)\\="
                             (when (> (point) 2000) (- (point) 2000))
                             t))
  (re-search-forward "\\=#[-+.<|]" nil t)
  (when (and (looking-at "@") (eq (char-before) ?\,))
    (forward-char)))

(defun js-slime-symbol-start-pos ()
  "Return the starting position of the symbol under point.
The result is unspecified if there isn't a symbol under the point."
  (save-excursion (js-slime-beginning-of-symbol) (point)))

(defvar ac-js-source-slime-simple
  '((init . ac-slime-init)
    (candidates . ac-source-slime-simple-candidates)
    (candidate-face . ac-slime-menu-face)
    (selection-face . ac-slime-selection-face)
    (prefix . js-slime-symbol-start-pos)
    (symbol . "l")
    (document . ac-slime-documentation)
    (match . ac-source-slime-case-correcting-completions))
  "Source for slime completion.")

(defun set-up-slime-js-ac (&optional fuzzy)
  "Add an optionally-fuzzy slime completion source to `ac-sources'."
  (interactive)
  (add-to-list 'ac-sources ac-js-source-slime-simple))

回应我自己关于正则表达式全局状态的问题。有很多。

Emacs 正则表达式使用主模式中定义的语法表来确定要匹配哪些字符。我在 lisp 模式下看到点号匹配但在 js 模式下没有看到是因为它们有不同的定义。在 lisp 模式下,'.' 被定义为符号,在 js2-mode 中 '.' 被定义为标点符号。

因此,解决问题的另一种方法是重新定义 js2-mode 中 '.' 的语法。我尝试了这个方法,并将 '.' 重新定义为单词,使用 (modify-syntax-entry ?. "w")。然而,我决定不采用这个结果,因为它可能会在后面破坏某些东西。

此外,我要感谢 #emacs 中的人们,他们真的帮助了我,教我有关语法表和 elisp 正则表达式全局变量的恐惧。


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