Some emacs functions takes a user input string as argument. For example, M-x search-forward, takes a user input string and search for it in buffer.
There are some search string that I uses frequently. Hence I would like to make my own function and hard-code this search string as a parameter for search-forward. For this function search-forward, this is easy because this function's function parameter list has a parameter for search string, as in its defun declaration: (search-forward STRING &optional BOUND NOERROR COUNT). I can just pass the string into STRING paramater.
But for some other function that does similar string search, it does not specify the search string as a parameter. For example, in Magnar's multiple-cursor library, mc/mark-all-in-region-regexp, is a function that search for regexp string provided by user. I would like to make my own short-cut function that takes a fixed string, say, "abc". However, mc/mark-all-in-region-regexp 's parameter list does not have a parameter for search string. Here is the function parameter list: (mc/mark-all-in-region-regexp BEG END). It only has parameter for the region begin and end position. However, if you execute it as a M-x command, i.e. M-x mc/mark-all-in-region-regexp ENTER, then it prompt you to enter the search string.
My question is, how do I write my function, to pass my search string into mc/mark-all-in-region-regexp?
My initial trial is like this. But not achieving what I expected.
(defun my-mc-mark-non-empty-lines ()
(interactive)
(mc/mark-all-in-region)
(insert-string "abc")
)
When crafting a programmatic solution that deals with a function originally designed to request input from the user, it is generally advisable to devise a means to pass a value in the form of an argument or have the value derived from a variable.
For example, the author of the function at issue previously created an additional argument in a commit on April 3, 2015 -- the following is the diff -- i.e., - means removed, + means added.
-(defun mc/mark-all-in-region (beg end)
+(defun mc/mark-all-in-region (beg end &optional search)
"Find and mark all the parts in the region matching the given search"
(interactive "r")
- (let ((search (read-from-minibuffer "Mark all in region: "))
+ (let ((search (or search (read-from-minibuffer "Mark all in region: ")))
(case-fold-search nil))
(if (string= search "")
(message "Mark aborted")
The following link contains an example to programmatically input a yes/no response requested by the user (which is kind of semi-related to your question), but there are already 7 upvotes to the comment by Drew wherein he stated don't do that: https://emacs.stackexchange.com/questions/19077/how-to-programmatically-answer-yes-to-those-commands-that-prompt-for-a-decisio
Related
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 would like to be able to store text between 2 positions (the string in between), but I don't know where to conveniently store it, perhaps just locally, or even globally (let or setq). The answer is probably out there, but I couldn't find it.
Example:
I would like to store text in a symbol in order to search for it backwards. Let's say the region from (point) until the first whitespace character.
My previous way of doing this was using (kill-ring-save), but I know this is a bad practice.
From (here) (message "hello")(point)
I would be interested in both better techniques for doing this, as well as the best way to store a string which is somehwere around (point).
The regular no-frills answer would be to just use let. Contrary to what you seem to believe, it does not allocate global storage. In fact, it does just the opposite.
(let ((myvalue "temporary string"))
(message myvalue) )
=> "temporary string"
myvalue
=> Lisp error: (void-variable myvalue)
And you can easily write a function with a variable whose value is set only during the function's execution. The interactive form allows you to easily obtain the values of point and mark.
(defun mysearch (point mark)
(interactive "r")
(let ((str (buffer-substring-no-properties point mark))
(message "your search for %s can commence ..." str) ) )
A common idiom is to use save-excursion to move point to another place, then grab the region between the original location and where you ended up, then do something with it. When you exit the save-excursion, the cursor's position (and several other things) will be restored to how they were before.
(defun mysearch ()
(interactive)
(save-excursion
(let ((here (point)) str)
(forward-word -1)
(setq str (buffer-substring-no-properties (point) here))
(message "your search for %s can commence ..." str) ) ) )
Perhaps you also want to look at http://ergoemacs.org/emacs/elisp_idioms.html
If you need to persist the value between function invocations, then the common thing to do is to defvar a variable like #phils suggests. Several variables with a common prefix sounds like you should be creating a separate module for yourself. For a flexible solution with low namespace footprint, create your own obarray (and achieve some sort of guru status). See also http://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html#Definition%20of%20mapatoms
If a temporary local scope is all you require, then you definitely want to use let.
Otherwise you would usually define a variable (keeping in mind when you name it that elisp has no name spaces, so best practice is to use as reliably unique a prefix for all symbol names in a given library as practical).
(defvar SYMBOL &optional INITVALUE DOCSTRING)
If you omit the INITVALUE argument, the variable will not be bound initially, but ensures that your variable will use dynamic binding once used.
Then you just setq the variable as required.
Edit:
To obtain a buffer's contents between two points, use either of
(buffer-substring START END)
(buffer-substring-no-properties START END)
depending on whether or not you wish to preserve text properties.
I'm trying to get create a capture template that converts an URL to an org-mode link with the <title> as the link name.
My conversion function looks like this:
(defun get-page-title (url)
"Get title of web page, whose url can be found in the current line"
;; Get title of web page, with the help of functions in url.el
(with-current-buffer (url-retrieve-synchronously url)
;; find title by grep the html code
(goto-char 0)
(re-search-forward "<title>\\([^<]*\\)</title>" nil t 1)
(setq web_title_str (match-string 1))
;; find charset by grep the html code
(goto-char 0)
;; find the charset, assume utf-8 otherwise
(if (re-search-forward "charset=\\([-0-9a-zA-Z]*\\)" nil t 1)
(setq coding_charset (downcase (match-string 1)))
(setq coding_charset "utf-8")
;; decode the string of title.
(setq web_title_str (decode-coding-string web_title_str (intern
coding_charset)))
)
(concat "[[" url "][" web_title_str "]]")
))
When called from normal emacs lisp code it returns the correct result. But when used in this org-capture-template it only returns bad url.
setq org-capture-templates
(quote
(("l" "Link" entry (file+headline "" "Links")
"* \"%c\" %(get-page-title \"%c\")"))))
Is the order of expansion different? Do I need to escape the string differently? Magic?
The first %c is only their to debug the string and indeed is getting printed as "url".
Please don't even bother pointing out that parsing XML with regexp is the wrong approach. Cthulhu is already haunting me and this isn't going to make it worse.
The problem is the order of expansion of template parameters. The simple % templates are expanded after the sexp has been evaluated. The original error message still contains a template and thus is expanded into the contents of the clipboard and thus the error message contains not the string that was originally passed to get-page-title.
The solution is to access the kill ring from within the sexp:
%(get-page-title (current-kill 0))
EDIT This behavior is now documented in org-mode.
Wouldn't the solution be to use org-protocol.el?
http://orgmode.org/worg/org-contrib/org-protocol.html
I just tested it with the following template (adding a sub-heading for your desired title as headline).
Template:
("t"
"Testing Template"
entry
(file+headline "~/org/capture.org" "Testing")
"* %^{Title}\n** %:description\n\n Source: %u, %c\n\n%i"
:empty-lines 1)
Then using a browser-based keybind (in my case with Opera, although examples for Firefox, Uzbl, Acrobat and Conkeror are provided as well) I was able to capture the following:
** Testing for StackExchange
*** org-protocol.el - Intercept calls from emacsclient to trigger custom actions
Source: [2011-08-05 Fri], [[http://orgmode.org/worg/org-contrib/org-protocol.html]
[org-protocol.el - Intercept calls from emacsclient to trigger custom actions]]
org-protocol intercepts calls from emacsclient to trigger custom actions
without external dependencies.
(I broke the org-link simply to keep the scrolling to a minimum, it was not on two lines originally)
#aboabo shared an undocumented variable in https://stackoverflow.com/a/21080770/255961 that provides a more general solution to the question's topic of how to use sexp with keyword values in a template (beyond kill ring). The variable org-store-link-plist stores all the information being passed to the capture. So you can access its values directly from a function like this:
(defun url()
(plist-get org-store-link-plist :url))
("w" "capture" entry (file "~/refile.org")
"* [[%:link][%:description]] :NOTE:\n%(url)%U\n"
:immediate-finish t)
PS, According to the manual page (quote below) it sounds to me like your approach in teh question should work also. But I agree what you describe is what seems to be actually happening - it seems like a bug relative to the manual.
%(sexp) Evaluate Elisp sexp and replace with the result. For convenience,
%:keyword (see below) placeholders within the expression will be
expanded prior to this.
I'm new to elisp. http://www.gnu.org/s/emacs/manual/html_node/elisp/Interactive-Codes.html#Interactive-Codes lists 'code characters' for interactive parameters, which AFAIK modifies the behaviour of the input mechanism when prompting the user for input (eg: if you specify that the input is a filename that exists, emacs' autocomplete functionality will look for file names that exists).
I'm trying to find a code for a bookmark name that already exists - ie: emacs will prompt the user for a bookmark name, and upon pressing tab emacs will show possible bookmark name completions.
Does such a code exist?
Use completing-read for that. You could write a function that prompts the user for a bookmark like so:
(defun my-function ()
(interactive)
(let ((bookmark (completing-read "Bookmark: " (bookmark-all-names))))
...))
If you prefer the prompting to be part of interactive (so that the result will be bound automatically to your function's arguments), you could use the following alternative:
(defun my-function (bookmark)
(interactive (list (completing-read "Bookmark: " (bookmark-all-names))))
...)
For Emacs to find the function bookmark-all-names you also have to add the following line to your .emacs file:
(require 'bookmark)
Function bookmark-completing-read is the standard way to complete a bookmark name. You do not need the lower-level function completing-read for this. Example:
(bookmark-completing-read "Bookmark" bookmark-current-bookmark)
If you use Bookmark+ then bookmark-completing-read accepts some optional arguments (similar to completing-read) that can help:
ALIST -- an alist of bookmarks to choose from (instead of all bookmarks: bookmark-alist)
PRED -- a predicate that filters the list of bookmark candidates
HIST -- an input history list
There is also a non-strict version of the function, bmkp-completing-read-lax, which is useful if you want to accept a new bookmark name or complete against existing names.
Emacs Lisp function often start like this:
(lambda () (interactive) ...
What does "(interactive)" do?
Just to clarify (it is in the quoted docs that Charlie cites) (interactive) is not just for key-bound functions, but for any function. Without (interactive), it can only be called programmatically, not from M-x (or via key-binding).
EDIT: Note that just adding "(interactive)" to a function won't necessarily make it work that way, either -- there could be many reasons functions are not interactive. Scoping, dependencies, parameters, etc.
I means that you're including some code for the things you need to make a function callable when bound to a key -- things like getting the argument from CTRL-u.
Have a look at CTRL-h f interactive for details:
interactive is a special form in `C source code'.
(interactive args)
Specify a way of parsing arguments for interactive use of a function.
For example, write
(defun foo (arg) "Doc string" (interactive "p") ...use arg...)
to make ARG be the prefix argument when `foo' is called as a command.
The "call" to `interactive' is actually a declaration rather than a function;
it tells `call-interactively' how to read arguments
to pass to the function.
When actually called, `interactive' just returns nil.
The argument of `interactive' is usually a string containing a code letter
followed by a prompt. (Some code letters do not use I/O to get
the argument and do not need prompts.) To prompt for multiple arguments,
give a code letter, its prompt, a newline, and another code letter, etc.
Prompts are passed to format, and may use % escapes to print the
arguments that have already been read.
Furthermore it’s worth mentioning that interactive's main purpose is, in an interactive context (e.g. when user calls function with key binding), let user specify function arguments that otherwise could be only given programmatically.
For instance, consider function sum returns sum of two numbers.
(defun sum (a b)
(+ a b))
You may call it by (sum 1 2) but you can do it only in a Lisp program (or in a REPL). If you use the interactive special form in your function, you can ask the user for the arguments.
(defun sum (a b)
(interactive
(list
(read-number "First num: ")
(read-number "Second num: ")))
(+ a b))
Now M-x sum will let you type two numbers in the minibuffer, and you can still do (sum 1 2) as well.
interactive should return a list that would be used as the argument list if function called interactively.
(interactive) is for functions meant to interact with the user, be it through M-x or through keybindings.
M-x describe-function RET interactive RET for detailed info on how to use it, including parameter to catch strings, integers, buffer names, etc.
One of the "gotchas" that this clarifies is that the argument to interactive is actually a kind of mini-formatting language (like for printf) that specifies the following (for the surrounding function's input):
schema (number of arguments and their type)
source (e.g., marked-region in buffer and/or user input, etc.)
For example,
'r'
Point and the mark, as two numeric arguments, smallest first.
means that the interactive-annotated function needs exactly two arguments.
e.g. this will work
(defun show-mark (start stop)
(interactive "r")
(print start)
(print stop))
This will break:
(defun show-mark (start)
(interactive "r")
(print start))
Wrong number of arguments: ((t) (start) (interactive "r") (print start)), 2