branch: externals/org-modern
commit ca440cd41499ccbc664eb42ab457f177267fce33
Author: JD Smith <93749+jdtsm...@users.noreply.github.com>
Commit: JD Smith <93749+jdtsm...@users.noreply.github.com>

    major rewrite using org-element + before/after-change-functions
    
    Includes an updated prefix string cache, and the use of a display
    property alias `org-modern-indent-display' for indented block styling.
    Note that the shorthand omi/ and :omi/ are also now adopted.
---
 README.md            |  17 +-
 org-modern-indent.el | 509 +++++++++++++++++++++++++++++++--------------------
 2 files changed, 323 insertions(+), 203 deletions(-)

diff --git a/README.md b/README.md
index 556a331fd2..ee6f663dd9 100644
--- a/README.md
+++ b/README.md
@@ -10,8 +10,21 @@ This small package approximately reproduces the block 
styling of `org-modern` wh
 
 
 ## Updates
-
-- v0.1 features a complete re-write to use font-lock directly.  This has a few 
benefits: 
+- v0.5 Another complete rewrite which dramatically improves
+  performance and accuracy.  Now based on `org-element` and
+  implemented via `before/after-change-functions`. Benefits include:
+  1. Higher performance and more reliable fontification.
+  2. Ability to detect and correctly treat _damaged_ blocks
+     (header/footer line altered or removed) as well as _merged_ blocks.
+  2. Caches all prefix strings for lower memory usage/GC churn.
+  3. No more "runaway" formatting when partial blocks are created:
+     only _real_ blocks (according to `org-element`) are fontified.
+  
+  Note that v0.5 implements indented block styling using display
+  properties on the indentation text, so navigation will "skip over"
+  it.
+- v0.1 features a complete re-write to use font-lock directly.  This
+  has a few benefits:
   1. No longer relies on org-mode face names for recognizing
      blocks, so `org-src-block-faces` can have arbitrary faces
      applied, e.g. for different `src` languages, as in the screenshot.
diff --git a/org-modern-indent.el b/org-modern-indent.el
index 4d3cdd49a1..a294c5b469 100644
--- a/org-modern-indent.el
+++ b/org-modern-indent.el
@@ -1,10 +1,10 @@
-;;; org-modern-indent.el --- org-indent blocks like org-modern -*- 
lexical-binding: t; -*-
-;; Copyright (C) 2022-2024  J.D. Smith
+;;; org-modern-indent.el --- Indent blocks like org-modern -*- 
lexical-binding: t -*-
+;; Copyright (C) 2022-2025  J.D. Smith
 
 ;; Author: J.D. Smith
 ;; Homepage: https://github.com/jdtsmith/org-modern-indent
-;; Package-Requires: ((emacs "27.1") (org "9.5.2") (compat "29.1.4.0"))
-;; Version: 0.1.4
+;; Package-Requires: ((emacs "27.1") (org "9.6.1") (compat "30.0"))
+;; Version: 0.5.0
 ;; Keywords: convenience
 ;; Prefix: org-modern-indent
 ;; Separator: -
@@ -24,247 +24,354 @@
 
 ;;; Commentary:
 
-;; org-modern-indent provides the block highlighting of org-modern,
-;; when org-indent is enabled.
+;; org-modern-indent approximates the block highlighting style of
+;; org-modern, when org-indent is enabled.
 ;;   
-;; Can be used with or without org-modern enabled.
+;; Can be used with or without org-modern.
 
 ;;; Code:
 (require 'compat)
 (require 'org-indent)
+(require 'org-element)
 (eval-when-compile (require 'cl-lib))
 
+;;;; Face and style
 (defgroup org-modern-indent nil
   "Org-modern style blocks which works with org-indent."
   :group 'org
   :prefix "org-modern-indent-")
 
 ;; Face for org-modern-indent line
-(defface org-modern-indent-bracket-line
+(defface omi/bracket-line
   '((t (:inherit (org-meta-line) :weight light)))
   "Face for bracket line in org-modern-indent."
   :group 'faces)
 
-(defconst org-modern-indent-begin (propertize "╭" 'face 
'org-modern-indent-bracket-line))
-(defconst org-modern-indent-guide (propertize "│" 'face 
'org-modern-indent-bracket-line))
-(defconst org-modern-indent-end   (propertize "╰" 'face 
'org-modern-indent-bracket-line))
+(defconst omi/begin (propertize "╭" 'face 'omi/bracket-line))
+(defconst omi/guide (propertize "│" 'face 'omi/bracket-line))
+(defconst omi/end   (propertize "╰" 'face 'omi/bracket-line))
 
-(defvar org-modern-indent-begin-re
+(defvar omi/begin-re
   "\\([ \t]*\\)\\(#\\+\\)\\(?:begin\\|BEGIN\\)_\\S-")
-(defvar org-modern-indent--font-lock-keywords
-  `((,(concat "^" org-modern-indent-begin-re)
-     (0 (org-modern-indent--block-bracket)))))
-
-(defun org-modern-indent--block-bracket ()
-  "Prettify blocks with in-text brackets.
-For use with `org-indent'.  Uses either in-text brackets, for
-auto-indented org text (with real spaces in the buffer, e.g. in
-plain lists), or `line-prefix' brackets, when the #+begin part of
-the block is flush left in the buffer."
-  (save-excursion
-    (goto-char (match-beginning 0))
-    (if (= (length (match-string 1)) 0)
-       (org-modern-indent--block-bracket-flush)
-      (org-modern-indent--block-bracket-indented)))
-  nil)
-
-(defvar org-modern-indent--block-prefixes (make-hash-table :test 'eq))
-(defun org-modern-indent--block-bracket-prefix (prefix)
-  "Return a vector of 3 prefix strings based on the length of the current 
PREFIX.
-The three returned prefixes include begin, guide, and end bracket
-indicators, and are cached by prefix length, for speed.
-Additionally, the original prefix string is included at the end
-of the returned vector.  If PREFIX is nil or empty, nil is
-returned."
-  (unless (or (not prefix) (string-empty-p prefix))
-    (let* ((l (length prefix)))
-      (or (gethash l org-modern-indent--block-prefixes)
-         (puthash l (cl-loop for type in '("begin" "guide" "end")
-                             for tstr = (symbol-value
-                                         (intern (concat "org-modern-indent-" 
type)))
-                             with pstr = (substring prefix 0 -1)
-                             collect (concat pstr tstr) into prefix-brackets
-                             finally return (vconcat prefix-brackets (list 
prefix)))
-                  org-modern-indent--block-prefixes)))))
-
-(defvar org-modern-indent--end-re
-       (rx bol (group (* space)) (* any)
-           "#+" (or "end" "END") ?_ (* (not space)) eol))
-
-(defun org-modern-indent--block-bracket-flush ()
-  "Insert brackets for org blocks flush with the line prefix."
-  (let* ((line-pref (get-text-property (point) 'line-prefix))
-        (beg (match-beginning 0))
-        (pind (match-beginning 2))
-        (vec (org-modern-indent--block-bracket-prefix line-pref))
-        (block-start (min (1+ (line-end-position)) (point-max))))
-    (with-silent-modifications
-      (put-text-property pind (1+ pind) 'org-modern-indent-block-type 'flush)
-      (when vec
-       (add-text-properties beg block-start
-                            `( line-prefix ,(aref vec 0)
-                               wrap-prefix ,(aref vec 1)))
-       (goto-char (match-end 0))
-       (when (re-search-forward org-modern-indent--end-re nil 'noerror)
-         (let ((b (line-beginning-position))
-               (p (line-beginning-position 2)))
-           (when (> b block-start)
-             (add-text-properties block-start b
-                                  `(line-prefix ,(aref vec 1) wrap-prefix 
,(aref vec 1))))
-           (add-text-properties b p
-                                `(line-prefix ,(aref vec 2) wrap-prefix ,(aref 
vec 3)))))))))
-
-(defun org-modern-indent--block-bracket-indented ()
-  "Insert brackets on space-indented org blocks, e.g. within plain lists."
-  (let* ((pf (get-text-property (point) 'line-prefix)) ; prefix from org-indent
-        (pind (match-beginning 2))                    ; at the #
-        (flush (eq (get-text-property pind 'org-modern-indent-block-type) 
'flush))
-        (indent (current-indentation)) ; space up to #+begin_
-        (block-indent (+ (point) indent))
-        (search (concat "^[[:blank:]]\\{" (number-to-string indent) "\\}"))
-        (wrap (concat
-               (if pf (propertize (make-string (length pf) ?\s) 'face 
'org-indent))
-               (if (> indent 1) (make-string (1- indent) ?\s))
-               org-modern-indent-guide))
-        orig-prefix)
-    (with-silent-modifications
-      (when flush                ; formerly this block was flush left
-       (when-let ((vec (org-modern-indent--block-bracket-prefix pf)))
-         (setq pf (aref vec 3)        ; for resetting prefix to saved
-               orig-prefix `(line-prefix ,pf))
-         (add-text-properties (point) (min (line-beginning-position 2) 
(point-max))
-                              `(line-prefix ,pf wrap-prefix ,pf))) ; restore
-       (put-text-property pind (1+ pind) 'org-modern-indent-block-type 
'indent))
-      (put-text-property (point) block-indent 'face nil)
-      (put-text-property (1- block-indent) block-indent
-                        'display org-modern-indent-begin)
-      (while
-         (progn
-           (add-text-properties
-             (point) (min (line-beginning-position 2) (point-max))
-             `(wrap-prefix ,wrap ,@orig-prefix))
-           (forward-line)
-           (setq block-indent (+ (point) indent))
-           (let ((next-line-beg (line-beginning-position 2)))
-             (when (< block-indent next-line-beg)
-               (put-text-property (point) block-indent 'face nil))
-             (cond
-              ((eobp) nil)
-              ((looking-at org-modern-indent--end-re)
-               (if (>= (length (match-string 1)) indent)
-                   (put-text-property (1- block-indent) block-indent
-                                      'display org-modern-indent-end))
-               (when flush
-                 (add-text-properties
-                  (point) (min (line-beginning-position 2) (point-max))
-                  `(wrap-prefix ,pf ,@orig-prefix)))
-               nil)
-              (t (if (and (<= block-indent next-line-beg) (looking-at-p 
search))
-                     (put-text-property (1- block-indent) block-indent
-                                        'display org-modern-indent-guide))
-                 t))))))))
-
-(defvar-local org-modern-indent--init nil)
-(defun org-modern-indent--wait-and-refresh (buf)
+
+;;;; Utility
+(defsubst omi/-lbp (p &optional n)
+  "Return the line beginning position N at point P."
+  (save-excursion (goto-char p) (line-beginning-position n)))
+
+;;;; Block prefix cache
+(defvar omi/-prefixes (make-hash-table :test #'equal)
+  "A hash table of cached line prefixes.
+The hash index is a combination of the (unstyled) `org-indent' length
+and the \"real\" (space) indentation at the block beginning.  Each hash
+value is a vector of length 3:
+
+  [BEGIN GUIDE END]
+
+holding the wrap/indent prefix strings for the block begin, end, and
+guide (body).")
+
+(defun omi/-prefix (org-indent extra-indent)
+  "Cache and return prefix strings based on the indent levels.
+There are 2 types of indentation: ORG-INDENT (styled with `org-indent'
+face), and EXTRA-INDENT (unstyled).  See `org-modern-indent--prefix' for
+the contents."
+  (unless (and (= org-indent 0) (= extra-indent 0))
+    (let* ((key (+ org-indent (* 1000 extra-indent)))
+          (cached (gethash key omi/-prefixes)))
+      (or cached
+         (puthash key
+                  (cl-loop for type in '("begin" "guide" "end")
+                           for tstr = (symbol-value
+                                       (intern (concat "org-modern-indent-" 
type)))
+                           with olen = (if (> extra-indent 0) org-indent
+                                         (1- org-indent))
+                           with ostr = (and (> olen 0)
+                                            (propertize (make-string olen ?\s)
+                                                        'face '(org-indent 
default)))
+                           with pstr = (and (> extra-indent 0)
+                                            (make-string (1- extra-indent) 
?\s))
+                           collect (concat ostr pstr tstr))
+                  omi/-prefixes)))))
+
+;;;; Finding and operating on blocks
+(defsubst omi/-block-p (el)
+  "Return non-nil if EL is an org block element."
+  (when-let ((el) (type (car el)))
+    (memq type
+         '(center-block comment-block dynamic-block
+                        example-block export-block quote-block
+                        special-block src-block verse-block))))
+
+(defun omi/-block-at-point (&optional pos)
+  "Return the org block element at POS, if any.
+Considers both the element at point, and its parent.  Does not consider
+affiliated content like title as part of the block."
+  (let ((pos (or pos (point))))
+    (when-let ((element (org-element-at-point pos)))
+      (when (or (omi/-block-p element)
+               (omi/-block-p
+                (setq element (org-element-property :parent element))))
+       (unless (< pos (org-element-property :post-affiliated element))
+         element)))))
+
+(defsubst omi/-block-beg-end (node)
+  "Return a cons of NODE's (BEG . END).
+BEG is at the beginning of the #+BEGIN line, and END is at the end of
+the #+END line."
+  (let* ((bbeg (org-element-property :post-affiliated node)) ; on #+begin
+        (blank-lines (org-element-property :post-blank node))
+        (bend (save-excursion
+                (goto-char (org-element-property :end node))
+                (if (eobp) (point)
+                  (line-end-position (- blank-lines))))))
+    (cons bbeg bend)))
+
+(defun omi/-walk-blocks (beg end fun)
+  "Walk all org blocks intersecting the region from BEG..END.
+FUN is called on each block with the beginning and end positions of the
+block (at the beginning and end of the lines containing the header and
+footer, respectively).  Note that the first block's beginning may lie
+prior to BEG, and the last block's end my fall past END, if either only
+partially overlaps the region."
+  (org-with-wide-buffer
+   (goto-char beg)
+   (let ((node (omi/-block-at-point)) finished)
+     (while (not finished)
+       (when node
+        (cl-destructuring-bind (bbeg . bend) (omi/-block-beg-end node)
+          (funcall fun bbeg bend)
+          (when (>= bend end) (setq finished t)))) ; last block
+       (unless finished
+        (if (re-search-forward omi/begin-re end t)
+            (setq node (omi/-block-at-point))
+          (setq finished t)))))))
+
+;;;; Drawing block brackets
+(defun omi/-draw-block (beg end beg0 end0 org-indent real-block-indent)
+  "Insert brackets for block between BEG and END.
+BEG0 and END0 represents the block's full range, corresponding to the
+line beginning/end positions of the block's #+BEGIN/END header/footer
+lines.  The `org-indent' prefix length at block header is ORG-INDENT,
+and REAL-BLOCK-INDENT is the amount of \"real\" (hard space) block
+indentation.  REAL-BLOCK-INDENT may be zero."
+  (with-silent-modifications
+    (pcase-let*
+       (((seq beg-str guide-str end-str)
+         (omi/-prefix org-indent real-block-indent))
+        ((seq beg-ind-str guide-ind-str end-ind-str)
+         (and (> real-block-indent 0) (omi/-prefix real-block-indent 0)))
+        (beg-bol (omi/-lbp beg))
+        (body-start (max (omi/-lbp beg0 2) beg-bol))
+        (lp-begin (and (= real-block-indent 0) `(line-prefix ,beg-str)))
+        (lp-guide (and (= real-block-indent 0) `(line-prefix ,guide-str))))
+      (when (> body-start beg) ;; BEGIN
+       (add-text-properties beg-bol body-start
+                            `(,@lp-begin wrap-prefix ,guide-str))
+       (when (> real-block-indent 0)
+         (put-text-property beg-bol (+ beg-bol real-block-indent)
+                            'omi/display beg-ind-str)))
+      (when (> end body-start)
+       (let* ((end-bol (omi/-lbp end))
+              (end0-bol (omi/-lbp end0))
+              (after-end (omi/-lbp end 2))
+              (body-final (if (= end-bol end0-bol) end-bol after-end)))
+         (add-text-properties body-start body-final ;; GUIDE BODY
+                              `(,@lp-guide wrap-prefix ,guide-str))
+         (when (> real-block-indent 0)
+           (goto-char body-start)
+           (while (< (point) body-final)
+             (when (>= (current-indentation) real-block-indent)
+               (put-text-property (point) (+ (point) real-block-indent)
+                                  'omi/display guide-ind-str))
+             (forward-line)))
+         (when (= end-bol end0-bol) ;; END
+           (if (= real-block-indent 0)
+               (put-text-property end-bol after-end 'line-prefix end-str)
+             (goto-char end-bol)
+             (when (>= (current-indentation) real-block-indent)
+               (put-text-property end-bol (+ end-bol real-block-indent)
+                                  'omi/display end-ind-str)))))))))
+
+;;;; org-indent interfacing
+(defvar-local omi/-level-change-end nil)
+(defun omi/-refresh-maybe-watch (fun beg end &rest r)
+  "Watch for org-indent heading refreshes and record the new end position.
+FUN is the wrapped function `org-indent-refresh-maybe', and BEG,
+END, and R are its arguments."
+  ;; sadly org-indent-refresh-maybe modifies beg/end but does not return
+  (let ((oiap-orig (symbol-function 'org-indent-add-properties)))
+    (cl-letf (((symbol-function 'org-indent-add-properties)
+              (lambda (b e &optional delay)
+                (setq omi/-level-change-end (and (> e end) e))
+                (funcall oiap-orig b e delay))))
+      (apply fun beg end r))))
+
+(defun omi/-strip-display (beg end)
+  (with-silent-modifications
+    (remove-text-properties beg end '(omi/display nil))))
+
+(defvar-local omi/-init nil)
+(defun omi/-wait-and-refresh (buf)
   "Wait for org-indent to finish initializing BUF, then refresh."
   (if (or (not (bound-and-true-p org-indent-agentized-buffers))
          (not (memq buf org-indent-agentized-buffers)))
-      (org-modern-indent--add-keywords buf)
+      (omi/-init buf)
     ;; still waiting
     (when (buffer-live-p buf)
       (with-current-buffer buf
-       (if org-modern-indent--init
-           (let ((cnt (cl-incf (cadr org-modern-indent--init))))
+       (if omi/-init
+           (let ((cnt (cl-incf (cadr omi/-init))))
              (if (> cnt 5)
                  (user-error
                   "org-modern-indent: Gave up waiting for %s to initialize"
                   buf)
                (timer-activate
-                (timer-set-time (car org-modern-indent--init)
+                (timer-set-time (car omi/-init)
                                 (time-add (current-time) 0.2)))))
-         (setq
-          org-modern-indent--init
-          (list (run-at-time 0.1 nil #'org-modern-indent--wait-and-refresh buf)
-                1)))))))
+         (setq omi/-init
+               (list (run-at-time 0.1 nil #'omi/-wait-and-refresh buf)
+                     1)))))))
+
+(defun omi/-refresh ()
+  "Strip custom display property and refresh line prefix in entire buffer."
+  (with-silent-modifications
+    (org-with-wide-buffer
+     (when org-indent-mode
+       (omi/-strip-display (point-min) (point-max))
+       (org-indent-refresh-maybe (point-min) (point-max) nil)))))
+
+;;;; Before/after change
+(defun omi/-intersects-leader-at (target beg end)
+  "Return non-nil if BEG..END intersects initial non-blank text at TARGET."
+  (save-excursion
+    (goto-char target)
+    (back-to-indentation)
+    (let ((beg-targ (point))
+         (end-targ (progn (skip-chars-forward "^[:blank:]\n") (point))))
+      (and (<= beg end-targ) (<= beg-targ end)))))
+
+(defun omi/-before-change (beg end)
+  "Check the BEG..END range for modified block header/footer lines.
+Adds an `:org-modern-indent-block' text property to the block, with
+value `damaged' for damaged block."
+  (cl-labels
+      ((detect-block-damage (bl-beg bl-end)
+        "Detect and mark damaged blocks."
+        (unless (and (<= beg bl-beg) (>= end bl-end)) ; entire block 
replaced/deleted
+          (with-silent-modifications
+            (if (or (omi/-intersects-leader-at bl-beg beg end)
+                    (omi/-intersects-leader-at bl-end beg end))
+                (progn
+                  (put-text-property bl-beg (1+ bl-beg) :omi/indent nil) ; now 
unknown!
+                  (put-text-property bl-beg (omi/-lbp bl-end 2) :omi/block 
'damaged))
+              (put-text-property bl-beg (omi/-lbp bl-end 2) :omi/block t))))))
+    (omi/-walk-blocks beg end #'detect-block-damage)))
+
+(defun omi/-pos-in-leader-p (pos)
+  "Return non-nil if a block's header/footer leader text encompasses POS."
+  (when-let ((node (omi/-block-at-point pos)))
+    (org-with-wide-buffer
+     (cl-destructuring-bind (bbeg . bend) (omi/-block-beg-end node)
+       (or (omi/-intersects-leader-at bbeg pos pos)
+          (omi/-intersects-leader-at bend pos pos))))))
 
-(defun org-modern-indent--add-keywords (buf)
-  "Add keywords to buffer BUF and refresh.
+(defun omi/-after-change (beg end _len)
+  "Perform after-change operations on changed text from BEG..END.
+To be added after `org-indent-refresh-maybe' on
+`after-change-functions'."
+  (with-silent-modifications
+    (let ((beg-block (get-text-property beg :omi/block))
+         (end-block (get-text-property end :omi/block))
+         extend)
+      (when (and beg-block (or (eq beg-block 'damaged) (omi/-pos-in-leader-p 
beg)))
+       (setq extend t
+             beg (or (previous-single-property-change beg :omi/block) beg)))
+      (when (and end-block (or (eq end-block 'damaged) (omi/-pos-in-leader-p 
end)))
+       (setq extend t
+             end (or (next-single-property-change end :omi/block) end)))
+      (when extend
+       (remove-text-properties beg end '(:omi/block nil :omi/indent nil))
+       (org-indent-add-properties beg end)))
+    ;; If we had a level change, extend down to the next heading
+    (when omi/-level-change-end (setq end (max end omi/-level-change-end)))
+    (remove-text-properties (omi/-lbp beg) (omi/-lbp end 2) '(omi/display nil))
+    (omi/-walk-blocks
+     beg end
+     (lambda (bl-beg bl-end)
+       (let ((beg0 bl-beg) (end0 bl-end)
+            (pf (get-text-property bl-beg 'line-prefix))
+            oi-pos oi ci full-block)
+        (save-excursion
+          (goto-char bl-beg)
+          (back-to-indentation)
+          (setq oi-pos (point)
+                oi (get-text-property oi-pos :omi/indent)
+                ci (current-indentation)))
+        (unless (eq oi ci)
+          (put-text-property oi-pos (1+ oi-pos) :omi/indent ci))
+        (when (and oi (= oi 0) (/= oi ci)) ; was flush, is now indented:
+          (org-indent-add-properties bl-beg bl-end)) ; repair block's prefixes
+        (when (< bl-beg beg)           ; 1st block straddles BEG
+          (if (eq oi ci) (setq bl-beg beg) (setq full-block t)))
+        (when (> bl-end end)           ; last block straddles END
+          (if (eq oi ci) (setq bl-end end) (setq full-block t)))
+        (when full-block
+          (with-silent-modifications
+            (remove-text-properties bl-beg bl-end '(omi/display nil))))
+        (omi/-draw-block bl-beg bl-end beg0 end0 (length pf) ci))))))
+
+
+;;;; Mode/setup
+(defun omi/-init (buf)
+  "Register buffer BUF and refresh.
 To be added to `org-indent-post-buffer-init-functions'."
   (when (buffer-live-p buf)         ; org-capture buffers vanish fast
     (with-current-buffer buf
-      (font-lock-add-keywords nil org-modern-indent--font-lock-keywords t)
-      (font-lock-flush))))
-
-(defun org-modern-indent--refresh ()
-  "Unfontify entire buffer and refresh line prefix."
-  (with-silent-modifications
-    (if org-indent-mode
-       (org-indent-refresh-maybe (point-min) (point-max) nil))
-    (font-lock-flush)))
-
-(defun org-modern-indent--unfontify-wrap (fun)
-  "Wrap FUN with extra font lock keywords."
-  (lambda (beg end)
-    (let* ((font-lock-extra-managed-props
-           (append '(display invisible) font-lock-extra-managed-props)))
-      (funcall fun beg end))))
-
-(defvar org-modern-indent--refresh-args nil)
-(defun org-modern-indent--store-refresh-args (args)
-  "Store the arguments ARGS for `org-indent-add-properties'.
-To be added as :filter-args advice."
-  (setq org-modern-indent--refresh-args args))
-
-(defun org-modern-indent--refresh-watch (fun beg end &rest r)
-  "Watch for org-indent heading refreshes and rebuild indent prefixes as 
needed.
-FUN is the wrapped function `org-indent-refresh-maybe', and BEG,
-END, and R are its arguments."
-  (let ((hmod org-indent-modified-headline-flag) p end2 is-flush)
-    (apply fun beg end r)
-    ;; Recover the args just passed to org-indent-add-properties
-    (setq end2 (cadr org-modern-indent--refresh-args))
-    (when (or hmod (/= end end2))
-      (setq p (1- beg))
-      (save-excursion
-       (while (< (setq p (next-single-property-change
-                          (1+ p) 'org-modern-indent-block-type nil end2))
-                 end2)
-         (goto-char p)
-         (setq is-flush
-               (eq (get-text-property p 'org-modern-indent-block-type) 'flush))
-         (when (looking-at org-modern-indent-begin-re)
-           (if is-flush
-               (org-modern-indent--block-bracket-flush)
-             (org-modern-indent--block-bracket-indented))))))))
+      (add-hook 'before-change-functions #'omi/-before-change nil t)
+      (or (memq #'omi/-after-change after-change-functions)
+         (cl-loop for func on after-change-functions
+                  if (eq (car func) 'org-indent-refresh-maybe) do
+                  (setcdr func (cons #'omi/-after-change (cdr func))) and 
return t)
+         (add-hook 'after-change-functions #'omi/-after-change 98 t))
+      (setq omi/-init t)
+      (org-with-wide-buffer (omi/-after-change (point-min) (point-max) nil)))))
 
 ;;;###autoload
-(define-minor-mode org-modern-indent-mode
+(define-minor-mode omi/mode
   "Org-modern-like block brackets within org-indent."
   :global nil
   :group 'org-modern-indent
-  (if org-modern-indent-mode
+  (if omi/mode
       (progn
        (advice-add 'org-indent-refresh-maybe :around
-                   #'org-modern-indent--refresh-watch)
-       (advice-add 'org-indent-add-properties :filter-args
-                   #'org-modern-indent--store-refresh-args)
-       (if (boundp 'org-indent-post-buffer-init-functions)
-           (add-hook 'org-indent-post-buffer-init-functions
-                     #'org-modern-indent--add-keywords)
-         ;; No hook available, use the less reliable method
-         (org-modern-indent--wait-and-refresh (current-buffer))))
+                   #'omi/-refresh-maybe-watch)
+       (advice-add 'org-indent-region :before #'omi/-strip-display)
+       (cond
+        ;; already registered before, just toggle
+        (omi/-init (omi/-init (current-buffer)))
+        ;; Register with buffer init
+        ((boundp 'org-indent-post-buffer-init-functions)
+         (add-hook 'org-indent-post-buffer-init-functions #'omi/-init nil t))
+        ;; No hook available, use the less reliable method
+        (t (omi/-wait-and-refresh (current-buffer))))
+       (cl-pushnew 'omi/display
+                   (alist-get 'display char-property-alias-alist)))
     ;; Disabling
-    (advice-remove 'org-indent-refresh-maybe
-                  #'org-modern-indent--refresh-watch)
-    (advice-remove 'org-indent-add-properties
-                  #'org-modern-indent--store-refresh-args)
-    (font-lock-remove-keywords nil org-modern-indent--font-lock-keywords)
+    (advice-remove 'org-indent-region #'omi/-strip-display)
+    (advice-remove 'org-indent-refresh-maybe #'omi/-refresh-maybe-watch)
+    (remove-hook 'before-change-functions #'omi/-before-change t)
+    (remove-hook 'after-change-functions #'omi/-after-change t)
     (if (boundp 'org-indent-post-buffer-init-functions)
-       (remove-hook 'org-indent-post-buffer-init-functions
-                    #'org-modern-indent--add-keywords)
-      (cancel-timer (car org-modern-indent--init))
-      (setq org-modern-indent--init nil))
-    (org-modern-indent--refresh)))
+       (remove-hook 'org-indent-post-buffer-init-functions #'omi/-init t)
+      (cancel-timer (car omi/-init))
+      (setq omi/-init nil))
+    (omi/-refresh)))
 
 (provide 'org-modern-indent)
 ;;; org-modern-indent.el ends here
+;; Local Variables:
+;; read-symbol-shorthands: (("omi/" . "org-modern-indent-") (":omi/" . 
":org-modern-indent-"))
+;; package-lint--sane-prefixes: "^omi/"
+;; End:
+ 

Reply via email to