Виділення змінних оболонок в лапках


13

In vim, наступний документ призведе до того, що $PWDрядки 2 та 3 будуть пофарбовані двома різними способами:

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

Перший екземпляр $PWDбуде в іншому кольорі від решти рядка, в якому він знаходиться. Це дає чітку візуальну вказівку на те, що змінна буде розширена, а не розглядається як буквальний текст. На відміну від цього, другий екземпляр $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)

Це працює для мене, але залишає "$" з виділенням рядка.
erikstokes

Це за дизайном, оскільки саме так було виділено змінну за межами рядка. Однак це можна легко змінити. Якщо ви заміните 2правило блокування шрифту на 0воно, воно повинно працювати. (Можливо, вам знадобиться розширити регулярний вираз, щоб включити трейлінг, }щоб ${FOO}правильно виділити .) Це число посилається на підгрупу повторної вирівнювання матчу, 0тобто означає, що весь збіг повинен бути виділений.
Lindydancer

Упакували це, додавши це до мого сховища .emacs.d, якщо хтось зацікавився: github.com/moonlite/.emacs.d/blob/… @Lindydancer Чи GPLv3 +, і ви як автор у цьому файлі чудово? (Я натискаю оновлення, якщо ні).
Маттіас Бенгтссон

Звучить добре. Напевно, мені б не довелося встигнути перетворити його у належний пакет. Однак я хотів би, щоб ви видалили мою електронну адресу і замість цього додали рядок на мою сторінку 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

@Lindydancer Схоже, це не так, як ELisp не дозволяє використовувати символи втечі в групах символів .
Czipperz

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.