Get the content as string of a region in a buffer by elisp program - emacs

Here is the problem that I'm solving:
Convert a region of text into a string data structure for subsequent processing by elisp program. The challenge is that
I want to execute an elisp program interactively without affecting the selection of a region
store the string value into a variable so that I can further manipulate it.
By my understanding, a region is defined by a mark and the subsequent cursor position. And I usually execute elisp program in *scratch* buffer. Furthermore, the region is also in the *scratch* buffer.
But to write the function call and execute it in the buffer, I need to move the cursor away from the end of the text selection (region) in order to write the program of
(setq grabbed (buffer-substring-no-properties (region-beginning) (region-end)))
but then the region of selection would change due to the cursor movement.
So I wonder how I could execute the elisp program while keeping the selection intact and still can access the return value.

If you want to run the function from some Elisp code but as if the user had invoked it via a keybinding, you can use call-interactively:
(setq variable-to-keep-the-value (call-interactively 'lines-to-list))
But in most cases, what you want instead is to take yourself the responsibility to choose to which part of text the function should apply:
(setq variable-to-keep-the-value
(lines-to-list (region-beginning) (region-end)))
Notice that the region's boundaries are nothing magical, regardless if they've been set by the mouse or what.

Finally, I found a desirable solution! It's using ielm buffer, the real repl of elisp.
In the ielm buffer, I can set working buffer (by C-c C-b) to be a buffer where I have the text to be manipulated, for example, *scratch*.
I can then select a region of the working buffer to be processed, and in the ielm buffer then I can type and execute elisp code to extract the text in the selected region in the working buffer, for example,
ELISP> (setq grabbed (buffer-substring-no-properties (region-beginning) (region-end)))
"One\nTwo\nThre"
ELISP> grabbed
"One\nTwo\nThre"
ELISP> (split-string grabbed)
("One" "Two" "Thre")
I can then work with the value held by the set variable, grabbed.
Here is a very helpful description of ielm:
https://www.masteringemacs.org/article/evaluating-elisp-emacs

Related

emacs dispatch help window from original buffer

Whenever I do apropos, describe-key, or some other help function in emacs, it displays the help in my other window. In order to get rid of it, I must change windows/buffers to go there, type "q", and then change back to my original working buffer.
Is there a way I can do this in code somehow? I know how to save-excursion, switch buffers, etc, but I don't know how to send the "q" to the minibuffer/emacs while I'm over in the other buffer. Thanks
The help-window-select variable might be exactly what you want.
If you set its value to true (setq help-window-select t) then the help window will automatically be selected when you open it via one of the help commands. You can then press q to quit out of it and go back to your original buffer. There are many other options so you should check those out too.
For the apropos window or any window that uses display-buffer you can use.
(add-to-list 'display-buffer-alist
'("*Apropos*" display-buffer-same-window))
display-buffer-same-window is one options of many; it opens the buffer in the current window. The other possible options can be seen by looking up the docs on the display-buffer function.
Here's my solution to this problem. I bind this command to C-c q:
(defvar my/help-window-names
'(
;; Ubiquitous help buffers
"*Help*"
"*Apropos*"
"*Messages*"
"*Completions*"
;; Other general buffers
"*Command History*"
"*Compile-Log*"
"*disabled command*")
"Names of buffers that `my/quit-help-windows' should quit.")
(defun my/quit-help-windows (&optional kill frame)
"Quit all windows with help-like buffers.
Call `quit-windows-on' for every buffer named in
`my/help-windows-name'. The optional parameters KILL and FRAME
are just as in `quit-windows-on', except FRAME defaults to t (so
that only windows on the selected frame are considered).
Note that a nil value for FRAME cannot be distinguished from an
omitted parameter and will be ignored; use some other value if
you want to quit windows on all frames."
(interactive)
(let ((frame (or frame t)))
(dolist (name my/help-window-names)
(ignore-errors
(quit-windows-on name kill frame)))))
I suggest putting (winner-mode 1) in your init file, and then using C-c<left> to call winner-undo (repeatedly, if necessary) to return to a previous window configuration.

&optional BUFFER for other-buffer function does not work?

When I need to switch to another buffer I have a key binding that will create a buffer called "*Buffer List*" from which I select the new buffer.
I need a command to switch between current buffer and the previous one. Except I don't want "*Buffer List*". I looked up function definition for other-buffer:
(other-buffer &optional BUFFER VISIBLE-OK FRAME)
Return most recently selected buffer other than BUFFER...
so I tried using:
(other-buffer "*Buffer List*")
Now if in the new buffer I execute above code with C-x C-e it will echo "*Buffer List*", instead of the initial buffer that I called "*Buffer List*" from. So &optional BUFFER does not seem to work the way I do it. Can anyone explain why?
BUFFER must be a buffer object. To use the buffer name you would need to use:
(other-buffer (get-buffer "*Buffer List*"))
Notice that when you can use a buffer's name as the argument, the documentation tends to name that argument BUFFER-OR-NAME (e.g. see the docstring for get-buffer itself), and to be explicit about the fact in the text.
If you see BUFFER as an argument, it likely requires the actual buffer object (as in this instance).

Open selection in different major mode.

Is it possible to select some parts of a text and open it in a different buffer with a different mode?
Fore example, if I often work in ESS mode (syntax highlighting for R),
astring <- '<form>
<input type="checkbox" id="foo", value="bar">
</form>'
if the text within the single quotes is selected, I would like to edit it in a new buffer HTML mode (similar to org-src-lang-modes in orgmode).
What you're describing is called an 'indirect buffer'. You create one by calling M-x clone-indirect-buffer. This creates a second copy of the buffer you're editing. Any changes made in one buffer are mirrored in the other. However, both buffers can have different major modes active, so one can be in ESS mode, and the other in HTML (or whatever you like).
See the manual for details.
Here is one method of handling the issue using narrow-to-region -- the example contemplates that the point (cursor) will be somewhere between the single quotes when typing M-x narrow-to-single-quotes. A simple two-line function can be used to exit -- (widen) (ess-mode); or, you can get fancy with recursive-edit. Of course, this is not the same as opening the text in a new buffer. A similar functionality can also be used to copy the region to a new buffer, but I am assuming that the original poster may want to incorporate the edited text back into the primary buffer.
(defun narrow-to-single-quotes ()
"When cursor (aka point) is between single quotes, this function will narrow
the region to whatever is between the single quotes, and then change the
major mode to `html-mode`. To exit, just type `M-x widen` and then
`M-x [whatever-previous-major-mode-was-used]`."
(interactive)
(let* (
(init-pos (point))
beg
end)
(re-search-backward "'" nil t)
(forward-char 1)
(setq beg (point))
(re-search-forward "'" nil t)
(backward-char 1)
(setq end (point))
(narrow-to-region beg end)
(html-mode)
(goto-char init-pos)))

A basic function for emacs

I have never written an emacs function before and was wondering if anyone could help me get started. I would like to have a function that takes a highlighted region parses it (by ",") then evaluates each chunk with another function already built into emacs.
The highlighted code may look something like this: x <- function(w=NULL,y=1,z=20){} (r code), and I would like to scrape out w=NULL, y=1, and z=20 then pass each one a function already included with emacs. Any suggestions on how to get started?
A lisp function is defined using defun (you really should read the elisp intro, it will save you a lot of time - "a pint of sweat saves a gallon of blood").
To turn a mere function into an interactive command (which can be called using M-x or bound to a key), you use interactive.
To pass the region (selection) to the function, you use the "r" code:
(defun my-command (beg end)
"Operate on each word in the region."
(interactive "r")
(mapc #'the-emacs-function-you-want-to-call-on-each-arg
;; split the string on any sequence of spaces and commas
(split-string (buffer-substring-no-properties beg end) "[ ,]+")))
Now, copy the form above to the *scratch* emacs buffer, place the point (cursor) on a function, say, mapc or split-string, then hit C-h f RET and you will see a *Help* buffer explaining what the function does.
You can evaluate the function definition by hitting C-M-x while the point is on it (don't forget to replace the-emacs-function-you-want-to-call-on-each-arg with something meaningful), and then test is by selecting w=NULL,y=1,z=20 and hitting M-x my-command RET.
Incidentally, C-h f my-command RET will now show Operate on each word in the region in the *Help* buffer.

Emacs - noninteractive call to shell-command-on-region always deletes region?

The Emacs Help page for the function shell-command-on-region says (elided for space):
(shell-command-on-region START END COMMAND &optional OUTPUT-BUFFER
REPLACE ERROR-BUFFER DISPLAY-ERROR-BUFFER)
...
The noninteractive arguments are START, END, COMMAND,
OUTPUT-BUFFER, REPLACE, ERROR-BUFFER, and DISPLAY-ERROR-BUFFER.
...
If the optional fourth argument OUTPUT-BUFFER is non-nil,
that says to put the output in some other buffer.
If OUTPUT-BUFFER is a buffer or buffer name, put the output there.
If OUTPUT-BUFFER is not a buffer and not nil,
insert output in the current buffer.
In either case, the output is inserted after point (leaving mark after it).
If REPLACE, the optional fifth argument, is non-nil, that means insert
the output in place of text from START to END, putting point and mark
around it.
This isn't the clearest, but the last few sentences just quoted seem to say that if I want the output of the shell command to be inserted in the current buffer at point, leaving the other contents of the buffer intact, I should pass a non-nil argument for OUTPUT-BUFFER and nil for REPLACE.
However, if I execute this code in the *scratch* buffer (not the real code I'm working on, but the minimal case that demonstrates the issue):
(shell-command-on-region
(point-min) (point-max) "wc" t nil)
the entire contents of the buffer are deleted and replaced with the output of wc!
Is shell-command-on-region broken when used non-interactively, or am I misreading the documentation? If the latter, how could I change the code above to insert the output of wc at point rather than replacing the contents of the buffer? Ideally I'd like a general solution that works not only to run a command on the entire buffer as in the minimal example (i.e., (point-min) through (point-max)), but also for the case of running a command with the region as input and then inserting the results at point without deleting the region.
You are wrong
It is not a good idea to use an interactive command like shell-command-on-region in emacs lisp code. Use call-process-region instead.
Emacs is wrong
There is a bug in shell-command-on-region: it does not pass the replace argument down to call-process-region; here is the fix:
=== modified file 'lisp/simple.el'
--- lisp/simple.el 2013-05-16 03:41:52 +0000
+++ lisp/simple.el 2013-05-23 18:44:16 +0000
## -2923,7 +2923,7 ## interactively, this is t."
(goto-char start)
(and replace (push-mark (point) 'nomsg))
(setq exit-status
- (call-process-region start end shell-file-name t
+ (call-process-region start end shell-file-name replace
(if error-file
(list t error-file)
t)
I will commit it shortly.
If you follow the link to the functions' source code, you'll quickly see that it does:
(if (or replace
(and output-buffer
(not (or (bufferp output-buffer) (stringp output-buffer)))))
I don't know why it does that, tho. In any case, this is mostly meant as a command rather than a function; from Elisp I recomend you use call-process-region instead.
In my case (emacs 24.3, don't know what version you're using), the documentation is slightly different in the optional argument:
Optional fourth arg OUTPUT-BUFFER specifies where to put the
command's output. If the value is a buffer or buffer name, put
the output there. Any other value, including nil, means to
insert the output in the current buffer. In either case, the
output is inserted after point (leaving mark after it).
The code that checks whether to delete the output (current) buffer contents is the following:
(if (or replace
(and output-buffer
(not (or (bufferp output-buffer) (stringp output-buffer)))))
So clearly putting t as in your case, it is not a string or a buffer, and it is not nil, so it will replace current buffer contents with the output. However, if I try:
(shell-command-on-region
(point-min) (point-max) "wc" nil nil)
then the buffer is not deleted, and the output put into the "Shell Command Output" buffer. At first sight, I'd say the function is not correctly implemented. Even the two versions of the documentation seem not to correspond with the code.