3

I'm trying to find a way to quickly close the window that I just created by running 'grep' (i.e. a kind of compilation window).

I'd like the solution to be independent of my current window layout and also of which window that's currently in focus. This so I can always use the same keyboard shortcut.

I thought I could find an Emacs command to switch to the most recently created window, i.e. the one just created by 'grep'. Then I could just use that command followed by 'q' to close the 'grep' window. However, I haven't been able to find such a command.

Unfortunately the 'other-window' command (C-x o) doesn't work as well as I'd like in the following configuration. Here the Emacs frame is split into two windows (C-x 3) with the cursor in the right window (W2). I.e. it initially looks like this:

.-------.-------.
| W1    | W2 _  |
|       |       |
|       |       |
|       |       |
'-------'-------'       

Then, after the grep command, it looks like this, with focus still on 'w2':

.-------.-------.
| W1    | W2 _  |
|       |       |
|-------|       |
| *grep*|       |
'-------'-------'       

The annoyance is now that 'C-x o' switches to 'W1' rather than 'grep'.

Now, when I'm in 'W2' I can use e.g. 'C-- C-x o' to switch to 'grep'. But unfortunately, but if the cursor is instead in 'W1', then 'C-- C-x o' leaves me in 'W2' rather than 'grep'. So I'll then have to remember which command to use depending on my location.

Note: I could create a shortcut that closes the 'grep' window/buffer, but it'd be nice if the solution here works also for other compilation-like windows.

Update/clarification:

If the Emacs frame isn't as tall, e.g. on a laptop, this window setup:

.-------.-------.
| W1    | W2 _  |
|       |       |
'-------'-------'       

results in 'W1' being replaced by 'grep' instead of a 'grep' window being added. I.e. it results in this:

.-------.-------.
| grep  | W2 _  |
|       |       |
'-------'-------'       

In this case, as some of the answers suggest deleting the 'grep' window, the resulting window setup ends up being this:

.---------------.
| W2 _          |
|               |
'---------------'       

So it turns out I don't necessarily/always want to delete the window containing the 'grep' buffer.

5 Answers 5

2

If you want to target whichever compilation (or similar) buffer is currently being used by next-error and previous-error, I would suggest this:

(defun my-delete-compilation-window ()
  "Delete all windows displaying the `next-error-find-buffer' buffer."
  (interactive)
  (when-let ((buf (next-error-find-buffer)))
    (delete-windows-on buf)))

Or based on the modified requirements:

(defun my-quit-compilation-window ()
  "Invoke `quit-window' for all windows displaying the compilation buffer."
  (interactive)
  (when-let ((buf (next-error-find-buffer)))
    (let (win)
      (while (setq win (get-buffer-window buf t))
        (quit-window nil win)))))

n.b. In either case you may need to (require 'subr-x) for the use of when-let.

2
  • This seems like a useful approach, but I need to use 'quit-window' to get the desired behaviour (see my update to the question). So the solution would need a way to find the window based on 'buf', so that (quit-window ...) can be used instead of (delete-windows-on buf).
    – chr
    Feb 22, 2020 at 19:45
  • You'll be wanting get-buffer-window or get-buffer-window-list then.
    – phils
    Feb 22, 2020 at 23:12
2

The Elisp below defines a command my-delete-compilation-window that deletes the first compilation window in the window list. That should normally be the last selected compilation window. The command is bound to C-c w but you can modify that to your own liking.

(defmacro with-compilation-window (&rest body)
  "Select first compilation window in `window-list' and eval BODY.
BODY is not evaluated if there is no window in `compilation-mode'."
  (declare (debug body))
  `(cl-loop for win being the windows do
        (with-selected-window win
          (when (derived-mode-p 'compilation-mode)
        (progn ,@body)
        (cl-return)))))

(defun my-delete-compilation-window ()
  "Delete compilation window found first in `window-list'."
  (interactive)
  (with-compilation-window
   (delete-window)))

(global-set-key (kbd "C-c w") #'my-delete-compilation-window)
1
  • This seems promising, although the action 'delete-window' is likely not what I want. However, pressing 'q' in the 'grep' window invokes 'quit-window' which does the "right" thing for me. So with 'quit-window' it might solve my issue - I just need to test it a bit further though.
    – chr
    Feb 22, 2020 at 19:37
1

Add the following to your init file:

(winner-mode 1)

Then whenever your window configuration is unexpectedly changed, or you simply want to go back to an earlier configuration, use C-c<left> to call winner-undo (which you can do repeatedly if necessary).

Obviously if additional window config changes have happened since the window in question was created (if you had navigated through the grep results, for instance), then this solution might be less practical; although note that you can use repeat to ease the process: C-c<left>C-xzzz...

C-c<right> returns you to the most recent configuration (immediately, rather than step-by-step).

1
  • Just leaving a comment/recommendation to others reading this to try 'winner-mode'. I tested it quickly and it seems very useful as a general solution even though I ended up selecting a different answer (also by phils).
    – chr
    Feb 23, 2020 at 9:58
0

Not necessarily a single key press, but this can help, I think: by default, C-x 0 in minor mode Icicle is bound to command icicle-delete-window. You can use a prefix arg to pick which window(s) to delete.

C-x 0 runs the command icicle-delete-window (found in icicle-mode-map), which is an interactive compiled Lisp function in icicles-cmd1.el.

It is bound to C-x C-z, C-x 0, remap delete-window.

(icicle-delete-window BUFFERP)

delete-window or prompt for buffer and delete all its windows.

When called from the minibuffer, remove the *Completions* window.

Otherwise:

  • With no prefix argument, delete the selected window.
  • With a prefix argument, prompt for a buffer and delete all windows, on any frame, that show that buffer.

    With a prefix argument, this is an Icicles multi-command - see command icicle-mode. Input-candidate completion and cycling are available. While cycling, these keys with prefix C- are active:

  • C-RET - Act on current completion candidate only

  • C-down - Move to next completion candidate and act
  • C-up - Move to previous completion candidate and act
  • C-next - Move to next apropos-completion candidate and act
  • C-prior - Move to previous apropos-completion candidate and act
  • C-end - Move to next prefix-completion candidate and act
  • C-home - Move to previous prefix-completion candidate and act
  • C-! - Act on all candidates (or all that are saved), successively (careful!)

With prefix C-M- instead of C-, the same keys (C-M-mouse-2, C-M-return, C-M-down, and so on) provide help about candidates.

Use mouse-2, RET, or S-RET to finally choose a candidate, or C-g to quit.

By default, Icicle mode remaps all key sequences that are normally bound to delete-window to icicle-delete-window. If you do not want this remapping, then customize option icicle-top-level-key-bindings.

0

Easiest way IMO which is usable across windows of all types is simply to use the excellent ace windows extension:

      (use-package ace-window
        :bind*
        ("C-x o" . ace-window)
        ("C-x O" . ace-delete-window))

Here's what I see when I "ace delete" with three windows open. It is clever when you have 2.. obviously, delete the other one.

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.