Comment ajouter une coloration syntaxique complexe dans un mode mineur?

10

Je voudrais mettre en évidence le code avec différents visages dans un mode mineur.

Voici une capture d'écran proche de ce que je veux:

python-syntax-highlight

Une chose qui me manque est d' avoir les caractères de commentaire #dans font-lock-comment-face. L'idée est d'avoir des commentaires qui "appartiennent" à un plan mis en évidence en texte brut, donc c'est plus facile à lire. Tout en ayant des commentaires réguliers avec leur visage moins proéminent habituel.

Voici le code que j'ai utilisé:

(setq-local font-lock-defaults
            '(python-font-lock-keywords
              nil nil nil nil
              (font-lock-syntactic-face-function
               . lpy-font-lock-syntactic-face-function)))

(defun lpy-font-lock-syntactic-face-function (state)
  "Return syntactic face given STATE.
Returns 'defalt face for comments that belong to an outline."
  (cond ((nth 3 state)
         (if (python-info-docstring-p state)
             font-lock-doc-face
           font-lock-string-face))
        ((save-excursion
           (while (and (> (point) (point-min))
                       (progn (move-beginning-of-line 0)
                              (eq (char-after) ?\#))))
           (forward-line 1)
           (looking-at "#\\*+ "))
         'default)
        (t
         font-lock-comment-face)))

Le fait est que je n'ai aucune idée de l'interface sur laquelle font-lock-syntactic-face-functionopère, à part qu'il reçoit une structure de données complexe state, a un état de point différent et renvoie un visage.

Quelqu'un pourrait-il expliquer cette interface? Y en a-t-il un meilleur peut-être?

abo-abo
la source

Réponses:

6

font-lock-syntactic-face-functionest une variable régulière de Font Lock, plus spécifiquement de la phase Syntactic Font Lock (accentuation du mien):

Si cette variable n'est pas nulle, il doit s'agir d'une fonction permettant de déterminer la face à utiliser pour un élément syntaxique donné (une chaîne ou un commentaire). La valeur est normalement définie via un élément other-vars dans font-lock-defaults.

La fonction est appelée avec un argument, l'état d'analyse au point renvoyé par parse-partial-sexp, et doit renvoyer un visage . La valeur par défaut renvoie font-lock-comment-face pour les commentaires et font-lock-string-face pour les chaînes (voir Faces pour le verrouillage des polices).

parse-partial-sexpretourne à son tour une liste qui décrit l'état syntaxique actuel d'Emacs, qui est essentiellement le résultat de l'application de la table de syntaxe au tampon actuel. La liste est assez complexe, donc je vais la ménager ici; vous pouvez voir la référence complète dans la docstring de parse-partial-sexp. Le but de cette fonction est de changer le visage appliqué à un élément syntaxique sous certaines règles. Le début de votre fonction le démontre: si la chaîne actuelle est une docstring, utilisez une autre face pour elle.

Cependant, le visage s'applique toujours à l' élément syntaxique entier , c'est-à-dire à la chaîne entière ou au commentaire. Vous ne pouvez pas mettre en évidence des parties individuelles avec cette fonction, et vous ne devriez regarder les données stateà cet effet, comme (python-info-docstring-p state)dans votre code. N'utilisez pas de point à cet endroit; Je ne sais même pas si la valeur de pointest correctement définie à ce stade du verrouillage des polices.


En assemblant les morceaux, vous utilisez la mauvaise fonction pour votre objectif, c'est pourquoi vous ne pouvez pas le faire fonctionner.

Je n'ai pas essayé d'implémenter la mise en évidence souhaitée, mais je pense que vous avez creusé de manière trop profonde pour votre objectif. Si je comprends bien, vous souhaitez simplement mettre en évidence les contours dans un commentaire.

Si j'ai raison, alors vous avez juste besoin font-lock-keywordsd'une manière spéciale, à savoir:

(my/find-outline-in-comment-p 0 'outline-face t)

où se outline-facetrouve le visage que vous souhaitez appliquer au titre, tsignifie remplacer tout verrouillage de police antérieur à cet endroit, et my/find-outline-in-commentest une fonction de correspondance (voir la docstring de font-lock-defaults) qui prend position et recherche le premier contour dans un commentaire entre (point)et cette position, renvoyant l'étendue du contour à mettre en surbrillance dans les données de correspondance.

Pour trouver le plan, vous devez rechercher les commentaires (en utilisant font-lock-comment-faceou l'état syntaxique), puis utiliser looking-atpour vérifier si le commentaire a un plan.

lunaryorn
la source
1

Pensez à définir font-lock-syntactic-face-functioncomme ça:

(setq font-lock-syntactic-face-function
      (lambda (state)
    (cond ((nth 3 state)
           font-lock-string-face)
          ((and (nth 4 state)(nth 8 state))
            MY-COMMENT-FACE
          (t  font-lock-comment-face))))

Cela a été testé avec python-mode.el, laissant une section commençant par "# *" sans comment-face:

(setq py--font-lock-syntactic-face-function
      (lambda (state)
    (cond ((nth 3 state)
           font-lock-string-face)
          ((and (nth 4 state)(nth 8 state)
            (progn (save-excursion
                 (goto-char (nth 8 state))
                 (looking-at (concat comment-start (regexp-quote "*"))))))
           nil)
          (t font-lock-comment-face))))

Bien qu'il soit administré avec le mode:

(font-lock-syntactic-face-function
                    . py--font-lock-syntactic-face-function)

Au lieu de nil, n'importe quel visage valide devrait fonctionner.

Andreas Röhler
la source