I have been trying to make a few changes to ido-mode to make it more useful. One of the things which I have been trying to do is to remap some of the keys which I use in ido-find-file. The main one is that I want to use C-d to call the ido-enter-dired function instead of having to press C-f+C-d which does the same thing.
This is my ido setup so far:
(defun ali/ido ()
"My configuration for ido-mode"
(require 'ido)
(setq ido-create-new-buffer 'always)
;; Making sure that ido works in M-x
(global-set-key
"\M-x"
(lambda ()
(interactive)
(call-interactively
(intern
(ido-completing-read
"M-x "
(all-completions "" obarray 'commandp))))))
;; Ido keybindings
(defun ido-keybindings ()
(define-key ido-completion-map (kbd "C-d") 'ido-enter-dired))
(add-hook 'ido-setup-hook 'ido-keybindings)
(ido-everywhere t)
(ido-mode 1))
However whenever, I try to use C-d in ido-find-file I always get this error:
Debugger entered--Lisp error: (error "Command attempted to use minibuffer while in minibuffer")
When called with the minibuffer active, your command uses a recursive minibuffer to read input using ido-completing-read.
Use this as your command instead:
(lambda ()
(interactive)
(let ((enable-recursive-minibuffers t)) ; <=====================
(call-interactively
(intern
(ido-completing-read
"M-x "
(all-completions "" obarray 'commandp))))))
C-h v enable-recursive-minibuffers tells us:
enable-recursive-minibuffers is a variable defined in C source code.
Its value is nil
Documentation:
Non-nil means to allow minibuffer commands while in the minibuffer.
This variable makes a difference whenever the minibuffer window is active.
Also see minibuffer-depth-indicate-mode, which may be handy if this
variable is non-nil.
You can customize this variable.
Related
Here are some excerpts from my .emacs:
(setq lexical-binding t)
;; .emacs
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(diff-switches "-u")
'(tab-always-indent (quote complete)))
;...
(require 'dired)
;...
(dotimes (i 12) (define-key dired-mode-map (kbd (concat "<f" (number-to-string (1+ i)) ">"))
(lambda ()
(interactive)
(goto-char (point-min))
(forward-line (+ 4 i)))))
This should bind keys f1 to f12 in dired-mode to commands that jump to particular files in the list of files (ignoring . and ..). However, initially, after starting emacs, these keys don't work - I get an error message forward-line: Symbol's value as variable is void: i. However, when I go to the top line of my .emacs and press C-x C-e to evaluate that line, and then go to the last line quoted above and press C-x C-e to evaluate that dotimes expression, those function keys start working!
Why is that?
By the way, it also doesn't work if I evaluate the whole buffer.
It turns out that it is necessary to replace
(setq lexical-binding t)
with
;; -*- lexical-binding: t -*-
The manual hints suggestively at this, but does not actually say so outright.
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)
Let's say I bind the key to a certain function as follows:
(global-set-key (kbd "C-c =") 'function-foo)
Now, I want the key binding to work as:
After I press C-c = for the first time, if I want to repeat the function-foo, I don't need to press C-c again, but simply repeat pressing =. Then, after I call the function-foo for enough times, I can just press keys other than = (or explicitly press C-g) to quit.
How to do this?
This may be the thing you are looking for:
(defun function-foo ()
(interactive)
(do-your-thing)
(set-temporary-overlay-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "=") 'function-foo)
map)))
There's a smartrep.el package that does exactly what you need. The documentation is a bit scarce but you can get a grip of how it's supposed to be used by looking into numerous emacs configs found on github. For example (taken from here):
(require 'smartrep)
(smartrep-define-key
global-map "C-q" '(("n" . (scroll-other-window 1))
("p" . (scroll-other-window -1))
("N" . 'scroll-other-window)
("P" . (scroll-other-window '-))
("a" . (beginning-of-buffer-other-window 0))
("e" . (end-of-buffer-other-window 0))))
This is what I use. I like it because you don't have to specify the repeating key.
(require 'repeat)
(defun make-repeatable-command (cmd)
"Returns a new command that is a repeatable version of CMD.
The new command is named CMD-repeat. CMD should be a quoted
command.
This allows you to bind the command to a compound keystroke and
repeat it with just the final key. For example:
(global-set-key (kbd \"C-c a\") (make-repeatable-command 'foo))
will create a new command called foo-repeat. Typing C-c a will
just invoke foo. Typing C-c a a a will invoke foo three times,
and so on."
(fset (intern (concat (symbol-name cmd) "-repeat"))
`(lambda ,(help-function-arglist cmd) ;; arg list
,(format "A repeatable version of `%s'." (symbol-name cmd)) ;; doc string
,(interactive-form cmd) ;; interactive form
;; see also repeat-message-function
(setq last-repeatable-command ',cmd)
(repeat nil)))
(intern (concat (symbol-name cmd) "-repeat")))
You want your function-foo to use set-temporary-overlay-map.
In addition to what #juanleon suggested, which uses set-temporary-overlay-map, here is an alternative that I use quite a bit. It uses standard library repeat.el.
;; This function builds a repeatable version of its argument COMMAND.
(defun repeat-command (command)
"Repeat COMMAND."
(interactive)
(let ((repeat-previous-repeated-command command)
(last-repeatable-command 'repeat))
(repeat nil)))
Use that to define different repeatable commands. E.g.,
(defun backward-char-repeat ()
"Like `backward-char', but repeatable even on a prefix key."
(interactive)
(repeat-command 'backward-char))
Then bind such a command to a key with a repeatable suffix, e.g., C-c = (for C-c = = = =...)
See this SO post for more information.
Suppose I define the following shortcut
(global-set-key (kbd "C-d C-j") "Hello!")
Is it possible to configure emacs so that if I type "C-d C-j C-j C-j" I will get "Hello! Hello! Hello!" rather than having to type "C-d C-j C-d C-j C-d C-j"?
I don’t think you can configure Emacs so that it does that for all commands. However, you can implement this functionality in the commands themselves. This is what is done for C-x e. Here is a macro I just wrote (guided by the standard definition of kmacro-call-macro in GNU Emacs 23.1.1) that makes it easy to add this functionality to your own commands:
(defmacro with-easy-repeat (&rest body)
"Execute BODY and repeat while the user presses the last key."
(declare (indent 0))
`(let* ((repeat-key (and (> (length (this-single-command-keys)) 1)
last-input-event))
(repeat-key-str (format-kbd-macro (vector repeat-key) nil)))
,#body
(while repeat-key
(message "(Type %s to repeat)" repeat-key-str)
(let ((event (read-event)))
(clear-this-command-keys t)
(if (equal event repeat-key)
(progn ,#body
(setq last-input-event nil))
(setq repeat-key nil)
(push last-input-event unread-command-events))))))
Here’s how you use it:
(defun hello-world ()
(interactive)
(with-easy-repeat
(insert "Hello, World!\n")))
(global-set-key (kbd "C-c x y z") 'hello-world)
Now you can type C-c x y z z z to insert Hello, World! three times.
If you are looking for something generic that works on all commands I cant see how that would work - how would emacs know if you are starting a new command or want to repeat the previous. A better example would be "C-c h", if you type "h" after that, should emacs repeat the command or insert a h?
That said, emacs already has a mechanism for this - the universal argument.
Try this key sequence:
C-u 3 C-d C-j
It is even fewer keypresses than C-d C-j C-j C-j C-j
Try something like this:
(global-set-key (kbd "C-c C-j") (lambda()
(interactive)
(insert "Hello!")
(message "Type j to print Hello!")
(while (equal (read-event) ?j)
(insert "Hello!"))
(push last-input-event unread-command-events)))
Idea taken from kmacro-call-macro
No. The sequence "ctrl-d ctrl-j" is what is bound to the string "Hello!" Emacs binds the sequence as a whole to the given string. Here's some good info on the topic:
Link
On the other hand, if you wanted just three instances of "Hello!", you could define that sequence C-d C-j C-d C-j C-d C-j as "Hello! Hello! Hello!", but it would be shorter to just define a simpler sequence for the string you want.
I use this all the time. You'll need library repeat.el (part of GNU Emacs) to use it.
(defun make-repeatable (command)
"Repeat COMMAND."
(let ((repeat-message-function 'ignore))
(setq last-repeatable-command command)
(repeat nil)))
(defun my-hello ()
"Single `hello'."
(interactive)
(insert "HELLO!"))
(defun my-hello-repeat ()
(interactive)
(require 'repeat)
(make-repeatable 'my-hello))
Now bind my-hello-repeat:
(global-set-key (kbd "") 'my-hello-repeat)
Now just hold down the home key to repeat HELLO!.
I use this same technique in multiple libraries, including Bookmark+, thing-cmds, and wide-n.
smartrep is all you want
(require 'smartrep)
(defvar ctl-d-map (make-keymap)) ;; create C-d map
(define-key global-map "\C-d" ctl-d-map)
(smartrep-define-key
global-map "C-d"
'(("C-j" . (insert "hello"))))
Currently, in order to evaluate elist in Emacs, I need to position the cursor on the last parenthesis and emit C-x e.
Is it possible to evaluate the entire buffer as a single elisp program without a need to position cursor?
M-x eval-buffer
or Alt+x and then type 'eval-buffer' or just type part of it and tab to autocomplete.
I placed this in my .emacs!
It allows you to eval a region if there is one or the entire buffer.
I bound it to C-xE.
(defun eval-region-or-buffer ()
(interactive)
(let ((debug-on-error t))
(cond
(mark-active
(call-interactively 'eval-region)
(message "Region evaluated!")
(setq deactivate-mark t))
(t
(eval-buffer)
(message "Buffer evaluated!")))))
(add-hook 'emacs-lisp-mode-hook
(lambda ()
(local-set-key (kbd "C-x E") 'eval-region-or-buffer)))
C-c C-l to load the entire file at once.