在引号内突出显示外壳变量


13

在vim中,以下文档将使第$PWD2行和第3行以两种不同的方式着色:

#/bin/sh
echo "Current Directory: $PWD"
echo 'Current Directory: $PWD'

的第一个实例$PWD将与它所在的字符串的其余部分具有不同的颜色。这清楚地表明变量将被扩展,而不是被视为原义文本。相比之下,的第二个实例的$PWD颜色将与字符串的其余部分相同,因为单引号会将其视为文字文本。

是否有现有的emacs模式提供这种类型的“ shell引用意识”?


1
当然,这不会很难添加sh-mode吗?也许可以将其添加到Emacs本身。
PythonNut

Answers:


11

下面的代码使用带有函数的字体锁定规则而不是regexp,该函数$VAR仅在出现在双引号字符串内时才搜索的出现。该函数(syntax-ppss)用于确定这一点。

字体锁定规则使用该prepend标志将其自身添加到现有字符串突出显示的顶部。(请注意,许多程序包都t为此使用。不幸的是,这会覆盖现有突出显示的所有方面。例如,使用时prepend将保留字符串背景色(如果有),同时替换前景色。)

(defun sh-script-extra-font-lock-is-in-double-quoted-string ()
  "Non-nil if point in inside a double-quoted string."
  (let ((state (syntax-ppss)))
    (eq (nth 3 state) ?\")))

(defun sh-script-extra-font-lock-match-var-in-double-quoted-string (limit)
  "Search for variables in double-quoted strings."
  (let (res)
    (while
        (and (setq res
                   (re-search-forward
                    "\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\)"
                    limit t))
             (not (sh-script-extra-font-lock-is-in-double-quoted-string))))
    res))

(defvar sh-script-extra-font-lock-keywords
  '((sh-script-extra-font-lock-match-var-in-double-quoted-string
     (2 font-lock-variable-name-face prepend))))

(defun sh-script-extra-font-lock-activate ()
  (interactive)
  (font-lock-add-keywords nil sh-script-extra-font-lock-keywords)
  (if (fboundp 'font-lock-flush)
      (font-lock-flush)
    (when font-lock-mode
      (with-no-warnings
        (font-lock-fontify-buffer)))))

您可以通过将最后一个函数添加到合适的钩子来调用use,例如:

(add-hook 'sh-mode-hook 'sh-script-extra-font-lock-activate)

这对我有用,但是将字符串突出显示后保留“ $”。
erikstokes

这是设计使然,因为它是如何突出显示字符串外部的变量。但是,这很容易更改。如果2将字体锁定规则中的替换为,则0它应该可以工作。(您可能需要扩展正则表达式以包括尾部}${FOO}正确突出显示。)此数字是指匹配项的regexp子组,0表示应突出显示整个匹配项。
Lindydancer 2015年

如果有人感兴趣,请将 其打包,同时将其添加到我的.emacs.d存储库中:github.com/moonlite/.emacs.d/blob / ... @Lindydancer GPLv3 +和您作为该文件的作者是否还好?(如果没有,我会推送更新)。
Mattias Bengtsson

听起来不错。我可能不必花时间将其放入适当的包装中。但是,我希望您删除我的电子邮件地址,而是在EmacsWiki页面(emacswiki.org/emacs/AndersLindgren)上添加一行。另外,您可以删除版权符号,因为它是不必要的,并且会使源代码不为ascii。
Lindydancer

3

我通过以下方式改进了@Lindydancer的答案:

  • 内联sh-script-extra-font-lock-is-in-double-quoted-string函数,因为它仅使用一次
  • 转义变量有效。
  • 数字变量($10$1等)突出显示。

破解代码

(defun sh-script-extra-font-lock-match-var-in-double-quoted-string (limit)
  "Search for variables in double-quoted strings."
  (let (res)
    (while
        (and (setq res (progn (if (eq (get-byte) ?$) (backward-char))
                              (re-search-forward
                               "[^\\]\\$\\({#?\\)?\\([[:alpha:]_][[:alnum:]_]*\\|[-#?@!]\\|[[:digit:]]+\\)"
                               limit t)))
             (not (eq (nth 3 (syntax-ppss)) ?\")))) res))

(defvar sh-script-extra-font-lock-keywords
  '((sh-script-extra-font-lock-match-var-in-double-quoted-string
     (2 font-lock-variable-name-face prepend))))

(defun sh-script-extra-font-lock-activate ()
  (interactive)
  (font-lock-add-keywords nil sh-script-extra-font-lock-keywords)
  (if (fboundp 'font-lock-flush)
      (font-lock-flush)
    (when font-lock-mode (with-no-warnings (font-lock-fontify-buffer)))))

[^\\\\]为可写[^\\],这是一组不应该匹配的字符,你的代码中包含反斜线的两倍。在较旧的Emacs版本中必须使用font-lock-fontify-buffer,在较新的版本中应调用,font-lock-flush并且font-lock-fontify-buffer不建议从elisp 调用。我的原始代码遵循此规则,而您的代码则没有。无论如何,将其迁移到GitHub存档并共同努力可能是一个更好的主意。
Lindydancer

@Lindydancer不能[^\\]逃脱]吗?据我所知,这就是正则表达式在Java中的工作方式。
Czipperz 2015年

@Lindydancer似乎不一样,因为ELisp 不允许您在字符组中使用转义字符
Czipperz 2015年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.