@@ -567,7 +567,7 @@ buffer."
567
567
;; foo.bar
568
568
(t (funcall skip-dot-identifier)))))))
569
569
570
- (defun rust-mode-indent-line ()
570
+ (defun rust-mode-- indent-line ()
571
571
(interactive)
572
572
(let ((indent
573
573
(save-excursion
@@ -769,6 +769,123 @@ buffer."
769
769
(save-excursion (= (progn (goto-char pos1) (line-end-position))
770
770
(progn (goto-char pos2) (line-end-position)))))
771
771
772
+ (defun rust-mode-indent-line ()
773
+ "Indent the current line, and indent code examples in comments.
774
+
775
+ Indent the current line as `rust-mode-indent-line' does. If
776
+ point is inside a block comment containing a Markdown code
777
+ example (delimited by triple backquotes), then also indent the
778
+ current line within the code example."
779
+ (interactive)
780
+
781
+ ;; First, reindent the current line.
782
+ (rust-mode--indent-line)
783
+
784
+ ;; If point is inside a comment:
785
+ (let ((ppss (syntax-ppss)))
786
+ (when (nth 4 ppss)
787
+ (rust-with-comment-fill-prefix
788
+ (lambda ()
789
+ (let* ((orig-buf (current-buffer))
790
+ (orig-point (point))
791
+ (orig-eol (line-end-position))
792
+ (orig-bol (line-beginning-position))
793
+ (orig-mode major-mode)
794
+ (com-start (nth 8 ppss))
795
+ (com-prefix (replace-regexp-in-string "\\s-*\\'" ""
796
+ (or fill-prefix "")))
797
+ (com-re (regexp-quote com-prefix))
798
+ (cb-re (concat "^" com-re "\\(\\s-*\\)```"))
799
+ cb-start cb-pad cb-hidden-marker indented rel-point)
800
+
801
+ ;; If point is within the prefix (not inside the comment
802
+ ;; body), don't do anything fancy.
803
+ (when (>= orig-point (+ orig-bol (length com-prefix)))
804
+ (save-excursion
805
+ ;; If we're in a // comment block, use the fill prefix to
806
+ ;; find the start of the block. If we're in a /*
807
+ ;; comment, the start is determined by ppss.
808
+ (when (string-match "^\\s-*//" com-prefix)
809
+ (setq com-start orig-bol)
810
+ (while (and (= (forward-line -1) 0)
811
+ (looking-at com-re))
812
+ (setq com-start (point))))
813
+
814
+ ;; Search for ``` lines within the comment block, and
815
+ ;; identify the start of the current code block if any.
816
+ (goto-char com-start)
817
+ (while (re-search-forward cb-re orig-bol t)
818
+ (setq cb-start (unless cb-start (line-end-position))
819
+ cb-pad (match-string 1))))
820
+
821
+ (when cb-start
822
+ ;; We're inside a code block. Copy preceding contents to
823
+ ;; a temporary buffer.
824
+ (with-temp-buffer
825
+ (insert-buffer-substring orig-buf cb-start orig-eol)
826
+ (forward-char (- orig-point orig-eol))
827
+ (save-excursion
828
+ ;; For each line in the temporary buffer, remove
829
+ ;; the comment prefix, left padding if present, and
830
+ ;; hidden-line marker if present. For example, if
831
+ ;; the code block begins with:
832
+ ;;
833
+ ;; ^ /// ```$
834
+ ;;
835
+ ;; then trim lines as follows:
836
+ ;;
837
+ ;; ^ ///$ becomes ^$
838
+ ;; ^ /// let x = 2;$ becomes ^ let x = 2;$
839
+ ;; ^ /// # fn main() {$ becomes ^fn main() {$
840
+ ;;
841
+ ;; If the line we're indenting isn't a hidden line,
842
+ ;; then remove hidden lines completely - non-hidden
843
+ ;; lines are indented as if the hidden lines don't
844
+ ;; exist.
845
+ (let ((trim-re (concat com-re "\\(?:" cb-pad "\\)?"
846
+ "\\(\\s-*# \\)?")))
847
+ (beginning-of-line)
848
+ (if (and (looking-at trim-re) (match-beginning 1))
849
+ (setq cb-hidden-marker "# ")
850
+ (setq cb-hidden-marker ""
851
+ trim-re (concat com-re "\\(?:" cb-pad "\\)?"
852
+ "\\(\\s-*# .*\\)?")))
853
+
854
+ (goto-char (point-min))
855
+ (while (not (eobp))
856
+ (when (looking-at trim-re)
857
+ (delete-region (point) (match-end 0)))
858
+ (forward-line 1))))
859
+
860
+ ;; Reindent the line. Copy local settings from the
861
+ ;; parent buffer, but disable indent-tabs-mode unless
862
+ ;; it is enabled in the parent buffer and the code
863
+ ;; block is already tab-aligned.
864
+ (funcall orig-mode)
865
+ (mapc (lambda (v)
866
+ (when (custom-variable-p (or (car-safe v) v))
867
+ (if (symbolp v)
868
+ (makunbound (make-local-variable v))
869
+ (set (make-local-variable (car v)) (cdr v)))))
870
+ (buffer-local-variables orig-buf))
871
+ (or (string-suffix-p "\t" cb-pad)
872
+ (= 0 (length com-prefix) (length cb-pad))
873
+ (setq-local indent-tabs-mode nil))
874
+ (rust-mode--indent-line)
875
+
876
+ ;; Extract the indented line and copy back into the
877
+ ;; original buffer.
878
+ (setq rel-point (- (point) (point-max)))
879
+ (beginning-of-line)
880
+ (setq indented
881
+ (concat com-prefix cb-pad cb-hidden-marker
882
+ (buffer-substring (point) (point-max)))))
883
+ (goto-char orig-eol)
884
+ (unless (equal indented (buffer-substring orig-bol orig-eol))
885
+ (delete-region orig-bol orig-eol)
886
+ (insert indented))
887
+ (forward-char rel-point)))))))))
888
+
772
889
;;; Font-locking definitions and helpers
773
890
774
891
(defun rust-next-string-interpolation (limit)
0 commit comments