0
0
Fork 1
mirror of https://git.savannah.gnu.org/git/emacs/org-mode.git synced 2024-09-29 20:07:46 +00:00

org-macs: Fix last commit

* lisp/org-macs.el (org--string-from-props): Do not raise an error on
  unsupported display properties.  Change signature to avoid creating
  new strings unnecessarily.  Update docstring accordingly.
(org-string-width): Apply signature change.
* testing/lisp/test-org-macs.el (test-org/string-width): Add test.

Reported-by: Colin Baxter <m43cap@yandex.com>
<http://lists.gnu.org/r/emacs-orgmode/2018-10/msg00346.html>
This commit is contained in:
Nicolas Goaziou 2018-10-26 14:37:57 +02:00
parent 4832a432f0
commit 4b905774ac
2 changed files with 44 additions and 30 deletions

View file

@ -826,58 +826,70 @@ end of string are ignored."
results ;skip trailing separator results ;skip trailing separator
(cons (substring string i) results))))))) (cons (substring string i) results)))))))
(defun org--string-from-props (s property) (defun org--string-from-props (s property beg end)
"Return the visible part of string S. "Return the visible part of string S.
Visible part is determined according to text PROPERTY, which is Visible part is determined according to text PROPERTY, which is
either `invisible' or `display'." either `invisible' or `display'. BEG and END are 0-indices
(let ((len (length s)) delimiting S."
(new nil) (let ((width 0)
(i 0) (cursor beg))
(cursor 0)) (while (setq beg (text-property-not-all beg end property nil s))
(while (setq i (text-property-not-all i len property nil s)) (let* ((next (next-single-property-change beg property s end))
(let* ((end (next-single-property-change i property s len)) (props (text-properties-at beg s))
(props (text-properties-at i s))
(spec (plist-get props property)) (spec (plist-get props property))
(value (value
(pcase property (pcase property
(`invisible (`invisible
;; If `invisible' property in PROPS means text is to ;; If `invisible' property in PROPS means text is to
;; be invisible, return the empty string. Otherwise ;; be invisible, return 0. Otherwise return nil so
;; return nil so that the part is skipped. ;; as to resume search.
(and (or (eq t buffer-invisibility-spec) (and (or (eq t buffer-invisibility-spec)
(assoc-string spec buffer-invisibility-spec)) (assoc-string spec buffer-invisibility-spec))
"")) 0))
(`display (`display
(pcase spec (pcase spec
(`nil nil) (`nil nil)
(`(space . ,props)
(let ((width (plist-get props :width)))
(and (wholenump width) width)))
(`(image . ,_) (`(image . ,_)
;; Since we are returning a string, create (ceiling (car (image-size spec))))
;; a place-holder with the same width as the
;; image.
(make-string (ceiling (car (image-size spec))) ?\s))
((pred stringp) ((pred stringp)
;; Displayed string could contain invisible parts, ;; Displayed string could contain invisible parts,
;; but no nested display. ;; but no nested display.
(org--string-from-props spec 'invisible)) (org--string-from-props spec 'invisible 0 (length spec)))
(_ (error "Un-handled `display' value: %S" spec)))) (_
;; Un-handled `display' value. Ignore it.
;; Consider the original string instead.
nil)))
(_ (error "Unknown property: %S" property))))) (_ (error "Unknown property: %S" property)))))
(when value (when value
(setq new (concat new (substring s cursor i) value)) (cl-incf width
(setq cursor end)) ;; When looking for `display' parts, we still need
(setq i end))) ;; to look for `invisible' property elsewhere.
(if new (concat new (substring s cursor)) (+ (cond ((eq property 'display)
;; If PROPERTY was not found, return S as-is. (org--string-from-props s 'invisible cursor beg))
s))) ((= cursor beg) 0)
(t (string-width (substring s cursor beg))))
value))
(setq cursor next))
(setq beg next)))
(+ width
;; Look for `invisible' property in the last part of the
;; string. See above.
(cond ((eq property 'display)
(org--string-from-props s 'invisible cursor end))
((= cursor end) 0)
(t (string-width (substring s cursor end)))))))
(defun org-string-width (string) (defun org-string-width (string)
"Return width of STRING when displayed in the current buffer. "Return width of STRING when displayed in the current buffer.
Unlike `string-width', this function takes into consideration Unlike `string-width', this function takes into consideration
`invisible' and `display' text properties. It supports the `invisible' and `display' text properties. It supports the
latter in a limited way; it raises an error if it cannot handle latter in a limited way, mostly for combinations used in Org.
a given `display' combination." Results may be off sometimes if it cannot handle a given
(string-width `display' value."
(org--string-from-props (org--string-from-props string 'display) (org--string-from-props string 'display 0 (length string)))
'invisible)))
(defun org-not-nil (v) (defun org-not-nil (v)
"If V not nil, and also not the string \"nil\", then return V. "If V not nil, and also not the string \"nil\", then return V.

View file

@ -63,7 +63,9 @@
(should (= 5 (org-string-width #("1a3" 1 2 (display "abc"))))) (should (= 5 (org-string-width #("1a3" 1 2 (display "abc")))))
;; `display' string can also contain invisible characters. ;; `display' string can also contain invisible characters.
(should (= 4 (org-string-width (should (= 4 (org-string-width
#("123" 1 2 (display #("abc" 1 2 (invisible t)))))))) #("123" 1 2 (display #("abc" 1 2 (invisible t)))))))
;; Test `space' property in `display'.
(should (= 2 (org-string-width #(" " 0 1 (display (space :width 2)))))))
;;; Regexp ;;; Regexp