bbatsov/adoc-mode

Noticeable lag when typing in larger code blocks

Closed this issue · 38 comments

lread commented

Thanks!

First, thanks for maintaining adoc-mode! I very much appreciate it!

Discovery

I'm a doom emacs user.
I noticed the lag when using adoc-mode I installed via doom.
It seems doom installs packages from melpa rather than melpa.stable(?), so I'm using a 0.8 snapshot release.

Expected behavior

When editing larger adoc code blocks, adoc-mode should be responsive enough to not impede usability.

Actual behavior

When editing larger code adoc blocks, keystroke lag is long enough to affect usability.
I find myself making edits I did not intend to make.

This is a recording of me holding down the x key:

adoc-mode-lag

Steps to reproduce the problem

I noticed the problem when editing the etaoin user guide.
I grabbed one of the larger code blocks (which doesn't really seem that big to me) and saved it to test.adoc:

[source,clojure]
----
(require '[etaoin.api :as e]
         '[etaoin.keys :as k]
         '[clojure.string :as str])

;; Start WebDriver for Firefox
(def driver (e/firefox)) ;; a Firefox window should appear

;; let's perform a quick Wiki session

;; navigate to wikipedia
(e/go driver "https://en.wikipedia.org/")
;; wait for the search input to load
(e/wait-visible driver [{:id :simpleSearch} {:tag :input :name :search}])

;; search for something interesting
(e/fill driver {:tag :input :name :search} "Clojure programming language")
(e/wait driver 1)
(e/fill driver {:tag :input :name :search} k/enter)
(e/wait-visible driver {:class :mw-search-results})

;; click on first match
(e/click driver [{:class :mw-search-results} {:class :mw-search-result-heading} {:tag :a}])
(e/wait-visible driver {:id :firstHeading})

;; check our new url location
;; (wikipedia can tack on a querystring, for result consistency we'll ignore it)
(-> (e/get-url driver) (str/split #"\?") first)
;; => "https://en.wikipedia.org/wiki/Clojure"

;; and our new title
(e/get-title driver)
;; => "Clojure - Wikipedia"

;; does page have Clojure in it?
(e/has-text? driver "Clojure")
;; => true

;; navigate through history
(e/back driver)
(e/forward driver)
(e/refresh driver)
(e/get-title driver)
;; => "Clojure - Wikipedia"

;; let's explore the info box
;; What's its caption? Let's select it with a css query:
(e/get-element-text driver {:css "table.infobox caption"})
;; => "Clojure"

;; Ok,now let's try something trickier
;; Maybe we are interested what value the infobox holds for the Family row:
(let [wikitable (e/query driver {:css "table.infobox.vevent tbody"})
      row-els (e/children driver wikitable {:tag :tr})]
  (for [row row-els
        :let [header-col-text (e/with-http-error
                                (e/get-element-text-el driver
                                                       (e/child driver row {:tag :th})))]
        :when (= "Family" header-col-text)]
    (e/get-element-text-el driver (e/child driver row {:tag :td}))))
;; => ("Lisp")

;; Etaoin gives you many options, we can do the same-ish in one swoop in XPath:
(e/get-element-text driver "//table[@class='infobox vevent']/tbody/tr/th[text()='Family']/../td")
;; => "Lisp"

;; When we are done we quit, which stops the Firefox WebDriver
(e/quit driver) ;; the Firefox Window should close
----

I started trying to reproduce the issue using eldev emacs from the adoc-mode project root, but because:

  1. I'd already spent many hours figuring out eldev and did not want to spend more at this time
  2. The problem is related to syntax highlighting which requires the language mode for the code block, so I wanted to load clojure-mode
  3. I also wanted to compare performance with org mode code blocks, so wanted to load current org

...I opted to create a custom emacs initialization script adoc-test.el:

(require 'package)

(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/") t)

;; isolate our installed packages
(setq package-user-dir "~/emacs-packages-testing123")

(package-initialize)

(unless package-archive-contents
  (package-refresh-contents))

(unless (package-installed-p 'use-package)
  (package-install 'use-package))

(require 'use-package)

(use-package adoc-mode
  :ensure t
  :mode "\\.adoc\\'")

;; we'll install and test with latest org mode for comparison
(use-package org
  :ensure t)

;; syntax highlighting for code blocks requires language mode
(use-package clojure-mode
  :ensure t)

I then launched emacs like so:

emacs --no-init-file -load adoc-test.el

To feel the lag, nagivate inside the code block and start typing.
In the animated gif above, I held down the x key.

Experiments

How does org mode do?

The adoc-mode block highlighting code is based on org mode's.

test.org:

#+NAME: <name>
#+BEGIN_SRC clojure
  (require '[etaoin.api :as e]
	   '[etaoin.keys :as k]
	   '[clojure.string :as str])

  ;; Start WebDriver for Firefox
  (def driver (e/firefox)) ;; a Firefox window should appear

  ;; let's perform a quick Wiki session

  ;; navigate to wikipedia
  (e/go driver "https://en.wikipedia.org/")
  ;; wait for the search input to load
  (e/wait-visible driver [{:id :simpleSearch} {:tag :input :name :search}])

  ;; search for something interesting
  (e/fill driver {:tag :input :name :search} "Clojure programming language")
  (e/wait driver 1)
  (e/fill driver {:tag :input :name :search} k/enter)
  (e/wait-visible driver {:class :mw-search-results})

  ;; click on first match
  (e/click driver [{:class :mw-search-results} {:class :mw-search-result-heading} {:tag :a}])
  (e/wait-visible driver {:id :firstHeading})

  ;; check our new url location
  ;; (wikipedia can tack on a querystring, for result consistency we'll ignore it)
  (-> (e/get-url driver) (str/split #"\?") first)
  ;; => "https://en.wikipedia.org/wiki/Clojure"

  ;; and our new title
  (e/get-title driver)
  ;; => "Clojure - Wikipedia"

  ;; does page have Clojure in it?
  (e/has-text? driver "Clojure")
  ;; => true

  ;; navigate through history
  (e/back driver)
  (e/forward driver)
  (e/refresh driver)
  (e/get-title driver)
  ;; => "Clojure - Wikipedia"

  ;; let's explore the info box
  ;; What's its caption? Let's select it with a css query:
  (e/get-element-text driver {:css "table.infobox caption"})
  ;; => "Clojure"

  ;; Ok,now let's try something trickier
  ;; Maybe we are interested what value the infobox holds for the Family row:
  (let [wikitable (e/query driver {:css "table.infobox.vevent tbody"})
	row-els (e/children driver wikitable {:tag :tr})]
    (for [row row-els
	  :let [header-col-text (e/with-http-error
				  (e/get-element-text-el driver
							 (e/child driver row {:tag :th})))]
	  :when (= "Family" header-col-text)]
      (e/get-element-text-el driver (e/child driver row {:tag :td}))))
  ;; => ("Lisp")

  ;; Etaoin gives you many options, we can do the same-ish in one swoop in XPath:
  (e/get-element-text driver "//table[@class='infobox vevent']/tbody/tr/th[text()='Family']/../td")
  ;; => "Lisp"

  ;; When we are done we quit, which stops the Firefox WebDriver
  (e/quit driver) ;; the Firefox Window should close
#+END_SRC

Let's retry our test under in an org mode code block:
org-mode-lag

To me, this seems fine.

What if we disable adoc-mode syntax highlighting?

If I (setq adoc-fontify-code-blocks-natively nil) this should disable syntax highlighting.
Let's retry our test.
adoc-mode-no-hl-lag

Interesting that we still feel some stutter here. Much less than with syntax highlighting enabled, but still there.

What about adoc-mode melpa stable?

The current stable version of adoc-mode is 0.7.0, let's retry with that.

  1. change melpa to stable.melpa in adoc-test.el
  2. rm -rf ~/emacs-packages-testing123

And then launch emacs as above, emacs --no-init-file -load adoc-test.el
adoc-mode-070-lag

This feels fine to me.

Environment & Version information

Adoc-Mode version information

adoc-mode, version 0.8.0-snapshot

Version 20230413.800

Emacs version

28.2

Operating system

Pop!_OS 22.04

Hardware

iMac 2013, 32gb RAM, SSD drive.

Next Steps

I'm admittedly an emacs elisp neophyte, but am happy to take a stab at some ways to improve performance here, if possible.

I'm curious as to why org-mode code blocks seem to edit without noticeable lag.
Perhaps they've made tweaks over the years that we could pick up?
Or maybe adoc-mode is, by design, doing more work?

It's interesting there still some slowdown, even when font-locking is disabled. I never worked with big code block in adoc-mode, which is probably why I didn't notice the problem.

@TobiasZawada can speak more about the current implementation, which I believe came straight from org-mode, so I was expecting similar performance. Running the Emacs profiler will give you some insights where exactly the slowdown is happening - see https://www.gnu.org/software/emacs/manual/html_node/elisp/Profiling.html for details.

@bbatsov Notice: I am out of office for about three weeks. I don't know whether I have a chance to go online in this time.

lread commented

I can try out the Emacs profiler and also compare with the org-mode implementation.

lread commented

Ok, I've lots to learn, but I have discovered that if I totally disable font-locking via (font-lock-mode -1), I experience no lag. So the lag does seem to be related to font-lock.

This is how I'd start to debug this issue. Add this in Eldev-local (I found a function name with font-lock and code in project sources):

(defadvice font-lock-fontify-region (around debug-it activate)
  (eldev-time-it "font-lock-fontify-region"
    (eldev-nest-debugging-output ad-do-it)))

(defadvice adoc-fontify-code-block-natively (around debug-it activate)
  (eldev-time-it "adoc-fontify-code-block-natively"
    (eldev-nest-debugging-output ad-do-it)))

Then run Eldev like this (Lee's initial problem was that Emacs was compiled without X support as I understand, for me this worked fine immediately):

$ eldev emacs README.adoc

In the buffer, find a [source block, e.g. with C-s and start inserting x. After a while, this is what I get in the console from which Eldev is started, in response to just one keystroke:

    font-lock-fontify-region: 0.00 s
  adoc-fontify-code-block-natively: 0.00 s
font-lock-fontify-region: 0.07 s
    font-lock-fontify-region: 0.00 s
  adoc-fontify-code-block-natively: 0.00 s
    font-lock-fontify-region: 0.00 s
  adoc-fontify-code-block-natively: 0.00 s
font-lock-fontify-region: 0.26 s

Obviously, a third of a second (0.07 + 0.26) is way too much.

I don't plan to dig deeper and try to solve the issue myself, I'm just trying to demonstrate how it is possible to use Eldev to [try and] figure out such problems. In the above output you can see that adoc-fontify-code-block-natively is actually not to blame, but probably you know the code better and can get something useful with this method by adding advices and timing other functions. (Profiling didn't yield anything useful for me, but Emacs profiling practically never does, oh well.)

lread commented

Thanks @doublep!

Lee's initial problem was that Emacs was compiled without X support as I understand, for me this worked fine immediately

Yup, after I switched to emacs with X support, eldev worked fine.
Your idea of using eldev to time things did not occur to me, thanks for sharing that.

I spent a lot of time trying out font-lock-studio, font-lock-profiler, the emacs profiler, comparing org's implementation to adoc-mode, etc. After a while it felt like I was pulling at straws without any approach I understood that would help to diagnose this issue. At that time I decided to pause and work on other things.

If nobody else dives in, I might shake off my feeling of defeat and try again. 🙂

@lread As I already mentioned in a comment of this issue I am currently in vacation. Depending on how much spare time I have next week I will fix this issue.

The most likely cause is that for each edit of the code block the full code block is refontified.

I am just using the phone to write this message. So I cannot study how Orgmode avoids that. I guess font-lock-studio is the best tool for the investigation.

lread commented

Thanks @TobiasZawada, I look forward to learning from your fix!
Enjoy the rest of your vacation!

Even if Orgmode seems to do fine in our case, there have been complains: https://emacs.stackexchange.com/questions/46561/org-mode-9-too-slow-with-long-code-blocks

Even if Orgmode seems to do fine in our case, there have been complains: https://emacs.stackexchange.com/questions/46561/org-mode-9-too-slow-with-long-code-blocks

lread commented

Hey congrats @TobiasZawada! How did you pinpoint the cause?

lread commented

@bbatsov do preview builds get automatically created on melpa?
Would love to test try fix while clojure mode is active.

@lread Yeah. Feel free to test the latest version there.

@lread Melpa shows for adoc mode the date 20230724.2040. So, the fix is there. Note, you have to use the melpa archive and not melpa-stable in order to try the fix.

@lread You asked how I determined the cause of the problem.
I run font-lock-studio for the adoc-test file buffer. Thereby I noted that after the fontification of the code block other keywords were applied to the code block region. This should be avoided by the text property font-lock-fontified. Afterwards, I investigated Orgmode in that respect.

I didn't know about https://github.com/Lindydancer/font-lock-studio - pretty cool tool!

lread commented

Thanks for the info @TobiasZawada.

Am I doing something wrong? I still see some serious lag.

After doing an rm -rf ~/emacs-packages-testing123
I repeated my test as originally described.

Here's me typing x again:
adoc-mode-lag-jul24

I double-checked I am getting the current adoc-mode:

❯ ls -l ~/emacs-packages-testing123
total 20
drwxrwxr-x 2 lee lee 4096 Jul 25 08:52 adoc-mode-20230724.2040
drwxrwxr-x 5 lee lee 4096 Jul 25 08:52 archives
drwxrwxr-x 2 lee lee 4096 Jul 25 08:52 bind-key-20230203.2004
drwxrwxr-x 2 lee lee 4096 Jul 25 08:52 clojure-mode-20230626.715
drwxrwxr-x 2 lee lee 4096 Jul 25 08:52 use-package-20230426.2324

Did lag go away for you @TobiasZawada when you tried my test?

@lread I did check with the original test and there was no longer a recognisable time lag in the fontification of the source block.

When I find time today in the evening I will doublecheck.

So, until this is cleared, I reopen the issue.

lread commented

Thanks very much @TobiasZawada!

Looks like the current implementation of the keyword search in adoc-mode is just slower than that one in Orgmode.
I have learned that the font-lock-fontified property does not avoid the further keyword processing of the region.
Source blocks amplify the problem of the slow keyword search by increasing the region that must be re-fontified (through adoc-font-lock-extend-after-change-region that is registered at font-lock-extend-after-change-region-function).

Orgmode also applies other keywords to source blocks.

The last commit introduces adoc-kwf-search. This function works like re-search-forward but skips matches that have a non-nil text property adoc-code-block.
That reduces the fontification lag significantly. But we are still not on the level of Orgmode.

@lread Would be nice if you could test this version directly with https://github.com/bbatsov/adoc-mode/blob/SrcBlock/33font-lock-fontified_missing/adoc-mode.el

@bbatsov When I replace the start of adoc-get-font-lock-keywords with

(defun adoc-get-font-lock-keywords ()
  "Return list of keywords for `adoc-mode'."
  (append
   (list
    '(adoc-fontify-code-blocks) ; listing
    )
   (ignore

and add a closing parenthesis at its end, the fontification of the test file becomes faster than the Orgmode version. (I've got another test case where I put the full text of adoc-mode.el into a code block of an adoc-mode-document. This makes the speed differences even more obvious. Emacs freezes for a minute or so at opening that test case with the original version of adoc-mode.el while the org-version of the file is opened with only a small time-lag.)

The fast fontification of the adoc-buffer with the modified adoc-get-font-lock-keywords is a strong indication that the fontification lag is actually not caused by adoc-fontify-code-blocks but by the slow processing of the other keywords.

As I already mentioned above, I was wrong in assuming that stretches of the buffer that are already marked by the text property font-lock-fontified are not processed for the other keywords (with unset override attribute).

I am slowly running out of spare time. Nevertheless, I'll try my best to dig deeper into the problem in the remaining time.

@TobiasZawada Thanks for the update and no rush. I don't have much time for adoc-mode myself these days, so this is going to take as much time as it takes. I'm guessing the general font-locking code has a lot of room for improvement, but I've yet to take a closer look into it.

After Emacs 29 is out it might be nice to consider using something like tree-sitter for the font-locking as that would be much much faster and more reliable than regular expressions.

@bbatsov I put here the result of font-lock-profiler-report. It indicates clearly the culprit (keyword 38: (adoc-kw-delimiter-line-fallback)):

   0             4             1%  (adoc-fontify-code-blocks (0 nil))
   1             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(=[ \t]+\\)\\([^ \t\n].*?\\)\\(\\([ \t]+=\\)?[ \t]*\\(?:\n\\|\\'\\)\\)" '(0))) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 adoc-title-0-face t) (3 '(face nil adoc-reserved block-del) t) (4 '(face adoc-meta-hide-face) t t))
   2             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(==[ \t]+\\)\\([^ \t\n].*?\\)\\(\\([ \t]+==\\)?[ \t]*\\(?:\n\\|\\'\\)\\)" '(0))) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 adoc-title-1-face t) (3 '(face nil adoc-reserved block-del) t) (4 '(face adoc-meta-hide-face) t t))
   3             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(===[ \t]+\\)\\([^ \t\n].*?\\)\\(\\([ \t]+===\\)?[ \t]*\\(?:\n\\|\\'\\)\\)" '(0))) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 adoc-title-2-face t) (3 '(face nil adoc-reserved block-del) t) (4 '(face adoc-meta-hide-face) t t))
   4             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(====[ \t]+\\)\\([^ \t\n].*?\\)\\(\\([ \t]+====\\)?[ \t]*\\(?:\n\\|\\'\\)\\)" '(0))) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 adoc-title-3-face t) (3 '(face nil adoc-reserved block-del) t) (4 '(face adoc-meta-hide-face) t t))
   5             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(=====[ \t]+\\)\\([^ \t\n].*?\\)\\(\\([ \t]+=====\\)?[ \t]*\\(?:\n\\|\\'\\)\\)" '(0))) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 adoc-title-4-face t) (3 '(face nil adoc-reserved block-del) t) (4 '(face adoc-meta-hide-face) t t))
   6             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(======[ \t]+\\)\\([^ \t\n].*?\\)\\(\\([ \t]+======\\)?[ \t]*\\(?:\n\\|\\'\\)\\)" '(0))) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 adoc-title-5-face t) (3 '(face nil adoc-reserved block-del) t) (4 '(face adoc-meta-hide-face) t t))
   7             0             1%  ((lambda (end) (and adoc-enable-two-line-title (adoc-kwf-search "\\(\\)\\(^.*?[a-zA-Z0-9_].*?\\)[ \t]*\n\\(\\(?:\\(?:==\\)+=?\\)\\)[ \t]*\\(?:\n\\|\\'\\)" end t) (< (abs (- (length (match-string 2)) (length (match-string 3)))) 3) (or (not (numberp adoc-enable-two-line-title)) (not (equal adoc-enable-two-line-title (length (match-string 2))))) (not (text-property-not-all (match-beginning 0) (match-end 0) 'adoc-reserved nil)))) (2 adoc-title-0-face t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
   8             0             1%  ((lambda (end) (and adoc-enable-two-line-title (adoc-kwf-search "\\(\\)\\(^.*?[a-zA-Z0-9_].*?\\)[ \t]*\n\\(\\(?:\\(?:--\\)+-?\\)\\)[ \t]*\\(?:\n\\|\\'\\)" end t) (< (abs (- (length (match-string 2)) (length (match-string 3)))) 3) (or (not (numberp adoc-enable-two-line-title)) (not (equal adoc-enable-two-line-title (length (match-string 2))))) (not (text-property-not-all (match-beginning 0) (match-end 0) 'adoc-reserved nil)))) (2 adoc-title-1-face t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
   9             0             1%  ((lambda (end) (and adoc-enable-two-line-title (adoc-kwf-search "\\(\\)\\(^.*?[a-zA-Z0-9_].*?\\)[ \t]*\n\\(\\(?:\\(?:~~\\)+~?\\)\\)[ \t]*\\(?:\n\\|\\'\\)" end t) (< (abs (- (length (match-string 2)) (length (match-string 3)))) 3) (or (not (numberp adoc-enable-two-line-title)) (not (equal adoc-enable-two-line-title (length (match-string 2))))) (not (text-property-not-all (match-beginning 0) (match-end 0) 'adoc-reserved nil)))) (2 adoc-title-2-face t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  10             0             1%  ((lambda (end) (and adoc-enable-two-line-title (adoc-kwf-search "\\(\\)\\(^.*?[a-zA-Z0-9_].*?\\)[ \t]*\n\\(\\(?:\\(?:\\^\\^\\)+\\^?\\)\\)[ \t]*\\(?:\n\\|\\'\\)" end t) (< (abs (- (length (match-string 2)) (length (match-string 3)))) 3) (or (not (numberp adoc-enable-two-line-title)) (not (equal adoc-enable-two-line-title (length (match-string 2))))) (not (text-property-not-all (match-beginning 0) (match-end 0) 'adoc-reserved nil)))) (2 adoc-title-3-face t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  11             0             1%  ((lambda (end) (and adoc-enable-two-line-title (adoc-kwf-search "\\(\\)\\(^.*?[a-zA-Z0-9_].*?\\)[ \t]*\n\\(\\(?:\\(?:\\+\\+\\)+\\+?\\)\\)[ \t]*\\(?:\n\\|\\'\\)" end t) (< (abs (- (length (match-string 2)) (length (match-string 3)))) 3) (or (not (numberp adoc-enable-two-line-title)) (not (equal adoc-enable-two-line-title (length (match-string 2))))) (not (text-property-not-all (match-beginning 0) (match-end 0) 'adoc-reserved nil)))) (2 adoc-title-4-face t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  12             0             0%  ("^\\(\\(?:ifn?def\\|endif\\)::\\)\\([^ \t\n]*?\\)\\(\\[\\).+?\\(\\]\\)[ \t]*$" (1 '(face adoc-preprocessor-face adoc-reserved block-del)) (2 '(face adoc-delimiter adoc-reserved block-del)) (3 '(face adoc-hide-delimiter adoc-reserved block-del)) (4 '(face adoc-hide-delimiter adoc-reserved block-del)))
  13             0             0%  ("^\\(\\(include1?::\\)\\([^ \t\n]*?\\)\\(\\[\\)\\(.*?\\)\\(\\]\\)\\)[ \t]*$" (1 '(face nil adoc-reserved block-del)) (2 adoc-preprocessor-face) (3 adoc-delimiter) (4 adoc-hide-delimiter) (5 adoc-delimiter) (6 adoc-hide-delimiter))
  14             0             0%  ("^\\('\\{3,\\}+\\)[ \t]*$" (1 '(face adoc-complex-replacement-face adoc-reserved block-del)))
  15             0             0%  ("^\\(<\\{3,\\}+\\)[ \t]*$" (1 '(face adoc-delimiter adoc-reserved block-del)))
  16             0             0%  ("^\\(//\\(?:[^/].*\\|\\)\\(?:\n\\|\\'\\)\\)" (1 '(face adoc-comment-face adoc-reserved block-del)))
  17             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(image\\)::\\([^ \t\n]*?\\)\\[\\(\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\][ \t]*$" '(0))) (0 '(face adoc-meta-face adoc-reserved block-del) t) (1 adoc-complex-replacement-face t) (2 adoc-internal-reference-face t) (3 '(face adoc-meta-face adoc-reserved nil adoc-attribute-list ("alt")) t))
  18             0             0%  ((lambda (end) (adoc-kwf-std end "^\\([a-zA-Z0-9_]+\\)::\\([^ \t\n]*?\\)\\[\\(\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\][ \t]*$" '(0))) (0 '(face adoc-meta-face adoc-reserved block-del)) (1 adoc-command-face t) (3 '(face adoc-meta-face adoc-reserved nil adoc-attribute-list t) t))
  19             0             0%  ((lambda (end) (adoc-kwf-std end "^\\([ \t]*\\)\\(-\\|\\*\\{1,5\\}\\)\\([ \t]+\\)" '(0))) (0 '(face nil adoc-reserved block-del) t) (2 adoc-list-face t) (3 adoc-align-face t))
  20             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(\\)\\(\\+\\)\\([ \t]+\\)" '(0))) (0 '(face nil adoc-reserved block-del) t) (2 adoc-list-face t) (3 adoc-align-face t))
  21             0             0%  ((lambda (end) (adoc-kwf-std end "^\\([ \t]*\\)\\([0-9]+\\.\\|[a-z]\\.\\|[A-Z]\\.\\|[ivx]+)\\|[IVX]+)\\)\\([ \t]+\\)" '(0))) (0 '(face nil adoc-reserved block-del) t) (2 adoc-list-face t) (3 adoc-align-face t))
  22             0             0%  ((lambda (end) (adoc-kwf-std end "^\\([ \t]*\\)\\(\\.\\{1,5\\}\\)\\([ \t]+\\)" '(0))) (0 '(face nil adoc-reserved block-del) t) (2 adoc-list-face t) (3 adoc-align-face t))
  23             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(\\)\\(<?[0-9]*>\\)\\([ \t]+\\)" '(0))) (0 '(face nil adoc-reserved block-del) t) (2 adoc-list-face t) (3 adoc-align-face t))
  24             0             0%  ((lambda (end) (when (adoc-kwf-std end "^\\([ \t]*\\)\\(.*[^:\n]\\)\\(\\(::\\)\\(?:[ \t]+\\|$\\)\\)" '(0)) (let ((pos (match-beginning 0))) (when (> pos (point-min)) (put-text-property (1- pos) pos 'adoc-reserved 'block-del))) t)) (1 '(face nil adoc-reserved block-del) t) (2 adoc-gen-face t) (3 '(face adoc-align-face adoc-reserved block-del) t) (4 adoc-list-face t))
  25             0             0%  ((lambda (end) (when (adoc-kwf-std end "^\\([ \t]*\\)\\(.*[^;\n]\\)\\(\\(;;\\)\\(?:[ \t]+\\|$\\)\\)" '(0)) (let ((pos (match-beginning 0))) (when (> pos (point-min)) (put-text-property (1- pos) pos 'adoc-reserved 'block-del))) t)) (1 '(face nil adoc-reserved block-del) t) (2 adoc-gen-face t) (3 '(face adoc-align-face adoc-reserved block-del) t) (4 adoc-list-face t))
  26             0             0%  ((lambda (end) (when (adoc-kwf-std end "^\\([ \t]*\\)\\(.*[^:\n]\\)\\(\\(:::\\)\\(?:[ \t]+\\|$\\)\\)" '(0)) (let ((pos (match-beginning 0))) (when (> pos (point-min)) (put-text-property (1- pos) pos 'adoc-reserved 'block-del))) t)) (1 '(face nil adoc-reserved block-del) t) (2 adoc-gen-face t) (3 '(face adoc-align-face adoc-reserved block-del) t) (4 adoc-list-face t))
  27             0             0%  ((lambda (end) (when (adoc-kwf-std end "^\\([ \t]*\\)\\(.*[^:\n]\\)\\(\\(::::\\)\\(?:[ \t]+\\|$\\)\\)" '(0)) (let ((pos (match-beginning 0))) (when (> pos (point-min)) (put-text-property (1- pos) pos 'adoc-reserved 'block-del))) t)) (1 '(face nil adoc-reserved block-del) t) (2 adoc-gen-face t) (3 '(face adoc-align-face adoc-reserved block-del) t) (4 adoc-list-face t))
  28             0             0%  ((lambda (end) (when (adoc-kwf-std end "^\\([ \t]*\\)\\(.*[^ \t\n]\\)\\(\\(\\?\\?\\)\\)$" '(0)) (let ((pos (match-beginning 0))) (when (> pos (point-min)) (put-text-property (1- pos) pos 'adoc-reserved 'block-del))) t)) (1 '(face nil adoc-reserved block-del) t) (2 adoc-gen-face t) (3 '(face adoc-align-face adoc-reserved block-del) t) (4 adoc-list-face t))
  29             0             0%  ((lambda (end) (when (adoc-kwf-std end "^\\(\\)\\(.*[^ \t\n]\\)\\(\\(:-\\)\\)$" '(0)) (let ((pos (match-beginning 0))) (when (> pos (point-min)) (put-text-property (1- pos) pos 'adoc-reserved 'block-del))) t)) (1 '(face nil adoc-reserved block-del) t) (2 adoc-gen-face t) (3 '(face adoc-align-face adoc-reserved block-del) t) (4 adoc-list-face t))
  30             0             0%  (#[257 "\300�\301\302#\207" [adoc-kwf-std "^\\(\\+\\)[ \t]*$" (1)] 5 "\n\n(fn END)"] (1 '(face adoc-meta-face adoc-reserved block-del) t))
  31             0             0%  ((lambda (end) (adoc-kwf-std end "\\(^/\\{4,\\}\\)[ \t]*\n\\([ \t]*[^ \t\n].*\n\\(?:\\(?:.*\n\\)*?[ \t]*[^ \t\n].*\n\\)??\\)??\\(^/\\{4,\\}\\)[ \t]*$" '(1 3))) (0 '(face nil font-lock-multiline t) t) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 '(face adoc-comment-face face adoc-verbatim-face adoc-reserved t) t t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  32             0             0%  ((lambda (end) (adoc-kwf-std end "\\(^\\+\\{4,\\}\\)[ \t]*\n\\([ \t]*[^ \t\n].*\n\\(?:\\(?:.*\n\\)*?[ \t]*[^ \t\n].*\n\\)??\\)??\\(^\\+\\{4,\\}\\)[ \t]*$" '(1 3))) (0 '(face nil font-lock-multiline t) t) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 '(face adoc-passthrough-face face adoc-verbatim-face adoc-reserved t) t t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  33             0             0%  ((lambda (end) (adoc-kwf-std end "\\(^\\.\\{4,\\}\\)[ \t]*\n\\([ \t]*[^ \t\n].*\n\\(?:\\(?:.*\n\\)*?[ \t]*[^ \t\n].*\n\\)??\\)??\\(^\\.\\{4,\\}\\)[ \t]*$" '(1 3))) (0 '(face nil font-lock-multiline t) t) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 '(face adoc-verbatim-face face adoc-verbatim-face adoc-reserved t) t t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  34             0             0%  ((lambda (end) (adoc-kwf-std end "\\(^_\\{4,\\}\\)[ \t]*\n\\([ \t]*[^ \t\n].*\n\\(?:\\(?:.*\n\\)*?[ \t]*[^ \t\n].*\n\\)??\\)??\\(^_\\{4,\\}\\)[ \t]*$" '(1 3))) (0 '(face nil font-lock-multiline t) t) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 nil t t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  35             0             0%  ((lambda (end) (adoc-kwf-std end "\\(^=\\{4,\\}\\)[ \t]*\n\\([ \t]*[^ \t\n].*\n\\(?:\\(?:.*\n\\)*?[ \t]*[^ \t\n].*\n\\)??\\)??\\(^=\\{4,\\}\\)[ \t]*$" '(1 3))) (0 '(face nil font-lock-multiline t) t) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 nil t t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  36             0             0%  ((lambda (end) (adoc-kwf-std end "\\(^\\*\\{4,\\}\\)[ \t]*\n\\([ \t]*[^ \t\n].*\n\\(?:\\(?:.*\n\\)*?[ \t]*[^ \t\n].*\n\\)??\\)??\\(^\\*\\{4,\\}\\)[ \t]*$" '(1 3))) (0 '(face nil font-lock-multiline t) t) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 adoc-secondary-text-face t t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  37             0             0%  ((lambda (end) (adoc-kwf-std end "\\(^--\\)[ \t]*\n\\([ \t]*[^ \t\n].*\n\\(?:\\(?:.*\n\\)*?[ \t]*[^ \t\n].*\n\\)??\\)??\\(^--\\)[ \t]*$" '(1 3))) (0 '(face nil font-lock-multiline t) t) (1 '(face adoc-meta-hide-face adoc-reserved block-del) t) (2 nil t t) (3 '(face adoc-meta-hide-face adoc-reserved block-del) t))
  38             0            91%  ((lambda (end) (adoc-kwf-std end "\\(?:\\(?:^/\\{4,\\}\\)[ \t]*$\\|\\(?:^\\+\\{4,\\}\\)[ \t]*$\\|\\(?:^-\\{4,\\}\\)[ \t]*$\\|\\(?:^\\.\\{4,\\}\\)[ \t]*$\\|\\(?:^_\\{4,\\}\\)[ \t]*$\\|\\(?:^=\\{4,\\}\\)[ \t]*$\\|\\(?:^\\*\\{4,\\}\\)[ \t]*$\\|\\(?:^--\\)[ \t]*$\\)" '(0))) (0 '(face adoc-meta-face adoc-reserved block-del) t))
  39             0             0%  ("^|=\\{3,\\}[ \t]*$" (0 adoc-table-face))
  40             0             0%  ("^\\(\\(?:\\(?:\\(?:[0-9]+\\)\\|\\(?:\\.[0-9]+\\)\\|\\(?:[0-9]+\\)\\(?:\\.[0-9]+\\)\\)[*+]\\)?\\(?:\\(?:\\(?:[<^>]\\)\\|\\(?:\\.[<^>]\\)\\|\\(?:[<^>]\\)\\(?:\\.[<^>]\\)\\)\\)?\\(?:[demshalv]\\)?\\)\\(|\\)\\(?:[^|\n]*?[ \t]\\(\\(?:\\(?:\\(?:[0-9]+\\)\\|\\(?:\\.[0-9]+\\)\\|\\(?:[0-9]+\\)\\(?:\\.[0-9]+\\)\\)[*+]\\)?\\(?:\\(?:\\(?:[<^>]\\)\\|\\(?:\\.[<^>]\\)\\|\\(?:[<^>]\\)\\(?:\\.[<^>]\\)\\)\\)?\\(?:[demshalv]\\)?\\)\\(|\\)\\(?:[^|\n]*?[ \t]\\(\\(?:\\(?:\\(?:[0-9]+\\)\\|\\(?:\\.[0-9]+\\)\\|\\(?:[0-9]+\\)\\(?:\\.[0-9]+\\)\\)[*+]\\)?\\(?:\\(?:\\(?:[<^>]\\)\\|\\(?:\\.[<^>]\\)\\|\\(?:[<^>]\\)\\(?:\\.[<^>]\\)\\)\\)?\\(?:[demshalv]\\)?\\)\\(|\\)\\(?:[^|\n]*?[ \t]\\(\\(?:\\(?:\\(?:[0-9]+\\)\\|\\(?:\\.[0-9]+\\)\\|\\(?:[0-9]+\\)\\(?:\\.[0-9]+\\)\\)[*+]\\)?\\(?:\\(?:\\(?:[<^>]\\)\\|\\(?:\\.[<^>]\\)\\|\\(?:[<^>]\\)\\(?:\\.[<^>]\\)\\)\\)?\\(?:[demshalv]\\)?\\)\\(|\\)\\)?\\)?\\)?" (1 '(face adoc-delimiter adoc-reserved block-del) nil t) (2 '(face adoc-table-face adoc-reserved block-del) nil t) (3 '(face adoc-delimiter adoc-reserved block-del) nil t) (4 '(face adoc-table-face adoc-reserved block-del) nil t) (5 '(face adoc-delimiter adoc-reserved block-del) nil t) (6 '(face adoc-table-face adoc-reserved block-del) nil t) (7 '(face adoc-delimiter adoc-reserved block-del) nil t) (8 '(face adoc-table-face adoc-reserved block-del) nil t))
  41             0             0%  ("^\\(:[a-zA-Z0-9_][^.\n]*?\\(?:\\..*?\\)?:[ \t]*\\)\\(.*?\\)$" (1 adoc-delimiter) (2 adoc-secondary-text-face nil t))
  42             0             0%  ("^\\(\\(\\[\\)\\(quote\\|verse\\)\\(?:\\(,\\)\\(.*?\\)\\(?:\\(,\\)\\(.*?\\)\\)?\\)?\\(\\]\\)\\)[ \t]*$" (1 '(face nil adoc-reserved block-del)) (2 adoc-hide-delimiter) (3 adoc-delimiter) (4 adoc-hide-delimiter nil t) (5 adoc-secondary-text-face nil t) (6 adoc-delimiter nil t) (7 adoc-secondary-text-face nil t) (8 adoc-hide-delimiter))
  43             0             0%  ("^\\(\\[\\(?:CAUTION\\|WARNING\\|IMPORTANT\\|TIP\\|NOTE\\)\\]\\)[ \t]*$" (1 '(face adoc-complex-replacement-face adoc-reserved block-del)))
  44             0             0%  ((lambda (end) (adoc-kwf-std end "^\\[\\[\\(\\(?:[-a-zA-Z0-9_]+\\)\\)\\(?:,\\(.*?\\)\\)?\\]\\][ \t]*$" '(0))) (0 '(face adoc-meta-face adoc-reserved block-del)) (1 adoc-anchor-face t) (2 adoc-secondary-text-face t t))
  45             0             0%  (#[257 "\300�\301\302#\207" [adoc-kwf-std "^\\(\\[\\(.*\\)\\]\\)[ \t]*$" (0)] 5 "\n\n(fn END)"] (1 '(face adoc-meta-face adoc-reserved block-del)) (2 '(face adoc-meta-face adoc-attribute-list t)))
  46             0             0%  ((lambda (end) (adoc-kwf-std end "^\\(\\.\\)\\(\\.?\\(?:[0-9]+[^+*]\\|[^. \t\n]\\).*\\)\\(\n\\|\\'\\)" '(1))) (1 '(face adoc-meta-face adoc-reserved block-del)) (2 adoc-gen-face) (3 '(face nil adoc-reserved block-del)))
  47             0             0%  ((lambda (end) (and (adoc-kwf-search "\\(^\\+?[ \t]*\n\\(?:[ \t]+[^ \t\n].*\\(?:\n\\(?:[^+ \t\n]\\|[ \t]+[^ \t\n]\\|\\+[ \t]*[^ \t\n]\\).*?\\)*?\\(?:\n[ \t]*\\(?:\n\\|\\'\\)\\|\n\\+[ \t]*\n\\|\\'\\)\\)+\\)" end t) (not (text-property-not-all (match-beginning 0) (match-end 0) 'adoc-reserved nil)))) (1 '(face adoc-typewriter-face adoc-reserved t font-lock-multiline t)))
  48             0             0%  (#[257 "\300�\301\302\211\303����$\211\262�\203�\0\304`\305\"\203�\0m\203�\0\266\204\205*\0\306\307\224\307\225\310\302$?\207" ["^[ \t]*\\(\\(?:CAUTION\\|WARNING\\|IMPORTANT\\|TIP\\|NOTE\\):\\)\\([ \t]+\\)" t nil re-search-forward get-text-property adoc-code-block text-property-not-all 0 adoc-reserved] 11 "\n\n(fn END)"] (1 '(face adoc-complex-replacement-face adoc-reserved t)) (2 '(face adoc-align-face adoc-reserved t)))
  49             0             0%  ("^[ \t]+$" (0 '(face nil adoc-reserved block-del) t))
  50             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^A-Za-z0-9;:}&<>\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(`\\)\\([^ \t\n]\\|[^ \t\n]\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)[^ \t\n]\\)\\(`\\)\\(?:[^A-Za-z0-9\n]\\|[ \t]*$\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-typewriter-face append) (3 '(face adoc-verbatim-face adoc-reserved t) append) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  51             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(\\+\\+\\+\\)\\(\\(?:.+?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\+\\+\\+\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-typewriter-face append) (3 '(face adoc-verbatim-face adoc-reserved t) append) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  52             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(\\$\\$\\)\\(\\(?:.+?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\$\\$\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-typewriter-face append) (3 '(face adoc-verbatim-face adoc-reserved t) append) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  53             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(\\*\\*\\)\\(\\(?:.+?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\*\\*\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-bold-face append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  54             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^A-Za-z0-9;:}&<>\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(\\*\\)\\([^ \t\n]\\|[^ \t\n]\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)[^ \t\n]\\)\\(\\*\\)\\(?:[^A-Za-z0-9\n]\\|[ \t]*$\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-bold-face append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  55             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^A-Za-z0-9;:}&<>\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(``\\)\\([^ \t\n]\\|[^ \t\n]\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)[^ \t\n]\\)\\(''\\)\\(?:[^A-Za-z0-9\n]\\|[ \t]*$\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-replacement-face adoc-reserved t) t) (3 nil append) (3 nil) (4 '(face adoc-replacement-face adoc-reserved t) t))
  56             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^A-Za-z0-9;:}&<>\\\n]\\)\\(\\[[^][]+?\\]\\)?\\('\\)\\([^ \t\n]\\|[^ \t\n]\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)[^ \t\n]\\)\\('\\)\\(?:[^A-Za-z0-9\n]\\|[ \t]*$\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-emphasis-face append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  57             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^A-Za-z0-9;:}&<>\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(`\\)\\([^ \t\n]\\|[^ \t\n]\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)[^ \t\n]\\)\\('\\)\\(?:[^A-Za-z0-9\n]\\|[ \t]*$\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-replacement-face adoc-reserved t) t) (3 nil append) (3 nil) (4 '(face adoc-replacement-face adoc-reserved t) t))
  58             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(\\+\\+\\)\\(\\(?:.+?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\+\\+\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-typewriter-face append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  59             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^A-Za-z0-9;:}&<>\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(\\+\\)\\([^ \t\n]\\|[^ \t\n]\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)[^ \t\n]\\)\\(\\+\\)\\(?:[^A-Za-z0-9\n]\\|[ \t]*$\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-typewriter-face append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  60             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(__\\)\\(\\(?:.+?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(__\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-emphasis-face append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  61             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^A-Za-z0-9;:}&<>\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(_\\)\\([^ \t\n]\\|[^ \t\n]\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)[^ \t\n]\\)\\(_\\)\\(?:[^A-Za-z0-9\n]\\|[ \t]*$\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-emphasis-face append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  62             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(##\\)\\(\\(?:.+?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(##\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-gen-face append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  63             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^A-Za-z0-9;:}&<>\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(#\\)\\([^ \t\n]\\|[^ \t\n]\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)[^ \t\n]\\)\\(#\\)\\(?:[^A-Za-z0-9\n]\\|[ \t]*$\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 adoc-gen-face append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  64             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(~\\)\\(\\(?:.+?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(~\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 '(face adoc-subscript-face display (raise -0.3)) append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  65             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:^\\|\\=\\|[^\\\n]\\)\\(\\[[^][]+?\\]\\)?\\(\\^\\)\\(\\(?:.+?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\^\\)" '(1 2 4) '(3))) (1 '(face adoc-meta-face adoc-reserved t) t t) (2 '(face adoc-meta-hide-face adoc-reserved t) t) (3 '(face adoc-superscript-face display (raise 0.3)) append) (3 nil) (4 '(face adoc-meta-hide-face adoc-reserved t) t))
  66             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "\\((C)\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "©"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  67             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "\\((R)\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "®"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  68             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "\\((TM)\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "™"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  69             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "^\\(--\\)[ \t]" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "—"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  70             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "[ \t]\\(--\\)\\(?:[ \t]\\|$\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "—"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  71             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "[a-zA-Z0-9_]\\(--\\)[a-zA-Z0-9_]" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "—"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  72             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "[a-zA-Z0-9_]\\('\\)[a-zA-Z0-9_]" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "’"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  73             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "\\(\\.\\.\\.\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "…"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  74             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "\\(->\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "→"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  75             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "\\(=>\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "⇒"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  76             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "\\(<-\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "←"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  77             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203l\0�\204l\0�\203l\0\313\311\225\311\225\"\211?\211�\204k\0\314�\315\316#\210\210�\205r\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "\\(<=\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved make-overlay overlay-put after-string "⇐"] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  78             0             0%  (#[257 "\302\211\303�\203L\0�\203L\0`\262�\304�\302\303\211\305����$\211\262�\203*\0\306`\307\"\203*\0m\203�\0\266\204\262��?\206;\0\310\311\224\311\225\312\303$\262��\203�\0�\203�\0\211Tb\210\202�\0�\203\203\0�\204\203\0�\203\203\0\313\314!\203f\0\314\315\311!!\202i\0\316\317!\211;\205t\0\320\311\225\311\225\"\211?\211�\204\201\0\321�\322�#\210\266��\205\211\0�?\207" [adoc-insert-replacement adoc-replacement-failed t nil "\\(&[:_#a-zA-Z]\\(?:[-:_.]\\|[a-zA-Z0-9_]\\)*?;\\)" re-search-forward get-text-property adoc-code-block text-property-not-all 1 adoc-reserved functionp adoc-entity-to-string match-string-no-properties error "Invalid replacement type" make-overlay overlay-put after-string] 15 "\n\n(fn END)"] (1 '(face adoc-replacement-face adoc-reserved t) t))
  79             0             0%  ("{\\(\\w+\\(?:\\w*\\|-\\)*\\)\\([=?!#%@$][^}\n]*\\)?}" (0 adoc-replacement-face))
  80             0             0%  ((lambda (end) (adoc-kwf-std end "\\<\\(\\(?:\\(?:callto\\|f\\(?:ile\\|tp\\)\\|https?\\|irc\\|link\\|mailto\\)\\)\\)\\(:\\)\\([^ \t\n]*?\\)\\(\\[\\)\\(\\)\\(\\]\\)" '(0) '(0))) (1 '(face adoc-reference-face adoc-reserved t) append) (2 '(face adoc-reference-face adoc-reserved t) append) (3 '(face adoc-reference-face adoc-reserved t) append) (4 '(face adoc-meta-face adoc-reserved t) t) (6 '(face adoc-meta-face adoc-reserved t) t))
  81             0             0%  ((lambda (end) (adoc-kwf-std end "\\<\\(\\(?:\\(?:callto\\|f\\(?:ile\\|tp\\)\\|https?\\|irc\\|link\\|mailto\\)\\)\\)\\(:\\)\\([^ \t\n]*?\\)\\(\\[\\)\\(\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\]\\)" '(0) '(0))) (1 '(face adoc-internal-reference-face adoc-reserved t) t) (2 '(face adoc-internal-reference-face adoc-reserved t) t) (3 '(face adoc-internal-reference-face adoc-reserved t) t) (4 '(face adoc-meta-face adoc-reserved t) t) (5 '(face adoc-reference-face adoc-attribute-list adoc-reference-face) append) (6 '(face adoc-meta-face adoc-reserved t) t))
  82             0             0%  ((lambda (end) (adoc-kwf-std end "\\<\\(\\(?:anchor\\)\\)\\(:\\)\\([^ \t\n]*?\\)\\(\\[\\)\\(\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\]\\)" '(1 2 4 5) '(0))) (1 '(face adoc-command-face adoc-reserved t) t) (2 '(face adoc-meta-face adoc-reserved t) t) (3 adoc-anchor-face t) (4 '(face adoc-meta-face adoc-reserved t) t) (5 '(face adoc-meta-face adoc-attribute-list ("xreflabel")) t) (6 '(face adoc-meta-face adoc-reserved t) t))
  83             0             0%  ((lambda (end) (adoc-kwf-std end "\\<\\(\\(?:image\\)\\)\\(:\\)\\([^ \t\n]*?\\)\\(\\[\\)\\(\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\]\\)" '(1 2 4 5) '(0))) (1 '(face adoc-complex-replacement-face adoc-reserved t) t) (2 '(face adoc-meta-face adoc-reserved t) t) (3 adoc-internal-reference-face t) (4 '(face adoc-meta-face adoc-reserved t) t) (5 '(face adoc-meta-face adoc-attribute-list ("alt")) t) (6 '(face adoc-meta-face adoc-reserved t) t))
  84             0             0%  ((lambda (end) (adoc-kwf-std end "\\<\\(\\(?:xref\\)\\)\\(:\\)\\([^ \t\n]*?\\)\\(\\[\\)\\(\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\]\\)" '(1 2 4 5) '(0))) (1 '(face adoc-command-face adoc-reserved t) t) (2 '(face adoc-meta-face adoc-reserved t) t) (3 (if (string= (match-string 5) "") adoc-reference-face adoc-internal-reference-face) t) (4 '(face adoc-meta-face adoc-reserved t) t) (5 '(face adoc-meta-face adoc-attribute-list (("caption") (("caption" . adoc-reference-face)))) t) (6 '(face adoc-meta-face adoc-reserved t) t))
  85             0             0%  ((lambda (end) (adoc-kwf-std end "\\(\\(?:footnote\\)\\)\\(:\\)\\([^ \t\n]*?\\)\\(\\[\\)\\(\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\]\\)" '(1 2 4 5) '(0))) (1 '(face adoc-command-face adoc-reserved t) t) (2 '(face adoc-meta-face adoc-reserved t) t) (3 adoc-meta-face append) (4 '(face adoc-meta-face adoc-reserved t) t) (5 '(face adoc-meta-face adoc-attribute-list adoc-secondary-text-face) t) (6 '(face adoc-meta-face adoc-reserved t) t))
  86             0             0%  ((lambda (end) (adoc-kwf-std end "\\(\\(?:footnoteref\\)\\)\\(:\\)\\([^ \t\n]*?\\)\\(\\[\\)\\([^\n,]*?\\(?:\n[^\n,]*?\\)??\\)\\(\\]\\)" '(1 2 4 5) '(0))) (1 '(face adoc-command-face adoc-reserved t) t) (2 '(face adoc-meta-face adoc-reserved t) t) (3 adoc-meta-face append) (4 '(face adoc-meta-face adoc-reserved t) t) (5 '(face adoc-meta-face adoc-attribute-list (("id") (("id" . adoc-internal-reference-face)))) t) (6 '(face adoc-meta-face adoc-reserved t) t))
  87             0             0%  ((lambda (end) (adoc-kwf-std end "\\(\\(?:footnoteref\\)\\)\\(:\\)\\([^ \t\n]*?\\)\\(\\[\\)\\(\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\]\\)" '(1 2 4 5) '(0))) (1 '(face adoc-command-face adoc-reserved t) t) (2 '(face adoc-meta-face adoc-reserved t) t) (3 adoc-meta-face append) (4 '(face adoc-meta-face adoc-reserved t) t) (5 '(face adoc-meta-face adoc-attribute-list ("id" "text")) t) (6 '(face adoc-meta-face adoc-reserved t) t))
  88             0             0%  ((lambda (end) (adoc-kwf-std end "\\(?:\\b\\(?:https?\\|ftp\\|file\\|irc\\)://[^ \t\n<>]*[a-zA-Z0-9_/]\\)\\|\\(?:<\\(?:\\b\\(?:https?\\|ftp\\|file\\|irc\\)://[^ \t\n<>]*[a-zA-Z0-9_/]\\)>\\)\\|\\(?:[a-zA-Z0-9_][-a-zA-Z0-9_._]*@[-a-zA-Z0-9_._]*[a-zA-Z0-9_]\\)" '(0) '(0))) (0 '(face adoc-reference-face adoc-reserved t) append t))
  89             0             0%  ((lambda (end) (adoc-kwf-std end "\\<\\(\\w+\\)\\(:\\)\\([^ \t\n]*?\\)\\(\\[\\)\\(\\(?:.*?\\(?:\n\\(?:[ \t]*\\S-.*\n\\)*?.*?\\)??\\)\\)\\(\\]\\)" '(1 2 4 5) '(0))) (1 '(face adoc-command-face adoc-reserved t) t) (2 '(face adoc-meta-face adoc-reserved t) t) (3 adoc-meta-face append) (4 '(face adoc-meta-face adoc-reserved t) t) (5 '(face adoc-meta-face adoc-attribute-list t) t) (6 '(face adoc-meta-face adoc-reserved t) t))
  90             0             0%  ((lambda (end) (adoc-kwf-std end "\\(\\[\\[\\)\\(\\[[a-zA-Z0-9_:][a-zA-Z0-9_:.-]*?\\]\\)\\(\\]\\]\\)" '(1 3) '(0))) (1 '(face adoc-meta-face adoc-reserved t) t) (2 adoc-gen-face) (3 '(face adoc-meta-face adoc-reserved t) t))
  91             0             0%  ((lambda (end) (adoc-kwf-std end "\\(\\[\\[\\)\\([a-zA-Z0-9\"_:].*?\\)\\(\\]\\]\\)" '(1 3) '(0))) (1 '(face adoc-meta-face adoc-reserved t) t) (2 '(face adoc-meta-face adoc-attribute-list ("id" "xreflabel")) t) (3 '(face adoc-meta-face adoc-reserved t) t))
  92             0             0%  ("\\(<<\\)\\([a-zA-Z0-9\"].*?\\)\\(,\\)\\(.*?\\(?:\n.*?\\)??\\)\\(>>\\)" (1 adoc-hide-delimiter) (2 adoc-delimiter) (3 adoc-hide-delimiter) (4 adoc-reference-face) (5 adoc-hide-delimiter))
  93             0             0%  ("\\(<<\\)\\([a-zA-Z0-9\"].*?\\(?:\n.*?\\)??\\)\\(>>\\)" (1 adoc-hide-delimiter) (2 adoc-reference-face) (3 adoc-hide-delimiter))
  94            16             0%  ("(((?\\([^\\\n]\\|\\\\.\\)*?)))?" (0 adoc-delimiter))
  95             0             1%  ("^.*[^ \t\n].*[ \t]\\(\\+\\)[ \t]*$" (1 adoc-delimiter))
  96             0             0%  (adoc-flf-first-whites-fixed-width (1 adoc-align-face t))
  97             0             0%  ("^\\([ \t]+\\+[ \t]*\\)$" (1 adoc-warning-face t))
  98             0             0%  ("^\\(\\+[ \t]*\\)\n\\([ \t]+\\)[^ \t\n]" (1 adoc-warning-face t) (2 adoc-warning-face t))
  99             0             0%  (adoc-kwf-attribute-list (0 nil))
 100             0             0%  (adoc-flf-meta-face-cleanup (0 nil))
 101             0             0%  (adocTZA-fontify-links (0 font-lock-keyword-face))
 102             0             0%  ("^\\[#[[:alpha:]][-_0-9[:alpha:]]+\\]\n\\|\\[\\[[[:alpha:]][-_0-9[:alpha:]]+\\]\\]" (0 '(face markup-anchor-face invisible adocTZA-link keymap (keymap (mouse-3 keymap "Adoc Link Context Menu" (Toggle\ descriptive/literal\ links menu-item "Toggle descriptive/literal links" adocTZA-toggle-link-display)) (mouse-2 . adocTZA-link-follow) (follow-link . mouse-face)) mouse-face highlight) t))

I've got a time-out right now. Let us see whether I have spare time in the evening.

@bbatsov @lread The problem is that adoc-kwf-std restarts the search from (1+ saved-point) when the match is prevented. So the computational cost grows with squared length of the region to be re-fontified.

We have to find a better modified start point than (1+ saved-point) for repeating the search.
Maybe, I find some spare time in the evening...

lread commented

Nice sleuthing @TobiasZawada!

Limited to code blocks, if so why?

My original issue reproduction showed this happening within larger code blocks.
Have you found this lag can happen in general too?

Or, if the lag occurs in code blocks only, then do you know why?
I had imagined that the code block itself would not be affected by adoc-mode font-lock keywords because the code block is handled in its own separate buffer and when copied back to the main buffer the region is marked as fontitied.

Keyword Experiment

For all these tests I used my original "Steps to reproduce the problem" from this issue.

I did many experiments, but for one, I experimented with commenting out adoc-mode keywords.
There may be other keywords, but I found one, in particular, had a larger impact:

   (adoc-kw-llisti 'adoc-labeled-normal 1)

If I comment this one out lag is reduced but only by a bit.
This one matches adoc description lists that use semicolons, like:

Hello;; What's up?

A perhaps interesting thing, is that I still get significant lag with only...

   '(adoc-fontify-code-blocks)
   (adoc-kw-llisti 'adoc-labeled-normal 1)

...uncommented (all others commented out), I get enough lag for things to feel unpleasant.

If I then disable (adoc-kw-llisti 'adoc-labeled-normal 1) and uncomment its sisters...

   (adoc-kw-llisti 'adoc-labeled-normal 0)
   ;; (adoc-kw-llisti 'adoc-labeled-normal 1)
   (adoc-kw-llisti 'adoc-labeled-normal 2)
   (adoc-kw-llisti 'adoc-labeled-normal 3)

...no perceived lag. So why does (adoc-kw-llisti 'adoc-labeled-normal 1) have such a big impact? I do not know.

@lread It is very nice that you do more tests than me.
Addressing your question:

Limited to code blocks, if so why?

My working assumption is that the problem hits code blocks most because code blocks may be relative large and the factor introduced by adoc-kw-std depending on the square of the code block length hits hard.

And now I have an urgent request for you: Could you please test the newest version of https://raw.githubusercontent.com/bbatsov/adoc-mode/SrcBlock/33font-lock-fontified_missing/adoc-mode.el
?

1st with your standard test and 2nd with everything that comes to your mind.

Thanks in advance.

The ERT tests are fine. And my personal performance test that compares the fontification time of an adoc document with that one of an org document each with a code block containing the text of adoc-mode.el is also fine. No recognizable time difference between the two documents.

There is still a similar construct in adoc-kw-replacement which I did not replace. Let us see whether it causes any trouble.

lread commented

@TobiasZawada, happy to give your branch a whirl.

My testing process is painfully manual. I just spent some time trying to automate it but did not find a way to simulate real key presses as if I had typed them at the keyboard myself. Ideally I'd like to simulate the keypresses and also measure any lag.

But back to manual testing for now:

adoc-mode-33font-lock-fontified-missing-branch

Woah! Results seem very impressive!

(Reminder to self and maybe tip to others: https://gifcap.dev/ seems like a nice way to generate screen recordings).

lread commented

@TobiasZawada, I have updated my doom emacs config to use your branch.
Feeling awesomely lag-free so far!

For doom emacs lurkers:

Edit ~/.config/doom/packages.el:

(package! adoc-mode :recipe (:host github
                             :repo "bbatsov/adoc-mode"
                             :branch "SrcBlock/33font-lock-fontified_missing"))

To rebuild, you'll need to:

$ rm -rf ~/.config/emacs/.local/straight/build-28.2/adoc-mode
$ doom sync

@bbatsov @lread Lee Reed has comprehensively tested the branch (with exception of the change on adoc-insert-replacement). Thank you very much, Lee Reed!

I have added a working ERT for the not so intensively tested corner case adoc-insert-replacement.
(Who knows whether any user has actually activated adoc-insert-replacement.)

So we should finally be ready to merge !37.

@bbatsov

After Emacs 29 is out it might be nice to consider using something like tree-sitter for the font-locking as that would be much much faster and more reliable than regular expressions.

You are probably right. But we need the keyword based font-lock for Emacs versions < 29, if you do not want me to fork my own backwards-compatibility version again. I cannot switch from 27.1 to 29 at my office computer, since that computer is managed by the IT of the company and Emacs is more like accepted than wanted by the IT.

In the early phase of the Tree-Sitter version we also need it as fallback for people who have problems with the new version.

@bbatsov I think I open a new branch for restructuring adoc-kwf-std.
I kept the current version close to the original code since this is a bug-fix and adoc-kwf-std is one of the core functions of adoc-mode. So, changes should be kept small.

lread commented

FWIW, trying with emacs 29.1 now.
As expected, still awesomely lag-less.

@lread Note, Bozhidar has already informed us that he is currently very busy. If @bbatsov does not find time to review the PR until next weekend I will merge the Pullrequest myself.
The code review by Bozhidar would be nice but it is not a blocker.

I should have some time to take a closer look over the course of the week, so let's drive this to the finish line.

lread commented

That sounds great, thanks to you both!

I think everything is done here.