How do I make Emacs' other-window command ignore terminal windows? - emacs

Emacs does an okay job of being a window manager. I've been splitting up my Emacs frame like this:
+---------------------------+
| | |
| | |
| | B |
| A | |
| | |
| | |
| |-------------|
| | C |
+---------------------------+
C is usually a terminal with some kind of long-running process, like a web server or daemon. Occasionally I'll move the point there to restart the daemon, but most of the time I'd like to swap only between A and B. How can I make this convenient?

There's nothing built-in to do what you want. You can use the following code to do what you want (just customize the regular expression to match the name of the buffer(s) you want to avoid).
Note: the my-other-window doesn't implement all the features other-window does, that is left as an exercise for the reader.
my-other-window will try to switch to a window whose buffer doesn't match the avoid-window-regexp. If there's no such window available, then it just switches to the next one.
(require 'cl)
(defvar avoid-window-regexp "^[0-9]$")
(defun my-other-window ()
"Similar to 'other-window, only try to avoid windows whose buffers match avoid-window-regexp"
(interactive)
(let* ((window-list (delq (selected-window) (window-list)))
(filtered-window-list (remove-if
(lambda (w)
(string-match-p avoid-window-regexp (buffer-name (window-buffer w))))
window-list)))
(if filtered-window-list
(select-window (car filtered-window-list))
(and window-list
(select-window (car window-list))))))
And bind it appropriately:
(global-set-key (kbd "C-x o") 'my-other-window)

This works for eshell:
(add-hook 'eshell-mode-hook (lambda ()
(set-window-parameter (first (window-list)) 'no-other-window t)))
Setting no-other-window to non-nil makes the standard other-window function skip this. See other-window docs with C-h C-f other-window
There might be a better way to get the current window, but I don't know it yet.

Not the exact answer but I use windmove-mode for that which allow you to use the arrow to visually move between windows and then doing Control-Left or Control-Right to move only between A and B.
Other than that you probably can redefine other-buffer function with something that take buffer-list ignoring some patters when switch-to-buffer to it but I didn't write the code handy.

For the lazy, I use something like this in my .emacs
(fset 'doublejump
"\C-u2\C-xo")
(global-set-key (kbd "C-c o") 'doublejump)
and alternate between using single and double buffer switches.

Related

Emacs windmove move a buffer without switching

I have Emacs Windmove setup well and working, but I still have a small annoyance with it. There seems to be no way to slide one buffer over another buffer without switching the placement of both buffers. How can I slide a buffer over another buffer, displacing only that buffer.
Here's what I want to do:
___________ ___________ ___________
| | B | | | B | | | C |<-----
| A |_____| ---> | A |_____| ---> | A |_____| |
| | D | | | C | | | D | |
|____|_____| |____|_____| |____|_____| |
Buffer C opens up, ------^ With a key combo, maybe__|
covering buffer D I can slide up buffer C
to get back buffer D
EDIT: I forgot to mention I have some elisp that uses windmove to actually switch two buffers. The use case for what I want to do is that sometimes a buffer will open up in a certain window, covering up another buffer that I want to see. I want to slide the newly open buffer around without disturbing the other buffers, and to get the buffer back that was covered up. I hope that makes sense.
(defun slide-buffer (dir)
"Move current buffer into window at direction DIR.
DIR is handled as by `windmove-other-window-loc'."
(require 'windmove)
(let ((buffer (current-buffer))
(target (windmove-find-other-window dir)))
(if (null target)
(user-error "There is no window %s from here" dir)
(switch-to-prev-buffer)
(select-window target)
(switch-to-buffer buffer nil t))))
(defun slide-buffer-up () (interactive) (slide-buffer 'up))
(defun slide-buffer-down () (interactive) (slide-buffer 'down))
(defun slide-buffer-left () (interactive) (slide-buffer 'left))
(defun slide-buffer-right () (interactive) (slide-buffer 'right))
Bind it to C-S-<arrow>:
(define-key global-map (kbd "C-S-<up>") #'slide-buffer-up)
(define-key global-map (kbd "C-S-<down>") #'slide-buffer-down)
(define-key global-map (kbd "C-S-<left>") #'slide-buffer-left)
(define-key global-map (kbd "C-S-<right>") #'slide-buffer-right)
In your comment you say that you would like a "key combination to do it", meaning to (1) switch to the window showing buffer B and then (2) to switch the buffer shown in that window to buffer C.
How do you do that now? You use keys, no? So you already have a "key combination to do it". If you mean that you want a shorter key combination then write a command that chains together the commands bound to the keys you use now to do that.
There are several ways to do #1, and #2 is just C-x b C.
One way to do #1 is to use C-0 C-o in Icicles. It lets you pick a window by name, using completion. The command in question is icicle-choose-window-by-name.
Putting the two together, with Icicles you could use this code. Then hit F3 to do what you want.
(defun foo ()
(interactive)
(call-interactively #'icicle-choose-window-by-name)
(call-interactively #'switch-to-buffer))
(global-set-key [f3] 'foo)
There are other ways to choose a window, if you don't want to use Icicles. This is the place to start, when looking for info about selecting (navigating among) windows.

Save yanked text to string in Emacs

I am trying to store yanked text to a variable in Emacs.
It seems like the following works:
(let ((str nil))
(with-temp-buffer
(yank)
(setq str (buffer-string)))
I wondered, are there any simpler methods for achieving this? It seems like opening a temporary buffer just to get the yanked text is overkill.
The value you are looking for in your function is available as
(car kill-ring)
This should work:
(defun was-yanked ()
"When called after a yank, store last yanked value in let-bound yanked. "
(interactive)
(let (yanked)
(and (eq last-command 'yank)
(setq yanked (car kill-ring))))
Maybe message and also return it:
(defun was-yanked ()
"When called after a yank, store last yanked value in let-bound yanked. "
(interactive)
(let (yanked)
(and (eq last-command 'yank)
(setq yanked (car kill-ring))))
(when (interactive-p) (message "%s" yanked))
yanked)
You may want to use (current-kill 0) instead of (car kill-ring).
See the doc string of kill-ring:
,----
| List of killed text sequences.
| Since the kill ring is supposed to interact nicely with cut-and-paste
| facilities offered by window systems, use of this variable should
| interact nicely with `interprogram-cut-function' and
| `interprogram-paste-function'. The functions `kill-new',
| `kill-append', and `current-kill' are supposed to implement this
| interaction; you may want to use them instead of manipulating the kill
| ring directly.
,----
This also answers your second question, from your comment. See the doc for the functions mentioned in this doc string etc.

Emacs rearrange split panes

If I'm working in (terminal) Emacs and have 2 buffers on screen using a horizontal split:
+--------------------------+
| |
| |
| |
| |
+--------------------------+
| |
| |
| |
| |
+--------------------------+
Then I decide to open the slime repl, Emacs will split one of those horizontal panes vertically:
+--------------------------+
| |
| |
| |
| |
+-------------+------------+
| | |
| | slime |
| | |
| | |
+-------------+------------+
But what I want is to have slime on the right, using the full height of the window:
+-------------+------------+
| | |
| | |
| | |
| | |
+-------------+ slime |
| | |
| | |
| | |
| | |
+-------------+------------+
Is there any easy way to get from the arrangement Emacs automatically gave me, to the one I want (e.g. a rotate arrangement), or do I explicitly close and re-split the windows myself?
EDIT | Also curious if I can directly open a full vertical split if I'm currently using a full horizontal split, or if it's effectively impossible.
If you like pre-set window configurations, take a look at the "workspace management" pakages:
Perspective gives you named workspaces
Equilibrium Emacs Window Manager is similar but more sophisticated tool which allows to configure popup placement, window configuraion, buffers, fonts and keybindings.
There is more on the project management page on EmacsWiki.
To your second question, here is what I have in my configuration to flip horizontal/vertical splits (credit: https://github.com/yyr/emacs.d):
(defun split-window-func-with-other-buffer (split-function)
(lexical-let ((s-f split-function))
(lambda ()
(interactive)
(funcall s-f)
(set-window-buffer (next-window) (other-buffer)))))
(defun split-window-horizontally-instead ()
(interactive)
(save-excursion
(delete-other-windows)
(funcall (split-window-func-with-other-buffer 'split-window-horizontally))))
(defun split-window-vertically-instead ()
(interactive)
(save-excursion
(delete-other-windows)
(funcall (split-window-func-with-other-buffer 'split-window-vertically))))
(global-set-key "\C-x|" 'split-window-horizontally-instead)
(global-set-key "\C-x_" 'split-window-vertically-instead)
There are certainly libraries for transforming a frame's window configuration (flip, rotate, etc...), and other libraries for rotating the visible buffers through the available windows. Combining those would achieve your aim.
I like TransposeFrame for the former, and I can see at least a couple of options for the latter:
https://github.com/banister/window-rotate-for-emacs
http://www.emacswiki.org/emacs/TransposeWindows
In general, CategoryWindows on the Wiki should be useful to you.
Note that the window configuration transforms do need to delete and re-create the splits, so the original window objects do not all survive the process. In that respect, it's not actually possible to do what you're asking; but for most purposes, 'faking it' is sufficient.
Here's a function that does what you want. After loading it into emacs, select the buffer you want to rearrange and do an M-x my-shift-window-right. You can also bind it to a key with global-set-key.
(defun my-shift-window-right (&optional start-window)
"Reset the current window configuration with START-WINDOW
on the right and the rest of the windows on the left. START-WINDOW defaults to
the selected window. Return START-WINDOW, or nil if START-WINDOW isn't live or
if there is only one visible window."
(interactive (list (selected-window)))
(if (or (one-window-p)
(and start-window
(not (window-live-p start-window)))) nil
(let ((other-buffers '())
(start-window (or start-window (selected-window))))
;; add all visible buffers other than the current one to other-buffers list
(walk-windows #'(lambda (window)
(when (not (eq window start-window))
(add-to-list 'other-buffers (window-buffer window)))))
(delete-other-windows)
;; pop the first "other buffer" into a split window on the left
(set-window-buffer (select-window (split-window start-window nil 'left))
(pop other-buffers))
;; make a split window for each buffer in the "other-buffers" list
;; select the start-window and return it when finished
(dolist (buffer other-buffers (select-window start-window))
(set-window-buffer (split-window (selected-window) nil 'above) buffer)))))
This function cycles through the other visible windows and stores each of their buffers in a list called other-buffers. Then it rearranges the windows the way you described by iterating over the other-buffers list.

Initiating selection in replacement for Emacs' forward-word

I want to replace Emacs' default forward-word and backward-word to operate more like Visual Studio's - which I find better suited to Perl programming. I first tried hacking the syntax table, without achieving the effect I wanted. Then I came up with the following:
(defconst perl-movement-stop-chars "a-zA-Z$#%_0-9'")
(defconst perl-movement-stop-pattern (concat "[" perl-movement-stop-chars "]"))
(defconst non-perl-movement-stop-pattern (concat "[^" perl-movement-stop-chars "]"))
(defun perl-forward-word ()
(interactive)
(if (looking-at perl-movement-stop-pattern)
(progn
(if (re-search-forward non-perl-movement-stop-pattern nil t)
(backward-char)))
(if (re-search-forward perl-movement-stop-pattern nil t)
(backward-char))))
(defun perl-backward-word ()
(interactive)
(backward-char)
(if (looking-at perl-movement-stop-pattern)
(progn
(if (re-search-backward non-perl-movement-stop-pattern nil t)
(forward-char)))
(if (re-search-backward perl-movement-stop-pattern nil t)
(forward-char))))
(add-hook 'cperl-mode-hook
(lambda()
(local-set-key [C-right] 'perl-forward-word)
(local-set-key [C-left] 'perl-backward-word)
linum-mode))
This does what I want - nearly: I still have to handle the case when moving backward from inside the first word in the buffer. But that is not my question.
The problem with this is that the selection is not started when I type C-S-right, as it is when my hook is not installed (or in other modes). If I initiate the selection though (e.g. by hitting first S-right) my functions do extend it.
I know very, very little about elisp programming and I am just guessing my way here. I would appreciate a bit of help. Thanks...
To get shift-select-mode working, you'll need to use (interactive "^"). Try C-h f interactive RET.
BTW, you can simplify your code considerably: to move forward, just (re-search-forward ".\\(\\_<\\|\\_>\\)" nil t) and to move backward, use (re-search-backward "\\(\\_<\\|\\_>\\)." nil t).
I'm not sure exactly what you want, but I thought I'd offer this. I have a package which I call syntax-subword (available in Melpa). It makes word movement more fine-grained, to the point where I hardly ever move by characters, and use other solutions like isearch to move bigger distances.
From the comments:
;; This package provides `syntax-subword' minor mode, which extends
;; `subword-mode' to make word editing and motion more fine-grained.
;; Basically, it makes syntax changes, CamelCaseWords, and the normal
;; word boundaries the boundaries for word operations. Here's an
;; example of where the cursor stops using `forward-word' in
;; `emacs-lisp-mode':
;;
;; (defun FooBar (arg) "doc string"
;; | | | | | | standard
;; | | | | | | | subword-mode
;; || || | ||| |||| || || syntax-subword-mode
;; || | || | || | | vim

How do I make this Emacs frame keep its buffer and not get resized?

My Emacs frame looks like this:
+---------------------------+
| | |
| | |
| | B |
| A | |
| | |
| | |
| |-------------|
| | C |
+---------------------------+
C is usually a terminal with some kind of long-running process, like a web server or daemon. Unfortunately, all sorts of things like to switch the buffer in that window and occasionally it gets resized. How can I lock the buffer and height of window C?
If you don't want to be annoyed by window stealing and resizing, put the following lines in your .emacs for a definitive solution that works even with libraries like gud that tries to open a new frame when they can't steal your windows :
(see this answer for info on the following advice)
(defadvice pop-to-buffer (before cancel-other-window first)
(ad-set-arg 1 nil))
(ad-activate 'pop-to-buffer)
;; Toggle window dedication
(defun toggle-window-dedicated ()
"Toggle whether the current active window is dedicated or not"
(interactive)
(message
(if (let (window (get-buffer-window (current-buffer)))
(set-window-dedicated-p window
(not (window-dedicated-p window))))
"Window '%s' is dedicated"
"Window '%s' is normal")
(current-buffer)))
;; Press [pause] key in each window you want to "freeze"
(global-set-key [pause] 'toggle-window-dedicated)
and customize pop-up-windows variable to nil.
you could also use StickyWindows instead of window-dedicated feature.
One possibility is to dedicate the window to its buffer, using set-window-dedicated-p. This will not prevent the window from being resized manually, only protect it from being clobbered by display-buffer. For example,
(add-hook 'shell-mode-hook
(lambda ()
(interactive)
(set-window-dedicated-p (selected-window) 1)))
Replace shell-mode-hook as necessary.
This one also works fine (for emacs 24) https://lists.gnu.org/archive/html/help-gnu-emacs/2007-05/msg00975.html
(define-minor-mode sticky-buffer-mode
"Make the current window always display this buffer."
nil " sticky" nil
(set-window-dedicated-p (selected-window) sticky-buffer-mode))
You could use winner-mode to be able to undo the changes to be the window sizes.
You could also explicitly save and restore the window configuration in registers.