引用符内のシェル変数の強調表示


13

vimでは、次のドキュメントにより、$PWD2行目と3行目が2つの異なる方法で色付けされます。

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

の最初のインスタンスは$PWD、それが含まれる文字列の残りの部分とは異なる色になります。これにより、変数がリテラルテキストとして扱われるのではなく、展開されることを明確に視覚的に示します。対照的に、の2番目のインスタンスは$PWD、文字列の残りの部分と同じ色になります。これは、単一引用符によって文字列として扱われるためです。

このタイプの「シェル引用符認識」を提供する既存のemacsモードはありますか?


1
確かに、これを追加するのはそれほど難しくありませんsh-modeか?たぶん、Emacs自体に追加することができます。
PythonNut

回答:


11

以下のコードは、正規表現の代わりに関数を使用してフォントロックルールを使用し$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)))))

適切なフックに最後の関数を追加することで、これを使用して呼び出すことができます。例えば:

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

これでうまくいきますが、文字列が強調表示された「$」が残ります。
エリクスト

それは文字列外の変数がどのようにハイライトされたかという理由からです。ただし、これは簡単に変更できます。2font-lockルールのをで置き換えると、動作0するはずです。(正規表現を拡張して、適切}に強調表示${FOO}するために末尾を含める必要がある場合があります。)この番号は、一致の正規表現サブグループを指し、一致0全体が強調表示されることを意味します。
リンディダンサー

これをパッケージ化して、興味のある人がいる場合はこれを.emacs.dリポジトリに追加します:github.com/moonlite/.emacs.d/blob/…@Lindydancer GPLv3 +とそのファイルの作成者はあなたですか?(そうでない場合は更新をプッシュします)。
マティアスベンツソン

いいですね。おそらく、適切なパッケージにするために時間をかける必要はないでしょう。ただし、メールアドレスを削除し、代わりにEmacsWikiページ(emacswiki.org/emacs/AndersLindgren)に行を追加してください。また、著作権記号は必要ないため削除でき、ソースコードが非ASCIIになります。
リンディダンサー

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は[^\\]逃げません]か?私が知っているように、Javaで正規表現が機能する方法です。
Czipperz

@Lindydancerは、ELisp が文字グループでエスケープ文字を使用することを許可していないため、そうではないようです
チッパーズ

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.