Mise en surbrillance des variables shell dans les guillemets

13

Dans vim, le document suivant provoquera la $PWDcouleur des lignes 2 et 3 de deux manières différentes:

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

La première instance de $PWDsera dans une couleur différente du reste de la chaîne dans laquelle elle se trouve. Cela donne une indication visuelle claire que la variable sera développée, plutôt que traitée comme du texte littéral. En revanche, la deuxième instance de $PWDsera colorée de la même manière que le reste de la chaîne, car les guillemets simples la traitent comme du texte littéral.

Existe-t-il des modes emacs existants qui fournissent ce type de "reconnaissance de citations de shell"?

nispio
la source
1
Sûrement, ce ne serait pas terriblement difficile à ajouter sh-mode? Peut-être qu'il peut être ajouté à Emacs lui-même.
PythonNut

Réponses:

11

Le code ci-dessous utilise une règle de verrouillage de police avec une fonction au lieu d'une expression rationnelle, la fonction recherche les occurrences de $VARmais uniquement lorsqu'elles se trouvent à l'intérieur d'une chaîne entre guillemets doubles. La fonction (syntax-ppss)est utilisée pour déterminer cela.

La règle de verrouillage de police utilise l' prependindicateur pour s'ajouter au-dessus de la surbrillance de chaîne existante. (Notez que de nombreux packages l'utilisent t. Malheureusement, cela écrase tous les aspects de la mise en surbrillance existante. Par exemple, l'utilisation prependconservera une couleur d'arrière-plan de chaîne (s'il y en a une) tout en remplaçant la couleur de premier plan.)

(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)))))

Vous pouvez appeler use this en ajoutant la dernière fonction à un hook approprié, par exemple:

(add-hook 'sh-mode-hook 'sh-script-extra-font-lock-activate)
Lindydancer
la source
Cela fonctionne pour moi, mais laisse le "$" avec la surbrillance de la chaîne.
erikstokes
C'est par conception, car c'est ainsi qu'une variable en dehors d'une chaîne a été mise en évidence. Cependant, cela peut facilement être modifié. Si vous remplacez le 2dans la règle de verrouillage des polices par un, 0cela devrait fonctionner. (Vous devrez peut-être étendre l'expression régulière pour inclure une fin }pour surligner ${FOO}correctement.) Ce nombre fait référence au sous-groupe d'expression régulière de la correspondance, 0ce qui signifie que la correspondance entière doit être mise en surbrillance.
Lindydancer
Emballé cela tout en l'ajoutant à mon référentiel .emacs.d si quelqu'un l'intéresse: github.com/moonlite/.emacs.d/blob/… @Lindydancer La GPLv3 + et vous en tant qu'auteur dans ce fichier êtes-vous d'accord? (Je vais pousser une mise à jour sinon).
Mattias Bengtsson
Ça m'a l'air bien. Je n'aurais probablement pas eu le temps d'en faire un package approprié. Cependant, je voudrais que vous supprimiez mon adresse e-mail et que vous ajoutiez une ligne à ma page EmacsWiki ( emacswiki.org/emacs/AndersLindgren ). En outre, vous pouvez supprimer le signe du droit d'auteur car il n'est pas nécessaire et rend le code source non ascii.
Lindydancer
3

J'ai amélioré la réponse de @ Lindydancer de la manière suivante:

  • A souligné la sh-script-extra-font-lock-is-in-double-quoted-stringfonction, car elle n'a été utilisée qu'une seule fois
  • Échapper à la variable fonctionne.
  • Les variables numériques ( $10, $1, etc.) sont mis en évidence.

Pause pour le code

(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)))))
Czipperz
la source
Le [^\\\\]pourrait être écrit comme [^\\], c'est un ensemble de caractères qui ne doivent pas être mis en correspondance, et votre code comprend deux barres obliques inverses. Dans les anciennes versions d'Emacs doivent être utilisées font-lock-fontify-buffer, dans les plus récentes, vous êtes censé appeler font-lock-flushet appeler font-lock-fontify-bufferdepuis elisp est déconseillé. Mon code d'origine a suivi cela, pas votre code. Quoi qu'il en soit, il pourrait être préférable de migrer cela vers une archive GitHub et de rejoindre l'effort.
Lindydancer
@Lindydancer N'échappe pas [^\\]au ]? Voilà comment fonctionne regex en Java, comme je le sais.
Czipperz
@Lindydancer Il semble que ce ne soit pas le cas car ELisp ne vous permet pas d'utiliser des caractères d'échappement dans les groupes de caractères .
Czipperz