Function: line-move-finish

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

Signature

(line-move-finish COLUMN OPOINT FORWARD &optional NOT-IPMH)

Source Code

;; Defined in /usr/src/emacs/lisp/simple.el.gz
(defun line-move-finish (column opoint forward &optional not-ipmh)
  (let ((repeat t))
    (while repeat
      ;; Set REPEAT to t to repeat the whole thing.
      (setq repeat nil)

      (let (new
	    (old (point))
	    (line-beg (line-beginning-position))
	    (line-end
	     ;; Compute the end of the line
	     ;; ignoring effectively invisible newlines.
	     (save-excursion
	       ;; Like end-of-line but ignores fields.
	       (skip-chars-forward "^\n")
	       (while (and (not (eobp)) (invisible-p (point)))
		 (goto-char (next-char-property-change (point)))
		 (skip-chars-forward "^\n"))
	       (point))))

	;; Move to the desired column.
        (if (and line-move-visual
                 (not (or truncate-lines truncate-partial-width-windows)))
            ;; Under line-move-visual, goal-column should be
            ;; interpreted in units of the frame's canonical character
            ;; width, which is exactly what vertical-motion does.
            (vertical-motion (cons column 0))
          (line-move-to-column (truncate column)))

	;; Corner case: suppose we start out in a field boundary in
	;; the middle of a continued line.  When we get to
	;; line-move-finish, point is at the start of a new *screen*
	;; line but the same text line; then line-move-to-column would
	;; move us backwards.  Test using C-n with point on the "x" in
	;;   (insert "a" (propertize "x" 'field t) (make-string 89 ?y))
	(and forward
	     (< (point) old)
	     (goto-char old))

	(setq new (point))

	;; Process intangibility within a line.
	;; With inhibit-point-motion-hooks bound to nil, a call to
	;; goto-char moves point past intangible text.

	;; However, inhibit-point-motion-hooks controls both the
	;; intangibility and the point-entered/point-left hooks.  The
	;; following hack avoids calling the point-* hooks
	;; unnecessarily.  Note that we move *forward* past intangible
	;; text when the initial and final points are the same.
	(goto-char new)
	(with-suppressed-warnings ((obsolete inhibit-point-motion-hooks))
	  (let ((inhibit-point-motion-hooks (not not-ipmh)))
	    (goto-char new)

	    ;; If intangibility moves us to a different (later) place
	    ;; in the same line, use that as the destination.
	    (if (<= (point) line-end)
                (setq new (point))
	      ;; If that position is "too late",
	      ;; try the previous allowable position.
	      ;; See if it is ok.
	      (backward-char)
	      (if (if forward
		      ;; If going forward, don't accept the previous
		      ;; allowable position if it is before the target line.
		      (< line-beg (point))
		    ;; If going backward, don't accept the previous
		    ;; allowable position if it is still after the target line.
		    (<= (point) line-end))
		  (setq new (point))
		;; As a last resort, use the end of the line.
		(setq new line-end)))))

	;; Now move to the updated destination, processing fields
	;; as well as intangibility.
	(goto-char opoint)
	(with-suppressed-warnings ((obsolete inhibit-point-motion-hooks))
	  (let ((inhibit-point-motion-hooks (not not-ipmh)))
	    (goto-char
	     ;; Ignore field boundaries if the initial and final
	     ;; positions have the same `field' property, even if the
	     ;; fields are non-contiguous.  This seems to be "nicer"
	     ;; behavior in many situations.
	     (if (eq (get-char-property new 'field)
		     (get-char-property opoint 'field))
		 new
	       (constrain-to-field new opoint t t
				   'inhibit-line-move-field-capture)))))

	;; If all this moved us to a different line,
	;; retry everything within that new line.
	(when (or (< (point) line-beg) (> (point) line-end))
	  ;; Repeat the intangibility and field processing.
	  (setq repeat t))))))