(defun window-recenter-region-start-position (&optional from to window buffer) "Return window start position for recentered region. WINDOW specifies the window whose start position to return and defaults to the selected window. BUFFER specifies the buffer supposed to contain the region and defaults to WINDOW's buffer. FROM and TO specify the beginning and end of the region in BUFFER and default to the active region or the entire text of BUFFER." (let* ((window (or window (selected-window))) (buffer (or buffer (window-buffer window))) (from (or from (and (eq buffer (current-buffer)) (region-active-p) (region-beginning)) (with-current-buffer buffer (point-min)))) (to (or to (and (eq buffer (current-buffer)) (region-active-p) (region-end)) (with-current-buffer buffer (point-max)))) (body-width (window-body-width window t)) (body-height (window-body-height window t)) old-buffer old-start old-point remainder height start prev) ;; If WINDOW doesn't show BUFFEER, svae its buffeer, start and point ;; positions. (unless (eq (window-buffer window) buffer) (setq old-buffer (window-buffer window)) (setq old-start (window-start window)) (setq old-point (window-point window)) (set-window-buffer window buffer)) ;; The amount of pixels by which the region can be scrolled down in ;; the window. Initially, half of the difference of the height of ;; the window's body and that of the region. (setq remainder (round (/ (- body-height (cdr (window-text-pixel-size window from to body-width body-height))) 2.0))) ;; Now move back and subtract the height of one line preceding the ;; region until the remainder has been used. (save-excursion (goto-char from) (setq start (pos-bol)) (while (and (not (bobp)) (>= remainder 0) (setq prev (pos-bol 0)) (setq height (cdr (window-text-pixel-size window prev start body-width body-height))) ;; At least half of the line should fit. (>= remainder (/ height 2.0))) (setq remainder (- remainder height)) (setq start prev) (goto-char start))) ;; Restore WINDOW's old buffer, start and point. (when old-buffer (set-window-buffer window old-buffer) (set-window-point window old-point) (set-window-start window old-point)) ;; Return the new start position. start)) (defun recenter-region () (interactive) (mark-paragraph) (let ((from (region-beginning)) (to (region-end)) (body-width (window-body-width nil t)) (body-height (window-body-height nil t)) window-start window-end before at after) (set-window-start (selected-window) (window-recenter-region-start-position)) (setq window-start (window-start)) (setq window-end (window-end nil t)) (message "%s..%s L: %s P: %s - L: %s P: %s - %s..%s L: %s P: %s - L: %s P: %s B: %s S: %s" window-start from (count-lines window-start from) (setq before (cdr (window-text-pixel-size nil window-start from body-width body-height))) (count-lines from to) (setq at (cdr (window-text-pixel-size nil from to body-width body-height nil t))) to window-end (count-lines to window-end) (setq after (cdr (window-text-pixel-size nil to window-end body-width body-height))) (count-lines window-start window-end) (cdr (window-text-pixel-size nil window-start window-end body-width body-height)) body-height (+ before at after))))