@@ -152,37 +152,18 @@ for the Elixir programming language."
152
152
" For use with atoms & map keys."
153
153
:group 'font-lock-faces )
154
154
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
-
183
155
(eval-when-compile
184
156
(defconst elixir-rx-constituents
185
157
`(
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 " \" " " \"\"\" " " '" " '''" )))))
186
167
(atoms . ,(rx " :"
187
168
(or
188
169
(and
@@ -273,6 +254,89 @@ for the Elixir programming language."
273
254
(t
274
255
(rx-to-string (car sexps) t ))))))
275
256
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
+
276
340
(defconst elixir-font-lock-keywords
277
341
`(
278
342
; ; String interpolation
0 commit comments