Skip to content

Commit

Permalink
Merge pull request #104 from ziglang/fix-multiline-string-literals
Browse files Browse the repository at this point in the history
Fix multiline string literals
  • Loading branch information
jacobly0 authored Apr 16, 2024
2 parents a0ab963 + d78231a commit b4170b7
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 103 deletions.
27 changes: 24 additions & 3 deletions test/zig-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const string =
;"
'(("const" font-lock-keyword-face)
("string" font-lock-variable-name-face)
("\\\\ This newline is NOT escaped \\\n" zig-multiline-string-face))))
("\\\\ This newline is NOT escaped \\" zig-multiline-string-face))))

(ert-deftest test-font-lock-backslash-in-str-literal ()
(zig-test-font-lock
Expand Down Expand Up @@ -100,8 +100,8 @@ const python =
;"
'(("const" font-lock-keyword-face)
("python" font-lock-variable-name-face)
("\\\\def main():\n" zig-multiline-string-face)
("\\\\ print(\"Hello, world!\")\n" zig-multiline-string-face))))
("\\\\def main():" zig-multiline-string-face)
("\\\\ print(\"Hello, world!\")" zig-multiline-string-face))))

(ert-deftest test-font-lock-parameters-pointers-and-arrays ()
(zig-test-font-lock
Expand Down Expand Up @@ -164,6 +164,27 @@ const python =
("void" font-lock-type-face)))))
(zig-test-font-lock test-string expected))))

(ert-deftest test-font-lock-int-types ()
(zig-test-font-lock
"const Types = .{ u0, i7, u33, i123, u55555 };"
'(("const" font-lock-keyword-face)
("Types" font-lock-variable-name-face)
("u0" font-lock-type-face)
("i7" font-lock-type-face)
("u33" font-lock-type-face)
("i123" font-lock-type-face)
("u55555" font-lock-type-face))))

(ert-deftest test-font-lock-escaped-backslash ()
(zig-test-font-lock
"const a = foo('\\\\', \"C:\\\\\", \\\\
);"
'(("const" font-lock-keyword-face)
("a" font-lock-variable-name-face)
("'\\\\'" font-lock-string-face)
("\"C:\\\\\"" font-lock-string-face)
("\\\\" zig-multiline-string-face))))

;;===========================================================================;;
;; Indentation tests

Expand Down
175 changes: 75 additions & 100 deletions zig-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -163,55 +163,6 @@ If given a SOURCE, execute the CMD on it."

table))

(defconst zig-keywords
'(;; Storage
"const" "var" "extern" "packed" "export" "pub" "noalias" "inline"
"noinline" "comptime" "callconv" "volatile" "allowzero"
"align" "linksection" "threadlocal" "addrspace"

;; Structure
"struct" "enum" "union" "error" "opaque"

;; Statement
"break" "return" "continue" "asm" "defer" "errdefer" "unreachable"
"try" "catch" "async" "nosuspend" "await" "suspend" "resume"

;; Conditional
"if" "else" "switch" "and" "or" "orelse"

;; Repeat
"while" "for"

;; Other keywords
"fn" "usingnamespace" "test"))

(defconst zig-types
'(;; Integer types
"i2" "u2" "i3" "u3" "i4" "u4" "i5" "u5" "i6" "u6" "i7" "u7" "i8" "u8"
"i16" "u16" "i29" "u29" "i32" "u32" "i64" "u64" "i128" "u128"
"isize" "usize"

;; Floating types
"f16" "f32" "f64" "f80" "f128"

;; C types
"c_char" "c_short" "c_ushort" "c_int" "c_uint" "c_long" "c_ulong"
"c_longlong" "c_ulonglong" "c_longdouble"

;; Comptime types
"comptime_int" "comptime_float"

;; Other types
"bool" "void" "noreturn" "type" "error" "anyerror" "anyframe" "anytype"
"anyopaque"))

(defconst zig-constants
'(;; Boolean
"true" "false"

;; Other constants
"null" "undefined"))

(defconst zig-electric-indent-chars
'(?\; ?\, ?\) ?\] ?\}))

Expand All @@ -225,9 +176,62 @@ If given a SOURCE, execute the CMD on it."
(,(concat "@" zig-re-identifier) . font-lock-builtin-face)

;; Keywords, constants and types
(,(regexp-opt zig-keywords 'symbols) . font-lock-keyword-face)
(,(regexp-opt zig-constants 'symbols) . font-lock-constant-face)
(,(regexp-opt zig-types 'symbols) . font-lock-type-face)
(,(rx symbol-start
(|
;; Storage
"const" "var" "extern" "packed" "export" "pub" "noalias" "inline"
"noinline" "comptime" "callconv" "volatile" "allowzero"
"align" "linksection" "threadlocal" "addrspace"

;; Structure
"struct" "enum" "union" "error" "opaque"

;; Statement
"break" "return" "continue" "asm" "defer" "errdefer" "unreachable"
"try" "catch" "async" "nosuspend" "await" "suspend" "resume"

;; Conditional
"if" "else" "switch" "and" "or" "orelse"

;; Repeat
"while" "for"

;; Other keywords
"fn" "usingnamespace" "test")
symbol-end)
. font-lock-keyword-face)

(,(rx symbol-start
(|
;; Boolean
"true" "false"

;; Other constants
"null" "undefined")
symbol-end)
. font-lock-constant-face)

(,(rx symbol-start
(|
;; Integer types
(: (any ?i ?u) (| ?0 (: (any (?1 . ?9)) (* digit))))
"isize" "usize"

;; Floating types
"f16" "f32" "f64" "f80" "f128"

;; C types
"c_char" "c_short" "c_ushort" "c_int" "c_uint" "c_long" "c_ulong"
"c_longlong" "c_ulonglong" "c_longdouble"

;; Comptime types
"comptime_int" "comptime_float"

;; Other types
"bool" "void" "noreturn" "type" "anyerror" "anyframe" "anytype"
"anyopaque")
symbol-end)
. font-lock-type-face)

;; Type annotations (both variable and type)
(,zig-re-type-annotation 1 font-lock-variable-name-face)
Expand Down Expand Up @@ -357,18 +361,19 @@ This is written mainly to be used as `end-of-defun-function' for Zig."
(and (not (looking-at " *\\(//[^\n]*\\)?\n"))
(current-column)))
(+ prev-block-indent-col zig-indent-offset))))
;; is-expr-continutation: True if this line continues an
;; is-expr-continuation: True if this line continues an
;; expression from the previous line, false otherwise.
(is-expr-continutation
(is-expr-continuation
(and
(not (looking-at "[]});]\\|else"))
(save-excursion
(zig-skip-backwards-past-whitespace-and-comments)
(when (> (point) 1)
(backward-char)
(not (looking-at "[,;([{}]")))))))
(or (zig-currently-in-str)
(not (looking-at "[,;([{}]"))))))))
;; Now we can calculate indent-col:
(if is-expr-continutation
(if is-expr-continuation
(+ base-indent-col zig-indent-offset)
base-indent-col)))))
;; If point is within the indentation whitespace, move it to the end of the
Expand All @@ -379,53 +384,23 @@ This is written mainly to be used as `end-of-defun-function' for Zig."
(indent-line-to indent-col)
(save-excursion (indent-line-to indent-col)))))

(defun zig-syntax-propertize-to-newline-if-in-multiline-str (end)
;; First, we need to check if we're in a multiline string literal; if we're
;; not, do nothing.
(when (zig-currently-in-str)
(let ((start (zig-start-of-current-str-or-comment)))
(when (save-excursion
(goto-char start)
(looking-at "\\\\\\\\"))
;; At this point, we've determined that we're within a multiline string
;; literal. Let `stop' be the position of the closing newline, or
;; `end', whichever comes first.
(let ((stop (if (save-excursion
(goto-char start)
(re-search-forward "\n" end t))
(prog1 (match-end 0)
;; We found the closing newline, so mark it as the
;; end of this string literal.
(put-text-property (match-beginning 0)
(match-end 0)
'syntax-table
(string-to-syntax "|")))
end)))
;; Zig multiline string literals don't support escapes, so mark all
;; backslashes (up to `stop') as punctation instead of escapes.
(save-excursion
(goto-char (1+ start))
(while (re-search-forward "\\\\" stop t)
(put-text-property (match-beginning 0) (match-end 0)
'syntax-table (string-to-syntax "."))
(goto-char (match-end 0))))
;; Move to the end of the string (or `end'), so that
;; zig-syntax-propertize can pick up from there.
(goto-char stop))))))
(defun zig-syntax-propertize-multiline-string (end)
(let* ((eol (save-excursion (search-forward "\n" end t)))
(stop (or eol end)))
(while (search-forward "\\" stop t)
(put-text-property (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax ".")))
(when eol (put-text-property (- eol 2) (1- eol) 'syntax-table (string-to-syntax "|")))
(goto-char stop)))

(defun zig-syntax-propertize (start end)
(goto-char start)
(zig-syntax-propertize-to-newline-if-in-multiline-str end)
(funcall
(syntax-propertize-rules
;; Multiline strings
;; Do not match backslashes that are preceded by single or
;; double-quotes.
("[^\\'\"]c?\\(\\\\\\)\\\\"
(1 (prog1 "|"
(goto-char (match-end 0))
(zig-syntax-propertize-to-newline-if-in-multiline-str end)))))
(point) end))
(when (eq t (zig-currently-in-str))
(zig-syntax-propertize-multiline-string end))
(while (search-forward "\\\\" end t)
(when (null (save-excursion (backward-char 2) (zig-currently-in-str)))
(backward-char)
(put-text-property (match-beginning 0) (point) 'syntax-table (string-to-syntax "|"))
(zig-syntax-propertize-multiline-string end))))

(defun zig-mode-syntactic-face-function (state)
(save-excursion
Expand Down

0 comments on commit b4170b7

Please sign in to comment.