diff --git a/lisp/org.el b/lisp/org.el index 85c1a4bc5..87758fdfd 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -20898,16 +20898,14 @@ this numeric value." (defun org-copy-visible (beg end) "Copy the visible parts of the region." (interactive "r") - (let (snippets s) - (save-excursion - (save-restriction - (narrow-to-region beg end) - (setq s (goto-char (point-min))) - (while (not (= (point) (point-max))) - (goto-char (org-find-invisible)) - (push (buffer-substring s (point)) snippets) - (setq s (goto-char (org-find-visible)))))) - (kill-new (apply 'concat (nreverse snippets))))) + (let ((result "")) + (while (/= beg end) + (when (get-char-property beg 'invisible) + (setq beg (next-single-char-property-change beg 'invisible nil end))) + (let ((next (next-single-char-property-change beg 'invisible nil end))) + (setq result (concat result (buffer-substring beg next))) + (setq beg next))) + (kill-new result))) (defun org-copy-special () "Copy region in table or copy current subtree. diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index 260d39127..37c7edf7a 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -5997,6 +5997,53 @@ Paragraph" (org-show-set-visibility 'minimal) (org-invisible-p2)))) +(defun test-org/copy-visible () + "Test `org-copy-visible' specifications." + (should + (equal "Foo" + (org-test-with-temp-text "Foo" + (let ((kill-ring nil)) + (org-copy-visible (point-min) (point-max)) + (current-kill 0 t))))) + ;; Skip invisible characters by text property. + (should + (equal "Foo" + (org-test-with-temp-text #("Foo" 1 7 (invisible t)) + (let ((kill-ring nil)) + (org-copy-visible (point-min) (point-max)) + (current-kill 0 t))))) + ;; Skip invisible characters by overlay. + (should + (equal "Foo" + (org-test-with-temp-text "Foo" + (let ((o (make-overlay 2 10))) + (overlay-put o 'invisible t)) + (let ((kill-ring nil)) + (org-copy-visible (point-min) (point-max)) + (current-kill 0 t))))) + ;; Handle invisible characters at the beginning and the end of the + ;; buffer. + (should + (equal "Foo" + (org-test-with-temp-text #("Foo" 0 8 (invisible t)) + (let ((kill-ring nil)) + (org-copy-visible (point-min) (point-max)) + (current-kill 0 t))))) + (should + (equal "Foo" + (org-test-with-temp-text #("Foo" 3 11 (invisible t)) + (let ((kill-ring nil)) + (org-copy-visible (point-min) (point-max)) + (current-kill 0 t))))) + ;; Handle multiple visible parts. + (should + (equal "abc" + (org-test-with-temp-text + #("aXbXc" 1 2 (invisible t) 3 4 (invisible t)) + (let ((kill-ring nil)) + (org-copy-visible (point-min) (point-max)) + (current-kill 0 t)))))) + (provide 'test-org)