Warum wird beim Einfügen eines Zeilenumbruchs mit der Syntax-Eigenschaftseigenschaft eine Hervorhebung eingefügt?

6

Ich versuche, einen Dur-Modus zu schreiben, der dreifach zitierte Zeichenfolgen hervorhebt. Hier ist ein minimal reproduzierbares Beispiel:

(defconst demo-triple-quoted-string-regex
  (rx "\"\"\""
      ;; After the delimiter, we're a sequence of
      ;; non-backslashes or blackslashes paired with something.
      (*? (or (not (any "\\"))
              (seq "\\" anything)))
      "\"\"\""))

(defun demo-stringify-triple-quote ()
  "Put `syntax-table' property on triple-quoted strings."
  (let* ((string-literal (match-string 0))
         (string-start-pos (- (point) (length string-literal)))
         (string-end-pos (point)))
    (unless (nth 4 (syntax-ppss)) ;; not inside comment
      (put-text-property string-start-pos string-end-pos
                         'syntax-table (string-to-syntax "|")))))

(defconst demo-syntax-propertize-function
  (syntax-propertize-rules
   (demo-triple-quoted-string-regex
    (0 (ignore (demo-stringify-triple-quote))))))

(define-derived-mode demo-mode prog-mode "Demo"
  "Major mode showing stack overflow question."
  (set (make-local-variable 'font-lock-defaults) '(()))
  (set (make-local-variable 'syntax-propertize-function)
       demo-syntax-propertize-function))

Dies führt jedoch zu einem wirklich bizarren Verhalten beim Ändern des Puffers. Hier ist mein Pufferinhalt:

dodgy when we put a newline after babel

"""
a
"
babel

"""

x = 1

M-x demo-mode gibt die richtige Hervorhebung:

Demo-vor

Wenn Sie jedoch plötzlich die Eingabetaste drücken, wird Folgendes angezeigt:

Demo-After

Was mache ich falsch?

Wilfred Hughes
quelle
Ich habe keine Lösung, aber ich habe das gleiche Problem mit der Fortsetzung von Kursivschrift und Fettdruck über Zeilenumbrüche im Organisationsmodus festgestellt.
Emacs User
1
Das erste Problem besteht darin, dass Sie die Syntax für alle Zeichen der Zeichenfolge festlegen, während dies nur für das erste und das letzte Zaunzeichen erfolgen sollte. Sie können überprüfen, ob Emacs jedes Paar Ihrer vermeintlichen Zeichenfolge als eine Sexp, dh eine einzelne Zeichenfolge, über behandelt forward-sexp.
Politza
1
Das zweite Problem ist, dass Sie die Zeichenfolgen nicht so anpassen können, wie Sie es sich vorstellen. Dies würde nur funktionieren, wenn garantiert ist, dass die Suche außerhalb einer bereits im Puffer vorhandenen Zeichenfolge beginnt . Immerhin passen Sie zu Paaren: Ein Tripel startet einen String genau dann, wenn ihm eine gerade Anzahl anderer Tripel vorangestellt ist. Zum Glück syntax-ppssverfolgt dies. Schauen Sie sich an, wie es gemacht wird python.el.
Politza
@politza Ich bin voller Ehrfurcht vor deinen elisp Fähigkeiten! Vielen Dank :). Ihre Korrekturen haben ausgereicht, damit mein Code funktioniert (siehe Antwort unten), sodass ich jetzt den Fehler im Julia-Modus beheben kann, der mich dazu gebracht hat.
Wilfred Hughes

Antworten:

3

Dank Politza und python-syntax-stringifymit Edebug habe ich das geschafft. Die Änderungen waren:

  • | sollte nur auf das erste und letzte Zeichen in der dreifach zitierten Zeichenfolge angewendet werden.
  • (Weil die Syntaxanalyse inkrementell ist?) Es ist nicht möglich, nach einer ganzen Zeichenfolge zu suchen. Suchen Sie stattdessen nach einem Trennzeichen und prüfen Sie, ob Sie sich in einer Zeichenfolge mit dreifachen Anführungszeichen befinden.

Arbeitscode:

(defconst demo-triple-quoted-string-regex
  (rx "\"\"\""))

(defun demo-stringify-triple-quote ()
  "Put `syntax-table' property on triple-quoted strings."
  (let* ((string-end-pos (point))
         (string-start-pos (- string-end-pos 3))
         (ppss (prog2
                   (backward-char 3)
                   (syntax-ppss)
                 (forward-char 3))))
    (unless (nth 4 (syntax-ppss)) ;; not inside comment
      (if (nth 8 (syntax-ppss))
          ;; We're in a string, so this must be the closing triple-quote.
          ;; Put | on the last " character.
          (put-text-property (1- string-end-pos) string-end-pos
                             'syntax-table (string-to-syntax "|"))
        ;; We're not in a string, so this is the opening triple-quote.
        ;; Put | on the first " character.
        (put-text-property string-start-pos (1+ string-start-pos)
                           'syntax-table (string-to-syntax "|"))))))

(defconst demo-syntax-propertize-function
  (syntax-propertize-rules
   (demo-triple-quoted-string-regex
    (0 (ignore (demo-stringify-triple-quote))))))

(define-derived-mode demo-mode prog-mode "Demo"
  "Major mode showing stack overflow question."
  (set (make-local-variable 'font-lock-defaults) '(()))
  (set (make-local-variable 'syntax-propertize-function)
       demo-syntax-propertize-function))
Wilfred Hughes
quelle
Warum rechnen Sie ppssim let*und verwenden diesen Wert dann nie?
Michael Norrish