I've been spoiled by my recent dip into Vim. It is easy to make a macro there that will combine key strokes that result in a prompt. For instance the following, with ,c, I get a prompt for color schemes, as well as the list generated by typing Tab.
" colorscheme switcher
nnoremap <leader>c :colorscheme <C-z><S-Tab>
Now I realize, I'm not sure how to do it Emacs. Here is a naive attempt at how the code would go,
(defun load-theme-prompt ()
(interactive)
(load-theme)
(kbd "<tab>"))
Of course that won't work, and I did try recording a macro and inserting (even tried kmacro), but it complained about ' not being a theme, but I didn't see any quotes in the macro output.
That is, I tried to record M-x load-theme <RET> <TAB>, and insert to buffer, but the function does not work, even if I trim parts off.
Here is the recorded macro that does not work,
(fset 'load-theme-prompt
[?\M-x ?l ?o ?a ?d tab ?t ?h tab return tab])
Trying M-x load-theme-prompt gives me the following error,
load-theme: Invalid theme name `'
With lawlist's comments, I've taken another shot, but now I get wrong number of arguments:
(defun load-theme-prompt ()
(interactive
(list
(intern (completing-read "Load custom theme: "
(mapcar 'symbol-name
(custom-available-themes))))
nil nil))
(load-theme "%s")
)
I've tried moving the nil nil into (load-theme "%s" nil nil) but still not working.
Just looking at your code, you should probably change it to something like this:
(defun load-theme-prompt (name arg2 arg3)
(interactive
(list
(intern (completing-read "Load custom theme: "
(mapcar 'symbol-name
(custom-available-themes))))
nil nil))
(load-theme name arg2 arg3))
(interactive ...) passes arguments to the function, but your function takes no arguments.
Also, you don't really want to pass a literal "%s" to load-theme.
Related
Need to insert some text in the ido mini-buffer during ido-find-file using a defun bound to a key chord. This behavior is the same as if the following sequence was typed interactively, C-x C-f, followed by C-e to edit the mini-buffer, followed by deleting the current text then typing or yanking the text that I want to insert. To that end I have run this defun and just after ido-find-file:
(global-set-key [f10] 'mytest)
(defun mytest ()
(interactive)
(ido-edit-input) ;#1
(delete-minibuffer-contents) ;#2
(insert "C:/users/family/" )) ;#3
My expectation is that the mini-buffer would contain the given string (#3) after one invocation of mytest. However it seems as if I need to run mytest 2x to get the inserted string into the mini-buffer. After the first invocation the ido mini-buffer is in edit mode, however is as if only the #1 was run (the original text is still present). After the 2nd invocation of mytest the ido mini-buffer seems as if #1, #2 and #3 have been executed.
I am using a stand-alone mini-buffer which is part of the one-on-one library.
Running GNU emacs 24.4 on Windows.
Here is my custom configuration of ido, which I run at emacs startup.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;IDO Config
(setq ido-enable-flex-matching t)
;
(setq ido-everywhere t)
(ido-everywhere 1)
;
(require 'ido)
(ido-mode 1)
;
(setq ido-auto-merge-work-directories-length -1)
;
;https://github.com/gempesaw/ido-vertical-mode.el/blob/master/ido-vertical-mode.el
;; Display ido results vertically, rather than horizontally
(setq ido-decorations (quote ("\n-> " "" "\n " "\n ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]")))
(defun ido-disable-line-trucation ()
(set (make-local-variable 'truncate-lines) nil))
(add-hook 'ido-minibuffer-setup-hook 'ido-disable-line-trucation)
;
(setq ido-ignore-buffers '("\\` " "^\*Mess" "^\*Back" ".*Completion"
"^\*Ido" "^\*trace" "^\*compilation" "^\*GTAGS" "^\*Help" "^session\.*" "^\*"))
;
;use IDO for more things
(setq recentf-max-saved-items 100)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I have confirmed that the logic is somewhat sound by binding the individual commands then running them interactively. It seems as if running the same defs from lisp is acting differently than running the same interactively.
Ido-edit-input is C-e during ido-find-file
(global-set-key [f11] 'delete-minibuffer-contents)
(global-set-key [f12] (lambda () (interactive) (insert "C:/users/family")))
Also tried inserting (sit-for 1) in the mytest defun on the possibility that there is some timing issue.
How can the defun mytest be modified to insert a string (#3) with a single invocation?
This isn't the answer to the question in the title, but it does do what you apparently want:
(defun my-ido-find-file-in-dir ()
(interactive)
(let ((default-directory "C:/users/family"))
(call-interactively 'ido-find-file)))
(global-set-key [f10] 'my-ido-find-file-in-dir)
I have most of my bookmarks prefixed by a letter in a way that
the first letter almost always uniquely determines the bookmark.
This way I can, for instance,
jump to my source folder (bookmarked as "s: source") with M-x bookmark-jump RET s RET.
I have it on a shortcut, so it's actually ~ s RET.
I'd like to get rid of RET in the end,
i.e. get M-x bookmark-quick-jump RET s or ~ s
to do the aforementioned job.
I'd also like it to fall back to the default behavior: to show me all bookmarks
that start with the given letter, in case there's not just one variant.
So far, I've got:
(defun bookmark-do-quick-jump (str)
(let ((completions (all-completions str bookmark-alist)))
(bookmark-jump
(if (eq 1 (length completions))
(car completions)
(completing-read "Jump to bookmark: " bookmark-alist nil t str)))))
There's still two hiccups:
Firstly, I need to jump into minibuffer somehow and stick in there this map (don't know how to do this):
(setq bookmark-quick-jump-map
(let ((map (make-sparse-keymap)))
(mapcar (lambda (key)
(define-key map key
(lambda()
(interactive)
(bookmark-do-quick-jump key))))
(loop for c from ?a to ?z
collect (string c)))
map))
Secondly, when I do a call
(bookmark-do-quick-jump "o")
It comes back with 3 variants (org-capture-last-stored, org-capture-last-stored-marker...).
I'm in minibuffer now, but I still need to press RET RET
to see these 3 variants. I'd like this to be done automatically.
I'd appreciate any responses that either directly answer my two sub-problems,
or an altogether different approach, as long as I can get the behavior and usability
that I described.
UPD:
I've solved the second thing by switching from completing-read to ido-completing-read:
(defun bookmark-do-quick-jump (str)
(let ((completions (all-completions str bookmark-alist)))
(bookmark-jump
(if (eq 1 (length completions))
(car completions)
(ido-completing-read "Jump to bookmark: " completions nil t str)))))
Btw, I forgot to mention that I use bookmark+. I'm not sure if jumping to dired
is supported by the default bookmark-jump.
We can remap self-insert-command during the completing-read to trigger the auto-completion and auto-acceptance behaviour.
I originally used (or (minibuffer-complete-and-exit) (minibuffer-completion-help)) which at first glance worked very nicely but, as noted in the comments, is less than ideal when one bookmark's name is the prefix of another, as it will immediately accept the shorter name, hence making the longer one inaccessible.
Calling minibuffer-complete and minibuffer-completion-help together breaks the completion functionality, however, so instead I've copied the relevant part of minibuffer-complete-and-exit to a new function. Using this resolves all of the earlier problems.
(require 'bookmark)
(defvar bookmark-do-quick-jump-map (copy-keymap minibuffer-local-must-match-map)
"Keymap for `bookmark-do-quick-jump'.
`minibuffer-local-must-match-map' is used by `completing-read' when its
REQUIRE-MATCH argument is t.
In `bookmark-do-quick-jump' we bind this modified copy to use in its place.")
(define-key bookmark-do-quick-jump-map
[remap self-insert-command] 'my-self-insert-complete-and-exit)
(defun bookmark-do-quick-jump ()
"Jump to specified bookmark with auto-completion and auto-acceptance."
(interactive)
(bookmark-maybe-load-default-file)
(let ((minibuffer-local-must-match-map bookmark-do-quick-jump-map))
(bookmark-jump
(completing-read "Jump to bookmark: " bookmark-alist nil t))))
(defun my-self-insert-complete-and-exit (n)
"Insert the character, then attempt to complete the current string,
automatically exiting when only one option remains, and displaying the
completion options otherwise."
(interactive "p")
(self-insert-command n)
(my-minibuffer-complete)
(let ((my-completions (completion-all-sorted-completions)))
(if (and my-completions (eq 0 (cdr my-completions)))
(exit-minibuffer)
(minibuffer-completion-help))))
(defun my-minibuffer-complete ()
"Copied from `minibuffer-complete-and-exit'."
(interactive)
(condition-case nil
(completion--do-completion nil 'expect-exact)
(error 1)))
Edit:
I took another stab at this using ido. It's a little unfortunate that you don't get the next 'important character' highlighted the way that you do with the regular minibuffer completion (as that was a nice indicator of what to type next), but this seems to work nicely in other respects.
(require 'bookmark)
(require 'ido)
(defvar bookmark-ido-quick-jump-map (copy-keymap minibuffer-local-map)
"Keymap for `bookmark-ido-quick-jump'.
Every time `ido-completing-read' is called it re-initializes
`ido-common-completion-map' and sets its parent to be `minibuffer-local-map'.
In `bookmark-ido-quick-jump' we provide this modified copy as a replacement
parent.")
(define-key bookmark-ido-quick-jump-map
[remap self-insert-command] 'my-self-insert-and-ido-complete)
(defun bookmark-ido-quick-jump ()
"Jump to selected bookmark, using auto-completion and auto-acceptance."
(interactive)
(bookmark-maybe-load-default-file)
(let ((minibuffer-local-map bookmark-ido-quick-jump-map)
(ido-enable-prefix t))
(bookmark-jump
(ido-completing-read "Jump to bookmark: "
(loop for b in bookmark-alist collect (car b))))))
(defun my-self-insert-and-ido-complete (n)
"Insert the character, then attempt to complete the current string,
automatically exiting when only one option remains."
(interactive "p")
(self-insert-command n)
;; ido uses buffer-local pre- and post-command hooks, so we need to
;; co-operate with those. We append our post-command function so that
;; it executes after ido has finished processing our self-insert.
(add-hook 'post-command-hook
'my-self-insert-and-ido-complete-post-command t t))
(defun my-self-insert-and-ido-complete-post-command ()
(remove-hook 'post-command-hook
'my-self-insert-and-ido-complete-post-command t)
;; Now that ido has finished its normal processing for the current
;; command, we simulate a subsequent `ido-complete' command.
(ido-tidy) ;; pre-command-hook
(ido-complete)
(ido-exhibit)) ;; post-command-hook
Here's another take:
(defun bookmark-do-quick-jump (str)
(let ((completions (all-completions str bookmark-alist)))
(if (null (cdr completions))
(bookmark-jump (car completions))
(minibuffer-with-setup-hook
(lambda () (insert str)
(minibuffer-completion-help))
(call-interactively 'bookmark-jump)))))
Or yet another (even more guaranteed untested):
(defadvice bookmark-jump (around quick-bookmarks activate)
(minibuffer-with-setup-hook
(lambda ()
(add-hook 'post-self-insert-hook
(lambda ()
(let ((completions
(all-completions (minibuffer-contents)
bookmark-alist)))
(if (cdr completions)
(minibuffer-completion-help)
(minibuffer-complete-and-exit))))
nil t))
ad-do-it))
Sounds like you're doing a lot of extra work. Just use Icicles.
User option icicle-incremental-completion non-nil and non-t means show all matches as soon as you type input.
Option icicle-top-level-when-sole-completion-flag non-nil means accept a solitary match without your needing to hit a key (e.g. RET).
Instead of customizing the options to have these values in general, you can just bind them to the values in your own command.
For example, I have the codes below:
(defun toggle-light ()
"Toggle setting tab widths between 4 and 8"
(setq a
(if (boundp 'a) a nil))
(interactive)
(if a
(progn
(load-theme 'solarized-dark t)
(setq a nil))
(progn
(load-theme 'solarized-light t)
(setq a t) )))
And now I want to refactor this blocks by replacing the variable name a with is-lighted, but without changing other character a in other words (for example, in interactive or tab).
Is there a built-in function in emacs that can finsih that job?
C-uM-% a RET is-lighted RET
The prefix argument ("delimited") to the standard query-replace functions wraps the pattern with word-boundary markers.
While phils's answer is correct and idiomatic, you should also learn about \b word boundary regular expression. Thus, equivalent regexp replace would be M-%\ba\b. See Backslash in Regular Expressions # Emacs Manual and Regular Expression # EmacsWiki.
I can run a shell command quickly by hitting M-!. One thing I'd like to do is perform shell quick operations on the current file. An example would be checking the file out through perforce:
M-! p4 edit buffer-file-name RET
(Yes there are perforce integrations, but I'm more interested in the minishell/variable problem rather than a specific workflow)
Of course, the buffer-file-name variable is not evaluated before the command is sent to the shell.
Is there an easy on-the-fly way to do this? Or will I have to roll a custom elisp function?
It seems current Emacs has something built-in to achieve the desired result, after M-! (shell-command) press <down>, you will get the file name you are currently visiting on the prompt. Now you can edit it to add the command you want to run on it.
In dired-mode it will give you the file your cursor is currently on.
Indeed using C-u M-: is almost right. I'm not so sure about using shell-quote-argument in eval-to-shell-argument since it only works on strings making it impossible to use eval-to-shell-argument to insert a number or a symbol. You could try something like:
(defun sm-minibuffer-insert-val (exp)
(interactive
(list (let ((enable-recursive-minibuffers t))
(read-from-minibuffer "Insert: "
nil read-expression-map t
'read-expression-history))))
(let ((val (with-selected-window (minibuffer-selected-window)
(eval exp)))
(standard-output (current-buffer)))
(prin1 val)))
and then bind this function in your minibuffer with (define-key minibuffer-local-map [?\M-:] 'sm-minibuffer-insert-val).
Of course, if the only thing you ever want to insert is the buffer-file-name, then your execute-shell-command-on-buffer is simpler.
I did roll my own elisp function, and it looks like this:
(defun execute-shell-command-on-buffer (shell-command-text)
(interactive "MShell command:")
(shell-command (format shell-command-text (shell-quote-argument buffer-file-name)))
)
https://gist.github.com/2367513
I bound it to M-", so now my example can be completed with:
M-"p4 edit %sRET
I won't accept this as the answer, because I did ask for solutions that don't require a function.
You can use C-u M-: (eval-expression with a universal prefix argument) to evaluate any Lisp expression and insert its value at point in the current buffer (including minibuffers, as long as you have enable-recursive-minibuffers set to a non-nil value).
In your example: C-u M-: buffer-file-name RET.
Note that the result of the expression is printed in Lisp form: that is, quoted in such a way that a subsequent call to read would construct an equal Lisp value. For strings, this means enclosing in double quotes, which will probably be interpreted as you expect by the inferior shell. However, you may run into problems with strings that contain special characters, which need different escaping by Elisp and the shell.
The more correct way uses shell-quote-argument, as in phils' solution. Here's a quick defun that reads a Lisp expression and inserts its value at point as a properly quoted shell word:
(defun eval-to-shell-argument (form)
(interactive "XEval: ")
(insert (shell-quote-argument form)))
The read-and-evaluate step happens automatically by using an "X" as the argument to interactive.
Edited to add: As #tenpn notes, the above solution doesn't work for inserting buffer-local variables like buffer-file-name in a minibuffer like the one M-! pops up (more precisely, it inserts the buffer-local value of the minibuffer, which is unlikely to be useful). Here is a revised version which seems to work. If the minibuffer is active, it makes the buffer of the previously-selected window temporarily active while reading and evaluating an expression.
Final edit: From #Stefan's answer I see that I should have used (minibuffer-selected-window) to find the previously-selected window. I've also added a (format "%s" ..) to allow inserting non-string values, while still quoting special characters in strings. Here's the final version:
(defun eval-to-shell-argument ()
(interactive)
(let* ((buffer
(if (minibufferp)
(window-buffer (minibuffer-selected-window))
(current-buffer)))
(result
(with-current-buffer buffer
(eval-minibuffer "Eval: "))))
(insert (shell-quote-argument (format "%s" result)))))
You can't do that with M-!, but you can evaluate arbitrary elisp from the minibuffer, so writing a function isn't strictly necessary:
M-: (shell-command (format "p4 edit %s" (shell-quote-argument buffer-file-name))) RET
In this case however, I think eshell is what you want to use:
M-x eshell-command RET p4 edit (eval buffer-file-name) RET
Edit: Except unfortunately that doesn't work, as the *eshell cmd* buffer is selected when that is evaluated. One solution would be:
M-x eshell-command RET p4 edit (eval buffer-file-name (other-buffer nil t)) RET
(Not quite as elegant, sorry.)
Everyone seems to be rolling their own version, so here's mine -- it will substitue the current filename or marked dired-files or current dired file wherever a % is in the shell command. It follows the same conventions as M-! so I bind it to that.
(defun my-shell-command (command &optional output-buffer error-buffer)
"Run a shell command with the current file (or marked dired files).
In the shell command, the file(s) will be substituted wherever a '%' is."
(interactive (list (read-from-minibuffer "Shell command: "
nil nil nil 'shell-command-history)
current-prefix-arg
shell-command-default-error-buffer))
(cond ((buffer-file-name)
(setq command (replace-regexp-in-string "%" (buffer-file-name) command nil t)))
((and (equal major-mode 'dired-mode) (save-excursion (dired-move-to-filename)))
(setq command (replace-regexp-in-string "%" (mapconcat 'identity (dired-get-marked-files) " ") command nil t))))
(shell-command command output-buffer error-buffer))
I am trying to have a dynamic prompt from my elisp function. I want something like replace-regexp where it will show you the last regexp entered. I tried
(interactive
(concat "sab" "bab")))
that doesnt work!
I also tried message like format
(interactive "s %s" last-used-regexp)
and that doesn't work!
Anyone know how to do this?
Thank you!
M-x find-function is your friend. It will tell you how anything in emacs works by showing you the source code. Using it, I find that query-regexp-replace calls query-replace-read-args which calls query-replace-read-from which calls read-from-minibuffer using a prompt created from the last used regexp, which is saved in the dotted pair query-replace-defaults.
So:
(defun my-func ()
"Do stuff..."
(interactive)
(read-from-minibuffer "Regexp? " (first query-replace-defaults)))
is a command that throws up a prompt with the last entered regexp as the default.
Use a variable for input history, and interactive with a list:
(defvar my-func-history nil)
(defun my-func (str)
(interactive (list (read-from-minibuffer "Input string: " (car my-func-history) nil nil 'my-func-history)))
(insert str))
If you don't want the last value entered in there initially, change the (car my-func-history) to nil. You can of course up/down arrow to go through the history at the prompt.