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

时间:2014-01-16 14:54:59

标签: regex emacs elisp

我最近花了太多时间试图在Emacs中调试一些自动完成模式功能,这个功能似乎是非确定性的,让我完全糊涂了。

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

在while循环中调用该命令,从当前点向后搜索以找到应自动完成的完整“单词”。供参考,the actual code

一些背景和我的调查

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

连接到Node.js后端的Slime REPL内的自动完成是完美的,

enter image description here

连接到Slime的js2模式缓冲区内的自动完成无法查找来自slime的完成。在此图像中,您可以看到它回落到缓冲区中已有的单词。

enter image description here

我已将此跟踪到Slime的slime-beginning-of-symbol功能。

假设我正在尝试完成fs.ch已经需要fs并且已经在范围内,该点位于h字符之后。

在slime repl缓冲区中,begin函数将点一直移回,直到它到达空格并匹配fs.ch

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

重现问题

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

  • 在暂存缓冲区c中,该点以fs.ch
  • 结束
  • 在slime repl f中,该点以fs.ch
  • 结束
  • 在js2-mode buffer c中,该点以fs.ch结束。
  • 在emacs-lisp-mode缓冲区f中,该点以{{1}}结束。

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

我将假设在这些模式中有一些东西可以设置或取消设置全局正则表达式var然后具有这种效果,但到目前为止我一直无法找到或暗示任何东西。

我甚至将其追踪到emacs c code,但在那时我意识到我完全在我的头上并决定寻求帮助。

帮助?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分: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正则表达式全局的恐怖。