How to create interactive elisp function with optional arguments - elisp

How do you write an elisp function, that should be bound to a key-press, that works without prompting by default, but when preceeded by Ctrl-u prompts the user for an argument. Something similar to (which is wrong syntax, but I hope you get the idea)?
(defun my-message (&optional (print-message "foo"))
(interactive "P")
(message print-message))
(global-set-key "\C-c\C-m" 'my-message)

The following use a feature of interactive that allows you to use code instead of a string. This code will only be executed when the function is called interactively (which makes this a different answer compared to the earlier answer). The code should evaluate to a list where the elements are mapped to the parameters.
(defun my-test (&optional arg)
(interactive (list (if current-prefix-arg
(read-from-minibuffer "MyPrompt: ")
nil)))
(if arg
(message arg)
(message "NO ARG")))
By using this method, this function can be called from code like (my-test) or (my-test "X") without it prompting the user for input. For most situations, you would like to design functions so that they only prompt for input when called interactively.

Following the same kind of implementation as your example, you could do something like this:
(defun my-message (&optional arg)
(interactive "P")
(let ((msg "foo"))
(when arg
(setq msg (read-from-minibuffer "Message: ")))
(message msg)))

If you just want to use the function as an interactive one, this code is all you need:
(defun my-message (&optional ask)
(interactive "P")
(message (if ask
(read-from-minibuffer "Message: ")
"foo")))

Related

How to advice-add a function with no arguments to a function that takes arguments?

Say I have a functions as follows:
(defun my/test-a (n)
(interactive)
(message n))
(defun my/test-b ()
(interactive)
(sleep-for .5)
(message "Message - B.")
(sleep-for .5))
I then advice my/test-a with mytest-b like so: (advice-add 'my/test-a :after #'my/test-b).
However when I call (my/test-a "Message - A.") I get a "Wrong number of arguments" error. My understanding is that add-advice is feeding the argument into my/test-b, which is not expecting any arguments.
How to advice-add a function with no arguments to a function that takes arguments?
I could change my/test-b so it takes an argument and doesn't use it, but that feels very messy.
Related followup - how could I advise find-file with a function with no arguments (like my/test-b)? I understand find-file is an unusual case, because it doesn't need an argument if called interactively. But if I run (advice-add 'find-file :after #'my/test-b) and then (call-interactively 'find-file) I get a "Wrong Number Of Arguments" error again.
TIA.
You can't do that.
Your advice function has to accept the arguments for the original function.
C-hig (elisp)Advice Combinators says:
:after
Call FUNCTION after the old function. Both functions receive the
same arguments, and the return value of the composition is the
return value of the old function. More specifically, the
composition of the two functions behaves like:
(lambda (&rest r) (prog1 (apply OLDFUN r) (apply FUNCTION r)))
A way to take arbitrary arguments and ignore them is:
(defun foo (&rest _args) ...)
The underscore tells the byte-compiler that the arguments are unused in the function body on purpose.

Evaluating code which refers to function parameters

Update: The original version of this question did not fully describe the constraints of my situation. It now includes an example with some hand-waving for the sake of simplicity as well as a testable minimum example.
I am trying to pass a snippet of code into a procedure for evaluation at a later point in time. The system with all of the constraints looks like this:
; External Library code - cannot be changed
(define (serialize-parameters . args)
(format some-file "~A~%" args))
(define (function-called-later-possibly-after-a-system-reboot callback)
(apply callback some-default-parameters (deserialize-parameters some-file)))
; Internal library code - can be changed, but the value of `code-snippet` cannot be hardcoded
(define (callback some-default-parameters code-snippet)
(eval code-snippet (current-module))
; Application code - can be changed, can be hardcoded
(define (main)
(serialize-parameters #:code-snippet '(format #t "~A~%" some-default-parameters)))
The main point is to allow the application to execute an arbitrary code snippet in a callback function. The callback function receives other parameters which are not known to the application and may change between calls.
An important constraint is that the parameters that the application wants to send to the callback are written to a file and then read back at a later point in time, possibly after a system reboot.
This example is easier to test, but does not capture all of the constraints:
(define (test foo bar)
(eval bar (current-module)))
(test "value of foo" '(format #t "~A~%" foo))
Running this program results in Unbound variable: foo. What I want is for the test function to be defined in such a way that the result of the call will be "value of foo\n" being printed to the terminal. Is this possible in Guile?
Thank you.
This will no work. eval takes an environment and you pass it (current-module). That are top level bindings in the module, like test but not any lexical bindings like foo or bar. They just don't exist in the environment returned by (current-module).
You can do this:
(define foo "value of foo")
(eval '(format #t "~A~%" foo) (current-module))
; prints "value of foo"
; ==> #t
Also, the elephant in the room is that you can do this with lambdas:
(define (test value proc)
(proc value))
(test "value to process" (lambda (foo) (format #t "~A~%" foo)))
; prints "value to process"
; ==> #t
Alternatively, but I'm guessing you can't have format in callback because "code-snippet" can have many different values:
(define (main)
(serialize-parameters #:code-snippet "~A~%"))
(define (callback some-default-parameters code-snippet)
(format #t code-snippet some-default-parameters))
EDIT
I think you can do it semi hard-coded:
(define (main)
(serialize-parameters #:code-snippet 'print-format))
(define (callback argument message)
(case message
((print-format) (format #t "~A~%" argument))
((other-message) (handle-message ...))
(else ...)))
You can even make it a dynamic dispatcher. Eg. you do something like this:
(define messages '())
(define (register-callback message proc)
(set! messages (cons (cons message proc) messages)))
(define (callback argument message)
(let ((found (assq message messages)))
(when found
((cdr found) argument))))
(register-callback 'print-format (lambda (arg) (format #t "~A~%" arg)))
(callback "test" 'print-format) ; prints "test"
Now only the message gets stored in a file, which easily can be any data literal.

What is the Scheme equivalent of this alias code written in CL?

I'm trying to write the Scheme equivalent of this CL code:
(defmacro alias (new-name prev-name)
`(defmacro ,new-name (&rest args)
`(,',prev-name ,#args)))
;; Sample use:
(alias co concatenate)
My aim is to be able to use shorthand names for symbol and function names like:
(alias sa string-append)
(sa "ok" "not ok")
To do that I've tried this but it didn't work:
(define-syntax alias (new-name prev-name)
`(define-syntax ,new-name (#!rest args)
`(,',prev-name ,#args)))
Any help is appreciated. Thank you.
You can do this easily with a syntax-rules macro that defines another syntax-rules macro:
(define-syntax alias
(syntax-rules ()
((_ new-name prev-name)
(define-syntax new-name
(... (syntax-rules ()
((_ arg ...)
(prev-name arg ...))))))))
The trickiest thing is this macro is the use of ... to escape nested uses of ....
However, this is not necessarily the best way to do this. The best way probably depends on your precise Scheme implementation, as Scheme is less a language and more a family of languages. Writing portable Scheme is usually not very useful.
If your scheme supports R6RS syntax-case and cognates (say, guile or chez scheme), identifier-syntax is the most direct way of implementing what you want:
(define-syntax new-name (identifier-syntax old-name))
Thus:
(define-syntax new-display (identifier-syntax display))
(new-display "hello\n")
Edit: I see you are using chicken. In that case you can use er-macro-transformer to reproduce your defmacro solution (this works with chicken-4.10.0 at any rate):
(define-syntax alias
(er-macro-transformer
(lambda (exp r c)
(let ([new-name (cadr exp)]
[old-name (caddr exp)])
`(define-syntax ,new-name
(ir-macro-transformer
(lambda (exp i c)
`(,',old-name ,#(cdr exp)))))))))
By the way, in Common Lisp you can make an alias a real function, not a macro, by settings symbol-function of a symbol denoting an alias like this:
CL-USER> (defun foo (name)
(format nil "Hello ~A!~%" name))
FOO
CL-USER> (setf (symbol-function 'bar)
#'foo)
#<INTERPRETED-FUNCTION FOO>
CL-USER> (bar "Bob")
"Hello Bob!
"

Common Lisp No Dispatch Character Defined

I am currently reading the chapter on read-time macros from Paul Graham's "On Lisp" book.
The problem I am encountering is the following. When I run one of his examples:
(set-dispatch-macro-character #\# #\?
#’(lambda (stream char1 char2)
‘#’(lambda (&rest ,(gensym))
,(read stream t nil t))))
I get the following error:
No dispatch function defined for #\’
Why is it happening? Could it be because I am running it at the REPL? What can one do to fix it?
The PDF from which you are copying the code uses punctuation marks outside the range of basic ASCII characters you are supposed to use here:
CL-USER> (char-name #\’)
"RIGHT_SINGLE_QUOTATION_MARK"
The usual quote symbol should instead use the apostrophe character:
CL-USER> (char-name #\')
"APOSTROPHE"
The same goes for backquote:
CL-USER> (char-name #\‘)
"LEFT_SINGLE_QUOTATION_MARK"
You should be writing instead:
(set-dispatch-macro-character #\# #\?
#'(lambda (stream char1 char2)
`#'(lambda (&rest ,(gensym))
,(read stream t nil t))))
The #' is not necessary before lambda, since Common Lisp also defines a macro named lambda which expands into (function (lambda ...)).
You can test your new read macro as follows:
CL-USER> #?10
#<FUNCTION (LAMBDA (&REST #:G617)) {1001C541FB}>
CL-USER> (funcall *)
10
When using SBCL, I obtain warnings about unused variables. This happens because the code declares variables in anonymous functions but never uses them. This is not a serious problem, but generally speaking, it is better to declare which variables are ignored:
(set-dispatch-macro-character
#\# #\?
(lambda (stream &rest chars)
(declare (ignore chars))
(let ((rest (gensym)))
`(lambda (&rest ,rest)
(declare (ignore ,rest))
,(read stream t nil t)))))

Electric-pair-mode not detected for some characters with German keyboard layout

So I am trying to get a grip on Emacs 24.5 running on Mac Os 10.10.4.
I have a German keyboard and decided to keep the alt -key as Meta. As I still have to use it for some essential characters such as [ , | and } (resembling alt-5, alt-6 and alt-9) it decided to go with this solution:
(global-set-key "\M-5" (lambda () (interactive) (insert “[“)))
(global-set-key "\M-6" (lambda () (interactive) (insert “]”)))
(global-set-key "\M-7" (lambda () (interactive) (insert “|”)))
...
When I am enabling electric pair mode in the init-file with (electric-pair-mode 1) , it works just fine with ( ) and " ", but not with [ ], { } and ' '.
I then tried a different appraoch by using this code to swap the keys:
(defun redefine-key (key char)
(define-key function-key-map key char)
(global-unset-key key))
(redefine-key "\M-5" "[")
(redefine-key "\M-6" "]")
...
Interestingly, the pair feature now works for the square brackets [ ], but not the curly ones { }. Although the ' key on the German keyboard is not even related to the alt-key (it's accessed by the shift-key), it doesn't work at all. Same results for the autopair package, btw.
Please, anyone? Thanks so much!
The way electric-pair-mode works is by installing a callback function ("hook") called electric-pair-post-self-insert-function. As the name suggests, this hook gets invoked by Emacs after the function self-insert-command runs -- which is after you type a key.
And that's your problem here: calling insert is not the same as typing a key. It does not invoke self-insert-command and consequently, the above hook function never gets called. Even worse, you cannot simply invoke self-insert-command programmatically because, unlike insert, it doesn't take a parameter for the character to insert. You have to jump through hoops a bit, but you could try the following:
(global-set-key "\M-5" (lambda (&optional N) (interactive "P") (insert-as-self ?\[ N)))
(global-set-key "\M-6" (lambda (&optional N) (interactive "P") (insert-as-self ?\] N)))
(global-set-key "\M-7" (lambda (&optional N) (interactive "P") (insert-as-self ?\| N)))
(defun insert-as-self (CHAR N)
(let ((last-command-event CHAR)
(repeat (if N N 1)))
(self-insert-command repeat)))
Here, we locally set the special variable last-command-event to "fake" a key stroke before calling self-insert-command.
For curly braces and quotes to work, you have to do two things: First, add the respective (global-set-key ...) definitions to your .emacs file, similar to the ones above. Then let electric-pair-mode know that you want quotes and curlies to be handled by it by adding the following line to your .emacs file:
(setq electric-pair-pairs '((?\' . ?\') (?\" . ?\") (?\{ . ?\}))) –

Resources