How to write an Emacs function to wrap the marked region with specified text - emacs

I'm not too familiar with elisp, and am trying to learn. In emacs, I'd like to be able to do the following:
Mark via C-space
Go to where I want the the marking to end, so I have a region that is highlighted, suppose it is "highlighted text"
Hit a key-sequence
Have emacs ask me to input some text, say "plot", and
Have that highlighted text change to be "plot(highlighted text)". That is, I'd like to wrap the highlited text with parentheses and precede it with the text I input.
(defun wrap-text ()
)
I suppose the input of the function would be the highlighted text, but I don't know where to start looking. The other hard part would be the input text part. Could someone guide me? Thanks.

For your case, this should work:
(defun wrap-text (b e txt)
"simple wrapper"
(interactive "r\nMEnter text to wrap with: ")
(save-restriction
(narrow-to-region b e)
(goto-char (point-min))
(insert txt)
(insert "(")
(goto-char (point-max))
(insert ")")))
(global-set-key (kbd "C-x M-w") 'wrap-text)

Something a bit closer to your version, but with some changes :
you can use 'let' to create a local-variable
region-beginning and region-end gives you the equivalent of what trey did with
Here is an example :
(defun wrap-in-function ()
"Wrap marked region with a specified PREFIX and closing parentheses."
(interactive)
(let ((prefix (read-from-minibuffer "function: ")))
(save-excursion
(goto-char (region-beginning))
(insert (concat prefix "(")))
(save-excursion
(goto-char (region-end))
(insert ")"))))
Another difference between the two versions is the position of the point after you called the function ; trey version might be better to use (matter of taste).
EDIT : edited following vinh remarks.

this requires 'cl but is otherwise pretty tiny. been using it for a few years.
(require 'cl) ;;if you haven't elsewhere
(defun decorate-region( beg end prefix suffix )
(interactive "r\nMPrefix: \nMSuffix: ")
(cl-set-buffer-substring beg end (concat prefix
(buffer-substring beg end)
suffix)))

thanks trey jackson. i didn't know u posted a solution so i went to #emacs on the freenode for help. after some research, i came up with the following:
(defun ess-R-wrap-content-vqn ()
"Wrap marked region with a specified PREFIX and closing parentheses."
(interactive)
(set (make-local-variable 'prefix) (read-from-minibuffer "function: "))
(set (make-local-variable 'prefix) (concat prefix "("))
(save-excursion (goto-char (region-beginning)) (insert prefix))
(save-excursion (goto-char (region-end)) (insert ")"))
)
(define-key ess-mode-map "\C-c\M-w" 'ess-R-wrap-content-vqn) ;; w is for wrap
i thought stackoverflow was going to notify me when a solution is posted. again, thanks. learning a little more of elisp from this.

Related

Eclipse-like Line Commenting in Emacs

In Eclipse, highlighting multiple rows and pressing Ctrl+/ comments each of the lines of the selection.
Emacs has a function comment-or-uncomment-region that is close what I want, but behaves differently if the region only partially covers the lines I'm trying to comment.
Is there any way I make a function similar to comment-or-uncomment-region, but have it comment each of the lines of the region regardless of how the region is selected?
In other words, I want the function to act as though the region occupies the whole line as long as the region includes that line, so it behaves as Eclipse's selection commenting does.
EDIT: I am actually using the comment-or-uncomment-region-or-line function mentioned as an answer instead of the function comment-or-uncomment-region that comes with Emacs.
I feel as though this is worth mentioning because the former seems to reflect how the line commenting works in Eclipse more. That is, the line the point is on is commented if no region exists.
I ended up combining parts from juanleon's and Ehvince's answers to get something just a little more like Eclipse's commenting.
Here is the final product:
(defun comment-eclipse ()
(interactive)
(let ((start (line-beginning-position))
(end (line-end-position)))
(when (or (not transient-mark-mode) (region-active-p))
(setq start (save-excursion
(goto-char (region-beginning))
(beginning-of-line)
(point))
end (save-excursion
(goto-char (region-end))
(end-of-line)
(point))))
(comment-or-uncomment-region start end)))
Please let me know if anything is wrong with it.
Note that emacs 25 has a new function comment-line bound to C-x C-;.
Here you have a function that do what you are describing:
(defun comment-or-uncomment-region-eclipse-style (beg end &optional arg)
(interactive "*r\nP")
(comment-or-uncomment-region
(save-excursion
(goto-char beg)
(beginning-of-line)
(point))
(save-excursion
(goto-char end)
(end-of-line)
(point)) arg))
FWIW, I don't use comment-or-uncomment-region. I use comment-region instead. It's similar, but it lets you decide whether to uncomment or comment. It lets you nest comments, instead of automatically uncommenting the region if it is already commented out. With a numeric prefix arg it uses that many comment-start chars (e.g., ;, ;;, ;;;,... in Lisp). With a plain C-u prefix arg it uncomments. I bind it to C-x C-;.
Anyway, I think this does what you want, using comment-region (see that for the general behavior):
(defun comment-region-lines (beg end &optional arg)
"Like `comment-region', but comment/uncomment whole lines."
(interactive "*r\nP")
(if (> beg end) (let (mid) (setq mid beg beg end end mid)))
(let ((bol (save-excursion (goto-char beg) (line-beginning-position)))
(eol (save-excursion (goto-char end) (line-end-position))))
(comment-region bol end arg)))
;; Suggested binding
(define-key ctl-x-map [(control ?\;)] 'comment-region-lines)
This saves and restores the region. And it works if only part of a single line is selected. I might even use it myself (which is saying quite a bit, since I have pretty set habits for this kind of thing).
Compared to Juanleon's solution, mine adds the fact that if you don't select a region it will (un)comment the current line and go the next line (instead of doing something based on marks you don't see):
(defun comment-or-uncomment-region-or-line ()
"Comments or uncomments the region or the current line if there's no active region."
(interactive)
(let (beg end)
(if (region-active-p)
(setq beg (region-beginning) end (region-end))
(setq beg (line-beginning-position) end (line-end-position)))
(comment-or-uncomment-region beg end)
(next-line)))
;; bind it to F7:
(global-set-key (kbd "<f7>")'comment-or-uncomment-region-or-line)
taken from: Emacs comment/uncomment current line
There is a file which provides the following
(defun ar-comment-or-uncomment-lor (&optional copy beg end)
"Comment line or region, unless it's already commented:
uncomment then.
..."
...
Afterwards cursor is at next line, which permits repeated execution.
With C-u the current line is copied and inserted as comment above - thus reminding the previous state when editing.
Get it here:
https://github.com/andreas-roehler/werkstatt/blob/master/ar-comment-lor.el
Here's a slight change to Ehvince's function which only advances to the next line if text was commented out. i.e., if uncommenting text, you usually want the cursor to remain.
(defun comment-or-uncomment-region-or-line ()
"Comments or uncomments the region or the current line if there's no active region."
(interactive)
(let (beg end)
(if (region-active-p)
(setq beg (region-beginning) end (region-end))
(setq beg (line-beginning-position) end (line-end-position)))
(comment-or-uncomment-region beg end)
(when (comment-only-p beg end)
(next-logical-line))))

A Simple 'copy-form Command

I want a command that copies a form to the kill ring. In emacs-live, the closest thing I could find was this command / key-binding
(global-set-key (kbd "M-]") 'kill-ring-save)
However kill-ring-save has some wonky behaviour. Ii copies more than 1 form, past the cursor. Ultimately, I want a simple function along the lines of what's below (this doesn't quite work).
(defun copy-form ()
(kill-ring-save (line-beginning-position) (live-paredit-forward)))
(global-set-key (kbd "M-]") 'copy-form)
I've searched high and low ( SO question and Google search), but can't seem to find a simple, working command to copy a balanced expression. Has someone already done this?
Thanks
Tim
Function sexp-at-point gives you the sexp ("form") at the cursor. Just copy that to the kill-ring, using kill-ring-save. E.g.:
(defun copy-sexp-at-point ()
(interactive)
(let ((bnds (bounds-of-thing-at-point 'sexp)))
(kill-ring-save (car bnds) (cdr bnds))))
Alternatively, just use kill-new:
(defun copy-sexp-at-point ()
(interactive)
(kill-new (thing-at-point 'sexp)))
The reason your copy-form cannot be bound to a key is that it is a function, not a command - it is missing an interactive form.
However, in your case you don't even need to write a new function.
Try a combination of
mark-sexp is an interactive compiled Lisp function in `lisp.el'.
It is bound to C-M-#, C-M-SPC.
and
M-w runs the command kill-ring-save, which is an interactive compiled
Lisp function in `simple.el'.
It is bound to <C-insertchar>, M-w, <menu-bar> <edit> <copy>.
I'm not sure I understand the question, but when I need to do what I consider as "copy a balanced form", I do: M-C-SPC M-w. If I want to cut it instead, I do M-C-SPC C-w.
Here's what I generally use. Somehow it's more useful for me
to kill the balanced expression instead of copying. If I want a
copy instead, I first kill, then undo.
This function kills a string, if the point is inside string,
otherwise the balanced expression, i.e. (),[],{},<>
or whatever is defined by the syntax.
(defun kill-at-point ()
"Kill the quoted string or the list that includes the point"
(interactive)
(let ((p (nth 8 (syntax-ppss))))
(cond
;; string
((eq (char-after p) ?\")
(goto-char p)
(kill-sexp))
;; list
((ignore-errors (when (eq (char-after) ?\()
(forward-char))
(up-list)
t)
(let ((beg (point)))
(backward-list)
(kill-region beg (point)))))))
I've also tried to add a special case for when the point is
inside the comment, but I couldn't find a generic
way to determine bounds of comment at point. If anyone knows,
please tell me.
This other function can be relevant as well. It marks instead
of killing, like the previous one. The nice thing that it
extends the region each time it's called.
I bind the first one to C-, and the second to
C-M-,.
(defun mark-at-point ()
"Mark the quoted string or the list that includes the point"
(interactive)
(let ((p (nth 8 (syntax-ppss))))
(if (eq (char-after p) ?\")
(progn
(goto-char p)
(set-mark (point))
(forward-sexp))
(progn
(when (eq (char-after) 40)
(forward-char))
(condition-case nil
(progn
(up-list)
(set-mark (point))
(let ((beg (point)))
(backward-list)
(exchange-point-and-mark)))
(error
(when (looking-back "}")
(exchange-point-and-mark)
;; assumes functions are separated by one empty line
(re-search-backward "^[^A-Z-a-z]" nil t)
(forward-char))))))))

Jump to the first occurrence of symbol in Emacs

I use the excellent highlight-symbol.el to move between different occurrences of the same symbol.
In this screenshot, foo_bar is highlighted, and I can call highlight-symbol-prev to jump to it. Note that this is syntax-aware, so it's smart enough to know that foo_bar_baz is different (something isearch doesn't understand).
I'd really like to be able to jump to the first occurrence of a symbol. This would be brilliant for finding where symbols were imported. How would I go about this?
Something along these lines should do what you want.
(defun goto-first-reference ()
(interactive)
(eval
`(progn
(goto-char (point-min))
(search-forward-regexp
(rx symbol-start ,(thing-at-point 'symbol) symbol-end))
(beginning-of-thing 'symbol))))
(eval-when-compile (require 'cl))
(require 'highlight-symbol)
(defmacro save-mark-ring (&rest body)
"Save mark-ring; execute BODY; restore the old mark-ring."
`(let ((old-mark-ring mark-ring))
,#body
(setq mark-ring old-mark-ring)))
(defun highlight-symbol-jump-to-first ()
"Jump to the first occurrence of the symbol at point."
(interactive)
(push-mark)
(save-mark-ring
(let (earliest-symbol-pos)
(loop do
(highlight-symbol-jump -1)
(setq earliest-symbol-pos (point))
while (< (point) earliest-symbol-pos)))))

Disable auto-fill-mode locally (or un fill-paragraph) with emacs

I use M-q for fill-paragraph, can I do the un-fill-paragraph in auto-fill-mode?
With org mode, I sometimes enter [[Very long HTML][Name with spaces]], and for the 'Name with spaces' the auto-fill mode break the whole line based on the inserted space, which makes it very ugly.
Is there a command something like un-fill-paragraph? Or, is there a way disable auto-fill-mode temporarily/locally?
Emacs does not record what was your line before calling fill-paragraph. So the only thing you can do is C-_ which runs the command undo. It can undo your fill-paragraph command but only if it is the preceding command call.
If you want to put a multi-line paragraph on one line you could do like this :
Select the region
C-M-% C-q C-j RET SPACE RET !
Xah Lee has updated his code since monotux's answer, and I refactored it somewhat for readability:
(defun my-toggle-fill-paragraph ()
;; Based on http://xahlee.org/emacs/modernization_fill-paragraph.html
"Fill or unfill the current paragraph, depending upon the current line length.
When there is a text selection, act on the region.
See `fill-paragraph' and `fill-region'."
(interactive)
;; We set a property 'currently-filled-p on this command's symbol
;; (i.e. on 'my-toggle-fill-paragraph), thus avoiding the need to
;; create a variable for remembering the current fill state.
(save-excursion
(let* ((deactivate-mark nil)
(line-length (- (line-end-position) (line-beginning-position)))
(currently-filled (if (eq last-command this-command)
(get this-command 'currently-filled-p)
(< line-length fill-column)))
(fill-column (if currently-filled
most-positive-fixnum
fill-column)))
(if (region-active-p)
(fill-region (region-beginning) (region-end))
(fill-paragraph))
(put this-command 'currently-filled-p (not currently-filled)))))
To remake a long line out of a paragraph in Org mode, I gave myself a new command. Here is the associated Emacs Lisp code:
(defun fp-unfill-paragraph (&optional justify region)
(interactive (progn
(barf-if-buffer-read-only)
(list (if current-prefix-arg 'full) t)))
(interactive)
(let ((fill-column 100000))
(fill-paragraph justify region)))
(global-set-key "\C-ceu" 'fp-unfill-paragraph)
Of course, you adjust the command keybinding as you see fit!
I use the following snippet to fill and un-fill paragraphs (using only M-q), it is really, really handy. I borrowed it from Xah Lee, but removed some comments and whitespace in order to make it fit in here. The link in the first comment goes to his original code.
;; http://xahlee.org/emacs/modernization_fill-paragraph.html
(defun compact-uncompact-block ()
"Remove or add line endings on the current block of text.
This is similar to a toggle for fill-paragraph and unfill-paragraph
When there is a text selection, act on the region.
When in text mode, a paragraph is considered a block. When in programing
language mode, the block defined by between empty lines.
Todo: The programing language behavior is currently not done.
Right now, the code uses fill* functions, so does not work or work well
in programing lang modes. A proper implementation to compact is replacing
newline chars by space when the newline char is not inside string.
"
(interactive)
(let (bds currentLineCharCount currentStateIsCompact
(bigFillColumnVal 4333999) (deactivate-mark nil))
(save-excursion
(setq currentLineCharCount
(progn
(setq bds (bounds-of-thing-at-point 'line))
(length (buffer-substring-no-properties (car bds) (cdr bds)))))
(setq currentStateIsCompact
(if (eq last-command this-command)
(get this-command 'stateIsCompact-p)
(if (> currentLineCharCount fill-column) t nil)))
(if (and transient-mark-mode mark-active)
(if currentStateIsCompact
(fill-region (region-beginning) (region-end))
(let ((fill-column bigFillColumnVal))
(fill-region (region-beginning) (region-end)))
)
(if currentStateIsCompact
(fill-paragraph nil)
(let ((fill-column bigFillColumnVal))
(fill-paragraph nil))))
(put this-command 'stateIsCompact-p
(if currentStateIsCompact
nil t)))))
(global-set-key (kbd "M-q") 'compact-uncompact-block)

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)