Max Nikulin <maniku...@gmail.com> writes:

> I have a more weird example. Consider you are going to get
>
> - [[#foo]] and [[#bar]]
>
> starting from
>
> - <point>[[#bar]]
>
> There is no problem till
>
> - [[#foo<point>[[#bar]]
>
> However in response to "]" point is moved after "["
>
> - [[#foo][<point>[#bar]]
>
> that is displayed as
>
> - <point>[#bar
>
> I do not see other ways than undo, SPC, and moving back. It would be 
> great to keep point between brackets "]<point>[" this case. I have no 
> idea if it is feasible to postpone hiding link target when such pattern 
> is typed.

May you try the attached patch (on top of the latest main)?
Does it feel better?

>From fce16d736a97943f2f2cde521806dd78ed97a9bc Mon Sep 17 00:00:00 2001
Message-ID: <fce16d736a97943f2f2cde521806dd78ed97a9bc.1714648357.git.yanta...@posteo.net>
From: Ihor Radchenko <yanta...@posteo.net>
Date: Thu, 2 May 2024 11:49:00 +0300
Subject: [PATCH] Honor `org-fold-catch-invisible-edits' when editing links

* lisp/org.el (org-activate-links): Mark links with 'org-link text
property.
* lisp/org-fold.el (org-fold-show-set-visibility): Reveal links at
point for 'local detail.
(org-fold-check-before-invisible-edit): When editing after links, do
not warn about inserting after invisible.
*
testing/lisp/test-org-fold.el (test-org-fold/org-catch-invisible-edits):
Update tests.
* lisp/org-fold-core.el (org-fold-core-region): Do not re-fontify
unnecessarily.
---
 lisp/org-fold-core.el         |  6 ++++--
 lisp/org-fold.el              | 37 +++++++++++++++++++--------------
 lisp/org.el                   |  1 +
 testing/lisp/test-org-fold.el | 39 +++++++++++++++++++++--------------
 4 files changed, 50 insertions(+), 33 deletions(-)

diff --git a/lisp/org-fold-core.el b/lisp/org-fold-core.el
index 41b16851f..1b2e41cf5 100644
--- a/lisp/org-fold-core.el
+++ b/lisp/org-fold-core.el
@@ -1047,9 +1047,11 @@ (defun org-fold-core-region (from to flag &optional spec-or-alias)
        ;; past the ellipsis.  See bug#65896.  The face properties are
        ;; assigned via `org-activate-folds'.
        (when (or (not spec) (org-fold-core-get-folding-spec-property spec :font-lock))
-         (when (equal ?\n (char-after from))
+         (when (and (equal ?\n (char-after from))
+                    (or flag (org-fold-folded-p from)))
            (font-lock-flush from (1+ from)))
-         (when (equal ?\n (char-after to))
+         (when (and (equal ?\n (char-after to))
+                    (or flag (org-fold-folded-p to)))
            (font-lock-flush to (1+ to)))
          (dolist (region (org-fold-core-get-regions :from from :to to :specs spec))
            (when (equal ?\n (char-after (cadr region)))
diff --git a/lisp/org-fold.el b/lisp/org-fold.el
index 1b62168c4..2c11383ba 100644
--- a/lisp/org-fold.el
+++ b/lisp/org-fold.el
@@ -658,8 +658,6 @@ (defun org-fold-show-set-visibility (detail)
     (org-fold-show-entry)
     ;; If point is hidden make sure to expose it.
     (when (org-invisible-p)
-      ;; FIXME: No clue why, but otherwise the following might not work.
-      (redisplay)
       ;; Reveal emphasis markers.
       (when (eq detail 'local)
         (let (org-hide-emphasis-markers
@@ -668,6 +666,7 @@ (defun org-fold-show-set-visibility (detail)
               (org-hide-macro-markers nil)
               (region (or (org-find-text-property-region (point) 'org-emphasis)
                           (org-find-text-property-region (point) 'org-macro)
+                          (org-find-text-property-region (point) 'org-link)
                           (org-find-text-property-region (point) 'invisible))))
           ;; Silence byte-compiler.
           (ignore org-hide-macro-markers)
@@ -882,30 +881,34 @@ (defun org-fold-check-before-invisible-edit (kind)
   "Check if editing KIND is dangerous with invisible text around.
 The detailed reaction depends on the user option
 `org-fold-catch-invisible-edits'."
+  ;; When cursor is at a link that was revealed during previous edit,
+  ;; re-fold it, so that we refresh the fontification.
+  (font-lock-ensure (max (point-min) (1- (point))) (point))
   ;; First, try to get out of here as quickly as possible, to reduce overhead
   (when (and org-fold-catch-invisible-edits
 	     (or (not (boundp 'visible-mode)) (not visible-mode))
 	     (or (org-invisible-p)
 		 (org-invisible-p (max (point-min) (1- (point))))))
-    ;; OK, we need to take a closer look.  Only consider invisibility
-    ;; caused by folding of headlines, drawers, and blocks.  Edits
-    ;; inside links will be handled by font-lock.
-    (let* ((invisible-at-point (org-fold-folded-p (point) '(headline drawer block)))
+    ;; OK, we need to take a closer look.
+    (let* ((invisible-at-point (org-invisible-p (point)))
 	   (invisible-before-point
-	    (and (not (bobp))
-	         (org-fold-folded-p (1- (point)) '(headline drawer block))))
+	    (and (not (bobp)) (org-invisible-p (1- (point)))))
+           (folded-before-point
+	    (and (not (bobp)) (org-fold-folded-p (1- (point)))))
 	   (border-and-ok-direction
 	    (or
 	     ;; Check if we are acting predictably before invisible
 	     ;; text.
 	     (and invisible-at-point (not invisible-before-point)
 		  (memq kind '(insert delete-backward)))
-             ;; Check if we are acting predictably after invisible text
-             ;; This works not well, and I have turned it off.  It seems
-             ;; better to always show and stop after invisible text.
-             ;; (and (not invisible-at-point) invisible-before-point
-             ;;  (memq kind '(insert delete)))
-             )))
+             ;; Check if we are acting predictably after invisible
+             ;; text.  After the folds (which are usually multi-line,
+             ;; always raise a warning; after inline invisible text
+             ;; (links or hidden markup markers), allow editing
+             ;; forward.
+             (and (not invisible-at-point) invisible-before-point
+                  (not folded-before-point)
+                  (memq kind '(insert delete))))))
       (when (or invisible-at-point invisible-before-point)
 	(when (eq org-fold-catch-invisible-edits 'error)
 	  (user-error "Editing in invisible areas is prohibited, make them visible first"))
@@ -922,10 +925,12 @@ (defun org-fold-check-before-invisible-edit (kind)
 	    ;; That's it, we do the edit after showing
 	    (message
 	     "Unfolding invisible region around point before editing")
-	    (sit-for 1))
+	    (sit-for 0.2))
 	   ((and (eq org-fold-catch-invisible-edits 'smart)
 		 border-and-ok-direction)
-	    (message "Unfolding invisible region around point before editing"))
+	    (message "Unfolding invisible region around point before editing")
+            ;; Flash links before they get hidden back due to fontification after edit.
+            (sit-for 0.2))
 	   (t
 	    ;; Don't do the edit, make the user repeat it in full visibility
 	    (user-error "Edit in invisible region aborted, repeat to confirm with text visible"))))))))
diff --git a/lisp/org.el b/lisp/org.el
index ad4d1b9d3..809fd8ba3 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -5351,6 +5351,7 @@ (defun org-activate-links (limit)
 								     :htmlize-link)
 					((and (pred functionp) f) (funcall f))
 					(_ `(:uri ,link)))
+                        'org-link t
 			'font-lock-multiline t)))
 	    (org-remove-flyspell-overlays-in start end)
 	    (org-rear-nonsticky-at end)
diff --git a/testing/lisp/test-org-fold.el b/testing/lisp/test-org-fold.el
index f58642be6..904bc6578 100644
--- a/testing/lisp/test-org-fold.el
+++ b/testing/lisp/test-org-fold.el
@@ -616,7 +616,8 @@ (ert-deftest test-org-fold/org-catch-invisible-edits ()
           (test-org-fold-with-default-template
             (dolist (txt '("Folded Paragraph inside heading"
                            "Folded Paragraph inside drawer"
-                           "Folded block"))
+                           "Folded block"
+                           "hiddenlink"))
               (search-forward txt)
               (message "Inside invisible %S" txt)
               (pcase org-fold-catch-invisible-edits
@@ -631,16 +632,13 @@ (ert-deftest test-org-fold/org-catch-invisible-edits ()
                  (should-not (org-invisible-p)))
                 (`error
                  (should-error (org-fold-check-before-invisible-edit kind))
-                 (should (org-invisible-p)))))
-            (search-forward "hiddenlink")
-            (message "Inside hidden link")
-            (org-fold-check-before-invisible-edit kind)
-            (should (org-invisible-p)))
+                 (should (org-invisible-p))))))
           ;; Edits at the left border.
           (test-org-fold-with-default-template
             (dolist (txt '("Folded heading"
                            ":FOLDED-DRAWER:"
-                           "#+begin_src emacs-lisp"))
+                           "#+begin_src emacs-lisp"
+                           "[link"))
               (search-forward txt)
               (message "Left of folded %S" txt)
               (pcase org-fold-catch-invisible-edits
@@ -660,12 +658,7 @@ (ert-deftest test-org-fold/org-catch-invisible-edits ()
                  (should-not (org-invisible-p (1+ (point)))))
                 (`error
                  (should-error (org-fold-check-before-invisible-edit kind))
-                 (should (org-invisible-p (1+ (point)))))))
-            (search-forward "hiddenlink")
-            (search-forward "lin")
-            (message "Left border of ]] in link")
-            (org-fold-check-before-invisible-edit kind)
-            (should (org-invisible-p (1+ (point)))))
+                 (should (org-invisible-p (1+ (point))))))))
           ;; Edits at the right border.
           (test-org-fold-with-default-template
             (dolist (txt '("Folded Paragraph inside heading."
@@ -689,8 +682,24 @@ (ert-deftest test-org-fold/org-catch-invisible-edits ()
             (search-forward "hiddenlink")
             (search-forward "link]]")
             (message "Right border of ]] in link")
-            (org-fold-check-before-invisible-edit kind)
-            (should (org-invisible-p (1- (point))))))))))
+            (pcase org-fold-catch-invisible-edits
+              (`nil
+               (org-fold-check-before-invisible-edit kind)
+               (should (org-invisible-p (1- (point)))))
+              (`show
+               (org-fold-check-before-invisible-edit kind)
+               (should-not (org-invisible-p (1- (point)))))
+              (`smart
+               (if (memq kind '(insert delete))
+                   (org-fold-check-before-invisible-edit kind)
+                 (should-error (org-fold-check-before-invisible-edit kind)))
+               (should-not (org-invisible-p (1- (point)))))
+              (`show-and-error
+               (should-error (org-fold-check-before-invisible-edit kind))
+               (should-not (org-invisible-p (1- (point)))))
+              (`error
+               (should-error (org-fold-check-before-invisible-edit kind))
+               (should (org-invisible-p (1- (point))))))))))))
 
 (ert-deftest test-org-fold/org-fold-display-inline-images ()
   "Test inline images displaying when cycling."
-- 
2.44.0

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>

Reply via email to