Basically, what I want to do is to customize comment-start
and comment-end
when invoking different commands to then call comment-dwim
or comment-line
with them.
What I managed to do so far is the following (thanks to http://ergoemacs.org/emacs/elisp_comment_command.html):
(defun rust-doc-comment-dwim (c)
"Comment or uncomment the current line or text selection."
(interactive)
;; If there's no text selection, comment or uncomment the line
;; depending whether the WHOLE line is a comment. If there is a text
;; selection, using the first line to determine whether to
;; comment/uncomment.
(let (p1 p2)
(if (use-region-p)
(save-excursion
(setq p1 (region-beginning) p2 (region-end))
(goto-char p1)
(if (wholeLineIsCmt-p c)
(my-uncomment-region p1 p2 c)
(my-comment-region p1 p2 c)
))
(progn
(if (wholeLineIsCmt-p c)
(my-uncomment-current-line c)
(my-comment-current-line c)
)) )))
(defun wholeLineIsCmt-p (c)
(save-excursion
(beginning-of-line 1)
(looking-at (concat "[ \t]*//" c))
))
(defun my-comment-current-line (c)
(interactive)
(beginning-of-line 1)
(insert (concat "//" c))
)
(defun my-uncomment-current-line (c)
"Remove “//c” (if any) in the beginning of current line."
(interactive)
(when (wholeLineIsCmt-p c)
(beginning-of-line 1)
(search-forward (concat "//" c))
(delete-backward-char 4)
))
(defun my-comment-region (p1 p2 c)
"Add “//c” to the beginning of each line of selected text."
(interactive "r")
(let ((deactivate-mark nil))
(save-excursion
(goto-char p2)
(while (>= (point) p1)
(my-comment-current-line c)
(previous-line)
))))
(defun my-uncomment-region (p1 p2 c)
"Remove “//c” (if any) in the beginning of each line of selected text."
(interactive "r")
(let ((deactivate-mark nil))
(save-excursion
(goto-char p2)
(while (>= (point) p1)
(my-uncomment-current-line c)
(previous-line) )) ))
(use-package rust-mode
:mode "\.rs'"
:bind ("C-M-;" . rust-doc-comment-dwim-following)
:bind ("C-M-," . rust-doc-comment-dwim-enclosing)
:config
(defun rust-doc-comment-dwim-following ()
(interactive)
(rust-doc-comment-dwim "/ "))
(defun rust-doc-comment-dwim-enclosing ()
(interactive)
(rust-doc-comment-dwim "! "))
)
Which allows to comment as ///
when pressing Ctrl-Alt-; and //!
when pressing Ctrl-Alt-, (and uncomment lines starting with ///
or //!
depending on the keys pressed)
But I would actually prefer to have something more like
(defun comment-dwim-line (&optional arg)
"Replacement for the comment-dwim command.
If no region is selected and current line is not blank and we are not at the end of the line,
then comment current line.
Replaces default behaviour of comment-dwim, when it inserts comment at the end of the line.
Taken from https://www.emacswiki.org/emacs/CommentingCode"
(interactive "*P")
(comment-normalize-vars)
(if (and (not (region-active-p)) (not (looking-at "[ \t]*$")))
(comment-or-uncomment-region (line-beginning-position) (line-end-position))
(comment-dwim arg)))
(defun rust-doc-comment-dwim-following (&optional arg)
(interactive)
(setq comment-start "/// ")
(comment-dwim-line arg)
(setq comment-start "// ")
)
And it kind of works but only for commenting. If I'm on an already commented line it will not uncomment it which is kind of strange. I don't know what I'm missing here because it's supposed to call my function with comment-start
temporarily equal to ///
.
comment-or-uncomment-region
in my custom comment function. I just don't understand why it won't uncomment. – Lhooq May 31 '20 at 08:30