changeset 42366:8c5f3e3e60da

(line-move-invisible): New subroutine. (line-move-to-column): New subroutine--smarter about advancing over invisible parts of a line, or lines, but only as long as hpos grows. (line-move-finish): New subroutine: repeatedly processes desired column, intangibility, and fields. (line-move): Use those subroutines. When moving lines downward, skip invisible text first rather than last.
author Richard M. Stallman <rms@gnu.org>
date Fri, 28 Dec 2001 05:15:59 +0000
parents 3af09e7320c0
children e79ed5ab7b08
files lisp/simple.el
diffstat 1 files changed, 90 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/simple.el	Fri Dec 28 05:12:42 2001 +0000
+++ b/lisp/simple.el	Fri Dec 28 05:15:59 2001 +0000
@@ -2530,6 +2530,15 @@
   :type 'boolean
   :group 'editing-basics)
 
+(defun line-move-invisible (pos)
+  "Return non-nil if the character after POS is currently invisible."
+  (let ((prop
+	 (get-char-property pos 'invisible)))
+    (if (eq buffer-invisibility-spec t)
+	prop
+      (or (memq prop buffer-invisibility-spec)
+	  (assq prop buffer-invisibility-spec)))))
+
 ;; This is the guts of next-line and previous-line.
 ;; Arg says how many lines to move.
 (defun line-move (arg)
@@ -2563,88 +2572,99 @@
 			 (bolp)))
 		  (signal (if (< arg 0)
 			      'beginning-of-buffer
-			    'end-of-buffer)
+a			    'end-of-buffer)
 			  nil))
 	    ;; Move by arg lines, but ignore invisible ones.
 	    (while (> arg 0)
+	      ;; If the following character is currently invisible,
+	      ;; skip all characters with that same `invisible' property value.
+	      (while (and (not (eobp)) (line-move-invisible (point)))
+		(goto-char (next-char-property-change (point))))
+	      ;; Now move a line.
 	      (end-of-line)
 	      (and (zerop (vertical-motion 1))
 		   (signal 'end-of-buffer nil))
-	      ;; If the following character is currently invisible,
-	      ;; skip all characters with that same `invisible' property value.
-	      (while (and (not (eobp))
-			  (let ((prop
-				 (get-char-property (point) 'invisible)))
-			    (if (eq buffer-invisibility-spec t)
-				prop
-			      (or (memq prop buffer-invisibility-spec)
-				  (assq prop buffer-invisibility-spec)))))
-		(if (get-text-property (point) 'invisible)
-		    (goto-char (or (next-single-property-change (point) 'invisible)
-				   (point-max)))
-		  (goto-char (next-overlay-change (point)))))
 	      (setq arg (1- arg)))
 	    (while (< arg 0)
 	      (beginning-of-line)
 	      (and (zerop (vertical-motion -1))
 		   (signal 'beginning-of-buffer nil))
-	      (while (and (not (bobp))
-			  (let ((prop
-				 (get-char-property (1- (point)) 'invisible)))
-			    (if (eq buffer-invisibility-spec t)
-				prop
-			      (or (memq prop buffer-invisibility-spec)
-				  (assq prop buffer-invisibility-spec)))))
-		(if (get-text-property (1- (point)) 'invisible)
-		    (goto-char (or (previous-single-property-change (point) 'invisible)
-				   (point-min)))
-		  (goto-char (previous-overlay-change (point)))))
-	      (setq arg (1+ arg))))
-	  (let ((buffer-invisibility-spec nil))
-	    (move-to-column (or goal-column temporary-goal-column))))
-      (setq new (point))
-      ;; If we are moving into some intangible text,
-      ;; look for following text on the same line which isn't intangible
-      ;; and move there.
-      (setq line-end (save-excursion (end-of-line) (point)))
-      (setq line-beg (save-excursion (beginning-of-line) (point)))
-      (let ((after (and (< new (point-max))
-			(get-char-property new 'intangible)))
-	    (before (and (> new (point-min))
-			 (get-char-property (1- new) 'intangible))))
-	(when (and before (eq before after)
-		   (not (bolp)))
-	  (goto-char (point-min))
-	  (let ((inhibit-point-motion-hooks nil))
-	    (goto-char new))
-	  (if (<= new line-end)
-	      (setq new (point)))))
-      ;; NEW is where we want to move to.
-      ;; LINE-BEG and LINE-END are the beginning and end of the line.
-      ;; Move there in just one step, from our starting position,
-      ;; with intangibility and point-motion hooks enabled this time.
-      (goto-char opoint)
-      (setq inhibit-point-motion-hooks nil)
-      (goto-char
-       (constrain-to-field new opoint nil t 'inhibit-line-move-field-capture))
-      ;; If intangibility processing moved us to a different line,
-      ;; readjust the horizontal position within the line we ended up at.
-      (when (or (< (point) line-beg) (> (point) line-end))
-	(setq new (point))
-	(setq inhibit-point-motion-hooks t)
-	(setq line-end (save-excursion (end-of-line) (point)))
-	(beginning-of-line)
-	(setq line-beg (point))
-	(let ((buffer-invisibility-spec nil))
-	  (move-to-column (or goal-column temporary-goal-column)))
-	(if (<= (point) line-end)
-	    (setq new (point)))
+	      (setq arg (1+ arg))
+	      (while (and (not (bobp)) (line-move-invisible (1- (point))))
+		(goto-char (previous-char-property-change (point)))))))
+
+      (line-move-finish (or goal-column temporary-goal-column) opoint)))
+  nil)
+
+(defun line-move-finish (column opoint)
+  (let ((repeat t))
+    (while repeat
+      ;; Set REPEAT to t to repeat the whole thing.
+      (setq repeat nil)
+
+      ;; Move to the desired column.
+      (line-move-to-column column)
+
+      (let ((new (point))
+	    (line-beg (save-excursion (beginning-of-line) (point)))
+	    (line-end (save-excursion (end-of-line) (point))))
+
+	;; Process intangibility within a line.
+	;; Move to the chosen destination position from above,
+	;; with intangibility processing enabled.
+
 	(goto-char (point-min))
-	(setq inhibit-point-motion-hooks nil)
-	(goto-char
-	 (constrain-to-field new opoint nil t
-			     'inhibit-line-move-field-capture)))))
-  nil)
+	(let ((inhibit-point-motion-hooks nil))
+	  (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))))
+
+	;; Now move to the updated destination, processing fields
+	;; as well as intangibility.
+	(goto-char opoint)
+	(let ((inhibit-point-motion-hooks nil))
+	  (goto-char
+	   (constrain-to-field new opoint nil t
+			       'inhibit-line-move-field-capture)))
+
+	;; If intangibility processing 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))))))
+
+(defun line-move-to-column (col)
+  "Try to find column COL, considering invisibility.
+This function works only in certain cases,
+because what we really need is for `move-to-column'
+and `current-column' to be able to ignore invisible text."
+  (move-to-column col)
+
+  (when (and line-move-ignore-invisible
+	     (not (bolp)) (line-move-invisible (1- (point))))
+    (let ((normal-location (point))
+	  (normal-column (current-column)))
+      ;; If the following character is currently invisible,
+      ;; skip all characters with that same `invisible' property value.
+      (while (and (not (eobp))
+		  (line-move-invisible (point)))
+	(goto-char (next-char-property-change (point))))
+      ;; Have we advanced to a larger column position?
+      (if (> (current-column) normal-column)
+	  ;; We have made some progress towards the desired column.
+	  ;; See if we can make any further progress.
+	  (line-move-to-column (+ (current-column) (- col normal-column)))
+	;; Otherwise, go to the place we originally found
+	;; and move back over invisible text.
+	;; that will get us to the same place on the screen
+	;; but with a more reasonable buffer position.
+	(goto-char normal-location)
+	(let ((line-beg (save-excursion (beginning-of-line) (point))))
+	  (while (and (not (bolp)) (line-move-invisible (1- (point))))
+	    (goto-char (previous-char-property-change (point) line-beg))))))))
 
 ;;; Many people have said they rarely use this feature, and often type
 ;;; it by accident.  Maybe it shouldn't even be on a key.