@@ -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
0 commit comments