Command to uncomment multiple lines without selecting them - emacs

Is there a command in emacs to uncomment an entire comment block without having to mark it first?
For instance, let's say the point is inside a comment in the following code:
(setq doing-this t)
;; (progn |<--This is the point
;; (er/expand-region 1)
;; (uncomment-region (region-beginning) (region-end)))
I would like a command that turns that into this:
(setq doing-this t)
(progn
(er/expand-region 1)
(uncomment-region (region-beginning) (region-end)))
It's fairly easy to write a command that (un)comments a single line, but I've yet to find one that uncomments as many lines as possible. Is there one available?

A quick reply --- code could be improved and made more useful. You might want to extend it to other kinds of comments, besides ;;;, for instance.
(defun uncomment-these-lines ()
(interactive)
(let ((opoint (point))
beg end)
(save-excursion
(forward-line 0)
(while (looking-at "^;;; ") (forward-line -1))
(unless (= opoint (point))
(forward-line 1)
(setq beg (point)))
(goto-char opoint)
(forward-line 0)
(while (looking-at "^;;; ") (forward-line 1))
(unless (= opoint (point))
(setq end (point)))
(when (and beg end)
(comment-region beg end '(4))))))
The key is comment-region. FWIW, I bind comment-region to C-x C-;. Just use it with C-u to uncomment.

You can use Emacs' comment handling functions to make a generalised version of Drew's command.
(defun uncomment-current ()
(interactive)
(save-excursion
(goto-char (point-at-eol))
(goto-char (nth 8 (syntax-ppss)))
(uncomment-region
(progn
(forward-comment -10000)
(point))
(progn
(forward-comment 10000)
(point)))))

Related

The `last-command' variable in Emacs Lisp

I wrote a snippet to copy previous line to point,if I repeat the command,it copy more previous line. It's here:
(defun my-copy-line (num)
"copy lines"
(interactive "p")
(save-excursion
(move-end-of-line 1)
(push-mark)
(move-beginning-of-line num)
(kill-ring-save (point) (mark))))
(defvar copy-line-num 1)
(defun my-copy-line-here (num)
"copy line ahead here"
(interactive "p")
(if (eq this-command last-command)
(setq copy-line-num (+ copy-line-num num)) ;count num lines up
(setq copy-line-default 1))
(save-excursion
(save-excursion ;make current line blank
(move-beginning-of-line 1)
(push-mark)
(move-end-of-line 1)
(kill-region (point) (mark))) ;不用kill-line,以免删除空白行
(push-mark)
(previous-line copy-line-num)
(my-copy-line 1)
(exchange-point-and-mark)
(yank))
(setq this-command 'my-copy-line-here))
I intended to yank previous line to override current line.If I repeat my-copy-line-here,I'll yank the 2th previous line,this is accomplished by the test (if (eq this-command last-command).But it failed ,Because every time after executing my-copy-line-here,it sets the last-command to yank,instead my-copy-line-here.I just can't figure out what's going on.I need your help.
`M-y (yank-pop) works similarly, pasting previous copied lines on repeated calls. Checking its sources, I see two differences with yours:
; explicit check for yank
(if (not (eq last-command 'yank))
; setting this command
(setq this-command 'yank)
Perhaps one or both of these together can be useful. Set this-command after calling yank maybe?

Emacs - mark the word forward and backward

Basically what I am asking is the equivalent function to vim's vb(bbww...) and vw(wwbb...):
I want to bind my meta-j and meta-k to mark the word before and after current point. Simple.el provided the mark-word function, which I bind to meta-k. And I changed the mark-word function a bit to:
(defun mark-backward (&optional arg allow-extend) ;
(interactive "P\np")
(cond ((and allow-extend
(or (and (eq last-command this-command) (mark t))
(and transient-mark-mode mark-active)))
(setq arg (if arg (prefix-numeric-value arg)
(if (< (mark) (point)) -1 1)))
(set-mark
(save-excursion
(goto-char (mark))
(forward-word arg)
(point))))
(t (push-mark
(save-excursion
(backward-word (prefix-numeric-value arg))
(point)) nil t))))
(global-set-key (kbd "M-k") 'mark-word)
(global-set-key (kbd "M-j") 'mark-backward)
This kinda worked. I want to undo some marking use the other key, how can I do that? (i.e. after I marked some word with M-k, I want to use M-j to unmark some word to left. Currently, when I hit M-j, emacs continue to mark forward).
(defun my-mark-word (N)
(interactive "p")
(if (and
(not (eq last-command this-command))
(not (eq last-command 'my-mark-word-backward)))
(set-mark (point)))
(forward-word N))
(defun my-mark-word-backward (N)
(interactive "p")
(if (and
(not (eq last-command this-command))
(not (eq last-command 'my-mark-word)))
(set-mark (point)))
(backward-word N))
(local-set-key (kbd "M-k") 'my-mark-word)
(local-set-key (kbd "M-j") 'my-mark-word-backward)
This should emulate VIMs behaviour (with other keystrokes, of course).
Remark: M-j is by default bound to indent-new-comment-line which is quite handy when writing commented blocks in source code. M-k is by default bound to kill-sentence.
You should replace forward-word with backward-word in one more place.
The code, however, still have problems selecting words to the left of the point.
Ps. Please edit your post -- the code posted is barely readable.

How could I improve this solution to the "create index entries" exercise of Emacs Lisp Intro?

I've programmed this solution for the exercise from section 11.4 (Looping Exercise):
(defun texinfo-index-dfns-in-par ()
"Create an index entry at the beginning of the paragraph for every '#dfn'."
(interactive)
(save-excursion
(forward-paragraph)
(let ((bound (point)))
(backward-paragraph)
(let ((insert-here (point)))
(while (search-forward "#dfn{" bound t)
(let* ((start (point))
(end (1- (search-forward "}" bound)))
(dfn (buffer-substring start end)))
(save-excursion
(goto-char insert-here)
(newline)
(setq insert-here (point))
(insert "#cindex " dfn)
(while (< insert-here (line-beginning-position))
(join-line))
(end-of-line)
(setq insert-here (point))
(forward-paragraph)
(setq bound (point)))))))))
Though it's working, it feels much to convoluted to me. I'd like to know how this code could be simplified. I'm also interested in other possible improvements.
Edit:
Tyler's answer was great. With narrowing I could write a much shorter and cleaner version:
(defun texinfo-index-dfns-in-par ()
"Create an index entry at the beginning of the paragraph for every '#dfn'."
(interactive)
(save-excursion
(mark-paragraph)
(save-restriction
(narrow-to-region (point) (mark))
(while (search-forward "#dfn{" nil t)
(let ((start (point))
(end (1- (search-forward "}"))))
(save-excursion
(goto-char (point-min))
(insert "\n#cindex " (buffer-substring start end))
(while (> (line-number-at-pos) 2) (join-line))
(narrow-to-region (line-end-position) (point-max))))))))
One thing to look at is narrowing. You can use narrowing to get around a lot of the bouncing back and forth you're doing.
(mark-paragraph)
(narrow-to-region)
Will limit the scope of your function to the current paragraph and move point to the beginning. You can then start your forward search without worrying about moving past the current paragraph. When you're done,
(widen)
restores the rest of the buffer to view.
You could replace your search-forwards and buffer-substring with an re-search-forward and match-string (note: untested):
(while (re-search-forward "#dfn{\\([^}]+\\)}" nil t)
(save-excursion
(goto-char (point-min))
(insert "\n#cindex " (match-string 1))
(while (> (line-number-at-pos) 2) (join-line))
(narrow-to-region (line-end-position) (point-max))))

emacs delete-trailing-whitespace except current line

I recently added Emacs (delete-trailing-whitespace) function to my 'before-save-hook for some programming modes, but I find it rather frustrating that it deletes whitespace from the line I am currently editing. Any suggestions as to how to fix this problem?
Since delete-trailing-whitespace respects narrowing, one solution is to narrow the buffer to the portion before the current line and call it, then narrow to the portion after the current line and call it again:
(defun delete-trailing-whitespace-except-current-line ()
(interactive)
(let ((begin (line-beginning-position))
(end (line-end-position)))
(save-excursion
(when (< (point-min) begin)
(save-restriction
(narrow-to-region (point-min) (1- begin))
(delete-trailing-whitespace)))
(when (> (point-max) end)
(save-restriction
(narrow-to-region (1+ end) (point-max))
(delete-trailing-whitespace))))))
Put this function on your before-save-hook instead of delete-trailing-whitespace.
This wrapper for delete-trailing-whitespace can be used to do what you want:
(defun delete-trailing-whitespace-except-current-line ()
"do delete-trailing-whitespace, except preserve whitespace of current line"
(interactive)
(let ((current-line (buffer-substring (line-beginning-position) (line-end-position)))
(backward (- (line-end-position) (point))))
(delete-trailing-whitespace)
(when (not (string-equal (buffer-substring (line-beginning-position) (line-end-position))
current-line))
(delete-region (line-beginning-position) (line-end-position))
(insert current-line)
(backward-char backward))))
I ran into the same problem, and found out that ws-butler perfectly solves it.
There is a simple sample config code:
;; autoload ws-butler on file open
(add-hook 'find-file-hook #'ws-butler-global-mode)
(setq require-final-newline t)
I simply have a wrapper to make two calls to `delete-trailing-whitespace':
(defun modi/delete-trailing-whitespace-buffer ()
"Delete trailing whitespace in the whole buffer, except on the current line.
The current line exception is because we do want to remove any whitespace
on the current line on saving the file (`before-save-hook') while we are
in-between typing something.
Do not do anything if `do-not-delete-trailing-whitespace' is non-nil."
(interactive)
(when (not (bound-and-true-p do-not-delete-trailing-whitespace))
(delete-trailing-whitespace (point-min) (line-beginning-position))
(delete-trailing-whitespace (line-end-position) (point-max))))
(add-hook 'before-save-hook #'modi/delete-trailing-whitespace-buffer)

Move line/region up and down in emacs

What is the easiest way to move selected region or line (if there is no selection) up or down in emacs? I'm looking for the same functionality as is in eclipse (bounded to M-up, M-down).
Update: Install the move-text package from Marmalade or MELPA to get the following code.
Here's what I use, which works on both regions and individual lines:
(defun move-text-internal (arg)
(cond
((and mark-active transient-mark-mode)
(if (> (point) (mark))
(exchange-point-and-mark))
(let ((column (current-column))
(text (delete-and-extract-region (point) (mark))))
(forward-line arg)
(move-to-column column t)
(set-mark (point))
(insert text)
(exchange-point-and-mark)
(setq deactivate-mark nil)))
(t
(let ((column (current-column)))
(beginning-of-line)
(when (or (> arg 0) (not (bobp)))
(forward-line)
(when (or (< arg 0) (not (eobp)))
(transpose-lines arg)
(when (and (eval-when-compile
'(and (>= emacs-major-version 24)
(>= emacs-minor-version 3)))
(< arg 0))
(forward-line -1)))
(forward-line -1))
(move-to-column column t)))))
(defun move-text-down (arg)
"Move region (transient-mark-mode active) or current line
arg lines down."
(interactive "*p")
(move-text-internal arg))
(defun move-text-up (arg)
"Move region (transient-mark-mode active) or current line
arg lines up."
(interactive "*p")
(move-text-internal (- arg)))
(global-set-key [M-S-up] 'move-text-up)
(global-set-key [M-S-down] 'move-text-down)
A line can be moved using transpose-lines bound to C-x C-t. I don't know about regions, though.
I found this elisp snippet that does what you want, except you need to change the bindings.
(defun move-text-internal (arg)
(cond
((and mark-active transient-mark-mode)
(if (> (point) (mark))
(exchange-point-and-mark))
(let ((column (current-column))
(text (delete-and-extract-region (point) (mark))))
(forward-line arg)
(move-to-column column t)
(set-mark (point))
(insert text)
(exchange-point-and-mark)
(setq deactivate-mark nil)))
(t
(beginning-of-line)
(when (or (> arg 0) (not (bobp)))
(forward-line)
(when (or (< arg 0) (not (eobp)))
(transpose-lines arg))
(forward-line -1)))))
(defun move-text-down (arg)
"Move region (transient-mark-mode active) or current line
arg lines down."
(interactive "*p")
(move-text-internal arg))
(defun move-text-up (arg)
"Move region (transient-mark-mode active) or current line
arg lines up."
(interactive "*p")
(move-text-internal (- arg)))
(global-set-key [\M-\S-up] 'move-text-up)
(global-set-key [\M-\S-down] 'move-text-down)
You should try drag-stuff !
It works exactly like eclipse Alt+Up/Down for single lines, as well as for selected region lines!
In addition to that it allows you to move words with Alt+Left/Right
This is exactly what you're looking for! And it is even available from the ELPA repos!
Other solutions never worked for me. Some of them were buggy(transposing lines while changing their order, wtf?) and some of them were moving exactly selected region, leaving unselected parts of the lines on their positions. But drag-stuff works exactly like in eclipse!
And even more! You can try selecting a region and using Alt+Left/Right ! This will transpose selected region by one character to the left or right. Amazing!
To enable it globally simply run this:
(drag-stuff-global-mode)
I have written a couple of interactive functions for moving lines up/down:
;; move line up
(defun move-line-up ()
(interactive)
(transpose-lines 1)
(previous-line 2))
(global-set-key [(control shift up)] 'move-line-up)
;; move line down
(defun move-line-down ()
(interactive)
(next-line 1)
(transpose-lines 1)
(previous-line 1))
(global-set-key [(control shift down)] 'move-line-down)
The keybindings are IntelliJ IDEA style, but you can use anything you want. I should probably implement some functions that operate on regions as well.
Here is my snippet to move the current line or the lines spanned by the active region. It respects cursor position and highlighted region. And it won't break lines when the region doesn't begin/end at line border(s). (It is inspired by eclipse; I found the eclipse way more convenient than 'transpose-lines'.)
;; move the line(s) spanned by the active region up/down (line transposing)
;; {{{
(defun move-lines (n)
(let ((beg) (end) (keep))
(if mark-active
(save-excursion
(setq keep t)
(setq beg (region-beginning)
end (region-end))
(goto-char beg)
(setq beg (line-beginning-position))
(goto-char end)
(setq end (line-beginning-position 2)))
(setq beg (line-beginning-position)
end (line-beginning-position 2)))
(let ((offset (if (and (mark t)
(and (>= (mark t) beg)
(< (mark t) end)))
(- (point) (mark t))))
(rewind (- end (point))))
(goto-char (if (< n 0) beg end))
(forward-line n)
(insert (delete-and-extract-region beg end))
(backward-char rewind)
(if offset (set-mark (- (point) offset))))
(if keep
(setq mark-active t
deactivate-mark nil))))
(defun move-lines-up (n)
"move the line(s) spanned by the active region up by N lines."
(interactive "*p")
(move-lines (- (or n 1))))
(defun move-lines-down (n)
"move the line(s) spanned by the active region down by N lines."
(interactive "*p")
(move-lines (or n 1)))
There is an entry in the emacs wiki just for this:
http://www.emacswiki.org/emacs/MoveLine
For moving regions:
http://www.emacswiki.org/emacs/MoveRegion
There's no built-in. You can use transpose-lines (C-x C-t) but you cannot use it repeatedly. Look at the functions on http://www.schuerig.de/michael/blog/index.php/2009/01/16/line-movement-for-emacs/.
It should be easy to adapt that to regions, too.
The transpose-paragraph function could help you.
You might also want to have a look to the transpose section in the Emacs manual.
Essentially:
C-t
Transpose two characters (transpose-chars).
M-t
Transpose two words (transpose-words).
C-M-t
Transpose two balanced expressions (transpose-sexps).
C-x C-t
Transpose two lines (transpose-lines).
I use the smart-shift package (in Melpa) for this. By default it rebinds C-C <arrow> to move a line or region. It moves horizontally by a major-mode-specific amount (e.g. c-basic-offset or python-indent-offset). Works on regions also.
;; binds C-C <arrows>
(when (require 'smart-shift nil 'noerror)
(global-smart-shift-mode 1))