【问题标题】:Emacs Lisp and non-deterministic regexesEmacs Lisp 和非确定性正则表达式
【发布时间】:2014-01-16 14:54:59
【问题描述】:

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

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

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

一些背景知识和我的调查

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

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

连接到 Slime 的 js2 模式缓冲区内的自动完成无法从 slime 中查找完成。在这张图片中,您可以看到它回退到缓冲区中已经存在的单词。

我已经追踪到 Slime 的 slime-beginning-of-symbol 函数。

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

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

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

重现问题

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

  • 在暂存缓冲区fs.ch 中,该点以c 结束。
  • 在 slime repl fs.ch 中,该点结束于 f
  • 在 js2 模式缓冲区 fs.ch 中,该点在 c 上结束。
  • 在 emacs-lisp-mode 缓冲区 fs.ch 中,该点以 f 结束。

我不知道为什么会这样

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

我什至追查到了emacs c code,但那时我意识到我完全不知所措并决定寻求帮助。

帮助?

【问题讨论】:

  • Emacs 正则表达式中的 \sCODE 匹配语法为 CODE 的任何字符。语法表可以并且将在缓冲区之间变化(语法表通常由主要模式建立)。见C-h i g (elisp) Regexp Backslash RET
  • 我认为你的问题是. 在这些缓冲区中有不同的语法。您可以在各自的缓冲区中检查M-x describe-syntax。也许,您需要modify-syntax-entry 来纠正这个问题。也许,您需要一个使用 make-syntax-table 创建的临时语法表,它继承了主要模式的标准。
  • 就是这样。我在#emacs 中提出了这个问题,他们也这么说。我以前不知道语法表。

标签: regex emacs elisp


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    我仍在学习 elisp 的方法,所以这可能是实现我需要的最类似于 hack 的方法,但它确实有效。

    我将正则表达式更改为:

    \\(\\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 模式下重新定义 . 的语法。我尝试了这个并重新定义了 .作为一个词与(modify-syntax-entry ?. "w")。但是我决定不坚持这个结果,因为它可能会破坏某些东西。

    另外,我要感谢#emacs 中的人,他们真的在这方面帮助了我,教我语法表和 elisp 正则表达式全局变量的可怕之处。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多