Wie füge ich eine komplexe Syntaxhervorhebung in einem Nebenmodus hinzu?

10

Ich möchte Code mit verschiedenen Gesichtern in einem Nebenmodus hervorheben.

Hier ist ein Screenshot, der genau dem entspricht, was ich möchte:

Python-Syntax-Highlight

Eine Sache, die mir fehlt, ist, die Kommentarzeichen #zu haben font-lock-comment-face. Die Idee ist, Kommentare zu haben, die zu einer als Klartext hervorgehobenen Gliederung "gehören", damit sie leichter zu lesen sind. Während regelmäßige Kommentare mit ihrem üblichen weniger prominenten Gesicht.

Hier ist der Code, den ich verwendet habe:

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

Die Sache ist, ich habe keine Ahnung von der Schnittstelle, auf der gearbeitet wird font-lock-syntactic-face-function, außer dass sie eine komplexe Datenstruktur empfängt state, einen anderen Punktzustand hat und ein Gesicht zurückgibt.

Könnte jemand diese Schnittstelle erklären? Gibt es vielleicht eine bessere?

abo-abo
quelle

Antworten:

6

font-lock-syntactic-face-functionist eine reguläre Variable aus Font Lock, genauer gesagt aus der Phase Syntactic Font Lock (Schwerpunkt Mine):

Wenn diese Variable nicht Null ist, sollte sie eine Funktion sein, um zu bestimmen, welche Fläche für ein bestimmtes syntaktisches Element (eine Zeichenfolge oder ein Kommentar) verwendet werden soll. Der Wert wird normalerweise durch ein anderes-vars-Element in den Standardeinstellungen für die Schriftsperre festgelegt.

Die Funktion wird mit einem Argument aufgerufen, dem Analysezustand am Punkt, der von zurückgegeben wird parse-partial-sexp, und sollte ein Gesicht zurückgeben . Der Standardwert gibt font-lock-comment-face für Kommentare und font-lock-string-face für Zeichenfolgen zurück (siehe Faces for Font Lock).

parse-partial-sexpIm Gegenzug wird eine Liste zurückgegeben, die den aktuellen syntaktischen Status von Emacs beschreibt. Dies ist im Wesentlichen das Ergebnis der Anwendung der Syntaxtabelle auf den aktuellen Puffer. Die Liste ist ziemlich komplex, daher werde ich sie hier ersparen. Sie können die vollständige Referenz in der Dokumentzeichenfolge von sehen parse-partial-sexp. Der Zweck dieser Funktion besteht darin, das Gesicht zu ändern, das unter bestimmten Regeln auf ein syntaktisches Element angewendet wird. Der Anfang Ihrer Funktion zeigt dies: Wenn die aktuelle Zeichenfolge eine Dokumentzeichenfolge ist, verwenden Sie eine andere Fläche.

Das Gesicht gilt jedoch immer für das gesamte syntaktische Element, dh die gesamte Zeichenfolge oder den gesamten Kommentar. Sie können mit dieser Funktion keine einzelnen Teile hervorheben, und Sie sollten nur die statefür diesen Zweck angegebenen Elemente betrachten - wie (python-info-docstring-p state)dies in Ihrem Code der Fall ist. Sie nicht verwenden Punkt an dieser Stelle; Ich bin mir nicht einmal sicher, ob der Wert von pointin dieser Phase der Schriftsperrung richtig definiert ist.


Wenn Sie die Teile zusammenfügen, verwenden Sie die falsche Funktion für Ihren Zweck, weshalb Sie sie nicht zum Laufen bringen können.

Ich habe nicht versucht, Ihre gewünschte Hervorhebung zu implementieren, aber ich denke, Sie haben viel zu tief für Ihren Zweck gegraben. Wenn ich die Dinge richtig verstehe, möchten Sie nur die Umrisse in einem Kommentar hervorheben.

Wenn ich recht habe, dann brauchen Sie nur font-lock-keywordsauf besondere Weise, nämlich:

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

Wo outline-faceist das Gesicht, das Sie auf die Überschrift anwenden möchten , tbedeutet, dass alle vorherigen Schriftsperrungen an dieser Stelle außer Kraft gesetzt werden, und my/find-outline-in-commentist eine Matcher-Funktion (siehe Dokumentzeichenfolge von font-lock-defaults), die eine Position einnimmt und nach dem ersten Umriss in einem Kommentar sucht zwischen (point)und dieser Position, wobei die Ausmaße der Gliederung zurückgegeben werden, die in den Übereinstimmungsdaten hervorgehoben werden sollen.

Um die Gliederung zu finden, suchen Sie nach Kommentaren (mit font-lock-comment-faceoder mit dem syntaktischen Status) und looking-atüberprüfen dann, ob der Kommentar eine Gliederung enthält.

Mondhorn
quelle
1

Überlegen Sie, font-lock-syntactic-face-functionwie folgt zu definieren :

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

Dies wurde mit python-mode.el getestet, wobei ein Abschnitt mit "# *" ohne Kommentarfläche zurückblieb:

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

Während es mit dem Modus verwaltet wird:

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

Stattdessen nilsollte jedes gültige Gesicht funktionieren.

Andreas Röhler
quelle