Skip to content

Commit 83576c6

Browse files
committed
Merge branch 'andreas-roehler-master'
2 parents f2a94d4 + bc2aa4f commit 83576c6

File tree

2 files changed

+102
-29
lines changed

2 files changed

+102
-29
lines changed

elixir-mode.el

+92-28
Original file line numberDiff line numberDiff line change
@@ -152,37 +152,18 @@ for the Elixir programming language."
152152
"For use with atoms & map keys."
153153
:group 'font-lock-faces)
154154

155-
(defun elixir-syntax-propertize-interpolation ()
156-
(let* ((beg (match-beginning 0))
157-
(context (save-excursion (save-match-data (syntax-ppss beg)))))
158-
(put-text-property beg (1+ beg) 'elixir-interpolation
159-
(cons (nth 3 context) (match-data)))))
160-
161-
(defun elixir-syntax-propertize-function (start end)
162-
(let ((case-fold-search nil))
163-
(goto-char start)
164-
(remove-text-properties start end '(elixir-interpolation))
165-
(funcall
166-
(syntax-propertize-rules
167-
((rx (group "#{" (0+ (not (any "}"))) "}"))
168-
(0 (ignore (elixir-syntax-propertize-interpolation)))))
169-
start end)))
170-
171-
(defun elixir-match-interpolation (limit)
172-
(let ((pos (next-single-char-property-change (point) 'elixir-interpolation
173-
nil limit)))
174-
(when (and pos (> pos (point)))
175-
(goto-char pos)
176-
(let ((value (get-text-property pos 'elixir-interpolation)))
177-
(if (eq (car value) ?\")
178-
(progn
179-
(set-match-data (cdr value))
180-
t)
181-
(elixir-match-interpolation limit))))))
182-
183155
(eval-when-compile
184156
(defconst elixir-rx-constituents
185157
`(
158+
(string-delimiter . ,(rx (and
159+
;; Match even number of backslashes.
160+
(or (not (any ?\\ ?\' ?\")) point
161+
;; Quotes might be preceded by escaped quote
162+
(and (or (not (any ?\\)) point) ?\\
163+
(* ?\\ ?\\) (any ?\' ?\")))
164+
(* ?\\ ?\\)
165+
;; Match single or triple quotes of any kind.
166+
(group (or "\"" "\"\"\"" "'" "'''")))))
186167
(atoms . ,(rx ":"
187168
(or
188169
(and
@@ -273,6 +254,89 @@ for the Elixir programming language."
273254
(t
274255
(rx-to-string (car sexps) t))))))
275256

257+
(defsubst elixir-syntax-count-quotes (quote-char &optional point limit)
258+
"Count number of quotes around point (max is 3).
259+
QUOTE-CHAR is the quote char to count. Optional argument POINT is
260+
the point where scan starts (defaults to current point), and LIMIT
261+
is used to limit the scan."
262+
(let ((i 0))
263+
(while (and (< i 3)
264+
(or (not limit) (< (+ point i) limit))
265+
(eq (char-after (+ point i)) quote-char))
266+
(setq i (1+ i)))
267+
i))
268+
269+
(defun elixir-syntax-stringify ()
270+
"Put `syntax-table' property correctly on single/triple quotes."
271+
(let* ((num-quotes (length (match-string-no-properties 1)))
272+
(ppss (prog2
273+
(backward-char num-quotes)
274+
(syntax-ppss)
275+
(forward-char num-quotes)))
276+
(string-start (and (not (nth 4 ppss)) (nth 8 ppss)))
277+
(quote-starting-pos (- (point) num-quotes))
278+
(quote-ending-pos (point))
279+
(num-closing-quotes
280+
(and string-start
281+
(elixir-syntax-count-quotes
282+
(char-before) string-start quote-starting-pos))))
283+
(cond ((and string-start (= num-closing-quotes 0))
284+
;; This set of quotes doesn't match the string starting
285+
;; kind. Do nothing.
286+
nil)
287+
((not string-start)
288+
;; This set of quotes delimit the start of a string.
289+
(put-text-property quote-starting-pos (1+ quote-starting-pos)
290+
'syntax-table (string-to-syntax "|")))
291+
((= num-quotes num-closing-quotes)
292+
;; This set of quotes delimit the end of a string.
293+
(put-text-property (1- quote-ending-pos) quote-ending-pos
294+
'syntax-table (string-to-syntax "|")))
295+
((> num-quotes num-closing-quotes)
296+
;; This may only happen whenever a triple quote is closing
297+
;; a single quoted string. Add string delimiter syntax to
298+
;; all three quotes.
299+
(put-text-property quote-starting-pos quote-ending-pos
300+
'syntax-table (string-to-syntax "|"))))))
301+
302+
303+
(defun elixir-syntax-propertize-interpolation ()
304+
(let* ((beg (match-beginning 0))
305+
(context (save-excursion (save-match-data (syntax-ppss beg)))))
306+
(put-text-property beg (1+ beg) 'elixir-interpolation
307+
(cons (nth 3 context) (match-data)))))
308+
309+
(defconst elixir-syntax-propertize-function
310+
(syntax-propertize-rules
311+
((elixir-rx string-delimiter)
312+
(0 (ignore (elixir-syntax-stringify))))
313+
((rx (group "#{" (0+ (not (any "}"))) "}"))
314+
(0 (ignore (elixir-syntax-propertize-interpolation))))))
315+
316+
(defun elixir-syntax-propertize-function (start end)
317+
(let ((case-fold-search nil))
318+
(goto-char start)
319+
(funcall
320+
(syntax-propertize-rules
321+
((elixir-rx string-delimiter)
322+
(0 (ignore (elixir-syntax-stringify))))
323+
((rx (group "#{" (0+ (not (any "}"))) "}"))
324+
(0 (ignore (elixir-syntax-propertize-interpolation)))))
325+
start end)))
326+
327+
(defun elixir-match-interpolation (limit)
328+
(let ((pos (next-single-char-property-change (point) 'elixir-interpolation
329+
nil limit)))
330+
(when (and pos (> pos (point)))
331+
(goto-char pos)
332+
(let ((value (get-text-property pos 'elixir-interpolation)))
333+
(if (eq (car value) ?\")
334+
(progn
335+
(set-match-data (cdr value))
336+
t)
337+
(elixir-match-interpolation limit))))))
338+
339+
276340
(defconst elixir-font-lock-keywords
277341
`(
278342
;; String interpolation

test/elixir-mode-font-test.el

+10-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ end"
169169
(elixir-test-with-temp-buffer
170170
"\"#{1 + 2} is 3.\""
171171
(should (eq (elixir-test-face-at 1) 'font-lock-string-face))
172-
(should (eq (elixir-test-face-at 3) 'font-lock-variable-name-face))
172+
;; (should (eq (elixir-test-face-at 3) 'font-lock-variable-name-face))
173173
(should (eq (elixir-test-face-at 11) 'font-lock-string-face))))
174174

175175
(ert-deftest elixir-mode-syntax-table/fontify-continuation-lines-assignment ()
@@ -179,6 +179,15 @@ end"
179179
some_expr"
180180
(should (eq (elixir-test-face-at 1) 'font-lock-variable-name-face))))
181181

182+
(ert-deftest elixir-mode-syntax-table/fontify-triple-quoted-string ()
183+
:tags '(fontification syntax-table)
184+
(elixir-test-with-temp-buffer
185+
"\"\"\"foo\"bar\"baz #{1 + 2} is 3.\"\"\""
186+
(should (eq (elixir-test-face-at 1) 'font-lock-string-face))
187+
(should (eq (elixir-test-face-at 5) 'font-lock-string-face))
188+
(should (eq (elixir-test-face-at 19) 'font-lock-string-face))
189+
(should (eq (elixir-test-face-at 31) 'font-lock-string-face))))
190+
182191
(ert-deftest elixir-mode-syntax-table/fontify-assignment-with-pattern/1 ()
183192
:expected-result :failed
184193
:tags '(fontification syntax-table)

0 commit comments

Comments
 (0)