Emacs lisp - autocomplete bookmark names - emacs

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.

Related

How to extend Neotree to open a file using hexl?

I'm trying to extend Neotree to open a file using hexl-mode with the shortcut C-c C-x. How would one do this?
I've tried to evaluate a key definition after the Neotree load where it uses my/neotree-hex to open a file path using neo-buffer--get-filename-current-line.
(defun my/neotree-hex
(hexl-find-file neo-buffer--get-filename-current-line))
(with-eval-after-load 'neotree
(define-key neotree-mode-map (kbd "C-c C-x")
'my/neotree-hex))
At the very least, you are missing the (empty) argument list in the function:
(defun my/neotree-hex ()
(hexl-find-file neo-buffer--get-filename-current-line))
I don't know what neo-buffer--get-filename-current-line is: if it is a function, then you are not calling it correctly - in lisp, you call a function by enclosing the (name of the) function and its arguments in parens: (func arg1 arg2 ...)[1]; so if it is a function and it takes no arguments, then your function should probably look like this:
(defun my/neotree-hex ()
(interactive)
(hexl-find-file (neo-buffer--get-filename-current-line)))
In order to be able to bind it to a key, you have to make your function a command, which means that you need to add the (interactive) form.
Disclaimer: I know nothing about neotree.
[1] You might want to read an introduction to lisp. One (specifically tailored to Emasc Lisp) is included with the emacs documentation, but is also available online. Eventually, you will want to read the Emacs Lisp Reference Manual. Calling a function is covered in the Introduction and is covered in detail in the Reference.

Emacs: How to select word under cursor and append to file

I want the following behavior:
Append the word under cursor into a file(~/vocabulary.txt, for example)
Better still to bind a key for it.
Could anyone show me how to do it?
Should I put those code into .emacs ?
Try the following function:
(defun my-write-to-file ()
"Save word at point to file"
(interactive)
(write-region (concat (thing-at-point 'word) "\n") nil "~/vocabulary.txt" 'append))
When called, this function will save the word at point (the word the cursor is on or the word right before the cursor) to ~/vocabulary.txt.
You can bind it to a key (C-c w in this case, but you can change it to whatever you like) like this:
(global-set-key (kbd "C-c w") 'my-write-to-file)
To use, simply put the function and the keybinding assignment in your .emacs.
#Elethan wrote you a command that does just what you ask for, and bound it to a key.
It might also help to mention some general commands that you can use for this kind of thing. M-x append-to-file appends the region contents to a file, and M-x write-region prepends.
The manual is your friend for things like this. See nodes Misc File Ops and Accumulating Text.
Be aware too that for the two commands just mentioned, as the manual says about append-to-file (it should say it about both):
You should use append-to-file only with files that are not being
visited in Emacs. Using it on a file that you are editing in Emacs
would change the file behind Emacs’s back, which can lead to losing some
of your editing.
Accumulating Text also tells you about commands for adding text to a buffer, including the case of adding to a buffer for a file that you are visiting (as opposed to what the above quote warns you about for append-to-file). These include commands append-to-buffer and prepend-to-buffer.

Interactively select multiple items

How can I let the user select multiple items from a list instead of just one? Like in the C-x b menu in helm.
Currently I can only select a single item instead of getting a complete list:
(defun test-main ()
(interactive)
(let ((choice (completing-read "Select: " '("item1 item2 item3"))))
(message choice)))
You can do that with completing-read-multiple:
(defun test-main ()
(interactive)
(let ((choice (completing-read-multiple "Select: " '("item1" "item2" "item3"))))
(message "%S" choice)))
It returns the selected items as a list, so if you type item2,item3 at the prompt, it returns ("item2" "item3").
Because that's what vanilla completing-read does. It reads and returns a single choice, providing completion to help you choose.
You can do what you are asking for with Icicles. It redefines function completing-read when Icicle mode is on.
Many Icicles commands are multi-commands, which means that you can make multiple input choices in a single command execution: a multiple-choice command. You can define your own multi-commands, using any actions.
And for any completion (not just for a multi-command), you can manipulate, save, and restore sets of completion candidates.
(You can also enter multiple inputs in the minibuffer. This is useful even for commands that read input without completion.)

Emacs: Is it possible to assign a number-key kb shortcut to a buffer?

I use desktop sessions to save project state between loads. Sometimes I am working on a feature that is shared between a few buffers, and would love to assign a quick keyboard shortcut like -# to a buffer. Then I could switch between a fe buffers by hitting cmd-1, cmd-2, cmd-3, etc. Thoughts?
Thanks!
I'm using this code for this purpose:
(require 'bookmark)
(defvar zz-minibuffer-map (copy-keymap minibuffer-local-must-match-map)
"Keymap for `bookmark-do-quick-jump'")
(define-key zz-minibuffer-map
[remap self-insert-command] 'zz-self-insert-complete-and-exit)
(define-key zz-minibuffer-map " " "-")
(defvar zz-display-function nil)
(defun zz-self-insert-complete-and-exit (n)
(interactive "p")
(self-insert-command n)
(ignore-errors
(completion--do-completion nil 'expect-exact))
(let ((candidates (completion-all-sorted-completions)))
(cond
((null candidates)
(backward-delete-char-untabify 1)
(minibuffer-complete))
((eq 1 (safe-length candidates))
(minibuffer-complete-and-exit)))))
;;;###autoload
(defun zz-bookmark-jump (bookmark)
"Jump to specified bookmark with auto-completion and auto-acceptance."
(interactive
(list
(if (window-minibuffer-p)
(error "Already in minibuffer")
(let ((minibuffer-local-must-match-map zz-minibuffer-map))
(completing-read "Jump to bookmark: " bookmark-alist nil t)))))
(ignore-errors
(bookmark-jump bookmark zz-display-function)))
Just bind zz-bookmark-jump to what you want, say M-m.
Now, if you name a bookmark as 1..., where ... is anything you want, and no other
bookmarks start with 1, M-m 1 will jump to that bookmark.
Here are some of my bookmarks for reference:
b: .bashrc ~/.bashrc
e: .emacs ~/.conf.d/.emacs
h: hooks.el - no file -
L: main.cc ~/Dropbox/source/c++/lattice/main.cc
m: magit - no file -
q: *scratch* - no file -
s: source ~/Dropbox/source/
I like to add : to make them look nice visually when I call bookmark-bmenu-list.
If you use Bookmark+ then you can use desktop bookmarks. "Jumping" to such a bookmark restores the saved desktop - each bookmark refers to a particular desktop file.
Bookmarks are persistent.
A bookmark name can use any characters - it could be 1 or 9 or 312. You can bind a single key (including a digit key, if you like) to the command that jumps to a bookmark whose name you enter (with completion).
You can also easily define a command that jumps to a given bookmark. And you can bind such a command to any single key you like: 1, 2,... or -1, -2,... (though that might not be a great idea ;-)).
(FWIW, a command name must be a symbol name, a symbol name must have symbol characters, and it cannot have the syntax of a number (which 2 and -2 do). So you could name commands a1, a2,... or _1, _2,... or -a1, -a2,.... But you are anyway unlikely to call such commands by their names.)
UPDATE
If you just want to switch/navigate among the files or buffers of a project, without closing other buffers etc. then look for project-support Emacs features and extensions. There are plenty available, including some (such as Dired) that come with vanilla Emacs.
With Bookmark+, for example, you can use bookmarks of various types, including the following, to help manage software projects:
Dired buffers, with specific sets of files and subdirectories
that are marked or omitted, and using specific listing switches.
*Bookmark List* buffers, with specific sets of bookmarks that
are marked or hidden.
Multiple alternative bookmark files. For example, use a
different one for each project. Or use different ones for
subprojects and use them together for a full project.
DeskTops (already mentioned), which include sets of variables and visited buffers
and files.
Sequence bookmarks, which combine other bookmarks.
You can also associate tags, in the delicious sense, with most
types of bookmarks. (Such tags are unrelated to the Emacs
source-code tags that use TAGS files.) A bookmark can have any
number of tags, and multiple bookmarks can have the same tag,
which means you can use them to organize their target objects.
And tags can be more than just names: they can be user-defined
attributes, with Emacs-Lisp objects as their values.
These and other Bookmark+ features give you different ways to
save, restore, filter, access, and otherwise organize projects, as
collections of information about source-code components and
related software.
Icicles enhances access to such Bookmark+ features, and it provides additional project-support features.

An alternative find file function with the same default folder, every time

I'd like to bind super and 9 to open the "find file:", "C-x C-f" menu with ~/x/ as the "default path" in the user input field, no matter what directory the file I currently have open is in. My elisp skills are unfortunately pretty basic. I would really appreciate some help with this.
(global-set-key (kbd "s-9") 'enter_find_file_with_dir_x_as_default)
(defun enter_find_file_with_dir_x_as_default ()
"Enter find file with the path ~/x/ as the default input every time."
())
Just define a command that calls read-file-name with the directory you want as the default (in the interactive spec), and then calls find-file on the file name read.
(defun my-find-file (file)
"..."
(interactive (list (read-file-name "File: " "~/x/")))
(find-file file))
See the doc for read-file-name, to decide what other arguments you might want (e.g., whether you accept only existing file names or allow a new-file buffer).
Note too that if you want to bind this to a key then it has to be a command, so it needs an interactive spec. If you just wanted a function that reads a file name starting in directory ~/x/ then the answer is read-file-name -- just pass it ~/x/ as its DIR argument.
See the Elisp manual, node Reading File Names, for more information. (C-h i; choose Elisp; i read-file-name.)