Преглед изворни кода

org-table: Improve shrinking on right-aligned and centered columns

* lisp/org-table.el (org-table--make-shrinking-overlay): New function.
(org-table--shrink-field): Use new function.
(org-table--shrink-columns): Update function.
* testing/lisp/test-org-table.el (test-org-table/toggle-column-width):
  Update test.
Nicolas Goaziou пре 7 година
родитељ
комит
e462125cfc
2 измењених фајлова са 87 додато и 49 уклоњено
  1. 84 46
      lisp/org-table.el
  2. 3 3
      testing/lisp/test-org-table.el

+ 84 - 46
lisp/org-table.el

@@ -3879,6 +3879,33 @@ When non-nil, return the overlay narrowing the field."
 	(when (org-table--shrunk-field) (push column shrunk)))
       (nreverse shrunk))))
 
+(defun org-table--make-shrinking-overlay (start end display field &optional pre)
+  "Create an overlay to shrink text between START and END.
+
+Use string DISPLAY instead of the real text between the two
+buffer positions.  FIELD is the real contents of the field, as
+a string, or nil.  It is meant to be displayed upon moving the
+mouse onto the overlay.
+
+Return the overlay."
+  (let ((show-before-edit
+	 (lambda (o &rest _)
+	   ;; Removing one overlay removes all other overlays in the
+	   ;; same column.
+	   (mapc #'delete-overlay
+		 (cdr (overlay-get o 'org-table-column-overlays)))))
+	(o (make-overlay start end)))
+    (overlay-put o 'insert-behind-hooks (and (not pre) (list show-before-edit)))
+    (overlay-put o 'insert-in-front-hooks (list show-before-edit))
+    (overlay-put o 'modification-hooks (list show-before-edit))
+    (overlay-put o 'org-overlay-type 'table-column-hide)
+    (when (stringp field) (overlay-put o 'help-echo field))
+    ;; Make sure overlays stays on top of table coordinates overlays.
+    ;; See `org-table-overlay-coordinates'.
+    (overlay-put o 'priority 1)
+    (org-overlay-display o display 'org-table t)
+    o))
+
 (defun org-table--shrink-field (width start end contents)
   "Shrink a table field to a specified width.
 
@@ -3888,13 +3915,13 @@ and END are, respectively, the beginning and ending positions of
 the field.  CONTENTS is its trimmed contents, as a string, or
 `hline' for table rules.
 
-Real field is hidden under an overlay.  The latter has the
+Real field is hidden under one or two overlays.  They have the
 following properties:
 
   `org-overlay-type'
 
     Set to `table-column-hide'.  Used to identify overlays
-    responsible for the task.
+    responsible for shrinking columns in a table.
 
   `org-table-column-overlays'
 
@@ -3906,48 +3933,58 @@ Whenever the text behind or next to the overlay is modified, all
 the overlays in the column are deleted, effectively displaying
 the column again.
 
-Return overlay hiding the field."
-  (unless (org-table--shrunk-field)
-    (let* ((overlay-start
-	    (cond
-	     ((= 0 width) start)		 ;hide everything
-	     ((<= (- end start) 1) start)	 ;column too short
-	     ((>= width (- end start)) (1- end)) ;enough room
-	     ((eq contents 'hline) (+ start width))
-	     (t
-	      ;; Find cut location so that WIDTH characters are
-	      ;; visible.
-	      (let* ((begin start)
-		     (lower begin)
-		     (upper (1- end)))
-		(catch :exit
-		  (while (> (- upper lower) 1)
-		    (let ((mean (+ (ash lower -1)
-				   (ash upper -1)
-				   (logand lower upper 1))))
-		      (pcase (org-string-width (buffer-substring begin mean))
-			((pred (= width)) (throw :exit mean))
-			((pred (< width)) (setq upper mean))
-			(_ (setq lower mean)))))
-		  upper)))))
-	   (display org-table-shrunk-column-indicator)
-	   (show-before-edit
-	    (list (lambda (o &rest _)
-		    ;; Removing one overlay removes all other overlays
-		    ;; in the same column.
-		    (mapc #'delete-overlay
-			  (cdr (overlay-get o 'org-table-column-overlays))))))
-	   (o (make-overlay overlay-start end)))
-      (overlay-put o 'insert-behind-hooks show-before-edit)
-      (overlay-put o 'insert-in-front-hooks show-before-edit)
-      (overlay-put o 'modification-hooks show-before-edit)
-      (overlay-put o 'org-overlay-type 'table-column-hide)
-      (when (stringp contents) (overlay-put o 'help-echo contents))
-      ;; Make sure overlays stays on top of table coordinates
-      ;; overlays.  See `org-table-overlay-coordinates'.
-      (overlay-put o 'priority 1)
-      (org-overlay-display o display 'org-table t)
-      o)))
+Return a list of overlays hiding the field, or nil if field is
+already hidden."
+  (cond
+   ((org-table--shrunk-field) nil)	;already shrunk: bail out
+   ((eq contents 'hline)		;no contents to hide
+    (list (org-table--make-shrinking-overlay
+	   (+ start width 1) end org-table-shrunk-column-indicator contents)))
+   ((or (= 0 width)			;shrink to one character
+	(>= 1 (org-string-width (buffer-substring start end))))
+    (list (org-table--make-shrinking-overlay
+	   start end org-table-shrunk-column-indicator contents)))
+   (t
+    ;; If the field is not empty, consider using two overlays: one for
+    ;; the blanks at the beginning of the field, and another one at
+    ;; the end of the field.  The former ensures a shrunk field is
+    ;; always displayed with a single white space character in front
+    ;; of it -- e.g., so that even right-aligned fields appear to the
+    ;; left -- and the latter cuts the field at WIDTH visible
+    ;; characters.
+    (let* ((pre-overlay
+	    (and (not (equal contents ""))
+		 (org-with-point-at start (looking-at "\\( [ \t]+\\)\\S-"))
+		 (org-table--make-shrinking-overlay
+		  start (match-end 1) org-table-separator-space nil 'pre)))
+	   (post-overlay
+	    (let* ((start (if pre-overlay (overlay-end pre-overlay)
+			    (1+ start)))
+		   (w (org-string-width (buffer-substring start (1- end)))))
+	      (if (>= width w)
+		  ;; Field is too short.  Extend its size by adding
+		  ;; white space characters to the right overlay.
+		  (org-table--make-shrinking-overlay
+		   (1- end) end (concat (make-string (- width w) ?\s)
+					org-table-shrunk-column-indicator)
+		   contents)
+		;; Find cut location so that WIDTH characters are visible.
+		(org-table--make-shrinking-overlay
+		 (let* ((begin start)
+			(lower begin)
+			(upper (1- end)))
+		   (catch :exit
+		     (while (> (- upper lower) 1)
+		       (let ((mean (+ (ash lower -1)
+				      (ash upper -1)
+				      (logand lower upper 1))))
+			 (pcase (org-string-width (buffer-substring begin mean))
+			   ((pred (= width)) (throw :exit mean))
+			   ((pred (< width)) (setq upper mean))
+			   (_ (setq lower mean)))))
+		     upper))
+		 end org-table-shrunk-column-indicator contents)))))
+      (delq nil (list pre-overlay post-overlay))))))
 
 (defun org-table--read-column-selection (select max)
   "Read column selection select as a list of numbers.
@@ -4015,10 +4052,11 @@ table."
 			  (string-match "\\`<[lrc]?\\([0-9]+\\)>\\'" contents))
 		 (setq width (string-to-number (match-string 1 contents)))))))
 	 (forward-line))
-       ;; Link overlay to the other overlays in the same column.
+       ;; Link overlays for current field to the other overlays in the
+       ;; same column.
        (let ((chain (list 'siblings)))
 	 (dolist (field fields)
-	   (let ((new (apply #'org-table--shrink-field (or width 0) field)))
+	   (dolist (new (apply #'org-table--shrink-field (or width 0) field))
 	     (push new (cdr chain))
 	     (overlay-put new 'org-table-column-overlays chain))))))))
 

+ 3 - 3
testing/lisp/test-org-table.el

@@ -2406,7 +2406,7 @@ See also `test-org-table/copy-field'."
   ;; With a column width cookie, limit overlay to the specified number
   ;; of characters.
   (should
-   (equal "| ab"
+   (equal "| abc"
 	  (org-test-with-temp-text "| <3>  |\n| <point>abcd |"
 	    (org-table-toggle-column-width)
 	    (buffer-substring (line-beginning-position)
@@ -2414,7 +2414,7 @@ See also `test-org-table/copy-field'."
 			       (car (overlays-in (line-beginning-position)
 						 (line-end-position))))))))
   (should
-   (equal "| a "
+   (equal "| a  "
 	  (org-test-with-temp-text "| <3>  |\n| <point>a   |"
 	    (org-table-toggle-column-width)
 	    (buffer-substring (line-beginning-position)
@@ -2423,7 +2423,7 @@ See also `test-org-table/copy-field'."
 						 (line-end-position))))))))
   ;; Width only takes into account visible characters.
   (should
-   (equal "| [[htt"
+   (equal "| [[http"
 	  (org-test-with-temp-text "| <4> |\n| <point>[[http://orgmode.org]] |"
 	    (org-table-toggle-column-width)
 	    (buffer-substring (line-beginning-position)