;;; -*- Mode:Emacs-Lisp -*-

;;; Various window manipulation commands optimized for slow terminal lines...
;;; By Jamie Zawinski <jwz@lucid.com>

(defvar split-window-track-cursor t
  "*If this is true, then the `split-window-vertically-carefully' command
will leave the cursor either in the top window or the bottom window, depending
on where the cursor was before the split.  If this is false, then the cursor 
is always left in the top window.")

(defun split-window-vertically-carefully (&optional arg)
  "Split current window into two windows, one above the other.  The uppermost
window will get at most ARG lines (no arg means split equally).

Both windows will be displaying the current buffer, but the second window will
be scrolled such that little redisplay will happen - the lines that were on the
screen before the split will still be on the screen, in the same places.  

If the variable 'split-window-track-cursor' is true, then an effort is made to
keep the cursor in the same place relative to the text on the screen as well.
If the cursor is below the half-way point in the window before the split, then
it will be moved to the bottom window; otherwise it will be in the top window.
If 'split-window-track-cursor' is false, then the cursor will always be left
in the top window, even if that means that the point must be moved."
  (interactive "P")
  (let ((p (point)))
    (goto-char (window-start))
    (let ((topp (point)))
      (split-window nil (and arg (prefix-numeric-value arg)))
      (let* ((top (selected-window))
	     (toph (window-height top))
	     (stay-in-top t))
	(goto-char topp) ; undo any scrolling that split-window may have done.
	(recenter 0)
	(if (< (count-lines (point) p) toph) ; if cursor fits in top window
	    (goto-char p)		     ; then keep it there; otherwise
	  (setq stay-in-top nil)	     ; move the point to EOW, and the
	  (forward-line (- toph 2)))	     ; cursor to the bottom window.
	(select-window (next-window))
	(goto-char topp)   ; undo any scrolling that split-window may have
	(recenter 0)	   ; done.
	(condition-case () (scroll-up toph)
	  ;; ignore errors in case we are already at EOB.
	  (error nil))
	(goto-char (window-start))
	(if (< (count-lines (point) p) (window-height))
	    ; if cursor fits in bottom window, keep it there.
	    (goto-char p))
	;; move cursor back to top window if appropriate.
	(if (or stay-in-top (null split-window-track-cursor))
	    (select-window top))))))


(defun delete-other-windows-carefully ()
  "Like delete-other-windows, but conspires to make the cursor remain in the
same position on the screen - the lines that stay the same will not be scrolled
up."
  (interactive)
  (let ((p (point)))
    (goto-char (window-start))
    (let ((top (car (cdr (window-edges)))))
      (delete-other-windows)
      (recenter 0)
      (condition-case c (scroll-down top)
	(beginning-of-buffer nil)
	(end-of-buffer nil)))
    (goto-char p)))

(or (fboundp 'window-edges)
    (fset 'delete-other-windows-carefully 'delete-other-windows))

(provide 'window-hacks)

