How to write a function that will define a keyboard shortcut - elisp

I'm trying to write a function that will set a shortcut programmatically, as in the MRE below:
(defun my/shortcut-definer (keypress end-message)
(interactive)
(global-set-key
(kbd keypress)
'(lambda () (interactive) (message end-message))))
(my/shortcut-definer "C-x x x" "Hello!")
I am tantalisingly close, but when I enter the chosen keyboard shortcut, I get the error:
Symbol’s value as variable is void: end-message
I think the problem is when defining the shortcut I wanted it to evaluate end-message but instead it included the symbol. How can I make it evaluate end-message in the lambda? (Assuming that is the error).

Looking at this link I found a solution to this problem as follows:
(defun my/shortcut-definer (keypress end-message)
(interactive)
(global-set-key
(kbd keypress)
`(lambda () (interactive) (message ,end-message))))

Related

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!
"

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 '((?\' . ?\') (?\" . ?\") (?\{ . ?\}))) –

Symbol's value as variable is void: dired-mode-map

I'm trying to remap some keys in dired like this:
(add-hook 'dired-mode-hook
(lambda ()
(require 'dired )
(define-key dired-mode-map (kbd "M-o") nil)))
(define-key dired-mode-map (kbd "M-o") 'other-window)
))
Unfortunately this doesn't seem to work, I get this error
Symbol's value as variable is void: dired-mode-map
Which is werid, because I should be loading in dired. What could I be doing wrong?
The original poster has two (2) many [pun intended] closing parentheses at this point: (define-key dired-mode-map (kbd "M-o") nil))) -- i.e., two (2) closing parentheses at the end of that line need to be eliminated. Furthermore, I do not see a reason to set the binding to nil before redefining it.
The following is another way of accomplishing the same goal. Add any additional key bindings after the progn statement as desired.
(eval-after-load "dired" '(progn
(define-key dired-mode-map (kbd "M-o") 'other-window) ))

How can I change a word in a buffer using elisp?

How can I change the word at point using elisp? Something quite like (upcase-word) but using my own function?
Background: I've written a function that detects the base of the number at point and can convert it to any other base. What I would like to do is to change the number directly in the buffer.
TIA
Markus
Try this code. I've included a sample interactive function using upcase:
(defun change-word-at-point (fun)
(cl-destructuring-bind (beg . end)
(bounds-of-thing-at-point 'word)
(let ((str (buffer-substring-no-properties beg end)))
(delete-region beg end)
(insert (funcall fun str)))))
(defun upcase-word ()
(interactive)
(change-word-at-point 'upcase))

How to create interactive elisp function with optional arguments

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")))

Resources