三重引用符で囲まれた文字列を強調表示するメジャーモードを記述しようとしています。次に、最小限の再現可能な例を示します。
(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))
ただし、これはバッファを変更するときに本当に奇妙な動作につながります。これが私のバッファの内容です:
dodgy when we put a newline after babel
"""
a
"
babel
"""
x = 1
M-x demo-mode
正しい強調表示を与える:
しかし、Enterキーを押すと、突然次のようになります。
何が悪いのですか?
私には解決策はありませんが、org-modeの行の折り返しでイタリックと太字が続くという同じ問題に気づきました。
—
Emacsユーザー
最初の問題は、構文を文字列のすべての文字に配置することですが、構文は最初と最後のフェンス文字に対してのみ実行する必要があります。Emacsがを介して、想定される文字列のすべてのペアを1つのsexp、つまり単一の文字列として扱うことを確認できます
—
politza
forward-sexp
。
2番目の問題は、想像したとおりに文字列を実際に一致させることができないことです。これは、バッファに既に存在する文字列の外側から検索が開始されることが保証されている場合にのみ機能します。結局のところ、ペアを一致させています。1つのトリプルは、偶数のその他のトリプルが前にある場合に限り、文字列を開始します。幸いにもこれ
—
politza
syntax-ppss
を追跡します。それがでどのように行われるかを見てくださいpython.el
。
@politza私はあなたのelispスキルに畏敬の念を抱いています!本当にありがとう :)。あなたの修正は私のコードを動作させるのに十分でした(以下の回答を参照)ので、これに私を巻き込んだジュリアモードのバグを修正することができます。
—
Wilfred Hughes