Emacs Lisp: How to Write Your Own Comment Command from Scratch
This page shows you how to write a command to insert/delete comment syntax chars of a programing language.
First, you should know about emacs's builtin comment package
newcomment.el. See: Emacs Lisp: How to Write Comment Command in Major Mode.
You want to write a emacs command to comment or uncomment code for your own language. You want to write it from scratch. (maybe because you don't like the newcomment.el behavior.)
The following code handles C++-style comment
// …. The code can be easily modified to handle any comment syntax that starts with a comment char and ends in a newline. (for example, Python's
It has 3 user-level functions:
- “my-comment-region” → prefix a
//to the beginning of each line in the text selection.
- “my-uncomment-region” → remove the first occurrence of
//(if any) in each line of the current text selection.
- “my-comment-dwim” → use a heuristic to decided to comment or uncomment.
“my-comment-dwim” is the general command. If there are no text selection, then it will comment or uncomment the current line, depending on whether the current line is a comment (If the comment start in the middle of the line, the line is not considered a comment). If there is a text selection, then it will comment or uncomment the whole region. Which action it does depends on whether the first line in selection is a comment line.
(defun my-comment-dwim () "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) (my-uncomment-region p1 p2) (my-comment-region p1 p2) )) (progn (if (wholeLineIsCmt-p) (my-uncomment-current-line) (my-comment-current-line) )) ))) (defun wholeLineIsCmt-p () (save-excursion (beginning-of-line 1) (looking-at "[ \t]*//") )) (defun my-comment-current-line () (interactive) (beginning-of-line 1) (insert "//") ) (defun my-uncomment-current-line () "Remove “//” (if any) in the beginning of current line." (interactive) (when (wholeLineIsCmt-p) (beginning-of-line 1) (search-forward "//") (delete-backward-char 2) )) (defun my-comment-region (p1 p2) "Add “//” 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) (previous-line) )))) (defun my-uncomment-region (p1 p2) "Remove “//” (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) (previous-line) )) ))
or, buy something from my keyboard store.