|
374 | 374 | ("fn" . font-lock-function-name-face)
|
375 | 375 | ("static" . font-lock-constant-face)))))
|
376 | 376 |
|
377 |
| -(defun rust-extend-region-raw-string () |
| 377 | +(defun rust-font-lock-extend-region () |
378 | 378 | "Extend the region given by `font-lock-beg' and `font-lock-end'
|
379 |
| - to include the beginning of a string if it includes part of it. |
380 |
| - Adjusts to include the r[#] of a raw string as well." |
381 |
| - |
382 |
| - (let* ((orig-beg font-lock-beg) |
383 |
| - (orig-end font-lock-end) |
384 |
| - (beg-ppss (syntax-ppss font-lock-beg)) |
385 |
| - (beg-in-str (nth 3 beg-ppss)) |
386 |
| - (end-ppss (syntax-ppss font-lock-end)) |
387 |
| - (end-in-str (nth 3 end-ppss))) |
388 |
| - |
389 |
| - (when (and beg-in-str (> font-lock-beg (nth 8 beg-ppss))) |
390 |
| - (setq font-lock-beg str-beg) |
391 |
| - (while (equal ?# (char-before font-lock-beg)) |
392 |
| - (setq font-lock-beg (1- font-lock-beg))) |
393 |
| - (when (equal ?r (char-before font-lock-beg)) |
394 |
| - (setq font-lock-beg (1- font-lock-beg)))) |
395 |
| - |
396 |
| - (when end-in-str |
397 |
| - (save-excursion |
398 |
| - (goto-char (nth 8 end-ppss)) |
399 |
| - (ignore-errors (forward-sexp)) |
400 |
| - (setq font-lock-end (max font-lock-end (point))))) |
401 |
| - |
402 |
| - ;; If we have the beginning of a raw string in the region, make sure we have the end of |
403 |
| - ;; it. |
404 |
| - (when (or beg-in-str end-in-str) |
405 |
| - (save-excursion |
406 |
| - (goto-char font-lock-beg) |
407 |
| - (while (and (< (point) font-lock-end) (ignore-errors (rust-look-for-raw-string (buffer-end 1))))) |
408 |
| - (setq font-lock-end (max font-lock-end (point))))) |
| 379 | + to include the beginning of a string or comment if it includes |
| 380 | + part of it. Adjusts to include the r[#] of a raw string as |
| 381 | + well." |
| 382 | + |
| 383 | + (let ((orig-beg font-lock-beg) |
| 384 | + (orig-end font-lock-end)) |
| 385 | + (cond |
| 386 | + ;; If we are not syntactically fontified yet, we cannot correctly cover |
| 387 | + ;; anything less than the full buffer. The syntactic fontification |
| 388 | + ;; modifies the syntax, so until it's done we can't use the syntax to |
| 389 | + ;; determine what to fontify. |
| 390 | + ((< (or font-lock-syntactically-fontified 0) font-lock-end) |
| 391 | + (setq font-lock-beg 1) |
| 392 | + (setq font-lock-end (buffer-end 1))) |
| 393 | + |
| 394 | + ((let* ((beg-ppss (syntax-ppss font-lock-beg)) |
| 395 | + (beg-in-cmnt (and (nth 4 beg-ppss) (nth 8 beg-ppss))) |
| 396 | + (beg-in-str (nth 3 beg-ppss)) |
| 397 | + (end-ppss (syntax-ppss font-lock-end)) |
| 398 | + (end-in-str (nth 3 end-ppss))) |
| 399 | + |
| 400 | + (when (and beg-in-str (> font-lock-beg (nth 8 beg-ppss))) |
| 401 | + (setq font-lock-beg (nth 8 beg-ppss)) |
| 402 | + (while (equal ?# (char-before font-lock-beg)) |
| 403 | + (setq font-lock-beg (1- font-lock-beg))) |
| 404 | + (when (equal ?r (char-before font-lock-beg)) |
| 405 | + (setq font-lock-beg (1- font-lock-beg)))) |
| 406 | + |
| 407 | + (when (and beg-in-cmnt (> font-lock-beg beg-in-cmnt)) |
| 408 | + (setq font-lock-beg beg-in-cmnt)) |
| 409 | + |
| 410 | + (when end-in-str |
| 411 | + (save-excursion |
| 412 | + (goto-char (nth 8 end-ppss)) |
| 413 | + (ignore-errors (forward-sexp)) |
| 414 | + (setq font-lock-end (max font-lock-end (point))))) |
| 415 | + |
| 416 | + ;; If we have the beginning of a raw string in the region, make sure we have the end of |
| 417 | + ;; it. |
| 418 | + (when (or beg-in-str end-in-str) |
| 419 | + (save-excursion |
| 420 | + (goto-char font-lock-beg) |
| 421 | + (while (and (< (point) font-lock-end) (ignore-errors (rust-look-for-raw-string (buffer-end 1))))) |
| 422 | + (setq font-lock-end (max font-lock-end (point))))) |
| 423 | + ))) |
409 | 424 |
|
410 | 425 | (or (/= font-lock-beg orig-beg)
|
411 | 426 | (/= font-lock-end orig-end))
|
|
437 | 452 | (set-match-data (nth 1 ret-list))
|
438 | 453 | (nth 0 ret-list))))
|
439 | 454 |
|
440 |
| -(defun rust-look-for-raw-string (bound) |
441 |
| - ;; Find a raw string, but only if it's not in the middle of another string or |
442 |
| - ;; a comment |
| 455 | +(defun rust-look-for-non-standard-string (bound) |
| 456 | + ;; Find a raw string or character literal, but only if it's not in the middle |
| 457 | + ;; of another string or a comment. |
443 | 458 |
|
444 |
| - (let* ((raw-str-regexp |
| 459 | + (let* ((non-standard-str-regexp |
445 | 460 | (rx
|
446 |
| - (seq |
447 |
| - ;; The "r" starts the raw string. Capture it as group 1 to mark it as such syntactically: |
448 |
| - (group "r") |
449 |
| - |
450 |
| - ;; Then either: |
451 |
| - (or |
452 |
| - ;; a sequence at least one "#" (followed by quote). Capture all |
453 |
| - ;; but the last "#" as group 2 for this case. |
454 |
| - (seq (group (* "#")) "#\"") |
455 |
| - |
456 |
| - ;; ...or a quote without any "#". Capture it as group 3. This is |
457 |
| - ;; used later to match the opposite quote only if this capture |
458 |
| - ;; occurred |
459 |
| - (group "\"")) |
460 |
| - |
461 |
| - ;; The contents of the string: |
462 |
| - (*? anything) |
463 |
| - |
464 |
| - ;; If there are any backslashes at the end of the string, capture |
465 |
| - ;; them as group 4 so we can suppress the normal escape syntax |
466 |
| - ;; parsing: |
467 |
| - (group (* "\\")) |
468 |
| - |
469 |
| - ;; Then the end of the string--the backreferences ensure that we |
470 |
| - ;; only match the kind of ending that corresponds to the beginning |
471 |
| - ;; we had: |
472 |
| - (or |
473 |
| - ;; There were "#"s - capture the last one as group 5 to mark it as |
474 |
| - ;; the end of the string: |
475 |
| - (seq "\"" (backref 2) (group "#")) |
476 |
| - |
477 |
| - ;; No "#"s - capture the ending quote (using a backref to group 3, |
478 |
| - ;; so that we can't match a quote if we had "#"s) as group 6 |
479 |
| - (group (backref 3)))) |
480 |
| - ;; If it matches, it ends up with the starting character of the string |
481 |
| - ;; as group 1, any ending backslashes as group 4, and the ending |
482 |
| - ;; character as either group 5 or group 6. |
| 461 | + (or |
| 462 | + ;; Raw string: if it matches, it ends up with the starting character |
| 463 | + ;; of the string as group 1, any ending backslashes as group 4, and |
| 464 | + ;; the ending character as either group 5 or group 6. |
| 465 | + (seq |
| 466 | + ;; The "r" starts the raw string. Capture it as group 1 to mark it as such syntactically: |
| 467 | + (group "r") |
| 468 | + |
| 469 | + ;; Then either: |
| 470 | + (or |
| 471 | + ;; a sequence at least one "#" (followed by quote). Capture all |
| 472 | + ;; but the last "#" as group 2 for this case. |
| 473 | + (seq (group (* "#")) "#\"") |
| 474 | + |
| 475 | + ;; ...or a quote without any "#". Capture it as group 3. This is |
| 476 | + ;; used later to match the opposite quote only if this capture |
| 477 | + ;; occurred |
| 478 | + (group "\"")) |
| 479 | + |
| 480 | + ;; The contents of the string: |
| 481 | + (*? anything) |
| 482 | + |
| 483 | + ;; If there are any backslashes at the end of the string, capture |
| 484 | + ;; them as group 4 so we can suppress the normal escape syntax |
| 485 | + ;; parsing: |
| 486 | + (group (* "\\")) |
| 487 | + |
| 488 | + ;; Then the end of the string--the backreferences ensure that we |
| 489 | + ;; only match the kind of ending that corresponds to the beginning |
| 490 | + ;; we had: |
| 491 | + (or |
| 492 | + ;; There were "#"s - capture the last one as group 5 to mark it as |
| 493 | + ;; the end of the string: |
| 494 | + (seq "\"" (backref 2) (group "#")) |
| 495 | + |
| 496 | + ;; No "#"s - capture the ending quote (using a backref to group 3, |
| 497 | + ;; so that we can't match a quote if we had "#"s) as group 6 |
| 498 | + (group (backref 3)))) |
| 499 | + |
| 500 | + ;; Character literal: match the beginning ' of a character literal |
| 501 | + ;; as group 7, and the ending one as group 8 |
| 502 | + (seq |
| 503 | + (group "'") |
| 504 | + (or |
| 505 | + (seq |
| 506 | + "\\" |
| 507 | + (or |
| 508 | + (: "U" (= 8 xdigit)) |
| 509 | + (: "u" (= 4 xdigit)) |
| 510 | + (: "x" (= 2 xdigit)) |
| 511 | + (any "'nrt0\"\\"))) |
| 512 | + (not (any "'\\")) |
| 513 | + ) |
| 514 | + (group "'")) |
| 515 | + ) |
483 | 516 | )))
|
484 | 517 | (rust-conditional-re-search-forward
|
485 |
| - raw-str-regexp bound |
486 |
| - (lambda () (save-excursion |
487 |
| - (goto-char (match-beginning 0)) |
488 |
| - (not (rust-in-str-or-cmnt))))))) |
| 518 | + non-standard-str-regexp bound |
| 519 | + (lambda () |
| 520 | + (let ((pstate (syntax-ppss (match-beginning 0)))) |
| 521 | + (not |
| 522 | + (or |
| 523 | + (nth 4 pstate) ;; Skip if in a comment |
| 524 | + (and (nth 3 pstate) (wholenump (nth 8 pstate)) (< (nth 8 pstate) (match-beginning 0))) ;; Skip if in a string that isn't starting here |
| 525 | + ))))))) |
489 | 526 |
|
490 | 527 | (defvar rust-mode-font-lock-syntactic-keywords
|
491 | 528 | (append
|
492 |
| - ;; Handle single quoted character literals: |
493 |
| - (mapcar (lambda (re) (list re '(1 "\"") '(2 "\""))) |
494 |
| - '("\\('\\)[^']\\('\\)" |
495 |
| - "\\('\\)\\\\['nrt\"\\]\\('\\)" |
496 |
| - "\\('\\)\\\\x[[:xdigit:]]\\{2\\}\\('\\)" |
497 |
| - "\\('\\)\\\\u[[:xdigit:]]\\{4\\}\\('\\)" |
498 |
| - "\\('\\)\\\\U[[:xdigit:]]\\{8\\}\\('\\)")) |
499 |
| - ;; Handle raw strings: |
500 |
| - `((rust-look-for-raw-string (1 "|") (4 "_" nil t) (5 "|" nil t) (6 "|" nil t))))) |
| 529 | + ;; Handle raw strings and character literals: |
| 530 | + `((rust-look-for-non-standard-string (1 "|" nil t) (4 "_" nil t) (5 "|" nil t) (6 "|" nil t) (7 "\"" nil t) (8 "\"" nil t))))) |
501 | 531 |
|
502 | 532 | (defun rust-mode-syntactic-face-function (state)
|
503 | 533 | "Syntactic face function to distinguish doc comments from other comments."
|
@@ -768,7 +798,7 @@ This is written mainly to be used as `end-of-defun-function' for Rust."
|
768 | 798 | (setq-local indent-line-function 'rust-mode-indent-line)
|
769 | 799 |
|
770 | 800 | ;; Fonts
|
771 |
| - (add-to-list 'font-lock-extend-region-functions 'rust-extend-region-raw-string) |
| 801 | + (add-to-list 'font-lock-extend-region-functions 'rust-font-lock-extend-region) |
772 | 802 | (setq-local font-lock-defaults '(rust-mode-font-lock-keywords
|
773 | 803 | nil nil nil nil
|
774 | 804 | (font-lock-syntactic-keywords . rust-mode-font-lock-syntactic-keywords)
|
|
0 commit comments