Automatic creation of repeatable command - emacs

There are already some questions on the topic of repeatable emacs commands (i.e. the behaviour of C-x z [repeat-command], where each subsequent z repeats the last command), however, none of the automatic solutions can cope with non-prefix keybindings (My terminology: C-c p is a prefix keybinding with prefix C-c, the keystroke M-s-+ on the other hand is a non-prefix keybinding).
In my setup I have bound M-s-+ to text-scale-increase and M-s-- to text-scale-decrease. It would be nice to just hit + or - for repeated zooming after the initial command. This can be achieved by the following piece of elisp:
(defvar text-scale-temp-keymap (make-sparse-keymap))
(define-key text-scale-temp-keymap (kbd "+") 'text-scale-increase)
(define-key text-scale-temp-keymap (kbd "-") 'text-scale-decrease)
(defun text-scale-increase-rep (inc)
(interactive "p")
(text-scale-increase inc)
(set-temporary-overlay-map text-scale-temp-keymap t))
(defun text-scale-decrease-rep (inc)
(interactive "p")
(text-scale-decrease inc)
(set-temporary-overlay-map text-scale-temp-keymap t))
(global-set-key (kbd "M-s-+") 'text-scale-increase-rep)
(global-set-key (kbd "M-s--") 'text-scale-decrease-rep)
However, to repeat this code every time I want to create a repeatable keybinding is cumbersome and unnecessary. I'm asking for a way to automatise the task. Image this code
(make-repeatable-command 'text-scale-increase '(("+" . text-scale-increase)
("-" . text-scale-decrease)))
would create the command named text-scale-increase-rep and an overlay keymap named text-scale-increase-temporary-map with the corresponding keys.
I assume this is possible, but how?

Try this:
(defun defrepeatable (alist)
(lexical-let ((keymap (make-sparse-keymap))
(func (cdar alist)))
(mapcar (lambda(x) (define-key keymap (car x) (cdr x))) alist)
(lambda (arg)
(interactive "p")
(funcall func arg)
(set-temporary-overlay-map keymap t))))
(global-set-key (kbd "C-z")
(defrepeatable
'(("+" . text-scale-increase)
("-" . text-scale-decrease))))

An alternative --
You do not need all of that, if all you want to do is (a) define a repeatable command and (b) bind it to a (repeatable) key.
The solution I presented in the pages (1, 2) that you linked to, applies here too. The point of that solution was not that it is limited to use with a prefix key but that you can also use it to repeat a key that is on a prefix key.
Here is the same solution, applied to your example. You only need to define repeat-command once -- you can use it to define any number of repeatable commands.
(defun repeat-command (command)
"Repeat COMMAND."
(interactive)
(let ((repeat-previous-repeated-command command)
(last-repeatable-command 'repeat))
(repeat nil)))
(defun text-scale-increase-rep (inc)
(interactive "p")
(repeat-command 'text-scale-increase))
(defun text-scale-decrease-rep (inc)
(interactive "p")
(repeat-command 'text-scale-decrease))
(global-set-key (kbd "M-s-+") 'text-scale-increase-rep)
(global-set-key (kbd "M-s--") 'text-scale-decrease-rep)

Related

emacs: toggle binding of number row to <shift>-ed equivalent

In emacs, I would like to rebind the top row of my keyboard [1...0] so that hitting an unmodified key results in its shifted equivalent. That is, typing 1234567890 would result in !"£$%^&*() being inserted in the buffer.
I am using emacs 24.1.1 in Windows Vista, with viper-mode enabled. I am doing some Common Lisp programming using slime. I use viper so that I can avoid using Ctrl and Shift too often as I can get a bit of emacs pinkie (RSI). Having started programming in lisp, I have found that hitting S-9 and S-0 to open and close parentheses is starting to take its toll.
By including the following in my start-up file, I can bind 9 to ( and vice-versa.
(defvar my-keymap
(let ((map (make-sparse-keymap)))
(define-key map (kbd "9") '(lambda () (interactive) (insert "(")))
(define-key map (kbd "(") '(lambda () (interactive) (insert "9")))
map))
(viper-modify-major-mode
'lisp-mode
'insert-state
my-key-map)
This works well enough and is easily extended to the rest of the row, except that I would like to be able to toggle between the two modes without having to hold down shift (say, by toggling Caps Lock).
Is there any way to do this, or am I approaching it all wrong?
Here's an example I quickly hacked together, tested it in Emacs24 on Linux:
(setq viper-mode-key-mapping "custom")
(defvar custom-viper-keymap
(let ((map (make-sparse-keymap)))
(define-key map (kbd "9") '(lambda () (interactive) (insert "(")))
(define-key map (kbd "(") '(lambda () (interactive) (insert "9")))
map))
(defvar default-viper-keymap
(let ((map (make-sparse-keymap)))
(define-key map (kbd "9") '(lambda () (interactive) (insert "9")))
(define-key map (kbd "(") '(lambda () (interactive) (insert "(")))
map))
(defun switch-viper-mode-custom-keymap ()
(interactive)
(if (string= viper-mode-key-mapping "default")
(progn (setq viper-mode-key-mapping "custom")
(viper-modify-major-mode 'lisp-mode 'insert-state custom-viper-keymap))
(progn (setq viper-mode-key-mapping "default")
(viper-modify-major-mode 'lisp-mode 'insert-state default-viper-keymap))))
(global-set-key [(control f1)] 'switch-viper-mode-custom-keymap)
When I have viper-mode activated, pressing CTRL-F1 switches the keyboard mapping from custom to normal.

Emacs: scroll buffer not point

Is it possible to scroll the entire visible portion of the buffer in Emacs, but leave point where it is. Example: point is towards the bottom of the window and I want to see some text which has scrolled off the top of the window without moving point.
Edit: I suppose C-l C-l sort of does what I wanted.
try these. Change M-n and M-p key bindings according to your taste
;;; scrollers
(global-set-key "\M-n" "\C-u1\C-v")
(global-set-key "\M-p" "\C-u1\M-v")
;;;_*======================================================================
;;;_* define a function to scroll with the cursor in place, moving the
;;;_* page instead
;; Navigation Functions
(defun scroll-down-in-place (n)
(interactive "p")
(previous-line n)
(unless (eq (window-start) (point-min))
(scroll-down n)))
(defun scroll-up-in-place (n)
(interactive "p")
(next-line n)
(unless (eq (window-end) (point-max))
(scroll-up n)))
(global-set-key "\M-n" 'scroll-up-in-place)
(global-set-key "\M-p" 'scroll-down-in-place)
This might be of use. According to the EmacsWiki page on Scrolling;
The variable scroll-preserve-screen-position may be useful to some.
When you scroll down, and up again, point should end up at the same
position you started out with. The value can be toggled by the built
in mode M-x scroll-lock-mode.
I think this is better:
(defun gcm-scroll-down ()
(interactive)
(scroll-up 1))
(defun gcm-scroll-up ()
(interactive)
(scroll-down 1))
(global-set-key [(control down)] 'gcm-scroll-down)
(global-set-key [(control up)] 'gcm-scroll-up)
reference : emacs wiki
;; Preserve the cursor position relative to the screen when scrolling
(setq scroll-preserve-screen-position 'always)
;; Scroll buffer under the point
;; 'scroll-preserve-screen-position' must be set to a non-nil, non-t value for
;; these to work as intended.
(global-set-key (kbd "M-p") #'scroll-down-line)
(global-set-key (kbd "M-n") #'scroll-up-line)
Based on Bilal's answer:
(global-set-key [(meta down)] (lambda () (interactive) (scroll-down 1)))
(global-set-key [(meta up)] (lambda () (interactive) (scroll-up 1)))

Two key shortcut in emacs without repressing the first key?

Suppose I define the following shortcut
(global-set-key (kbd "C-d C-j") "Hello!")
Is it possible to configure emacs so that if I type "C-d C-j C-j C-j" I will get "Hello! Hello! Hello!" rather than having to type "C-d C-j C-d C-j C-d C-j"?
I don’t think you can configure Emacs so that it does that for all commands. However, you can implement this functionality in the commands themselves. This is what is done for C-x e. Here is a macro I just wrote (guided by the standard definition of kmacro-call-macro in GNU Emacs 23.1.1) that makes it easy to add this functionality to your own commands:
(defmacro with-easy-repeat (&rest body)
"Execute BODY and repeat while the user presses the last key."
(declare (indent 0))
`(let* ((repeat-key (and (> (length (this-single-command-keys)) 1)
last-input-event))
(repeat-key-str (format-kbd-macro (vector repeat-key) nil)))
,#body
(while repeat-key
(message "(Type %s to repeat)" repeat-key-str)
(let ((event (read-event)))
(clear-this-command-keys t)
(if (equal event repeat-key)
(progn ,#body
(setq last-input-event nil))
(setq repeat-key nil)
(push last-input-event unread-command-events))))))
Here’s how you use it:
(defun hello-world ()
(interactive)
(with-easy-repeat
(insert "Hello, World!\n")))
(global-set-key (kbd "C-c x y z") 'hello-world)
Now you can type C-c x y z z z to insert Hello, World! three times.
If you are looking for something generic that works on all commands I cant see how that would work - how would emacs know if you are starting a new command or want to repeat the previous. A better example would be "C-c h", if you type "h" after that, should emacs repeat the command or insert a h?
That said, emacs already has a mechanism for this - the universal argument.
Try this key sequence:
C-u 3 C-d C-j
It is even fewer keypresses than C-d C-j C-j C-j C-j
Try something like this:
(global-set-key (kbd "C-c C-j") (lambda()
(interactive)
(insert "Hello!")
(message "Type j to print Hello!")
(while (equal (read-event) ?j)
(insert "Hello!"))
(push last-input-event unread-command-events)))
Idea taken from kmacro-call-macro
No. The sequence "ctrl-d ctrl-j" is what is bound to the string "Hello!" Emacs binds the sequence as a whole to the given string. Here's some good info on the topic:
Link
On the other hand, if you wanted just three instances of "Hello!", you could define that sequence C-d C-j C-d C-j C-d C-j as "Hello! Hello! Hello!", but it would be shorter to just define a simpler sequence for the string you want.
I use this all the time. You'll need library repeat.el (part of GNU Emacs) to use it.
(defun make-repeatable (command)
"Repeat COMMAND."
(let ((repeat-message-function 'ignore))
(setq last-repeatable-command command)
(repeat nil)))
(defun my-hello ()
"Single `hello'."
(interactive)
(insert "HELLO!"))
(defun my-hello-repeat ()
(interactive)
(require 'repeat)
(make-repeatable 'my-hello))
Now bind my-hello-repeat:
(global-set-key (kbd "") 'my-hello-repeat)
Now just hold down the home key to repeat HELLO!.
I use this same technique in multiple libraries, including Bookmark+, thing-cmds, and wide-n.
smartrep is all you want
(require 'smartrep)
(defvar ctl-d-map (make-keymap)) ;; create C-d map
(define-key global-map "\C-d" ctl-d-map)
(smartrep-define-key
global-map "C-d"
'(("C-j" . (insert "hello"))))

Emacs tab between buffers

Is there a way to switch between buffers without having to go through the
buffer-list, or writing the name of the buffer that I want to switch to? More specific I wonder if emacs can tab between buffers much like how it is working in notepad++
Emacs 22.1 and higher supports the previous-buffer (C-x <left arrow>) and next-buffer (C-x <right arrow>) commands.
These two commands can be added to older Emacsen using this script.
I've never ended up using C-x <right> or C-x <C-right> much, because I find them cumbersome to repeat if I want to cycle past more than one buffer, so I've just written a couple of functions to let you continue to switch to next/previous-buffer with <C-right> and <C-left> if the last command was also a next/previous-buffer command.
e.g. C-x <C-left> <C-left> <C-left> <C-right> <C-left> would take you back three buffers, forward one, and backward again.
I've made the assumption that <C-left> & <C-right> are usually bound to forward/backward-word, and am calling those explicitly as the fallback.
(defun my-forward-word-or-buffer-or-windows (&optional arg)
"Enable <C-left> to call next-buffer if the last command was
next-buffer or previous-buffer, and winner-redo if the last
command was winner-undo or winner-redo."
(interactive "p")
(cond ((memq last-command (list 'next-buffer 'previous-buffer))
(progn (next-buffer)
(setq this-command 'next-buffer)))
((memq last-command (list 'winner-redo 'winner-undo))
(progn (winner-redo)
(setq this-command 'winner-redo)))
(t ;else
(progn (forward-word arg)
(setq this-command 'forward-word)))))
(defun my-backward-word-or-buffer-or-windows (&optional arg)
"Enable <C-left> to call previous-buffer if the last command
was next-buffer or previous-buffer, and winner-undo if the last
command was winner-undo or winner-redo."
(interactive "p")
(cond ((memq last-command (list 'next-buffer 'previous-buffer))
(progn (previous-buffer)
(setq this-command 'previous-buffer)))
((memq last-command (list 'winner-redo 'winner-undo))
(progn (winner-undo)
(setq this-command 'winner-undo)))
(t ;else
(progn (backward-word arg)
(setq this-command 'backward-word)))))
(global-set-key (kbd "<C-left>") 'my-backward-word-or-buffer-or-windows)
(global-set-key (kbd "<C-right>") 'my-forward-word-or-buffer-or-windows)
(I use Icicles for buffer switching, myself, but...)
If you want to repeat the previous command any number of times, just use C-x z z z z z z... In this case, e.g., C-x left C-x z z z...
If that's too cumbersome, bind (next|previous)-buffer to other, repeatable keys, as others have suggested.
But repeatable keys are in great demand. If you don't want to waste any, you can even put such commands on a prefix key, so that, e.g., you can do, e.g., C-x left left left... Here's a trick to do that (taken from the Bookmark+ code):
(defun my-repeat-command (command)
"Repeat COMMAND."
(let ((repeat-message-function 'ignore))
(setq last-repeatable-command command)
(repeat nil)))
(defun my-next-whatever-repeat (arg) ; `C-x right'
"Jump to the Nth-next whatever.
N defaults to 1, meaning the next whatever.
Plain `C-u' means start over at the first whatever (and no repeat)."
(interactive "P")
(require 'repeat)
(my-repeat-command 'next-whatever))
(define-key ctl-x-map [right] 'my-next-whatever-repeat
Although the following suggestion does use the buffer-list, Ivy (or Helm) and evil, I think it is a nice, nearly equivalent alternative to the common Ctrl-TAB way (incl. updating the buffer list) when using e.g. Spacemacs.
Of course the commands can be adapted to your personal config (vanilla Emacs)
(evil-global-set-key 'motion (kbd "<C-tab>") 'ivy-switch-buffer)
(evil-global-set-key 'insert (kbd "<C-iso-lefttab>") 'ivy-switch-buffer)
(define-key ivy-mode-map (kbd "<C-tab>") 'ivy-next-line-and-call)
(define-key ivy-mode-map (kbd "<C-iso-lefttab>") 'ivy-previous-line-and-call)
or for the equivalent for Helm
(evil-global-set-key 'motion (kbd "<C-tab>") 'helm-buffers-list)
(evil-global-set-key 'motion (kbd "<C-iso-lefttab>") 'helm-buffers-list)
(define-key helm-map (kbd "<C-tab>") 'helm-follow-action-forward)
(define-key helm-map (kbd "<C-iso-lefttab>") 'helm-follow-action-backward)
The keystring for the last command means Ctrl-Shift-tab in my keyboard. You can find the one to use with C-h k C-S-tab.
Indeed you still need to press RET or C-l after releasing <C-tab>.
For evil users using Helm, a possibly even nicer alternative is to bind helm-buffers-list to C-j and C-k, then set helm-follow-mode-persistent to t, and in the helm-buffers-list buffer activate helm-follow-mode with C-c C-f. Now you can switch (and preview) buffers with C-j and C-k.

.emacs global-set-key and calling interactive function with argument

In my .emacs i have the following function that transposes a line
(defun move-line (n)
"Move the current line up or down by N lines."
(interactive "p")
(let ((col (current-column))
start
end)
(beginning-of-line)
(setq start (point))
(end-of-line)
(forward-char)
(setq end (point))
(let ((line-text (delete-and-extract-region start end)))
(forward-line n)
(insert line-text)
;; restore point to original column in moved line
(forward-line -1)
(forward-char col))))
And I bind a key to it like this
(global-set-key (kbd "M-<down>") 'move-line)
;; this is the same as M-x global-set-key <return>
However, I want to bind M-up to move-line (-1) But I cant seem to be able to do it correctly:
;; M-- M-1 M-x global-set-key <return>
How do I define the above using global-set-key to call move-line -1?
Not minutes after asking the question I figured it out by copy+pasting code. However I have no clue how it works.
(global-set-key (kbd "M-<up>") (lambda () (interactive) (move-line -1)))
global-set-key only takes 2 arguments: the key sequence and the command you want to bind to it. So
(global-set-key (kbd "M-<down>") 'move-line)
works fine. But if you want to use move-line with an argument you need to wrap it in an anonymous (aka lamba) function so that it presents itself to global-set-key as one value.
You can simply ask for the number of lines you want and convert the input string into an integer:
(global-set-key (kbd "M-<up>")
(lambda ()
(interactive)
(move-line (string-to-int (read-string "Lines: ")))))
I found this when I had the same problem, but I ended up solving it in another way.
(global-set-key (kbd "M-<down>") 'move-line)
(global-set-key (kbd "M-<up>") (kbd "C-u -1 M-<down>"))
Definitely not a perfect solution, since M-<down> could be reassigned and C-u -1 might not make sense on it, but since it's just my local init file, it should be no problem.
Also this obvious only works well for keyboard commands that you want to have reversed.
You might want to check out the "transpose-lines" built-in function.