@@ -453,8 +453,71 @@ symbols."
453
453
(let ((beg-of-symbol (save-excursion (forward-thing 'symbol -1 ) (point ))))
454
454
(looking-back rustic-re-ident beg-of-symbol)))
455
455
456
+ (defvar-local rustic-macro-scopes nil
457
+ " Cache for the scopes calculated by `rustic-macro-scope' .
458
+ This variable can be `let' bound directly or indirectly around
459
+ `rustic-macro-scope' as an optimization but should not be otherwise
460
+ set." )
461
+
462
+ (defun rustic-macro-scope (start end )
463
+ " Return the scope of macros in the buffer.
464
+ The return value is a list of (START END) positions in the
465
+ buffer.
466
+ If set START and END are optimizations which limit the return
467
+ value to scopes which are approximately with this range."
468
+ (save-excursion
469
+ ; ; need to special case macro_rules which has unique syntax
470
+ (let ((scope nil )
471
+ (start (or start (point-min )))
472
+ (end (or end (point-max ))))
473
+ (goto-char start)
474
+ ; ; if there is a start move back to the previous top level,
475
+ ; ; as any macros before that must have closed by this time.
476
+ (let ((top (syntax-ppss-toplevel-pos (syntax-ppss ))))
477
+ (when top
478
+ (goto-char top)))
479
+ (while
480
+ (and
481
+ ; ; The movement below may have moved us passed end, in
482
+ ; ; which case search-forward will error
483
+ (< (point ) end)
484
+ (search-forward " !" end t ))
485
+ (let ((pt (point )))
486
+ (cond
487
+ ; ; in a string or comment is boring, move straight on
488
+ ((rustic-in-str-or-cmnt))
489
+ ; ; in a normal macro,
490
+ ((and (skip-chars-forward " \t\n\r " )
491
+ (memq (char-after )
492
+ '(?\[ ?\( ?\{ ))
493
+ ; ; Check that we have a macro declaration after.
494
+ (rustic-looking-back-macro))
495
+ (let ((start (point )))
496
+ (ignore-errors (forward-list ))
497
+ (setq scope (cons (list start (point )) scope))))
498
+ ; ; macro_rules, why, why, why did you not use macro syntax??
499
+ ((save-excursion
500
+ ; ; yuck -- last test moves point, even if it fails
501
+ (goto-char (- pt 1 ))
502
+ (skip-chars-backward " \t\n\r " )
503
+ (rustic-looking-back-str " macro_rules" ))
504
+ (save-excursion
505
+ (when (re-search-forward " [[({]" nil t )
506
+ (backward-char )
507
+ (let ((start (point )))
508
+ (ignore-errors (forward-list ))
509
+ (setq scope (cons (list start (point )) scope)))))))))
510
+ ; ; Return 'empty rather than nil, to indicate a buffer with no
511
+ ; ; macros at all.
512
+ (or scope 'empty ))))
513
+
456
514
(defun rustic-looking-back-macro ()
457
515
" Non-nil if looking back at an ident followed by a !"
516
+ " Non-nil if looking back at an ident followed by a !
517
+ This is stricter than rust syntax which allows a space between
518
+ the ident and the ! symbol. If this space is allowed, then we
519
+ would also need a keyword check to avoid `if !(condition)` being
520
+ seen as a macro."
458
521
(if (> (- (point ) (point-min )) 1 )
459
522
(save-excursion
460
523
(backward-char )
@@ -478,18 +541,27 @@ symbols."
478
541
; ; Rewind until the point no longer moves
479
542
(setq continue (/= starting (point )))))))
480
543
481
- (defun rustic-in-macro ()
482
- (save-excursion
483
- (when (> (rustic-paren-level) 0 )
484
- (backward-up-list )
485
- (rustic-rewind-irrelevant)
486
- (or (rustic-looking-back-macro)
487
- (and (rustic-looking-back-ident)
488
- (save-excursion
489
- (backward-sexp )
490
- (rustic-rewind-irrelevant)
491
- (rustic-looking-back-str " macro_rules!" )))
492
- (rustic-in-macro)))))
544
+ (defun rustic-in-macro (&optional start end )
545
+ " Return non-nil when point is within the scope of a macro.
546
+ If START and END are set, minimize the buffer analysis to
547
+ approximately this location as an optimization.
548
+ Alternatively, if `rustic-macro-scopes' is a list use the scope
549
+ information in this variable. This last is an optimization and
550
+ the caller is responsible for ensuring that the data in
551
+ `rustic-macro-scopes' is up to date."
552
+ (when (> (rustic-paren-level) 0 )
553
+ (let ((scopes
554
+ (or
555
+ rustic-macro-scopes
556
+ (rustic-macro-scope start end))))
557
+ ; ; `rustic-macro-scope' can return the symbol `empty' if the
558
+ ; ; buffer has no macros at all.
559
+ (when (listp scopes)
560
+ (seq-some
561
+ (lambda (sc )
562
+ (and (>= (point ) (car sc))
563
+ (< (point ) (cadr sc))))
564
+ scopes)))))
493
565
494
566
(defun rustic-looking-at-where ()
495
567
" Return T when looking at the \" where\" keyword."
0 commit comments