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.

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)))))