Function: line-move-visual

line-move-visual is a byte-compiled function defined in simple.el.gz.

Signature

(line-move-visual ARG &optional NOERROR)

Documentation

Move ARG lines forward.

If NOERROR, don't signal an error if we can't move that many lines.

View in manual

Probably introduced at or before Emacs version 23.1.

Source Code

;; Defined in /usr/src/emacs/lisp/simple.el.gz
;; Display-based alternative to line-move-1.
;; Arg says how many lines to move.  The value is t if we can move the
;; specified number of lines.
(defun line-move-visual (arg &optional noerror)
  "Move ARG lines forward.
If NOERROR, don't signal an error if we can't move that many lines."
  (let ((opoint (point))
	(hscroll (window-hscroll))
        (lnum-width (line-number-display-width t))
	target-hscroll)
    ;; Check if the previous command was a line-motion command, or if
    ;; we were called from some other command.
    (if (and (consp temporary-goal-column)
	     (memq last-command `(next-line previous-line ,this-command)))
	;; If so, there's no need to reset `temporary-goal-column',
	;; but we may need to hscroll.
        (if (or (/= (cdr temporary-goal-column) hscroll)
                (>  (cdr temporary-goal-column) 0))
            (setq target-hscroll (cdr temporary-goal-column)))
      ;; Otherwise, we should reset `temporary-goal-column'.
      (let ((posn (posn-at-point))
	    x-pos)
	(cond
	 ;; Handle the `overflow-newline-into-fringe' case
	 ;; (left-fringe is for the R2L case):
	 ((memq (nth 1 posn) '(right-fringe left-fringe))
	  (setq temporary-goal-column (cons (window-width) hscroll)))
	 ((car (posn-x-y posn))
	  (setq x-pos (- (car (posn-x-y posn)) lnum-width))
	  ;; In R2L lines, the X pixel coordinate is measured from the
	  ;; left edge of the window, but columns are still counted
	  ;; from the logical-order beginning of the line, i.e. from
	  ;; the right edge in this case.  We need to adjust for that.
	  (if (eq (current-bidi-paragraph-direction) 'right-to-left)
	      (setq x-pos (- (window-body-width nil t) 1 x-pos)))
	  (setq temporary-goal-column
		(cons (/ (float x-pos)
			 (frame-char-width))
                      hscroll)))
	 (executing-kbd-macro
	  ;; When we move beyond the first/last character visible in
	  ;; the window, posn-at-point will return nil, so we need to
	  ;; approximate the goal column as below.
	  (setq temporary-goal-column
		(mod (current-column) (window-text-width)))))))
    (if target-hscroll
	(set-window-hscroll (selected-window) target-hscroll))
    ;; vertical-motion can move more than it was asked to if it moves
    ;; across display strings with newlines.  We don't want to ring
    ;; the bell and announce beginning/end of buffer in that case.
    (or (and (or (and (>= arg 0)
		      (>= (vertical-motion
			   (cons (or goal-column
				     (if (consp temporary-goal-column)
					 (car temporary-goal-column)
				       temporary-goal-column))
				 arg))
			  arg))
		 (and (< arg 0)
		      (<= (vertical-motion
			   (cons (or goal-column
				     (if (consp temporary-goal-column)
					 (car temporary-goal-column)
				       temporary-goal-column))
				 arg))
			  arg)))
	     (or (>= arg 0)
		 (/= (point) opoint)
		 ;; If the goal column lies on a display string,
		 ;; `vertical-motion' advances the cursor to the end
		 ;; of the string.  For arg < 0, this can cause the
		 ;; cursor to get stuck.  (Bug#3020).
		 (= (vertical-motion arg) arg)))
	(unless noerror
	  (signal (if (< arg 0) 'beginning-of-buffer 'end-of-buffer)
		  nil)))))