6

I want to adjust the behavior of comment-dwim when editing c++ files: When a region is selected that either starts or ends in the middle of a line I would prefer /* ... */ comments. For the other cases // per line is fine.

Example:

int foo(int arg) {
    // int a = 0;
    int b = 3;
    return arg /*+ a*/ + b;
}

Can this be done?

As another reference point, QtCreator behaves the way I'm trying to describe.

2

The reason that c++-mode does not use the /* ... */ syntax is because the variables comment-start and comment-end are set to "// " and "" by default in C++-mode. Changing them to "/* " and " */" doesn't quite achieve the effect you asked for, because then it always uses the /* ... */ syntax instead of "//".

To use /* ... */ only for regions in c++-mode that contain multiple lines, you can do something like the following:

(defun my-with-c-sytle-comments (orig-fun beg end &optional arg)
  (if (and (member major-mode '(c-mode c++-mode java-mode))
           (save-excursion
             (goto-char end)
             (not (looking-at-p "[ \t]*$"))))
      (let (;; Set up comment style to use "/* ... */" instead of "// ..."
            (comment-start "/* ")
            (comment-end " */")
            ;; Use a single pair of "/*" and "*/" for the entire region rather a
            ;; separate one for each line.
            (comment-style 'multi-line)
            ;; Don't insert a "*" at the beginning of each line.  This can't be
            ;; blank because then Emacs will just ignore it and revert to the
            ;; default behavior of inserting the "*"'s.
            (comment-continue "XXX")
            ;; Remember the first and last lines of the region commented.
            (first-line (line-number-at-pos beg))
            (last-line (line-number-at-pos end)))
        (funcall orig-fun beg end arg)
        (when (< first-line last-line)
          ;; Delete the comment-continue string at the start of each line after
          ;; the first one.
          (save-excursion
            (goto-char (point-min))
            (forward-line (1- first-line))
            (while (< (line-number-at-pos) last-line)
              (forward-line)
              (beginning-of-line)
              ;; Make sure that the line starts with comment-continue plus a
              ;; space before we delete the prefix.
              (when (looking-at-p (regexp-quote (concat comment-continue " ")))
                (delete-region (point)
                               (+ (point)
                                  (1+ (length comment-continue)))))))))
    (funcall orig-fun beg end arg)))

(advice-add 'comment-region :around 'my-with-c-sytle-comments)
  • That's a good explanation. The proposed solution is still not quite what I'm looking for. But maybe I did not explain it good enough. For example if I select one ore many lines entirely I would prefer the // comments per line. Basically every time // would require a newline to be added I would rather take /**/. QtCreator behaves in exactly this way. I will add this to the original question. – B_old Mar 15 '18 at 21:10
  • 1
    @B_old Try the updated version – Qudit Mar 15 '18 at 21:36
  • 1
    @B_old Updated again! – Qudit Mar 17 '18 at 3:04
  • 1
    @B_old In that case, you can just remove the code that checks if the region spans only one line (as in the latest update). Note that I have not tested it as I do not have access to my computer atm but I think it should work. – Qudit Mar 18 '18 at 22:33
  • 1
    @B_old I Happened to encounter the variable that controls adding the "'"'s while working on some other stuff. It's comment-continue and the latest update shouldn't add the extra ""'s. – Qudit Mar 22 '18 at 6:29
0

Try binding the my/comment-line-or-region function to M-; and see if works as you expect. It checks if a region is active, and, if so, runs the comment-region function; and if there's no region, it runs my/comment-slash, which inserts // in the beginning of the line.

(defun my/comment-slash()
  (interactive)
  (back-to-indentation)
  (insert "// "))

(defun my/comment-line-or-region()
  (interactive)
  (if (region-active-p)
      (comment-region (region-beginning) (region-end))
    (my/comment-slash)))
  • comment-dwim and comment-region do the same thing when there is an active region that is not commented out. – Qudit Mar 8 '18 at 21:32
  • @Qudit I might be missing something because I use evil and I'm not familiar with many emacs core commands, but for me comment-dwim puts a commentary at the end of the line, while comment-region says there's nothing to comment if no region is active. I think my answer covers what he's asked. – Jesse Mar 9 '18 at 0:32
  • There may be a setting you've changed somewhere. My comment refers to the behavior in vanilla Emacs (version 25.3). – Qudit Mar 9 '18 at 0:35
  • Did you try with c-mode? Emacs handles comments differently depending on current major mode. – Jesse Mar 9 '18 at 0:40
  • 1
    @Jesse, I tried the function, but it will still insert // everywhere. I think that is just how comment-region behaves in C++ mode. – B_old Mar 9 '18 at 9:17

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.