Hi I am trying to define an interactive menu when using 'm' in neotree to give me similar options to what I used in Nerdtree.
I binded this key:
(evil-define-key
'normal neotree-mode-map
... More keybindings ...
(kbd "m") 'neotree-modify-mode-menu)
and my function is:
(defun neotree-modify-mode-menu (option)
"Asks for a mode and execute associated Neotree command"
(interactive "c(a)dd node | (d)elete node | (r)ename node")
(cond
((eq option ?a) (neotree-create-node))
((eq option ?d) (neotree-delete-node))
((eq option ?c) (neotree-copy-node))
((eq option ?r) (neotree-rename-node))
(:else (message (format "Invalid option %c" option)))))
it works for every option but not create-node. The reason is because create-node takes one argument as I can see here: https://github.com/jaypei/emacs-neotree/blob/dev/neotree.el#L1921 and the rest take no arguments.
So I get this error when calling the function from the keybinding:
Wrong number of arguments: #[(filename) "Å2w^#Æ^X GÇU\203^R^#ÈÅÆ\"\210 ÉÆOÊ\232?^PË !\203*^#ÌÍ \"\210ÈÅÆ\"\210^H\203[^#
ÎÏ \"!\203[^#Ð ÇÑÒ ÓÔ$TOÔ\"\210ÕÖÆ #\210× !\210ØÆ!\210^K\203[^#Ù !\210^H?\205u^#^LÎÚ \"!\205u^#Ð Ô\"\210× !\210ØÆ!)0\207" [is-file filename neo-confirm-create-file neo-create-file-auto-o\
pen neo-confirm-create-directory rlt nil 0 throw -1 ...] 8 ("/home/panavtec/.emacs.d/elpa/neotree-20170522.758/neotree.elc" . 64641) (let* ((current-dir (neo-buffer--get-filename-current-lin\
e neo-buffer--start-node)) (current-dir (neo-path--match-path-directory current-dir)) (filename (read-file-name "Filename:" current-dir))) (if (file-directory-p filename) (setq filename (con\
cat filename "/"))) (list filename))], 0
If i bind the key to neotree-create-node function it works:
(evil-define-key normal neotree-mode-map
(kbd "m") 'neotree-create-node)
How I can fix it?
Clearly you need to provide an argument for create node. What argument do you want to provide it? How do you expect to get that argument?
If you always want to use the same argument value then just hard-code it in your call to neotree-create-node.
Otherwise, have your interactive spec read it.
Your interactive spec is anyway wrong - see the Elisp manual, node Using Interactive.
I found the answer, when you are in a function that is called interactivly the argument of that function is automagically populated with the answer of the user. as I used "option" in my question:
(defun neotree-modify-mode-menu (option)
(interactive "c(a)dd node | (d)elete node | (r)ename node")
But if you need to call another function that need interactive you have to call it with call-interactively
Full code:
https://github.com/PaNaVTEC/dotfiles/commit/f69c855cb2d31d79ab81331a5ee53cb9cd8e2f38#diff-e68ea0da4891dbc0f47897e9562e9daeR29
Thanks.
Related
I have a defun that conveniently adds / removes parentheses to marked expressions. (see code in the end)
As a neophyte in emacs Lisp, I only know how to make simple key-bindings without argument.
However, I believe the defun would be made more convenient if its key-binding could take two optional arguments to specify whether to add / remove (), [], or {}
My current (simple) key-binding is as below, is there a trivial way to make it argument-taking as described?
(global-set-key (kbd "C-M-( )") 'end-of-statement)
Appreciate any advice or direction tips!
(Code: by Istvan Chung)
(defun surround-with-parens ()
(interactive)
(save-excursion
(goto-char (region-beginning))
(insert "("))
(goto-char (region-end))
(insert ")"))
(defun delete-surrounded-parens ()
(interactive)
(let ((beginning (region-beginning))
(end (region-end)))
(cond ((not (eq (char-after beginning) ?\())
(error "Character at region-begin is not an open-parenthesis"))
((not (eq (char-before end) ?\)))
(error "Character at region-end is not a close-parenthesis"))
((save-excursion
(goto-char beginning)
(forward-sexp)
(not (eq (point) end)))
(error "Those parentheses are not matched"))
(t (save-excursion
(goto-char end)
(delete-backward-char 1)
(goto-char beginning)
(delete-char 1))))))
I assume the question is for surround-with-parens, as delete-surrounded-parens is probably better off just guessing the parentheses used by itself.
I also assume that you are doing this for practice more so than for actually solving the problem. If you enable electric-pair-mode in recent Emacsen, configured pairs will wrap around any active region as your command does. But it's a good mid-level emacs lisp exercise.
As the comments noted, you have multiple options.
Command Argument
A command can take arguments, as you asked for. Commands are no different from other lisp functions, except that they have an interactive spec. The interactive spec tells Emacs how to run the command when it is invoked with a key or via M-x.
Simple (interactive) will pass no arguments to the function. (interactive "r") will pass the beginning and end of the region as two arguments. Etc. You can read about the different options in C-h f interactive. You can even write lisp code to calculate the arguments there.
You could use (interactive "cWrap with: "). This would prompt the user for a key, and pass the key to your function. For example, if the user types (, your function receives 40 as the argument, the character code for the opening parenthesis. ?\( is 40 as well, and (make-string 1 40) returns "(". You'll have to create a map to figure out the closing parenthesis.
The drawback here is that you need to press two keys: The first to invoke the command, and then a key to specify the parenthesis to use.
Multiple keys
You can also bind your command to different keys – for example, C-M-( and C-M-[. You can then use this-single-command-keys to get something that specifies the last key event. Sadly, this can be somewhat tricky to translate back to a key sequence. E.g. C-M-( returns [201326632].
Multiple commands
You could also just define one command per parenthesis type, all of which simply call a common function with arguments, and bind those commands to keys.
post-self-insert-hook
Finally, you can use the same method as electric-indent-mode does: Add a function to post-self-insert-hook and decide based on char-before what you want to do.
I have a problem when using Etags in Emacs. Everytime I tap \M+. to jump to a difinition point, a query is always popping up, like:
Find tag (default function_name):
And I have to tap 'Enter' to make sure of it.
But in most cases, I find I can choose the default one. So is there any method with which I can surpress this message?
I found the reason is because:
(defun find-tag (tagname &optional next-p regexp-p)
(interactive (find-tag-interactive "Find tag: "))
...
)
Why do I have to choose a tag? Why can not the default one just be the word under the point? Can I just remove this line? (interactive), or is there a good solution?
Going shortly through a couple of defuns in the etags sources via Emacs's awesome C-h f, one can find that the default tag to search is determined via a function named find-tag-default.
This means you could just define the following function:
(defun find-tag-under-point ()
(interactive)
(find-tag (find-tag-default)))
Then you can bind this to whatever key you want via define-key or global-set-key or local-set-key.
(The interactive form is always necessary if you want a function to be a "command" which can be called with M-x or bound to a key.)
You can write your own functionality over the find-tag (or any interactive function likewise)
(defun find-tag-under-point (&optional arg)
(interactive "P")
(cond ((eq arg 9)
(let ((current-prefix-arg nil))
(call-interactively 'find-tag)))
(arg
(call-interactively 'find-tag))
(t
(find-tag (find-tag-default)))))
(global-set-key (kbd "M-.") 'find-tag-under-point)
Then hotkey C-9M-. calls find-tag (old function) as usual, but the behaviour of find-tag-under-point (new-function) by default is what you want.
I'm writing a derived mode, based on comint-mode. The mode is an interface to a command line program (GRASS gis), and the comint mode completion works for the programs. I'm trying to add on support for completing the arguments to the program, via completion-at-point-functions. A toy example is:
(setq my-commands
'(("ls"
("my-completion-1")
("my-completion-2"))
("mv"
("my-completion-3")
("my-completion-4"))))
(defun my-completion-at-point ()
(interactive)
(let ((pt (point)) ;; collect point
start end)
(save-excursion ;; collect the program name
(comint-bol)
(re-search-forward "\\(\\S +\\)\\s ?"))
(if (and (>= pt (match-beginning 1))
(<= pt (match-end 1)))
() ;; if we're still entering the command, pass completion on to
;; comint-completion-at-point by returning nil
(let ((command (match-string-no-properties 1)))
(when (member* command my-commands :test 'string= :key 'car)
;; If the command is one of my-commands, use the associated completions
(goto-char pt)
(re-search-backward "\\S *")
(setq start (point))
(re-search-forward "\\S *")
(setq end (point))
(list start end (cdr (assoc command my-commands)) :exclusive 'no))))))
(push 'my-completion-at-point completion-at-point-functions)
This almost works. I get normal completion of program names. However, if I have entered ls at the command line, hitting tab inserts my-completion- and doesn't offer the two options. Hitting tab again inserts my-completion- a second time, so that I now have ls my-completion-mycompletion-.
My actual code includes a few lines to check for multi-line commands, but makes no changes to the completion code. With this version of the code, I hitting tab on a line that starts with one of the program names in my-commands I am presented with a list of the possible arguments to complete the command with, but nothing is inserted in the buffer, and the list does not get narrowed by typing the first few letters of an argument.
I've been over the manual, but I can't figure out the correct way to write a completion-at-point function. Any ideas what I'm missing?
I have looked briefly at pcomplete, but the didn't really understand the 'documentation', and didn't make any progress.
The problem seems to be with the way you're finding start and end to return the boundaries of the argument at point. I didn't spend long enough debugging it to be sure of the details, but I think if you call the function interactively you'll see that it returns the same value for start and end, and this means that the completion UI doesn't know to use the argument at point to select from the completion table you've passed it.
Changing the last part of your function to the following seems to be one fix:
(when (member* command my-commands :test 'string= :key 'car)
;; If the command is one of my-commands, use the associated completions
(goto-char pt)
(let ((start
(save-excursion
(skip-syntax-backward "^ ")
(point))))
(list start pt (cdr (assoc command my-commands)) :exclusive 'no)))))))
This gives the expected results when added as an element of completion-at-point-functions.
Here I've used skip-syntax-backward instead of regexp search, which I think is slightly more idiomatic Elisp for this kind of thing. It just says to move point backwards across anything that is not in syntax class "whitespace". The skip-syntax functions return the distance moved rather than the value of point, so we have to add a call to point at the end of the save-excursion.
If you do use regexp searches in a function like this, it's usually a good idea to pass t for the fourth argument, noerror, so that it doesn't pass on errors to the user if it fails to match. This does mean that you have to check for yourself whether the return value is nil, though.
Finally, instead of push to add the completion function you might want to use add-hook as follows:
(add-hook 'completion-at-point-functions 'my-completion-at-point nil t)
This does two useful things: it checks whether your function is already in the hook before adding it, and (by passing t for the fourth argument, local) it only adds the function to the buffer-local value of the completion-at-point hook. This is almost certainly what you want, since you don't want to use these completions in every other Emacs buffer when you press the TAB key.
From the documentation I can see I can access command line arguments (command-line-args).
I'd like to add my own arguments but Emacs complains at start up that it doesn't recognize them.
E.g.
emacs -my_argument
I get:
command-line-1: Unknown option `-my_argument'
What's a proper way to define my custom arguments and provide information to my Emacs session?
Is there a way to pop an argument from a command line?
Add something like this to your ~/.emacs, ~/.emacs.el, or ~/.emacs.d/init.el file:
(defun my-argument-fn (switch)
(message "i was passed -my_argument"))
(add-to-list 'command-switch-alist '("-my_argument" . my-argument-fn))
Then you can execute emacs -my_argument and it should print i was passed -my_argument to the minibuffer. You can find more information in the GNU elisp reference.
As stated in another post you can add your custom switches to command-switch-alist and emacs will call the handler function for any matching switch passed in on the command line. However, this operation is done after your .emacs file has been evaluated. This is fine for most cases but you may wish for a command line argument to alter the execution path or behaviour of your .emacs evaluation; I often do this to enable/disable configuration chunks (mainly for debugging).
To achieve this you can read command-line-args and check for your switch manually and then delete it from the list, this will stop emacs complaining about an unknown argument.
(setq my-switch-found (member "-myswitch" command-line-args))
(setq command-line-args (delete "-myswitch" command-line-args))
Which can alter your .emacs evaluation like so:
(unless my-switch-found
(message "Didn't find inhibit switch, loading some config.")
...)
And you could build this into a single step:
;; This was written in SO text-box, not been tested.
(defun found-custom-arg (switch)
(let ((found-switch (member switch command-line-args)))
(setq command-line-args (delete switch command-line-args))
found-switch))
(unless (found-custom-arg "-myswitch")
(message "Loading config...")
...)
For those who are interested, here is a code snip to show how to process custom arguments in Emacs lisp. In this case, I am processing an argument --suffix / -S to variable _suffix.
I pulled the idea from a BSD-Lite Script Emacs script.
(setq _suffix nil)
;; Process cli args
(while command-line-args-left
(setq k (car command-line-args-left))
(setq command-line-args-left (cdr command-line-args-left))
(setq command-line-args (delete k command-line-args))
(cond
(or (string-equal k "--cs-suffix")
(string-equal k "-S"))
(setq _suffix (intern (car command-line-args-left)))
(setq command-line-args-left (cdr command-line-args-left))
(setq command-line-args (delete _suffix command-line-args))
)))
This will roll through command-line-args-left and remove them all from command-line-args which will prevent Emacs from complaining.
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.