Subject: bug#39277: 26.3; Tcl font lock does not understand quoting

From: mvar <[email-masked]>
Date: Mon, 26 Oct 2020 22:44:03 +0200

Hadrien Lacour <[email-masked]> writes:

> Hello, tcl-mode's font lock (highlighting) chokes on this simple case:
>     puts {"hello}
> where it considers the double quote inside the curly braces as a
> "quoting" character.
> I have confirmed it works with `emacs -Q`.

hi Hadrien,

there's some generic(?) syntactic font lock getting triggered once the
doublequote character is found, that expects a closing doublequote - until then
everything is locked as a string. Is this what this bug is about (it was not
100% clear to me from your initial report) ? i'm attaching a patch that works
around this behavior but i don't know if it is the proper way to deal with the
problem (it certainly doesn't look pretty). The idea is to insert an additional
rule in tcl-syntax-propertize-function that will match the tcl-builtin-list
keywords ('puts' is in there among others) plus the brackets that follow, so
that if a doublequote is found in-between the brackets then there won't be any
automatic string locking that would mess up the closing brackets and everything
else (until another doublequote was found). Then in tcl-set-font-keywords a new
rule will match the brackets and any characters inside will be locked as a
string (including the single quote).

diff --git a/lisp/progmodes/tcl.el b/lisp/progmodes/tcl.el
index 33aad2d39f..5dd02c1367 100644
--- a/lisp/progmodes/tcl.el
+++ b/lisp/progmodes/tcl.el
@@ -410,7 +410,8 @@ tcl-font-lock-keywords
 (defconst tcl-syntax-propertize-function
   (syntax-propertize-rules
    ;; Mark the few `#' that are not comment-markers.
-   ("[^;[{ \t\n][ \t]*\\(#\\)" (1 ".")))
+   ("[^;[{ \t\n][ \t]*\\(#\\)" (1 "."))
+   ((concat "\\_<" (regexp-opt tcl-builtin-list t) "\\_>" "\s*{\\([^}].*\\)}") (2 "_")))
   "Syntactic keywords for `tcl-mode'.")
 
 ;; FIXME need some way to recognize variables because array refs look
@@ -506,6 +507,7 @@ tcl-set-font-lock-keywords
          ;; number of "namespace::" qualifiers.  A leading "::" refers
          ;; to the global namespace.
          '("\\${\\([^}]+\\)}" 1 font-lock-variable-name-face)
+         '("{\\([^}]+\\)}" 1 font-lock-string-face)
          '("\\$\\(\\(?:::\\)?\\(?:[[:alnum:]_]+::\\)*[[:alnum:]_]+\\)"
            1 font-lock-variable-name-face)
          '("\\(?:\\s-\\|^\\|\\[\\)set\\s-+{\\([^}]+\\)}"