@@ -362,6 +362,10 @@ See `prettify-symbols-compose-predicate'."
362
362
" bool"
363
363
" str" " char" ))
364
364
365
+ (defconst rust-expression-introducers
366
+ '(" if" " while" " match" " return" " box" " in" )
367
+ " List of Rust keywords that are always followed by expressions." )
368
+
365
369
(defconst rust-number-with-type
366
370
(eval-when-compile
367
371
(concat
@@ -526,22 +530,36 @@ symbols."
526
530
symbols)))))
527
531
528
532
(defun rust-looking-back-ident ()
529
- " Non-nil if we are looking backwards at a valid rust identifier."
530
- (let ((beg-of-symbol (save-excursion (forward-thing 'symbol -1 ) (point ))))
531
- (looking-back rust-re-ident beg-of-symbol)))
533
+ " Non-nil if we are looking backwards at a valid rust identifier.
534
+ If we are, regexp match 0 is the identifier."
535
+ (let ((outer-point (point )))
536
+ (save-excursion
537
+ (forward-thing 'symbol -1 )
538
+ (and (looking-at rust-re-ident)
539
+ (eq (match-end 0 ) outer-point)))))
532
540
533
541
(defun rust-looking-back-macro ()
534
- " Non-nil if looking back at an ident followed by a !
535
-
536
- This is stricter than rust syntax which allows a space between
537
- the ident and the ! symbol. If this space is allowed, then we
538
- would also need a keyword check to avoid `if !(condition)` being
539
- seen as a macro."
540
- (if (> (- (point ) (point-min )) 1 )
541
- (save-excursion
542
- (backward-char )
543
- (and (= ?! (char-after ))
544
- (rust-looking-back-ident)))))
542
+ " Non-nil if looking back at a potential macro name followed by a \" !\" .
543
+ If we are, regexp match 0 is the macro name."
544
+ (save-excursion
545
+ ; ; Look past whitespace and line breaks.
546
+ ; ; > is okay because we only use it for \n and \r, not "*/"
547
+ (skip-syntax-backward " ->" )
548
+ (when (eq (char-before ) ?! )
549
+ (forward-char -1 )
550
+ (skip-syntax-backward " ->" )
551
+ (when (rust-looking-back-ident)
552
+ (let ((ident (match-string 0 )))
553
+ (not (member ident rust-expression-introducers)))))))
554
+
555
+ (defun rust-looking-back-macro-rules ()
556
+ " Non-nil if looking back at \" macro_rules IDENT !\" ."
557
+ (save-excursion
558
+ (skip-syntax-backward " ->" )
559
+ (let ((outer-point (point )))
560
+ (forward-thing 'symbol -2 )
561
+ (and (looking-at (concat " macro_rules\\ s-*!\\ s-*" rust-re-ident))
562
+ (eq (match-end 0 ) outer-point)))))
545
563
546
564
; ;; Syntax definitions and helpers
547
565
@@ -562,90 +580,25 @@ seen as a macro."
562
580
; ; Rewind until the point no longer moves
563
581
(setq continue (/= starting (point )))))))
564
582
565
- (defvar-local rust-macro-scopes nil
566
- " Cache for the scopes calculated by `rust-macro-scope' .
567
-
568
- This variable can be `let' bound directly or indirectly around
569
- `rust-macro-scope' as an optimization but should not be otherwise
570
- set." )
571
-
572
- (defun rust-macro-scope (start end )
573
- " Return the scope of macros in the buffer.
574
-
575
- The return value is a list of (START END) positions in the
576
- buffer.
577
-
578
- If set START and END are optimizations which limit the return
579
- value to scopes which are approximately with this range."
580
- (save-excursion
581
- ; ; need to special case macro_rules which has unique syntax
582
- (let ((scope nil )
583
- (start (or start (point-min )))
584
- (end (or end (point-max ))))
585
- (goto-char start)
586
- ; ; if there is a start move back to the previous top level,
587
- ; ; as any macros before that must have closed by this time.
588
- (let ((top (syntax-ppss-toplevel-pos (syntax-ppss ))))
589
- (when top
590
- (goto-char top)))
591
- (while
592
- (and
593
- ; ; The movement below may have moved us passed end, in
594
- ; ; which case search-forward will error
595
- (< (point ) end)
596
- (search-forward " !" end t ))
597
- (let ((pt (point )))
598
- (cond
599
- ; ; in a string or comment is boring, move straight on
600
- ((rust-in-str-or-cmnt))
601
- ; ; in a normal macro,
602
- ((and (skip-chars-forward " \t\n\r " )
603
- (memq (char-after )
604
- '(?\[ ?\( ?\{ ))
605
- ; ; Check that we have a macro declaration after.
606
- (rust-looking-back-macro))
607
- (let ((start (point )))
608
- (ignore-errors (forward-list ))
609
- (setq scope (cons (list start (point )) scope))))
610
- ; ; macro_rules, why, why, why did you not use macro syntax??
611
- ((save-excursion
612
- ; ; yuck -- last test moves point, even if it fails
613
- (goto-char (- pt 1 ))
614
- (skip-chars-backward " \t\n\r " )
615
- (rust-looking-back-str " macro_rules" ))
616
- (save-excursion
617
- (when (re-search-forward " [[({]" nil t )
618
- (backward-char )
619
- (let ((start (point )))
620
- (ignore-errors (forward-list ))
621
- (setq scope (cons (list start (point )) scope)))))))))
622
- ; ; Return 'empty rather than nil, to indicate a buffer with no
623
- ; ; macros at all.
624
- (or scope 'empty ))))
625
-
626
- (defun rust-in-macro (&optional start end )
583
+ (defun rust-in-macro ()
627
584
" Return non-nil when point is within the scope of a macro.
628
-
629
- If START and END are set, minimize the buffer analysis to
630
- approximately this location as an optimization.
631
-
632
- Alternatively, if `rust-macro-scopes' is a list use the scope
633
- information in this variable. This last is an optimization and
634
- the caller is responsible for ensuring that the data in
635
- `rust-macro-scopes' is up to date."
636
- (when (> (rust-paren-level) 0 )
637
- (let ((scopes
638
- (or
639
- rust-macro-scopes
640
- (rust-macro-scope start end))))
641
- ; ; `rust-macro-scope' can return the symbol `empty' if the
642
- ; ; buffer has no macros at all.
643
- (when (listp scopes)
644
- (seq-some
645
- (lambda (sc )
646
- (and (>= (point ) (car sc))
647
- (< (point ) (cadr sc))))
648
- scopes)))))
585
+ If we are, return the position of the opening bracket of the macro's arguments."
586
+ (let ((ppss (syntax-ppss )))
587
+ ; ; If we're in a string or comment, we're definitely not on a token a macro
588
+ ; ; will see.
589
+ (when (not (or (nth 3 ppss) (nth 4 ppss)))
590
+ ; ; Walk outward to enclosing parens, looking for one preceded by "ident !"
591
+ ; ; or "macro_rules! ident".
592
+ (let (result
593
+ (enclosing (reverse (nth 9 ppss))))
594
+ (save-excursion
595
+ (while enclosing
596
+ (goto-char (car enclosing))
597
+ (if (or (rust-looking-back-macro)
598
+ (rust-looking-back-macro-rules))
599
+ (setq result (point ) enclosing nil )
600
+ (setq enclosing (cdr enclosing)))))
601
+ result))))
649
602
650
603
(defun rust-looking-at-where ()
651
604
" Return T when looking at the \" where\" keyword."
@@ -1089,7 +1042,7 @@ outside of this context."
1089
1042
(cond
1090
1043
1091
1044
; ; Certain keywords always introduce expressions
1092
- ((rust-looking-back-symbols '( " if " " while " " match " " return " " box " " in " ) ) t )
1045
+ ((rust-looking-back-symbols rust-expression-introducers ) t )
1093
1046
1094
1047
; ; "as" introduces a type
1095
1048
((rust-looking-back-symbols '(" as" )) nil )
@@ -1411,34 +1364,32 @@ whichever comes first."
1411
1364
1412
1365
(defun rust-syntax-propertize (start end )
1413
1366
" A `syntax-propertize-function' to apply properties from START to END."
1414
- ; ; Cache all macro scopes as an optimization. See issue #208
1415
- (let ((rust-macro-scopes (rust-macro-scope start end)))
1416
- (goto-char start)
1417
- (let ((str-start (rust-in-str-or-cmnt)))
1418
- (when str-start
1419
- (rust--syntax-propertize-raw-string str-start end)))
1420
- (funcall
1421
- (syntax-propertize-rules
1422
- ; ; Character literals.
1423
- (rust--char-literal-rx (1 " \" " ) (2 " \" " ))
1424
- ; ; Raw strings.
1425
- (" \\ (r\\ )#*\" "
1426
- (0 (ignore
1427
- (goto-char (match-end 0 ))
1428
- (unless (save-excursion (nth 8 (syntax-ppss (match-beginning 0 ))))
1429
- (put-text-property (match-beginning 1 ) (match-end 1 )
1430
- 'syntax-table (string-to-syntax " |" ))
1431
- (rust--syntax-propertize-raw-string (match-beginning 0 ) end)))))
1432
- (" [<>]"
1433
- (0 (ignore
1434
- (when (save-match-data
1435
- (save-excursion
1436
- (goto-char (match-beginning 0 ))
1437
- (rust-ordinary-lt-gt-p)))
1438
- (put-text-property (match-beginning 0 ) (match-end 0 )
1439
- 'syntax-table (string-to-syntax " ." ))
1440
- (goto-char (match-end 0 )))))))
1441
- (point ) end)))
1367
+ (goto-char start)
1368
+ (let ((str-start (rust-in-str-or-cmnt)))
1369
+ (when str-start
1370
+ (rust--syntax-propertize-raw-string str-start end)))
1371
+ (funcall
1372
+ (syntax-propertize-rules
1373
+ ; ; Character literals.
1374
+ (rust--char-literal-rx (1 " \" " ) (2 " \" " ))
1375
+ ; ; Raw strings.
1376
+ (" \\ (r\\ )#*\" "
1377
+ (0 (ignore
1378
+ (goto-char (match-end 0 ))
1379
+ (unless (save-excursion (nth 8 (syntax-ppss (match-beginning 0 ))))
1380
+ (put-text-property (match-beginning 1 ) (match-end 1 )
1381
+ 'syntax-table (string-to-syntax " |" ))
1382
+ (rust--syntax-propertize-raw-string (match-beginning 0 ) end)))))
1383
+ (" [<>]"
1384
+ (0 (ignore
1385
+ (when (save-match-data
1386
+ (save-excursion
1387
+ (goto-char (match-beginning 0 ))
1388
+ (rust-ordinary-lt-gt-p)))
1389
+ (put-text-property (match-beginning 0 ) (match-end 0 )
1390
+ 'syntax-table (string-to-syntax " ." ))
1391
+ (goto-char (match-end 0 )))))))
1392
+ (point ) end))
1442
1393
1443
1394
(defun rust-fill-prefix-for-comment-start (line-start )
1444
1395
" Determine what to use for `fill-prefix' based on the text at LINE-START."
0 commit comments