Reputation: 3811
I have written a small function to reverse the items in the marked region using the comma as item separator. The function code is:
(defun reverse-list (beg end)
"Reverses a list in-place, where comma ',' is the list item separator."
(interactive "r")
(if (region-active-p)
(let ((region-list (reverse (split-string (region-as-string) ","))))
(kill-region beg end)
(loop for s in region-list do (progn
(insert (chomp s))
(insert ", ")))
(delete-char -2))
(message "Error: No region selected!")))
where chomp
strips leading/trailing whitespace from a string and region-as-string
yields the region as a string.
The function is very useful, however it would be great to be able to select the separator on the fly. The behaviour I'm looking for is:
C-u
) ask the user to input a (possibly multi-char) separator string I tried to achieve this, but haven't been successful in doing so. It would be great if you could provide help!
Thanks in advance,
elemakil
Upvotes: 4
Views: 903
Reputation: 65854
You can use the interactive code P
to read the "raw" prefix argument. This is nil
if there was no prefix argument, and non-nil
if there was a prefix argument, so you can test this and decide whether to set the separator to ","
or to use read-string
to prompt the user to enter it.
Also, I'd make the following comments on your code:
Your function only works if called interactively, so that beg
and end
are really the beginning and end of the region. If called non-interactively, these might not match (or there might not even be a region) and in that case your function will go wrong (because it deletes the buffer between beg
and end
but inserts the reversal of the region). So you need to call (buffer-substring beg end)
, not (region-as-string)
.
[Edited, see comments] It's not a good idea to raise an error in the case where the region is inactive. In Emacs, the region continues to exist even when it's inactive (that is, no longer highlighted). Or the user might have turned off transient-mark-mode
and so never have an active region at all. In both cases, the user might still want to run your command.
At most, you might change the behavior of the command when the region is active (see for example, comment-dwim
).
You delete the region by calling kill-region
, which copies the removed text to the kill-ring. Is this really what you want to do? It might surprise the user. It's better to call delete-region
unless you actually mean to save the deleted text.
You don't ensure that point is in the right place before you start calling insert
. In interactive use, you'll get away with it, but for non-interactive use point could be anywhere, so you ought to move it explicitly. And also use save-excursion
, of course.
It seems very inelegant to insert an extra ", "
and then have to delete it afterwards. Better not to insert it in the first place.
Here's some revised code that fixes all of the above:
(defun reverse-list (beg end read-separator)
"Reverse the region in-place, treating it as a list of items
separated by commas. With a prefix argument, prompt for the
separator."
(interactive "r\nP")
(save-excursion
(let* ((separator (if read-separator (read-string "Separator: ") ","))
(region-list (nreverse (split-string (buffer-substring beg end) separator)))
(separator (concat separator " ")))
(goto-char beg)
(delete-region beg end)
(loop for s in region-list
for sep = "" then separator
do (insert sep) (insert (chomp s))))))
Upvotes: 7
Reputation: 2915
r -- Region: point and mark as 2 numeric args, smallest first. Does no I/O.
Because r
is always the first two argument. If you use C-u to pass arguments. Then you may need to pass the argument to the third argument as separator. But you can not pass the third argument without the first and second argument. (I am not sure here. I am a beginner too)
I purpose you to use a r
and a s
option to achieve it. Though you always need to provide the separator argument.
Example:
(defun reverse-list (beg end &optional sepeartor )
(interactive "r
ssepeartor:")
(princ beg)
(princ "*")
(princ end)
(princ sepeartor))
Upvotes: -1