328 lines
10 KiB
EmacsLisp
328 lines
10 KiB
EmacsLisp
;;; vim-window.el - Implementation of window commands.
|
|
|
|
;; Copyright (C) 2009, 2010 Frank Fischer
|
|
|
|
;; Author: Frank Fischer <frank.fischer@mathematik.tu-chemnitz.de>,
|
|
;;
|
|
;; This file is not part of GNU Emacs.
|
|
|
|
;;; Commentary:
|
|
|
|
;; This file contains implementations for the window operations.
|
|
;; Window operations are usually just simple commands and should not
|
|
;; be repeatable.
|
|
|
|
;;; Code:
|
|
|
|
(condition-case nil
|
|
(require 'windmove)
|
|
(error
|
|
(message "vim-mode: Could not load 'windmove', window-commands not available.")
|
|
nil))
|
|
|
|
(vim:define-keymap window-mode "window mode" :map-command wmap)
|
|
|
|
(vim:define-mode window "VIM window mode"
|
|
:ident "W"
|
|
:keymaps '(vim:window-mode-keymap)
|
|
:command-function 'vim:normal-mode-command)
|
|
|
|
(defun vim:resize-window (new-size &optional horizontal)
|
|
"Sets the current window's with or height to `new-size'."
|
|
(let ((wincfg (current-window-configuration))
|
|
(nwins (length (window-list)))
|
|
(count (if horizontal
|
|
(- new-size (window-width))
|
|
(- new-size (window-height)))))
|
|
|
|
(catch 'loop
|
|
(save-window-excursion
|
|
(while (not (zerop count))
|
|
(if (> count 0)
|
|
(progn (enlarge-window 1 horizontal) (decf count))
|
|
(progn
|
|
(shrink-window 1 horizontal)
|
|
(incf count)))
|
|
(if (= nwins (length (window-list)))
|
|
(setq wincfg (current-window-configuration))
|
|
(throw 'loop t)))))
|
|
(set-window-configuration wincfg)))
|
|
|
|
|
|
(defun vim:get-buffer-tree (wintree)
|
|
"Extracts the buffer tree from a given window-tree."
|
|
(if (consp wintree)
|
|
(cons (car wintree) (mapcar #'vim:get-buffer-tree (cddr wintree)))
|
|
(window-buffer wintree)))
|
|
|
|
|
|
(defun vim:restore-window-tree (win tree)
|
|
"Restores the given buffer-tree layout as subwindows of win."
|
|
(cond
|
|
((and (consp tree) (cddr tree))
|
|
(let ((newwin (split-window win nil (not (car tree)))))
|
|
(vim:restore-window-tree win (cadr tree))
|
|
(vim:restore-window-tree newwin (cons (car tree) (cddr tree)))))
|
|
((consp tree)
|
|
(set-window-buffer win (cadr tree)))
|
|
(t (set-window-buffer win tree))))
|
|
|
|
|
|
(vim:defcmd vim:window-split (count (argument:file file) nonrepeatable)
|
|
"Splits the current window horizontally, `count' lines height, editing a certain `file'."
|
|
(let ((new-win (split-window (selected-window) count)))
|
|
(when file
|
|
(vim:cmd-edit :argument file))))
|
|
|
|
|
|
(vim:defcmd vim:window-vsplit (count (argument:file file) nonrepeatable)
|
|
"Splits the current window vertically, `count' columns width, editing a certain `file'."
|
|
(let ((new-win (split-window (selected-window) count t)))
|
|
(when file
|
|
(vim:cmd-edit :argument file))))
|
|
|
|
|
|
(vim:defcmd vim:window-close (nonrepeatable)
|
|
"Closes the current window."
|
|
(delete-window))
|
|
|
|
|
|
(vim:defcmd vim:window-only (nonrepeatable)
|
|
"Closes all but the current window."
|
|
(delete-other-windows))
|
|
|
|
|
|
(vim:defcmd vim:window-left (count nonrepeatable)
|
|
"Move the cursor to new `count'-th window left of the current one."
|
|
(dotimes (i (or count 1))
|
|
(windmove-left)))
|
|
|
|
|
|
(vim:defcmd vim:window-right (count nonrepeatable)
|
|
"Move the cursor to new `count'-th window right of the current one."
|
|
(dotimes (i (or count 1))
|
|
(windmove-right)))
|
|
|
|
|
|
(vim:defcmd vim:window-up (count nonrepeatable)
|
|
"Move the cursor to new `count'-th window above the current one."
|
|
(dotimes (i (or count 1))
|
|
(windmove-up)))
|
|
|
|
|
|
(vim:defcmd vim:window-down (count nonrepeatable)
|
|
"Move the cursor to new `count'-th window below the current one."
|
|
(dotimes (i (or count 1))
|
|
(windmove-down)))
|
|
|
|
|
|
(vim:defcmd vim:window-bottom-right (nonrepeatable)
|
|
"Move the cursor to bottom-right window."
|
|
(do ((success t))
|
|
((not success))
|
|
(setq success nil)
|
|
(condition-case nil
|
|
(progn
|
|
(windmove-right)
|
|
(setq success t))
|
|
(error nil))
|
|
(condition-case nil
|
|
(progn
|
|
(windmove-down)
|
|
(setq success t))
|
|
(error nil))))
|
|
|
|
|
|
(vim:defcmd vim:window-top-left (nonrepeatable)
|
|
"Move the cursor to top-left window."
|
|
(do ((success t))
|
|
((not success))
|
|
(setq success nil)
|
|
(condition-case nil
|
|
(progn
|
|
(windmove-left)
|
|
(setq success t))
|
|
(error nil))
|
|
(condition-case nil
|
|
(progn
|
|
(windmove-up)
|
|
(setq success t))
|
|
(error nil))))
|
|
|
|
|
|
(vim:defcmd vim:window-lru (nonrepeatable)
|
|
"Move the cursor to the previous (last accessed) window."
|
|
(select-window (get-lru-window)))
|
|
|
|
|
|
(vim:defcmd vim:window-next (count nonrepeatable)
|
|
"Move the cursor to the next window in the cyclic order.
|
|
With `count' go to the count-th window in the order starting from
|
|
top-left."
|
|
(if (not count)
|
|
(select-window (next-window))
|
|
(vim:window-top-left)
|
|
(other-window (1- (or count 1)))))
|
|
|
|
|
|
(vim:defcmd vim:window-prev (count nonrepeatable)
|
|
"Move the cursor to the previous window in the cyclic order.
|
|
With `count' go to the count-th window in the order starting from
|
|
top-left."
|
|
(if (not count)
|
|
(select-window (previous-window))
|
|
(vim:window-top-left)
|
|
(other-window (1- (or count 1)))))
|
|
|
|
|
|
(vim:defcmd vim:window-new (count (argument:file file) nonrepeatable)
|
|
"Splits the current window horizontally and opens a new buffer or edits a certain `file'."
|
|
(split-window (selected-window) count)
|
|
(if file
|
|
(vim:cmd-edit :argument file)
|
|
(let ((buffer (generate-new-buffer "*new*")))
|
|
(set-window-buffer (selected-window) buffer)
|
|
(with-current-buffer buffer (normal-mode)))))
|
|
|
|
|
|
|
|
(vim:defcmd vim:window-vnew (count (argument:file file) nonrepeatable)
|
|
"Splits the current window vertically and opens a new buffer name or edits a certain `file'."
|
|
(split-window (selected-window) count t)
|
|
(if file
|
|
(vim:cmd-edit :argument file)
|
|
(let ((buffer (generate-new-buffer "*new*")))
|
|
(set-window-buffer (selected-window) buffer)
|
|
(with-current-buffer buffer (normal-mode)))))
|
|
|
|
|
|
(vim:defcmd vim:window-balance (nonrepeatable)
|
|
"Balances all window sizes."
|
|
(balance-windows))
|
|
|
|
|
|
(vim:defcmd vim:window-increase-height (count nonrepeatable)
|
|
"Increase current window height by `count'."
|
|
(vim:resize-window (+ (window-height) (or count 1))))
|
|
|
|
|
|
(vim:defcmd vim:window-decrease-height (count nonrepeatable)
|
|
"Decrease current window height by `count'."
|
|
(vim:resize-window (- (window-height) (or count 1))))
|
|
|
|
|
|
(vim:defcmd vim:window-increase-width (count nonrepeatable)
|
|
"Increase current window width by `count'."
|
|
(vim:resize-window (+ (window-width) (or count 1)) t))
|
|
|
|
|
|
(vim:defcmd vim:window-decrease-width (count nonrepeatable)
|
|
"Decrease current window width by `count'."
|
|
(vim:resize-window (- (window-width) (or count 1)) t))
|
|
|
|
|
|
(vim:defcmd vim:window-set-height (count nonrepeatable)
|
|
"Sets the height of the current window to `count'."
|
|
(vim:resize-window (or count (frame-height)) nil))
|
|
|
|
|
|
(vim:defcmd vim:window-set-width (count nonrepeatable)
|
|
"Sets the width of the current window to `count'."
|
|
(vim:resize-window (or count (frame-width)) t))
|
|
|
|
|
|
(vim:defcmd vim:window-rotate-upwards (nonrepeatable)
|
|
"Rotates the windows according to the currenty cyclic ordering."
|
|
(let ((wlist (window-list))
|
|
(blist (mapcar #'(lambda (w) (window-buffer w))
|
|
(window-list))))
|
|
(setq blist (append (cdr blist) (list (car blist))))
|
|
(while (and wlist blist)
|
|
(set-window-buffer (car wlist) (car blist))
|
|
(setq wlist (cdr wlist)
|
|
blist (cdr blist)))
|
|
(select-window (car (last (window-list))))))
|
|
|
|
|
|
(vim:defcmd vim:window-rotate-downwards (nonrepeatable)
|
|
"Rotates the windows according to the currenty cyclic ordering."
|
|
(let ((wlist (window-list))
|
|
(blist (mapcar #'(lambda (w) (window-buffer w))
|
|
(window-list))))
|
|
(setq blist (append (last blist) blist))
|
|
(while (and wlist blist)
|
|
(set-window-buffer (car wlist) (car blist))
|
|
(setq wlist (cdr wlist)
|
|
blist (cdr blist)))
|
|
(select-window (cadr (window-list)))))
|
|
|
|
|
|
(vim:defcmd vim:window-move-very-top (nonrepeatable)
|
|
"Closes the current window, splits the upper-left one horizontally
|
|
and redisplays the current buffer there."
|
|
(unless (one-window-p)
|
|
(let ((b (current-buffer)))
|
|
(delete-window)
|
|
(let ((btree (vim:get-buffer-tree (car (window-tree)))))
|
|
(vim:window-only)
|
|
(let ((newwin (selected-window))
|
|
(subwin (split-window)))
|
|
(vim:restore-window-tree subwin btree)
|
|
(set-window-buffer newwin b)
|
|
(select-window newwin))))
|
|
(balance-windows)))
|
|
|
|
|
|
(vim:defcmd vim:window-move-far-left (nonrepeatable)
|
|
"Closes the current window, splits the upper-left one vertically
|
|
and redisplays the current buffer there."
|
|
(unless (one-window-p)
|
|
(let ((b (current-buffer)))
|
|
(delete-window)
|
|
(let ((btree (vim:get-buffer-tree (car (window-tree)))))
|
|
(vim:window-only)
|
|
(let ((newwin (selected-window))
|
|
(subwin (split-window-horizontally)))
|
|
(vim:restore-window-tree subwin btree)
|
|
(set-window-buffer newwin b)
|
|
(select-window newwin))))
|
|
(balance-windows)))
|
|
|
|
|
|
(vim:defcmd vim:window-move-far-right (nonrepeatable)
|
|
"Closes the current window, splits the lower-right one vertically
|
|
and redisplays the current buffer there."
|
|
(unless (one-window-p)
|
|
(let ((b (current-buffer)))
|
|
(delete-window)
|
|
(let ((btree (vim:get-buffer-tree (car (window-tree)))))
|
|
(vim:window-only)
|
|
(let ((subwin (selected-window))
|
|
(newwin (split-window-horizontally)))
|
|
(vim:restore-window-tree subwin btree)
|
|
(set-window-buffer newwin b)
|
|
(select-window newwin))))
|
|
(balance-windows)))
|
|
|
|
|
|
|
|
|
|
(vim:defcmd vim:window-move-very-bottom (nonrepeatable)
|
|
"Closes the current window, splits the lower-right one horizontally
|
|
and redisplays the current buffer there."
|
|
(unless (one-window-p)
|
|
(let ((b (current-buffer)))
|
|
(delete-window)
|
|
(let ((btree (vim:get-buffer-tree (car (window-tree)))))
|
|
(vim:window-only)
|
|
(let ((subwin (selected-window))
|
|
(newwin (split-window)))
|
|
(vim:restore-window-tree subwin btree)
|
|
(set-window-buffer newwin b)
|
|
(select-window newwin))))
|
|
(balance-windows)))
|
|
|
|
|
|
(provide 'vim-window)
|
|
|
|
;;; vim-window.el ends here
|