Emacs: Build a menu from items in a list - emacs

Back with another Emacs question. I'm trying to make my package add a menu, but I'm running into some problems here.
I have a list with strings, and I for each item in this list I want to add an entry to the menu, calling a function with the string as an argument. Now the problem is that I cannot hardcode this menu, since the list is supposed to be edited by the user.
I was thinking of something along the lines of:
(dolist (item my-list)
(define-key global-map [menu-bar my-menu item]
(cons item `(lambda () (interactive) (my-function ,item)))))
Now the problem is that I only get one menu item, at <menu-bar> <my-menu> <item>. How can I use the value of the variable "item" in [menu-bar my-menu item], instead of the literal string "item"?
Also, having the lambda in the cons like that works, but I'm not quite happy with it - is there a better way to do this?

Answer to your first question:
(dolist (item my-list)
(define-key global-map (vector 'menu-bar 'my-menu item)
(cons item `(lambda () (interactive) (my-function ,item)))))

Related

How do I add auto-completion to my custom comint mode in Emacs?

I'm writing a comint mode for a legacy command-line tool.
I'd like to add basic auto-completion to it.
Suppose I have the following list of keywords used by the tool:
(defconst my-keywords '("export" "extract" "display"))
How would I add auto-completion to my mode, based on this list?
What I found so far:
I know there are examples of this in shell.el or in comint.el, but I did not manage to understand the code well enough to answer to this basic question. I did understand though that I could build a regexp list out of my-keywords, like this:
(regexp-opt my-keywords)
;; output:
"\\(?:display\\|ex\\(?:\\(?:por\\|trac\\)t\\)\\)"
Other than that, I gathered that I could use pcomplete, or company, or both – I'm fine with any solution actually, but how do I do it?
Comint also calls customizable comint-dynamic-complete-functions from its comint-completion-at-point function. Derived modes will often add functions to this hook (see shell-dynamic-complete-functions), eg.
(defconst my-keywords '("export" "extract" "display"))
(defun my-comint-dynamic-completion-function ()
(when-let* ((bds (bounds-of-thing-at-point 'symbol))
(beg (car bds))
(end (cdr bds)))
(when (> end beg)
(list beg end my-keywords :annotation-function (lambda (_) "my-keywords")))))
(define-derived-mode my-comint-mode comint-mode "my mode"
(add-hook 'comint-dynamic-complete-functions
#'my-comint-dynamic-completion-function nil 'local)
(make-local-variable 'company-backends)
(cl-pushnew 'company-capf company-backends))
By adding company-capf to your company-backends you will additionally get company support from your completion at point function (see elisp-completion-at-point for example of additional company-specific symbols for showing help/location/etc. of completion candidates).
Thanks to ergoemacs I found a first solution :
Define a completion function which returns a list of the form (start end my-keywords . nil), with start and end delimiting the entity to complete at point. I added a tweak to take into account the program prompt, for the first keyword.
Add this function to completion-at-point-functions, in the definition of the mode;
Add a tab shortcut to completion-at-point, in the mode-map.
(defconst my-keywords '("export" "extract" "display"))
;; 1 - custom completion function
(defun my-completion-at-point ()
"This is the function to be used for the hook `completion-at-point-functions'."
(interactive)
(let* (
(bds (bounds-of-thing-at-point 'symbol))
(start (max (car bds) (comint-line-beginning-position)))
(end (cdr bds)))
(list start end xyz-keywords . nil )))
;; 2 - adding it to my-completion-at-point
(define-derived-mode my-comint-mode comint-mode "My comint mode"
;; your code....
(add-hook 'completion-at-point-functions 'my-completion-at-point nil 'local))
;; 3 - add a tab shortcut in the map of the mode
(defvar my-mode-map
(let ((map (nconc (make-sparse-keymap) comint-mode-map)))
;; your code...
(define-key map "\t" 'completion-at-point)
map))

Emacs Org-mode: Quickly mark TODO as DONE

I'd like to have a shortcut to change the state of a TODO straight to DONE (and back) with the CLOSED time tag folded when I'm at any position on the line (not like speed-keys requiring to be before the first asterisk).
Currently I have 2 options:
C-c C-t d TAB (with org-use-fast-todo-selection set to t, d is my DONE state shortcut and TAB hides the subtree), or
S-right TAB (using org-shiftright, DONE is the first state after TODO).
Can you please help me bind this to a single shortcut like C-c C-d. Please note I have more states than TODO and DONE but this shortcut should just toggle between those too.
Bonus points: Additional command that also starts a new TODO item on the next line at the same level as the previous task.
Thank you very much!
Not sure what you mean by "time tag", but based on the workflows you listed, the following command should do what you want:
(defun org-toggle-todo-and-fold ()
(interactive)
(save-excursion
(org-back-to-heading t) ;; Make sure command works even if point is
;; below target heading
(cond ((looking-at "\*+ TODO")
(org-todo "DONE")
(hide-subtree))
((looking-at "\*+ DONE")
(org-todo "TODO")
(hide-subtree))
(t (message "Can only toggle between TODO and DONE.")))))
(define-key org-mode-map (kbd "C-c C-d") 'org-toggle-todo-and-fold)
As for inserting new TODO items on the same level as the current task, org-mode has built-in commands for this. You can read up on them by doing
C-h f org-insert-todo-heading RET
C-h f org-insert-todo-heading-respect-content RET
A simple toggle command could look like the following
(defun my-org-todo-toggle ()
(interactive)
(let ((state (org-get-todo-state))
post-command-hook)
(if (string= state "TODO")
(org-todo "DONE")
(org-todo "TODO"))
(run-hooks 'post-command-hook)
(org-flag-subtree t)))
(define-key org-mode-map (kbd "C-c C-d") 'my-org-todo-toggle)
The post-command-hook is a bit tricky, but is required since otherwise notes are added (and revealed) after the command, which makes the time log partially unfolded.
In order to start a new TODO item, you might have a look at the existing org-insert-todo-heading (bound to <M-S-return>)

Using 2 consecutive control key in Emacs [duplicate]

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.

Emacs quicker bookmark-jump?

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.

Overload a Keybinding in Emacs

I've looked through a number of other questions and el files looking for something i could modify to suit my needs but I'm having trouble so I came to the experts.
Is there anyway to have a key behave differently depending on where in the line the cursor is?
To be more specific I'd like to map the tab key to go to the end of the line if I'm in the middle of the line but work as a tab normally would if my cursor is positioned at the beginning of the line.
So far I have braces and quotes auto-pairing and re-positioning the cursor within them for C++/Java etc. I'd like to use the tab key to end-of-line if for example a function doesn't have any arguments.
Behaving differently depending on where point is in the line is the easy bit (see (if (looking-back "^") ...) in the code). "[Working] as a tab normally would" is the harder bit, as that's contextual.
Here's one approach, but I was thinking afterwards that a more robust method would be to define a minor mode with its own binding for TAB and let that function look up the fallback binding dynamically. I wasn't sure how to do that last bit, but there's a solution right here:
Emacs key binding fallback
(defvar my-major-mode-tab-function-alist nil)
(defmacro make-my-tab-function ()
"Return a major mode-specific function suitable for binding to TAB.
Performs the original TAB behaviour when point is at the beginning of
a line, and moves point to the end of the line otherwise."
;; If we have already defined a custom function for this mode,
;; return that (otherwise that would be our fall-back function).
(or (cdr (assq major-mode my-major-mode-tab-function-alist))
;; Otherwise find the current binding for this mode, and
;; specify it as the fall-back for our custom function.
(let ((original-tab-function (key-binding (kbd "TAB") t)))
`(let ((new-tab-function
(lambda ()
(interactive)
(if (looking-back "^") ;; point is at bol
(,original-tab-function)
(move-end-of-line nil)))))
(add-to-list 'my-major-mode-tab-function-alist
(cons ',major-mode new-tab-function))
new-tab-function))))
(add-hook
'java-mode-hook
(lambda () (local-set-key (kbd "TAB") (make-my-tab-function)))
t) ;; Append, so that we run after the other hooks.
This page of Emacs Wiki lists several packages (smarttab, etc.) which make TAB do different things depending on the context. You can probably modify one of them to do what you want.