6

I always work with Emacs in full screen mode and a vertical split down the middle, with windows on the left and right sides. How could I write an elisp command that would close all other windows on the same side of the vertical split where the current window is? The windows on the opposite side would remain untouched. I can't find any command to do this (C-x 1 leaves only the current window but destroys the split). Or maybe there is a package that already does this?

2 Answers 2

5

Here's a variation on delete-other-windows-vertically which (I think) addresses the limitation that I pointed out in a comment to @phils's answer, namely that it will delete all the other windows in a vertical stack, but it only affects windows that have the same left and right edges as the selected window; it does not touch anything else. So if you have a window configuration with your selected window on, say, the RHS, above a vertically split pair of windows, then those windows will not be deleted, because they don't have the same left edge and right edge as the selected window.

The basic algorithm of delete-other-windows-vertically is that it loops over all windows (using next-window) and applies a filter to all the windows (except itself) by filtering out any that don't satisfy the above criteria and adding the rest to a delenda list. At the end of that loop, it maps the delete-window function over the delenda list, deleting all the windows that were added to it.

This function is similar except that I chose to map a (different) filter over the list returned by window-list, instead of explicitly looping with next-window. I need to delete the selected window explicitly in this case (and also any nils that creep into the list: nil is treated specially to refer to the selected window in most window functions, e.g. delete-window, and I certainly don't want to delete that.)

The new filter checks that the left edge of a given window is on the LHS or the RHS of the frame and returns a symbol (lhs or rhs) to indicate: that's all it checks:

(defun my/window-side (win)
  (let ((left (car (window-edges win))))
    (if (< left (/ (frame-width) 2))
        'lhs
      'rhs)))

We can write a fairly generic function that maps a filter across a list of windows; e.g. the standard `delete-other-windows-vertically could be rewritten using this function, instead of explicitly looping:

(defun my/window-list-apply-filter (window filter)
  (let* ((window (or window (selected-window))))
    (delq window (mapcar (lambda (w) (funcall filter w)) (window-list)))))

It takes a window and a filter as argument and maps the filter across the window list, deleting the given window from the resulting list (if the window was specified as nil, using the convention described above, we explicitly replace it by the selected window).

We can then determine which side the selected window is on, and use the above function to filter all the other windows appropriately by checking whether it's on the same side as the selected window or not:

(defun my/delete-other-windows-on-same-side-as (&optional window)
  (interactive)
  (let* ((side (my/window-side window))
         (filter (lambda (w) (when (eq (my/window-side w) side) w))))
    (mapc #'delete-window (delq nil (my/window-list-apply-filter window filter)))))

We determine the side of the selected window and define a filter that checks whether any given window is on the same side. We then call the function that returns the filtered list, clean up nils and map delete-window across the resulting list.

The three functions above can be evaluated by hand or added to the init file (and emacs restarted) in order to test. And if you like @phils's keybinding, you can define it to call the last function here as follows:

(define-key ctl-x-map "!" #'my/delete-other-windows-on-same-side-as)

I've tested it manually in various situations and it does what I think the OP asked for, but if you run into any problems, please let me know.

5
  • Any reason not to contribute this as a bug fix?
    – phils
    Commented Sep 7 at 15:37
  • None that I know of, but that will require some extra work and testing. In the meantime, if you find anything wrong, let me know.
    – NickD
    Commented Sep 7 at 16:18
  • 1
    Initial tests work nicely. I'm now using it in place of delete-other-windows-vertically. If you don't hear any bug reports from me then it's all been working fine.
    – phils
    Commented Sep 10 at 6:28
  • FWIW, I confirm it works nicely for me as well. Consider submitting this as a bug fix to Emacs, I'd say. :) Commented Sep 10 at 7:40
  • Thank you both for the reports! I hope to work on it this week and submit it towards the end of the week. I'll post the bug report link here.
    – NickD
    Commented Sep 10 at 13:03
4
delete-other-windows-vertically is an interactive byte-compiled Lisp
function in `window.el'.

(delete-other-windows-vertically &optional WINDOW)

Delete the windows in the same column with WINDOW, but not WINDOW itself.
This may be a useful alternative binding for C-x 1
if you often split windows horizontally.

I bind this command to C-x!

4
  • 1
    Nice, but it doesn't quite do what the OP asked: if the vertical stack of windows contains single windows, it works; but if it contains some windows in a horizontal split, they are not deleted.
    – NickD
    Commented Sep 6 at 14:41
  • Huh; I've never noticed that. That's a bug, to my mind.
    – phils
    Commented Sep 6 at 17:30
  • This actually works quite well for me. I thought it would require some exotic script but it turns out there is this native function delete-other-windows-vertically all along. Commented Sep 18 at 16:49
  • Yep, it's always worked fine for me too :) I'd obviously never once used it in the scenario covered by NickD (I think it's just an unlikely use-case for me).
    – phils
    Commented Sep 18 at 21:21

Your Answer

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

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