+;; Returns non-nil if partial move was done.
+(defun line-move-partial (arg noerror to-end)
+ (if (< arg 0)
+ ;; Move backward (up).
+ ;; If already vscrolled, reduce vscroll
+ (let ((vs (window-vscroll nil t)))
+ (when (> vs (frame-char-height))
+ (set-window-vscroll nil (- vs (frame-char-height)) t)))
+
+ ;; Move forward (down).
+ (let* ((lh (window-line-height -1))
+ (vpos (nth 1 lh))
+ (ypos (nth 2 lh))
+ (rbot (nth 3 lh))
+ ppos py vs)
+ (when (or (null lh)
+ (>= rbot (frame-char-height))
+ (<= ypos (- (frame-char-height))))
+ (unless lh
+ (let ((wend (pos-visible-in-window-p t nil t)))
+ (setq rbot (nth 3 wend)
+ vpos (nth 5 wend))))
+ (cond
+ ;; If last line of window is fully visible, move forward.
+ ((or (null rbot) (= rbot 0))
+ nil)
+ ;; If cursor is not in the bottom scroll margin, move forward.
+ ((and (> vpos 0)
+ (< (setq py
+ (or (nth 1 (window-line-height))
+ (let ((ppos (posn-at-point)))
+ (cdr (or (posn-actual-col-row ppos)
+ (posn-col-row ppos))))))
+ (min (- (window-text-height) scroll-margin 1) (1- vpos))))
+ nil)
+ ;; When already vscrolled, we vscroll some more if we can,
+ ;; or clear vscroll and move forward at end of tall image.
+ ((> (setq vs (window-vscroll nil t)) 0)
+ (when (> rbot 0)
+ (set-window-vscroll nil (+ vs (min rbot (frame-char-height))) t)))
+ ;; If cursor just entered the bottom scroll margin, move forward,
+ ;; but also vscroll one line so redisplay wont recenter.
+ ((and (> vpos 0)
+ (= py (min (- (window-text-height) scroll-margin 1)
+ (1- vpos))))
+ (set-window-vscroll nil (frame-char-height) t)
+ (line-move-1 arg noerror to-end)
+ t)
+ ;; If there are lines above the last line, scroll-up one line.
+ ((> vpos 0)
+ (scroll-up 1)
+ t)
+ ;; Finally, start vscroll.
+ (t
+ (set-window-vscroll nil (frame-char-height) t)))))))
+
+