how to setup org-mode speed key sequence - emacs

I'm using org-mode's speed keys alot and I would like to have key sequences as speed keys for ease of remembering. In this case, I want to have "i n" insert a subheading, and "i t" insert a todo subheading.
I know I can setup a sequence by using a prefix keymap like this:
(progn
(define-prefix-command 'my-org-speed-command-insert-subheading-map)
(define-key my-org-speed-command-insert-subheading-map (kbd "n") 'jan/org-insert-subheading)
(define-key my-org-speed-command-insert-subheading-map (kbd "t") 'jan/org-insert-todo-subheading)
)
(global-set-key (kbd "C-c i") my-org-speed-command-insert-subheading-map)
so pressing "C-c i n" and "C-c i t" call the corresponding functions. Fine.
Now, when I give "my-org-speed-command-insert-subheading-map" as the function to be called by org speed commands
(setq org-speed-commands-user (quote ((":" . helm-M-x)
("a" . org-toggle-archive-tag)
("i" . my-org-speed-command-insert-subheading-map)
… … …
)))
it doesn't work as expected. What am I doing wrong?
I understand I can't call the prefix map like actual commands, and hence it isn't quoted when bound with global-set-key, so I suspect that the problem is related to this. But then how do I call it? Or is there a much simpler way for achieving my goal that I simply didn't see?
EDIT:
I found a way to work around the issue for now by having the "i" speed key call this function:
(defun my-org-i-map-function ()
(let (key1)
(setq key1 (read-key-sequence "press \"i\" for a simple subheading, \"t\" for a TODO-subheading"))
(cond
((equal key1 "i")(jan/org-insert-subheading nil))
((equal key1 "t")(jan/org-insert-todo-subheading nil))
(t (message "you didn't set a function for this key sequence")))
))
but this is a rather ugly solution as I'd have to call different functions for every first letter, and the second and third letter are buried in the function definitions. So using this approach extensively is bound to bring about lots of confusion in the longer run.

https://github.com/abo-abo/worf
GNU Emacs minor mode that provides vi-like bindings for org-mode
Take a look or maybe "hydra" package from the same author.

I'm pretty sure you are limited to single letters for speed commands. E.g. the docstring for org-speed-command-activate says:
"Hook for activating single-letter speed commands.
org-speed-commands-default specifies a minimal command set.
Use org-speed-commands-user for further customization."

Related

Run function before keymap commands

Is there a way to advise a keymap or otherwise run a function after a keymap prefix, but before commands in the keymap?
Say I have a keymap with bindings for hideshow, but these bindings are only useful after hs-minor-mode is activated. How can I run (hs-minor-mode) after the prefix is entered, but before the functions in the map are called?
I thought making a prefix command and advising it might work, but that is an error (below).
Example:
(let ((map (define-prefix-command 'my-activate-fold 'my-fold-map)))
(define-key map "a" #'hs-hide-all)
(define-key map "s" #'hs-show-all)
(define-key map "l" #'hs-hide-level)
(global-set-key (kbd "<f6>") 'my-activate-fold))
;; error: wrong-type-argument commandp my-activate-fold
(define-advice my-activate-fold (:before (fn &rest r) "activate-hideshow")
(hs-minor-mode)
(apply fn r))
If I understand correctly, I think you may be approaching this incorrectly. For your specific question, no, there is no way to define a function which will run after a prefix key is called but before the command (an interactive function) which is bound to the key is run. However, I'm not sure that is really what your after. You can of course define commands which can wrap another command and do whatever you want. However, I'm not sure that is what you want either. You might want to state exactly what you want rather than part of what you believe is the solution to what you want.
Normal practice is for a minor mode to define a keymap and you add your mode specific key bindings to that map in a mode initialisation hook. In the case of hs-minor-mode, that is called hs-minor-mode-map. This map only exists inside buffers running hs-minro-mode and it takes precedence over the global map. So this is where you want to place your mode specific bindings. To do this, create a function which adds the bindings to the map and attach that to the hs-minor-mode-hook, which is run when hs-minor-mode is loaded.
(add-hook 'hs-minor-mode-hook (lambda ()
(define-key 'hs-minor-mode-map "a" #'hs-hide-all)
...))
The key bindings defined above will only exist if hs-minor-mode is active in the buffer. If it is not active, the keys used in the binding will either be bound to whatever the next highest map in the mode is or the global map or nothing (see the section on keymaps in the elsip manual for full details).
If what you want is to have specific hs-minor-mode bindings only exist in specific modes, then you can define those bindings in the keymap for that mode. For example, if you wanted hs-minor-mode bindings that only exist when you run hs-minor-mode in js2-mode, but not when you run hs-minor-mode in c-mode, then you can add the bindings to the js2-mode-map and load hs-minor-mode as part of the js2-mode-hook
If it is something else you are after, you need to clarify.
FWIW, you could simply advise the commands themselves:
(defun my-ensure-hs-minor-mode (&rest _args)
"Ensure `hs-minor-mode' is active."
(unless (bound-and-true-p hs-minor-mode)
(hs-minor-mode 1)))
(advice-add 'hs-hide-all :before #'my-ensure-hs-minor-mode)
(advice-add 'hs-show-all :before #'my-ensure-hs-minor-mode)
(advice-add 'hs-hide-level :before #'my-ensure-hs-minor-mode)
Your keymap then just works:
(require 'hideshow)
(let ((map (define-prefix-command 'my-activate-fold 'my-fold-map)))
(define-key map "a" #'hs-hide-all)
(define-key map "s" #'hs-show-all)
(define-key map "l" #'hs-hide-level))
(global-set-key (kbd "<f6>") 'my-activate-fold)

Mode-specific or buffer-local text objects in evil?

Q: in Emacs, how does one make mode-specific key bindings for text objects in evil?
One may bind a key in a specific state (normal, insert, etc.) in a specific mode as the following example demonstrates:
(evil-define-key 'normal org-mode "a" 'some-command)
However, it's not clear to me how to bind a key in a mode-specific way to evil-outer-text-objects-map (or its -inner- counterpart). As an alternative, it's also not clear how one might bind keys in these maps in a buffer-local way through a mode hook.
It doesn't look like evil-local-set-key will do it, because it expects a state (normal, insert, etc.) as its first argument, and that's not relevant to this task.
It's also not clear how to use local-set-key in this instance, because it expects a key and a command as arguments, but does not take a map as an argument.
This is kinda late but for the first part of your question you can use local maps like:
(defun my-elisp-mode-configuration ()
(with-eval-after-load 'evil
(define-key evil-visual-state-local-map "ie" 'sp-evil-i-sexp)
(define-key evil-operator-state-local-map "ie" 'sp-evil-i-sexp)))
(add-hook 'emacs-lisp-mode-hook #'my-elisp-mode-configuration)
In this example I bind 'inner' e operator to a custom sp-evil-i-sexp text object for elisp mode only.
Coming to your second question; evil overrides local maps so using local-set-key won't suffice. Instead you can use:
local evil maps with hooks; like evil-normal-state-local-map as in the previous example
use evil-define-key; ie: (evil-define-key 'normal emacs-lisp-mode-map (kbd " ") 'my-leader)
Note that you can not override Evil's bindings this way but those unemployed or employed at a global or local level. Use the first method in case you want to override Evil bindings.
And there is evil-make-overriding-map which causes local-map to override Evil's bindings but this is rarely what you want because you want hjkl to work at least but useful for modes like dired which evil makes less sense.
Footnote: There is nothing special about Evil's operators or text objects from Emacs's perspective. They're just bound keymaps. Eg: i key is bound to the evil-inner-text-objects-map which includes text objects like w as in:
(define-key evil-visual-state-map "i" evil-inner-text-objects-map)
(define-key evil-inner-text-objects-map "w" 'evil-inner-word)
You can find these lines in evil-maps.el
When reading the mailing list someone mentioned it is better to put keybindings in eval-after-load instead of hooks, so here it is:
(eval-after-load "<mode>"
'(progn
<object-definition>))
As for defining new text objects, I must recommend this function from #gordon-gustafson:
(defmacro define-and-bind-text-object (key start-regex end-regex)
(let ((inner-name (make-symbol "inner-name"))
(outer-name (make-symbol "outer-name")))
`(progn
(evil-define-text-object ,inner-name (count &optional beg end type)
(evil-select-paren ,start-regex ,end-regex beg end type count t))
(evil-define-text-object ,outer-name (count &optional beg end type)
(evil-select-paren ,start-regex ,end-regex beg end type count nil))
(define-key evil-inner-text-objects-map ,key (quote ,inner-name))
(define-key evil-outer-text-objects-map ,key (quote ,outer-name)))))
So the <object-definitions> part would become:
(define-and-bind-text-object "<key>" "<start-regex>" "<end-regex>")

key chords in isearch

I really love key-chord.el. It's become an integral part of my workflow, but sometimes I wish I could have them in the minibuffer (for things like evil-search). Specifically, I'd like jj to exit out of evil-search and move down a line. Is this possible?
I know I can hack together a command that acts as both a prefix and a command (see this SO question), so I could bind j to a self inserting command, and jj to my special command. How would I be able to break the event loop after a specified idle time? I do type jj once in a blue moon, and I'd still like the flexibility of a timeout.
Is there any other way which I am unaware of to achieve what I want?
EDIT:
Origionally, this question was about the minibuffer in general. key-chord.el seems to work fine with minibuffer-local-map. It does not, however, work with isearch-mode-map. Binding a command to a single regular key like j does work in isearch. This is what I'm trying to solve.
I have found a solution which manually reproduces the behaviour of key-chord.el.
(defun isearch-exit-chord-worker (&optional arg)
(interactive "p")
(execute-kbd-macro (kbd "<backspace> <return>")))
(defun isearch-exit-chord (arg)
(interactive "p")
(isearch-printing-char)
(unless (fboundp 'smartrep-read-event-loop)
(require 'smartrep))
(run-at-time 0.3 nil 'keyboard-quit)
(condition-case e
(smartrep-read-event-loop
'(("j" . isearch-exit-chord-worker)
("k" . isearch-exit-chord-worker)))
(quit nil)))
;; example bindings
(define-key isearch-mode-map "j" 'isearch-exit-chord)
(define-key isearch-mode-map "k" 'isearch-exit-chord)
This approach actually has several advantages over key-chord.el.
It does not use an input method, so you can use a different input method in conjunction with this.
The first character is shown immediately, and retracted if it is incorrect, while key-chord.el only shows it after a delay.
I have found this to be useful:
(defun isearch-enable-key-chord ()
(key-chord-mode 1)
(key-chord-define isearch-mode-map "jj" 'isearch-cancel))
(add-hook 'isearch-mode-hook 'isearch-enable-key-chord)

how to emulate a specific key press in Emacs Lisp

Context: I want to make a minor mode where pressing f twice fast results in whatever the pressing of ( should do at that time. This doesn't always mean just insertion of (. For example, in buffers where paredit mode or autopair mode is enabled, pressing of ( usually results in insertion of (). In a paredit mode buffer, that sometimes results in wrapping the selected text: for example, if I select a b and press (, that should result in replacing the selection with (a b).
For detection of f being pressed twice, I just need to take the logic in the short code in http://www.emacswiki.org/emacs/electric-dot-and-dash.el
So the only missing piece is a Lisp code snippet that tells Emacs "Trigger pressing of ( now!"
The first thing that came to my mind was that the snippet should do
find the command bound to the key (
and then call call-interactively on that command.
but that breaks down if the auto pairing package (autopair or paredit or other similar package) binds ( to a command that has a logic that looks up what key was used to call the command, or if the package simply relies on post-self-insert-hook or post-command-hook instead of binding (.
update
I've looked up Key Chord documentation and it turns out what I am trying to do with answers to this question has a simpler solution:
(require 'key-chord)
(key-chord-mode 1)
(defvar my-easy-open-paren-mode-map
(let ((map (make-sparse-keymap)))
(key-chord-define map ",." (kbd "("))
map))
(define-minor-mode my-easy-open-paren-mode
"In this mode, pressing . and , together is another way of pressing the open paren.")
(defvar my-easy-semicolon-mode-map
(let ((map (make-sparse-keymap)))
(key-chord-define map ";;" (kbd "C-e ;"))
map))
(define-minor-mode my-easy-semicolon-mode
"In this mode, pressing semicolon twice fast is another way of pressing C-e and semicolon.")
(add-hook 'prog-mode-hook 'my-easy-open-paren-mode)
(add-hook 'c-mode-common-hook 'my-easy-semicolon-mode)
Triggering key press may still be useful in other contexts though.
You might appreciate the Key Chord library for binding functions to a double key-press. (I wouldn't recommend using f if you'll be writing in English, mind you; but YMMV.)
post-self-insert-hook would still run if the binding was self-insert-command. post-command-hook will run in any case, but if you're worried about it seeing an incorrect function and/or input event, you can manipulate those...
After looking up the binding, your function can set this-command to the function you're about to call-interactively, and last-command-event to the required key. e.g.:
(defun my-fake-paren ()
(interactive)
(let ((command (key-binding "(")))
(setq last-command-event ?\()
(setq this-command command)
(call-interactively command)))
I use Key Chord for this sort of thing, although the page you link appears to do the same thing. The trick is getting the call to call-interactively to work correctly. I wrapped it in a let that reset the variable last-command-event, such that call-interactively thinks it was a "(". This works for me in paredit and fundamental modes.
(require 'key-chord)
(key-chord-mode 1)
(defun my-paren-call ()
(interactive)
(let ((last-command-event ?\())
(call-interactively (key-binding "("))))
(key-chord-define-global "ff" 'my-paren-call)

Emacs: function that writes down an elisp code that adds a keybinding specified by the user

How can I make an interactive function that interactively read a key from the user (like when you press C-h k) and then writes some line like this:
(global-set-key (kbd "C-x C-s") 'hello)
where the "C-x C-s" part is replaced appropriately with the read key.
Some beginning users have problem making keybindings and in fact I get confused about it too, so I thought let's just automate it.
This seems to work:
(defun insert-key (key)
(interactive (list (read-key-sequence "Key: ")))
(insert "(global-set-key (kbd \"" (key-description key) "\") 'hello)\n"))
Huh? Maybe I'm misunderstanding the question, but if not, this is the answer: global-set-key is a command. And it does just what is requested (IIUC): It reads a key sequence (type, click, etc.), and then it reads the command to bind the key sequence to.