I want to copy a text from one buffer to another with text properties. So I have
(with-current-buffer from-buffer
(setq text-to-copy (buffer-substring beg end)))
How can I insert the text-to-copy to another buffer with all text properties? I'm interested especially in 'face' properties.
The function buffer-substring returns a list, for example ("substring" 42 51 (face font-lock-keyword-face) 52 59 (face font-lock-function-name-face))
If I pass this list to (insert text-to-copy) it seems that it ignores text properties
If font-lock-mode is turned on in the target buffer of insertion, the face property will be reset once the fontification kicks in. I think you'll need to either turn off font-lock-mode, or munge the text properties to replace 'face' with 'font-lock-face' before insertion.
The 'insert' function should handle strings that include text-properties, as-is. Since buffer-substring by default will return a string with text-properties if present, '(insert text-to-copy)' should be all you need to do.
If on the other hand you wanted to extract the string without the text-properties, you'd want to be using buffer-substring-no-properties instead
That should work. This is from Emacs 23.1.1:
buffer-substring is a built-in function in `C source code'.
(buffer-substring start end)
Return the contents of part of the current buffer as a string.
The two arguments start and end are character positions;
they can be in either order.
The string returned is multibyte if the buffer is multibyte.
This function copies the text properties of that part of the buffer
into the result string; if you don't want the text properties,
use `buffer-substring-no-properties' instead.
You can use the command describe-text-properties interactively to see what it is you actually got:
describe-text-properties is an interactive compiled Lisp function in
`descr-text.el'.
It is bound to <C-down-mouse-2> <dp>, <menu-bar> <edit> <props> <dp>.
(describe-text-properties pos &optional output-buffer)
Describe widgets, buttons, overlays and text properties at pos.
Interactively, describe them for the character after point.
If optional second argument output-buffer is non-nil,
insert the output into that buffer, and don't initialize or clear it
otherwise.
Related
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
I am learning how to use Emacs and org-mode, and am wondering whether Emacs can support tags within rather than just at the end of headlines (whether natively or through a package or configuration in ~/.emacs).
Put differently, Emacs natively supports tags in this form:
* This is a headline. :tag1:tag2:
Is there a way to get Emacs to recognize tags in the format below in addition?
* This is a headline with :tag1: and :tag2:.
I've been searching for answers for several hours, and haven't found this question anywhere else; I'd be grateful for any advice!
The real answer to this question is in #lawlist's comment above, that (to quote #lawlist) it "is not possible [to get org-mode to recognize tags within a line of text instead of at the end of the line] without substantially modifying several aspects of org-mode yourself."
For this reason, if #lawlist writes the comment up as an answer, I'll accept it. I'm also writing up this additional answer, though, for anyone like me who comes along and, learning this, wants a way to take some text and automatically generate org-mode tags for it. Following the discussion in the comments above, I've written a function in elisp below, which allows a user to highlight some text and automatically find any tags within the text (here, in the form {{tag}}) and concatenate them in org-mode tag format at the end of the first line.
(defvar tag-regexp-for-generating-org-mode-tag-list-from-text "{{\\(.*?\\)}}"
"A regular expression, in double-quotes, used for finding 'tags' within lines of text (these can then be translated into org-mode syntax tags.
For example, in the string \"This text contains the 'tags' {{tag1}} and {{tag2}}\", the default regular expression
\"{{\\(.*?\\)}}\"
would find \"tag1\" and \"tag2\", which could then be transformed into org-mode syntax tags, \":tag1:tag2:\"")
;; Following https://emacs.stackexchange.com/a/12335, use just the selected region.
(defun generate-org-mode-tag-list-from-selected-text (beginning-of-selected-region end-of-selected-region)
"Take a highlighted section of text, find all strings within that text that match the search parameters defined in the variable tag-regexp-for-generating-org-mode-tag-list-from-text (by default, strings of the form {{tag1}} {{tag2}}), and concatenate them into a set of org-mode tags (:tag1:tag2:)
When text is highlighted, the argumentes beginning-of-selected-region and end-of-selected-region will be automatically populated.
"
(interactive "r") ;; 'r' mode will auto-populate 'beginning-of-selected-region' and 'end-of-selected-region' above with the values of region-beginning and region-end.
(if (use-region-p) ;; If a region is actively highlighted
(progn ;; Start a multi-line sequence of commands
;; Following https://learnxinyminutes.com/docs/elisp/, go to the beginning-of-selected-region (here, of the selected region), and do a find-and-replace.
(setq list-of-tag-strings (list)) ;; Create a blank list, which we'll fill in below.
(goto-char beginning-of-selected-region) ;; Go to the beginning of the selected region (we'll then search forward from there.
;; A regex of "{{\\(.*?\\)}}" below looks for tags in {{this}} form. You can specify any other regex here instead.
(while (re-search-forward tag-regexp-for-generating-org-mode-tag-list-from-text end-of-selected-region 't) ;; Search forward, but only up to the end-point of the selected region (otherwise, end-of-selected-region could be replaced with nil here).
(add-to-list 'list-of-tag-strings ;; Add to the list called list-of-tag-strings
(replace-regexp-in-string "[[:space:]|:|-]+" "_" (match-string 1)) ;; Since org-mode tags cannot have spaces or colons (or dashes?) within them, replace any of those in the first capture group from the regular expression above ('match-string 1' returns whatever was in the parentheses in the regular expression above) with an underscore.
t) ;; Append (first checking for duplicate items) the first capture group from the regular expression above (i.e., what's inside the parentheses in the regular expression) to a list. The t tells the function to append (rather than prepend) to the list.
) ;; End of while statement
;; Go to the end of the first line of the selected region.
(goto-char beginning-of-selected-region)
(end-of-line)
(if (> (length list-of-tag-strings) 0) ;; If the length of the list of found tags is greater than 0:
(insert " " ":" (mapconcat 'identity list-of-tag-strings ":") ":")) ;; Insert two spaces, a ':', the items from the list each separated by a ':', and a final ':'.
(message "Tags gathered from the selected region (which comprises character markers %d to %d) and printed on the first line of the region." beginning-of-selected-region end-of-selected-region))
;; 'Else' part of the statement:
(message "No region is selected for gathering tags. To run the function, you need to highlight a region first.")
))
You can then highlight text like this, and run the function with M-x generate-tag-list-from-selected-text:
This is a test {{with}} some {{tags}} in it.
This is another test with an {{additional tag}} and {{one:more}}.
This text will then become
This is a test {{with}} some {{tags}} in it. :with:tags:additional_tag:one_more:
This is another test with an {{additional tag}} and {{one:more}}.
Since this is the first function I've written in elisp, I used two sources for understanding the basics of elisp syntax, specifically regarding a) using just a selected area of text and b) running find-and-replace operations on that text. Given that the function uses the generic structure of the code vs. its specific content, I'm thinking that I'm within my rights to open up the function with a CC0 dedication (I do this because of StackOverflow's ongoing discussion about licensing of code on this site).
I have file where some parts (lines) are fixed width, and other parts are free text.
The format of the fixed width lines behaves somewhat like a table.
Each line has a certain number of field, each field have a fixed length (in characters).
When editing these lines one should use something similar to overwrite-mode.
I am trying figure out how to solve this in Emacs Lisp.
Here is what I have so far:
(defun test-overlay ()
(interactive)
(let ((ovl (make-overlay 1 5 (current-buffer) t t)))
(overlay-put ovl 'face '(:background "grey50"))
(overlay-put ovl 'intangible t)
))
How can I make the overlay behave like the minor mode overwrite-mode?
That is, the overlay should not expand when text is added at the right edge.
When entering text, the text in the overlay should move to the left, the text at the left edge being chopped off (deleted). Pressing Delete at the right edge should delete characters at the right, moving in spaces at the left edge..
Instead of using overlays, use text properties --- specifically the text property read-only. Set its value to nil for the text you want to be writable, and to non-nil for text you want to be read-only. (There is no read-only overlay property.)
From (elisp) Special Properties:
`read-only'
If a character has the property `read-only', then modifying that
character is not allowed. Any command that would do so gets an
error, `text-read-only'. If the property value is a string, that
string is used as the error message.
Insertion next to a read-only character is an error if inserting
ordinary text there would inherit the `read-only' property due to
stickiness. Thus, you can control permission to insert next to
read-only text by controlling the stickiness. *Note Sticky
Properties::.
Since changing properties counts as modifying the buffer, it is not
possible to remove a `read-only' property unless you know the
special trick: bind `inhibit-read-only' to a non-`nil' value and
then remove the property. *Note Read Only Buffers::.
You need to use the modification-hooks property. That let you do the same kind of things as with after-change-functions and hence specify the exact behavior you're looking for.
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.
I want to copy a string to the clipboard (not a region of any particular buffer, just a plain string). It would be nice if it were also added to the kill-ring. Here's an example:
(copy-to-clipboard "Hello World")
Does this function exist? If so, what is it called and how did you find it? Is there also a paste-from-clipboard function?
I can't seem to find this stuff in the Lisp Reference Manual, so please tell me how you found it.
You're looking for kill-new.
kill-new is a compiled Lisp function in `simple.el'.
(kill-new string &optional replace yank-handler)
Make string the latest kill in the kill ring.
Set `kill-ring-yank-pointer' to point to it.
If `interprogram-cut-function' is non-nil, apply it to string.
Optional second argument replace non-nil means that string will replace
the front of the kill ring, rather than being added to the list.
Optional third arguments yank-handler controls how the string is later
inserted into a buffer; see `insert-for-yank' for details.
When a yank handler is specified, string must be non-empty (the yank
handler, if non-nil, is stored as a `yank-handler' text property on string).
When the yank handler has a non-nil PARAM element, the original string
argument is not used by `insert-for-yank'. However, since Lisp code
may access and use elements from the kill ring directly, the string
argument should still be a "useful" string for such uses.
I do this:
(with-temp-buffer
(insert "Hello World")
(clipboard-kill-region (point-min) (point-max)))
That gets it on the clipboard. If you want it on the kill-ring add a kill-region form also.
The command to put your selection on the window system clipboard is x-select-text. You can give it a block of text to remember. So a (buffer-substring (point) (mark)) or something should give you what you need to pass to it. In Joe's answer, you can see the interprogram-cut-function. Look that up for how to find this.
In my .emacs file, i use this
(global-set-key "\C-V" 'yank)
(global-set-key "\C-cc" 'kill-ring-save)
I could not use Ctrl-C (or System-copy), but this may be enough in case old habits kick in.