Emacs tab between buffers - emacs

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.

Related

Automatic creation of repeatable command

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)

How to highlight a particular line in emacs?

I need to highlight facility for emacs in order to mark some lines in file while working with it.
It should be smth like M-s h l but should work based on line number, not on a regexp. I want to highlight a current line, but the hl-line-mode is not suitable, as I need to highlight many lines, every time I press a specific key on each of them.
I just quickly wrote the following:
(defun find-overlays-specifying (prop pos)
(let ((overlays (overlays-at pos))
found)
(while overlays
(let ((overlay (car overlays)))
(if (overlay-get overlay prop)
(setq found (cons overlay found))))
(setq overlays (cdr overlays)))
found))
(defun highlight-or-dehighlight-line ()
(interactive)
(if (find-overlays-specifying
'line-highlight-overlay-marker
(line-beginning-position))
(remove-overlays (line-beginning-position) (+ 1 (line-end-position)))
(let ((overlay-highlight (make-overlay
(line-beginning-position)
(+ 1 (line-end-position)))))
(overlay-put overlay-highlight 'face '(:background "lightgreen"))
(overlay-put overlay-highlight 'line-highlight-overlay-marker t))))
(global-set-key [f8] 'highlight-or-dehighlight-line)
(Here find-overlays-specifying came from the manual page)
It will highlight current line, and when used again it will remove it.
Maybe the following could be useful as well: removing all your highlight from the buffer (could be dangerous, you might not want it if you highlight important things)
(defun remove-all-highlight ()
(interactive)
(remove-overlays (point-min) (point-max))
)
(global-set-key [f9] 'remove-all-highlight)
You can use bm.el. You can install bm.el from MELPA.
bm.el provides bm-toggle to highlight and unhighlight current line.
bm.el also provides bm-bookmark-regexp which highlights only matched lines.
And you can jump between highlighted lines by bm-previous and bm-next
Following is sample configuration of bm.el
(require 'bm)
(global-set-key (kbd "<f5>") 'bm-toggle)
(global-set-key (kbd "<f6>") 'bm-previous)
(global-set-key (kbd "<f7>") 'bm-next)
(global-set-key (kbd "<f8>") 'bm-bookmark-regexp)
Bookmark+ does what you are asking for. Use C-x p RET (by default) to set a bookmark at point. And you can configure the kind of highlighting you want for such bookmarks. This is similar to what bm.el offers (syohex's answer), but more flexible.

Kill the *terminal* buffer with C-d

I found a nice post a few
days ago detailing how to kill the shell buffer with the C-d key. Basically,
after killing the process with C-d you can now tap C-d again to also kill
the buffer.
I was trying to implement something similar for term-mode, but I ran into a
problem. After you kill the term process (with the usual C-d) it seems that
the key-map being used by the buffer changes, but I can't find out what it is!
For example, launch the term command (M-x term RET RET) and then just
immediatelly hit C-d. Once the process is dead, the buffer still reports being
in term-mode, but they key-map it's using is neither term-mode-map nor
term-raw-map.
So
I either need to find out what map it is using so I can bind C-d to kill-buffer.
Or I need another way to kill the buffer with C-d in term-mode.
Try this out:
(defun delete-char-or-kill-terminal-buffer (N &optional killflag)
(interactive "p\nP")
(if (string= (buffer-name) "*terminal*")
(kill-buffer (current-buffer))
(delete-char N killflag)))
(global-set-key (kbd "C-d") 'delete-char-or-kill-terminal-buffer)
When the *terminal* process exits, the mode of the buffer switches to fundamental, which is why the C-d doesn't do what you want.
While Trey Jackson's version is absolutely correct, below is another version which doesn't require knowing the buffer name. It is then easier to manage multiple terminal buffers.
(defun term-handle-exit--close-buffer (&rest args)
(when (null (get-buffer-process (current-buffer)))
(insert "Press <C-d> to kill the buffer.")
(use-local-map (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-d")
(lambda ()
(interactive)
(kill-buffer (current-buffer))))
map))))
(advice-add 'term-handle-exit :after #'term-handle-exit--close-buffer)

delete (NOT kill) a line in emacs. External clipboard is not appended to the kill ring

Many times I find myself in need of pasting a path from wherever to emacs' minibuffer. To clear the minibuffer fast I navigate to the beginning and do C-k (kill line).
This effectively overrides whatever path I had in the system clipboard with the temporary path I just killed in the minibuffer. Navigating the kill ring with M-y won't bring the path I had in the system clipboard.
Is there a way to delete the current line without killing it( i.e. removing it and adding it to the kill ring)?
So far I'm marking the line and pressing delete having delete-selection-mote active. I would like a one key solution similar to C-k.
As of Emacs 23.2, you can set save-interprogram-paste-before-kill to a non-nil value (hat tip Tyler) to copy the clipboard selection onto the kill ring, so that it is available via C-y M-y:
(setq save-interprogram-paste-before-kill t)
If you're on an older Emacs, the following advice has the same functionality:
(defadvice kill-new (before kill-new-push-xselection-on-kill-ring activate)
"Before putting new kill onto the kill-ring, add the clipboard/external selection to the kill ring"
(let ((have-paste (and interprogram-paste-function
(funcall interprogram-paste-function))))
(when have-paste (push have-paste kill-ring))))
And, you could do something like this (horrible keybinding, customize to suit) to delete the line from the point forward:
(define-key minibuffer-local-map (kbd "C-S-d") 'delete-line)
(defun delete-line (&optional arg)
(interactive "P")
;; taken from kill-line
(delete-region (point)
;; It is better to move point to the other end of the kill
;; before killing. That way, in a read-only buffer, point
;; moves across the text that is copied to the kill ring.
;; The choice has no effect on undo now that undo records
;; the value of point from before the command was run.
(progn
(if arg
(forward-visible-line (prefix-numeric-value arg))
(if (eobp)
(signal 'end-of-buffer nil))
(let ((end
(save-excursion
(end-of-visible-line) (point))))
(if (or (save-excursion
;; If trailing whitespace is visible,
;; don't treat it as nothing.
(unless show-trailing-whitespace
(skip-chars-forward " \t" end))
(= (point) end))
(and kill-whole-line (bolp)))
(forward-visible-line 1)
(goto-char end))))
(point))))
As of Emacs 23.2, this problem can be addressed with save-interprogram-paste-before-kill. If you set this variable to t then stuff in the clipboard gets added to the kill-ring, and isn't discarded by your next kill.
The documentation:
Save clipboard strings into kill ring before replacing them.
When one selects something in another program to paste it into Emacs,
but kills something in Emacs before actually pasting it,
this selection is gone unless this variable is non-nil,
in which case the other program's selection is saved in the `kill-ring'
before the Emacs kill and one can still paste it using C-y M-y.
From Xahlee's page, it shows several commands that are annoying.
(defun my-delete-word (arg)
"Delete characters forward until encountering the end of a word.
With argument, do this that many times.
This command does not push erased text to kill-ring."
(interactive "p")
(delete-region (point) (progn (forward-word arg) (point))))
(defun my-backward-delete-word (arg)
"Delete characters backward until encountering the beginning of a word.
With argument, do this that many times.
This command does not push erased text to kill-ring."
(interactive "p")
(my-delete-word (- arg)))
(defun my-delete-line ()
"Delete text from current position to end of line char."
(interactive)
(delete-region
(point)
(save-excursion (move-end-of-line 1) (point)))
(delete-char 1)
)
(defun my-delete-line-backward ()
"Delete text between the beginning of the line to the cursor position."
(interactive)
(let (x1 x2)
(setq x1 (point))
(move-beginning-of-line 1)
(setq x2 (point))
(delete-region x1 x2)))
; Here's the code to bind them with emacs's default shortcut keys:
(global-set-key (kbd "M-d") 'my-delete-word)
(global-set-key (kbd "<M-backspace>") 'my-backward-delete-word)
(global-set-key (kbd "C-k") 'my-delete-line)
(global-set-key (kbd "C-S-k") 'my-delete-line-backward)
There isn't.
from the GNU Emacs Manual:
We have already described the basic deletion commands C-d
(delete-char) and (delete-backward-char). See Erasing.
The other delete commands are those that delete only whitespace
characters: spaces, tabs and newlines. M-\ (delete-horizontal-space)
deletes all the spaces and tab characters before and after point. With
a prefix argument, this only deletes spaces and tab characters before
point. M- (just-one-space) does likewise but leaves a single
space after point, regardless of the number of spaces that existed
previously (even if there were none before). With a numeric argument
n, it leaves n spaces after point.
What about something like:
(defun del-line (p1)
(interactive "d")
(move-end-of-line 1)
(when (eq p1 (point)) ; special case when p1 is already at the end of the line
(forward-line))
(delete-region p1 (point)))
The behavior should be similar to C-k but without affecting the system clipboard or the kill-ring.
ETA: I read Trey's solution more carefully, and it looks like this is just a simple case of his solution. It worked in my (very!) limited tests, but probably fails for some special cases where the more complicated kill-line code works correctly.
Found an answer to this.
Posted it first here: https://unix.stackexchange.com/questions/26360/emacs-deleting-a-line-without-sending-it-to-the-kill-ring/136581#136581
;; Ctrl-K with no kill
(defun delete-line-no-kill ()
(interactive)
(delete-region
(point)
(save-excursion (move-end-of-line 1) (point)))
(delete-char 1)
)
(global-set-key (kbd "C-k") 'delete-line-no-kill)

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