diff options
| author | Micah Chalmer <micah@micahchalmer.net> | 2013-09-05 22:38:37 -0400 |
|---|---|---|
| committer | Micah Chalmer <micah@micahchalmer.net> | 2013-09-06 01:02:20 -0400 |
| commit | 5b34e5956994187c97979275d69a26957481a132 (patch) | |
| tree | 3e887b1abd91f373f620282d8bda55c0a46f6995 /rust-mode.el | |
| parent | 69811ea101e93bd1b51329c13506736981b751ee (diff) | |
| download | rust-mode-5b34e5956994187c97979275d69a26957481a132.tar.gz | |
Add paragraph fill and auto-fill for multi-line comments
Diffstat (limited to 'rust-mode.el')
| -rw-r--r-- | rust-mode.el | 124 |
1 files changed, 123 insertions, 1 deletions
diff --git a/rust-mode.el b/rust-mode.el index 8651fb6..e809a34 100644 --- a/rust-mode.el +++ b/rust-mode.el @@ -209,6 +209,114 @@ collect `(,(rust-re-item-def item) 1 ,face)))) +(defun rust-fill-prefix-for-comment-start (line-start) + "Determine what to use for `fill-prefix' based on what is at the beginning of a line." + (let ((result + ;; Replace /* with same number of spaces + (replace-regexp-in-string + "\\(?:/\\*+\\)[!*]" + (lambda (s) + ;; We want the * to line up with the first * of the comment start + (concat (make-string (- (length s) 2) ?\x20) "*")) + line-start))) + ;; Make sure we've got at least one space at the end + (if (not (= (aref result (- (length result) 1)) ?\x20)) + (setq result (concat result " "))) + result)) + +(defun rust-in-comment-paragraph (body) + ;; We might move the point to fill the next comment, but we don't want it + ;; seeming to jump around on the user + (save-excursion + ;; If we're outside of a comment, with only whitespace and then a comment + ;; in front, jump to the comment and prepare to fill it. + (when (not (nth 4 (syntax-ppss))) + (beginning-of-line) + (when (looking-at (concat "[[:space:]\n]*" comment-start-skip)) + (goto-char (match-end 0)))) + + ;; We need this when we're moving the point around and then checking syntax + ;; while doing paragraph fills, because the cache it uses isn't always + ;; invalidated during this. + (syntax-ppss-flush-cache 1) + ;; If we're at the beginning of a comment paragraph with nothing but + ;; whitespace til the next line, jump to the next line so that we use the + ;; existing prefix to figure out what the new prefix should be, rather than + ;; inferring it from the comment start. + (let ((next-bol (line-beginning-position 2))) + (while (save-excursion + (end-of-line) + (syntax-ppss-flush-cache 1) + (and (nth 4 (syntax-ppss)) + (save-excursion + (beginning-of-line) + (looking-at paragraph-start)) + (looking-at "[[:space:]]*$") + (nth 4 (syntax-ppss next-bol)))) + (goto-char next-bol))) + + (syntax-ppss-flush-cache 1) + ;; If we're on the last line of a multiline-style comment that started + ;; above, back up one line so we don't mistake the * of the */ that ends + ;; the comment for a prefix. + (when (save-excursion + (and (nth 4 (syntax-ppss (line-beginning-position 1))) + (looking-at "[[:space:]]*\\*/"))) + (goto-char (line-end-position 0))) + (funcall body))) + +(defun rust-with-comment-fill-prefix (body) + (let* + ((line-string (buffer-substring-no-properties + (line-beginning-position) (line-end-position))) + (line-comment-start + (when (nth 4 (syntax-ppss)) + (cond + ;; If we're inside the comment and see a * prefix, use it + ((string-match "^\\([[:space:]]*\\*+[[:space:]]*\\)" + line-string) + (match-string 1 line-string)) + ;; If we're at the start of a comment, figure out what prefix + ;; to use for the subsequent lines after it + ((string-match (concat "[[:space:]]*" comment-start-skip) line-string) + (rust-fill-prefix-for-comment-start + (match-string 0 line-string)))))) + (fill-prefix + (or line-comment-start + fill-prefix))) + (funcall body))) + +(defun rust-find-fill-prefix () + (rust-with-comment-fill-prefix (lambda () fill-prefix))) + +(defun rust-fill-paragraph (&rest args) + "Special wrapping for `fill-paragraph' to handle multi-line comments with a * prefix on each line." + (rust-in-comment-paragraph + (lambda () + (rust-with-comment-fill-prefix + (lambda () + (let + ((fill-paragraph-function + (if (not (eq fill-paragraph-function 'rust-fill-paragraph)) + fill-paragraph-function))) + (apply 'fill-paragraph args) + t)))))) + +(defun rust-do-auto-fill (&rest args) + "Special wrapping for `do-auto-fill' to handle multi-line comments with a * prefix on each line." + (rust-with-comment-fill-prefix + (lambda () + (apply 'do-auto-fill args) + t))) + +(defun rust-fill-forward-paragraph (arg) + ;; This is to work around some funny behavior when a paragraph separator is + ;; at the very top of the file and there is a fill prefix. + (let ((fill-prefix nil)) (forward-paragraph arg))) + +(defun rust-comment-indent-new-line (&optional arg) + (rust-with-comment-fill-prefix + (lambda () (comment-indent-new-line arg)))) ;; For compatibility with Emacs < 24, derive conditionally (defalias 'rust-parent-mode @@ -234,7 +342,21 @@ ;; Misc (set (make-local-variable 'comment-start) "// ") (set (make-local-variable 'comment-end) "") - (set (make-local-variable 'indent-tabs-mode) nil)) + (set (make-local-variable 'indent-tabs-mode) nil) + + ;; Allow paragraph fills for comments + (set (make-local-variable 'comment-start-skip) + "\\(?://[/!]*\\|/\\*[*!]?\\)[[:space:]]*") + (set (make-local-variable 'paragraph-start) + (concat "[[:space:]]*\\(?:" comment-start-skip "\\|\\*/?[[:space:]]*\\|\\)$")) + (set (make-local-variable 'paragraph-separate) paragraph-start) + (set (make-local-variable 'normal-auto-fill-function) 'rust-do-auto-fill) + (set (make-local-variable 'fill-paragraph-function) 'rust-fill-paragraph) + (set (make-local-variable 'fill-forward-paragraph-function) 'rust-fill-forward-paragraph) + (set (make-local-variable 'adaptive-fill-function) 'rust-find-fill-prefix) + (set (make-local-variable 'comment-multi-line) t) + (set (make-local-variable 'comment-line-break-function) 'rust-comment-indent-new-line) + ) ;;;###autoload |
