branch: elpa/adoc-mode
commit 3c3665ad9069052d56934e94a6fa21958d0b667b
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>

    Add Asciidoctor preview and export integration
    
    Bridge the gap with AsciiDoc tooling elsewhere by shelling out to the
    asciidoctor CLI. A new adoc-asciidoctor.el provides a preview that renders
    the buffer (via stdin, so unsaved edits and relative paths work) into an
    xwidget or eww side pane, a live-preview minor mode that refreshes on save,
    and HTML/DocBook/PDF/EPUB export commands that run through compile. All of 
it
    hangs off a C-c C-c transient and the AsciiDoc menu, and degrades gracefully
    when asciidoctor isn't installed.
    
    Also broaden the compilation error matcher to recognise modern asciidoctor:
    diagnostics, not just the legacy AsciiDoc.py asciidoc: format, so jumping to
    warnings and errors actually works.
---
 CHANGELOG.md                       |   5 +
 README.adoc                        |  42 +++++-
 adoc-asciidoctor.el                | 263 +++++++++++++++++++++++++++++++++++++
 adoc-mode.el                       |  16 ++-
 test/adoc-mode-asciidoctor-test.el | 128 ++++++++++++++++++
 5 files changed, 452 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 574f718bb1..ab6fd0766c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,13 @@
 
 ## main (unreleased)
 
+### New features
+
+- Add Asciidoctor integration for previewing and exporting documents, 
reachable from the new `adoc-asciidoctor-menu` transient on `C-c C-c` (and the 
AsciiDoc menu). `adoc-preview` renders the current buffer with `asciidoctor` 
and shows the HTML in a side pane - an xwidget WebKit widget when available, 
otherwise `eww`, configurable via `adoc-preview-backend` - and 
`adoc-live-preview-mode` re-renders on every save. The preview feeds the buffer 
to `asciidoctor` through its standard input, s [...]
+
 ### Changes
 
+- The compilation error matcher now also recognises modern `asciidoctor:` 
diagnostics, not just the legacy AsciiDoc.py `asciidoc:` format, so jumping to 
warnings and errors works with current Asciidoctor output.
 - `[source,ocaml]` code blocks now fontify with `neocaml-mode` when it is 
available, falling back to `tuareg-mode` and then `caml-mode`. To support this, 
a value in `adoc-code-lang-modes` may now be either a single major mode or a 
list of candidate modes tried in order (the first defined one wins).
 
 ### Bugs fixed
diff --git a/README.adoc b/README.adoc
index b15d9886ea..883fdac15c 100644
--- a/README.adoc
+++ b/README.adoc
@@ -51,7 +51,8 @@ Here are some of the main features of `adoc-mode`:
 - navigate to anchors (`C-c C-a`) and follow URLs, `include::` macros, and 
xrefs at point (`C-c C-o` / `M-.`)
 - nested `imenu` index with hierarchical heading structure
 - outline folding built on `outline-minor-mode` (enabled out of the box): 
`TAB` cycles the subtree at point, `S-TAB` cycles the whole buffer (overview / 
contents / show all), one-line title style only
-- integration with `flyspell-mode` (skips non-prose regions), comment commands 
(`M-;`), and compilation mode
+- preview and export via Asciidoctor (`C-c C-c`): live HTML preview in an 
xwidget or `eww` side pane, plus export to HTML, DocBook, PDF, and EPUB with 
navigable warnings and errors
+- integration with `flyspell-mode` (skips non-prose regions) and comment 
commands (`M-;`)
 - filling that respects AsciiDoc hard line breaks (a line ending in ` +`) and 
section titles
 
 === Demo
@@ -109,6 +110,45 @@ from the _AsciiDoc_ menu in the menu bar.
 
 This section only describes some not so obvious features.
 
+=== Preview and Export
+
+`adoc-mode` can render and export documents by shelling out to the
+https://asciidoctor.org/[Asciidoctor] command-line tool, so you need
+`asciidoctor` on your `PATH` for these commands to work. PDF and EPUB export
+additionally need the `asciidoctor-pdf` and `asciidoctor-epub3` converters.
+
+Press kbd:[C-c C-c] to open the _Asciidoctor_ transient menu, or use the
+_AsciiDoc → Preview / Export_ menu. From there you can:
+
+- `adoc-preview` - render the current buffer and show the HTML in a side pane.
+- `adoc-live-preview-mode` - a minor mode that re-renders the preview every 
time
+  you save the buffer.
+- `adoc-export-html` / `adoc-export-docbook` / `adoc-export-pdf` /
+  `adoc-export-epub` - export the file next to the source. These run through
+  `compile`, so you can jump to any warnings or errors with kbd:[M-g M-n].
+
+The preview feeds the buffer to Asciidoctor through its standard input, so it
+reflects unsaved edits and resolves relative `include::` and image paths.
+
+The preview pane is chosen by `adoc-preview-backend`. By default
+(`auto`) it uses an embedded WebKit widget when your Emacs was built with
+xwidget support, and falls back to `eww` otherwise. You can force a specific
+backend:
+
+[source,emacs-lisp]
+----
+;; one of: auto (default), xwidget, eww, browser
+(setq adoc-preview-backend 'eww)
+----
+
+Pass extra arguments to every Asciidoctor invocation via
+`adoc-asciidoctor-extra-args`, e.g. to enable section numbers:
+
+[source,emacs-lisp]
+----
+(setq adoc-asciidoctor-extra-args '("-a" "sectnums"))
+----
+
 === Image Preview
 
 If you click kbd:[mouse-3] on an image link like
diff --git a/adoc-asciidoctor.el b/adoc-asciidoctor.el
new file mode 100644
index 0000000000..b8704ff126
--- /dev/null
+++ b/adoc-asciidoctor.el
@@ -0,0 +1,263 @@
+;;; adoc-asciidoctor.el --- Asciidoctor integration for adoc-mode -*- 
lexical-binding: t; -*-
+;;
+;; Copyright 2022-2026 Bozhidar Batsov <[email protected]> and adoc-mode 
contributors
+;;
+;; This file is not part of GNU Emacs.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
+;; Floor, Boston, MA 02110-1301, USA.
+
+;;; Commentary:
+
+;; Preview and export support for `adoc-mode' that shells out to the
+;; `asciidoctor' command-line tool.  AsciiDoc, unlike Markdown, needs the real
+;; processor to render faithfully (attributes, `include::', conditionals,
+;; tables), so we delegate to Asciidoctor rather than approximating in Elisp.
+;;
+;; The entry point is the `adoc-asciidoctor-menu' transient (bound to
+;; `C-c C-c' in `adoc-mode').  From there you can render a preview in an
+;; xwidget (falling back to `eww') or export to HTML, DocBook, PDF and EPUB.
+;; Export runs through `compile' so Asciidoctor's warnings and errors are
+;; navigable.
+
+;;; Code:
+
+(require 'compile)
+(require 'subr-x)
+(require 'transient)
+
+(declare-function xwidget-webkit-browse-url "xwidget" (url &optional 
new-session))
+(declare-function eww-open-file "eww" (file &optional new-buffer))
+
+;;; Customization
+
+(defgroup adoc-asciidoctor nil
+  "Asciidoctor integration for `adoc-mode'."
+  :group 'adoc
+  :prefix "adoc-")
+
+(defcustom adoc-asciidoctor-command "asciidoctor"
+  "Name of, or path to, the Asciidoctor executable."
+  :type 'string
+  :group 'adoc-asciidoctor)
+
+(defcustom adoc-asciidoctor-extra-args nil
+  "Extra command-line arguments passed to every Asciidoctor invocation.
+Each element is a separate argument string, for example
+\"-a\" followed by \"sectnums\"."
+  :type '(repeat string)
+  :group 'adoc-asciidoctor)
+
+(defcustom adoc-preview-backend 'auto
+  "How `adoc-preview' displays the rendered HTML.
+The value is one of the following symbols:
+
+`auto'     Use an xwidget when one is available, otherwise `eww'.
+`xwidget'  Render in an embedded WebKit widget (needs xwidget support).
+`eww'      Render in Emacs' built-in `eww' browser.
+`browser'  Open in the external browser via `browse-url'."
+  :type '(choice (const :tag "Auto-detect" auto)
+                 (const :tag "Embedded WebKit (xwidget)" xwidget)
+                 (const :tag "Emacs Web Wowser (eww)" eww)
+                 (const :tag "External browser" browser))
+  :group 'adoc-asciidoctor)
+
+;;; Running Asciidoctor
+
+(defun adoc--asciidoctor-ensure ()
+  "Signal a `user-error' unless the Asciidoctor executable is available."
+  (unless (executable-find adoc-asciidoctor-command)
+    (user-error "Cannot find the Asciidoctor executable %S; \
+customize `adoc-asciidoctor-command'" adoc-asciidoctor-command)))
+
+(defun adoc--asciidoctor-source-file ()
+  "Return the file the current buffer visits, or signal a `user-error'."
+  (or buffer-file-name
+      (user-error "Current buffer is not visiting a file")))
+
+(defvar-local adoc--preview-file nil
+  "Absolute path to the current buffer's temporary preview HTML file.")
+
+(defun adoc--asciidoctor-render-preview ()
+  "Render the current buffer to its preview HTML file.
+Return the file on success, or nil on failure (so callers can avoid
+displaying a blank or stale page).  The buffer contents are piped
+through Asciidoctor's standard input, so unsaved edits are included and
+no save is required.  The base directory and the output file both live
+in `default-directory', which keeps relative `include::' and image paths
+resolving correctly when the generated HTML is loaded over `file://'.
+
+Asciidoctor exits 0 even on a recoverable ERROR when reading from
+standard input, so any diagnostics on its error output are reported
+regardless of the exit status."
+  (adoc--asciidoctor-ensure)
+  (let ((base (expand-file-name default-directory))
+        (errfile (make-temp-file "adoc-asciidoctor-err")))
+    (unless (and adoc--preview-file (file-exists-p adoc--preview-file))
+      (setq adoc--preview-file
+            (make-temp-file (expand-file-name "adoc-preview-" base) nil 
".html")))
+    (unwind-protect
+        (let ((status (apply #'call-process-region
+                             (point-min) (point-max)
+                             adoc-asciidoctor-command nil
+                             (list nil errfile) nil
+                             (append adoc-asciidoctor-extra-args
+                                     (list "-B" base
+                                           "-b" "html5"
+                                           "-o" adoc--preview-file
+                                           "-"))))
+              (errors (with-temp-buffer
+                        (insert-file-contents errfile)
+                        (string-trim (buffer-string)))))
+          (unless (string-empty-p errors)
+            (message "Asciidoctor: %s" errors))
+          ;; Only hand back the file when the run actually succeeded; a
+          ;; non-zero exit may leave the output empty or untouched.
+          (and (integerp status) (zerop status) adoc--preview-file))
+      (delete-file errfile))))
+
+(defun adoc--asciidoctor-compile (backend-args)
+  "Run Asciidoctor on the current file with BACKEND-ARGS through `compile'.
+The buffer is saved first when modified so the on-disk file is current.
+Asciidoctor is invoked with the file's base name from its own directory,
+so the locations it reports resolve against `default-directory' in the
+compilation buffer."
+  (adoc--asciidoctor-ensure)
+  (let ((file (adoc--asciidoctor-source-file)))
+    (when (buffer-modified-p)
+      (save-buffer))
+    (let* ((default-directory (file-name-directory file))
+           (command (mapconcat
+                     #'shell-quote-argument
+                     (append (list adoc-asciidoctor-command)
+                             adoc-asciidoctor-extra-args
+                             backend-args
+                             (list (file-name-nondirectory file)))
+                     " ")))
+      (compilation-start
+       command nil
+       (lambda (_mode)
+         (format "*asciidoctor: %s*" (file-name-nondirectory file)))))))
+
+;;; Export commands
+
+;;;###autoload
+(defun adoc-export-html ()
+  "Export the current AsciiDoc buffer to HTML5."
+  (interactive)
+  (adoc--asciidoctor-compile '("-b" "html5")))
+
+;;;###autoload
+(defun adoc-export-docbook ()
+  "Export the current AsciiDoc buffer to DocBook 5."
+  (interactive)
+  (adoc--asciidoctor-compile '("-b" "docbook5")))
+
+;;;###autoload
+(defun adoc-export-pdf ()
+  "Export the current AsciiDoc buffer to PDF.
+Requires the `asciidoctor-pdf' converter to be installed."
+  (interactive)
+  (adoc--asciidoctor-compile '("-r" "asciidoctor-pdf" "-b" "pdf")))
+
+;;;###autoload
+(defun adoc-export-epub ()
+  "Export the current AsciiDoc buffer to EPUB3.
+Requires the `asciidoctor-epub3' converter to be installed."
+  (interactive)
+  (adoc--asciidoctor-compile '("-r" "asciidoctor-epub3" "-b" "epub3")))
+
+;;; Preview
+
+(defun adoc--preview-resolve-backend ()
+  "Resolve `adoc-preview-backend' to a concrete backend symbol."
+  (if (eq adoc-preview-backend 'auto)
+      (if (and (display-graphic-p)
+               (fboundp 'xwidget-webkit-browse-url))
+          'xwidget
+        'eww)
+    adoc-preview-backend))
+
+(defun adoc--preview-display (file)
+  "Display preview FILE according to the resolved backend.
+Focus stays in the source buffer so the viewer acts as a side pane."
+  (let ((url (concat "file://" file))
+        (backend (adoc--preview-resolve-backend)))
+    (pcase backend
+      ('browser (browse-url url))
+      ('xwidget
+       (save-selected-window
+         (xwidget-webkit-browse-url url))
+       (when-let* ((buf (get-buffer "*xwidget-webkit*")))
+         (display-buffer-in-side-window
+          buf '((side . right) (window-width . 0.5)))))
+      ('eww
+       (require 'eww)
+       (save-window-excursion
+         (eww-open-file file))
+       (when-let* ((buf (get-buffer "*eww*")))
+         (display-buffer-in-side-window
+          buf '((side . right) (window-width . 0.5)))))
+      (_ (error "Unknown `adoc-preview-backend': %S" backend)))))
+
+(defun adoc--preview-update ()
+  "Re-render the current buffer and (re)display its preview.
+Does nothing visible when the render fails, leaving any previous
+preview in place rather than showing a blank page."
+  (when-let* ((file (adoc--asciidoctor-render-preview)))
+    (adoc--preview-display file)))
+
+(defun adoc--preview-cleanup ()
+  "Delete the current buffer's temporary preview file, if any."
+  (when (and adoc--preview-file (file-exists-p adoc--preview-file))
+    (ignore-errors (delete-file adoc--preview-file)))
+  (setq adoc--preview-file nil))
+
+;;;###autoload
+(defun adoc-preview ()
+  "Render the current AsciiDoc buffer and show it in a preview pane."
+  (interactive)
+  (adoc--preview-update))
+
+;;;###autoload
+(define-minor-mode adoc-live-preview-mode
+  "Re-render the AsciiDoc preview whenever the buffer is saved."
+  :lighter " AdocPreview"
+  (if adoc-live-preview-mode
+      (progn
+        (add-hook 'after-save-hook #'adoc--preview-update nil t)
+        (add-hook 'kill-buffer-hook #'adoc--preview-cleanup nil t)
+        (adoc--preview-update))
+    (remove-hook 'after-save-hook #'adoc--preview-update t)
+    (remove-hook 'kill-buffer-hook #'adoc--preview-cleanup t)
+    (adoc--preview-cleanup)))
+
+;;; Transient menu
+
+;;;###autoload (autoload 'adoc-asciidoctor-menu "adoc-asciidoctor" nil t)
+(transient-define-prefix adoc-asciidoctor-menu ()
+  "Preview and export the current AsciiDoc document with Asciidoctor."
+  ["Preview"
+   ("p" "Preview" adoc-preview)
+   ("l" "Live preview mode" adoc-live-preview-mode)]
+  ["Export"
+   ("h" "HTML5" adoc-export-html)
+   ("d" "DocBook 5" adoc-export-docbook)
+   ("f" "PDF" adoc-export-pdf)
+   ("e" "EPUB3" adoc-export-epub)])
+
+(provide 'adoc-asciidoctor)
+
+;;; adoc-asciidoctor.el ends here
diff --git a/adoc-mode.el b/adoc-mode.el
index 3a48c92577..6e49a25ea2 100644
--- a/adoc-mode.el
+++ b/adoc-mode.el
@@ -53,6 +53,7 @@
 (require 'subr-x)
 (require 'adoc-mode-image)
 (require 'adoc-mode-tempo)
+(require 'adoc-asciidoctor)
 
 (defconst adoc-mode-version "0.9.0"
   "adoc mode version number.")
@@ -4061,6 +4062,7 @@ ITEMS is a list of (name pos . level)."
     (define-key map "\C-c\C-a" 'adoc-goto-ref-label)
     (define-key map "\C-c\C-o" 'adoc-follow-thing-at-point)
     (define-key map (kbd "M-.") 'adoc-follow-thing-at-point)
+    (define-key map "\C-c\C-c" 'adoc-asciidoctor-menu)
     (easy-menu-define adoc-mode-menu map "Menu for adoc mode"
       `("AsciiDoc"
         ["Next heading" adoc-next-visible-heading]
@@ -4092,6 +4094,16 @@ ITEMS is a list of (name pos . level)."
         ["Follow thing at point" adoc-follow-thing-at-point]
         ["Goto anchor" adoc-goto-ref-label]
         "---"
+        ("Preview / Export"
+         ["Preview" adoc-preview]
+         ["Live preview mode" adoc-live-preview-mode
+          :style toggle :selected adoc-live-preview-mode]
+         "---"
+         ["Export to HTML5" adoc-export-html]
+         ["Export to DocBook 5" adoc-export-docbook]
+         ["Export to PDF" adoc-export-pdf]
+         ["Export to EPUB3" adoc-export-epub])
+        "---"
         ;; names|wording / rough order/ help texts are from asciidoc manual
         ("Templates / cheat sheet"
          ("Text formatting - constrained quotes"
@@ -4313,9 +4325,11 @@ Turning on Adoc mode runs the normal hook 
`adoc-mode-hook'."
   (setq-local imenu-create-index-function adoc-imenu-create-index-function)
 
   ;; compilation
+  ;; Matches both the modern Asciidoctor (`asciidoctor: ...') and the legacy
+  ;; Python AsciiDoc (`asciidoc: ...') diagnostic formats.
   (add-to-list 'compilation-error-regexp-alist-alist
                '(asciidoc
-                 "^asciidoc: +\\(?:ERROR\\|\\(WARNING\\|DEPRECATED\\)\\): 
+\\([^:\n]*\\): line +\\([0-9]+\\)"
+                 "^asciidoc\\(?:tor\\)?: 
+\\(?:ERROR\\|\\(WARNING\\|DEPRECATED\\)\\): +\\([^:\n]*\\): line +\\([0-9]+\\)"
                  2 3 nil (1 . nil)))
   (setq-local compilation-error-regexp-alist
               (cons 'asciidoc compilation-error-regexp-alist))
diff --git a/test/adoc-mode-asciidoctor-test.el 
b/test/adoc-mode-asciidoctor-test.el
new file mode 100644
index 0000000000..01dcece6f7
--- /dev/null
+++ b/test/adoc-mode-asciidoctor-test.el
@@ -0,0 +1,128 @@
+;;; adoc-mode-asciidoctor-test.el --- Asciidoctor integration tests -*- 
lexical-binding: t; -*-
+
+;; Copyright © 2026 Bozhidar Batsov
+
+;;; Commentary:
+
+;; Buttercup tests for the Asciidoctor integration layer: the executable
+;; guard, export command-line construction, preview backend resolution, and
+;; the compilation error regexp that makes Asciidoctor diagnostics navigable.
+;; These tests mock out the actual shelling out, so they need no `asciidoctor'
+;; on PATH.
+
+;;; Code:
+
+(require 'adoc-mode-test-helpers)
+(require 'adoc-asciidoctor)
+(require 'cl-lib)
+
+(describe "adoc--asciidoctor-ensure"
+  (it "throws a user-error when the executable is missing"
+    (spy-on 'executable-find :and-return-value nil)
+    (expect (adoc--asciidoctor-ensure) :to-throw 'user-error))
+
+  (it "returns normally when the executable is found"
+    (spy-on 'executable-find :and-return-value "/usr/bin/asciidoctor")
+    (expect (adoc--asciidoctor-ensure) :not :to-throw)))
+
+(describe "adoc--asciidoctor-source-file"
+  (it "throws a user-error for a non-file buffer"
+    (with-temp-buffer
+      (expect (adoc--asciidoctor-source-file) :to-throw 'user-error))))
+
+(describe "adoc-export commands"
+  (before-each
+    (spy-on 'executable-find :and-return-value "/usr/bin/asciidoctor")
+    (spy-on 'compilation-start))
+
+  (cl-flet ((command-for (export-fn)
+              ;; Visit a real temp file so `adoc--asciidoctor-compile' has a
+              ;; file to operate on, run the export, and return the command
+              ;; string handed to `compilation-start'.
+              (let ((file (make-temp-file "adoc-export-" nil ".adoc")))
+                (unwind-protect
+                    (with-current-buffer (find-file-noselect file)
+                      (funcall export-fn)
+                      (spy-calls-most-recent 'compilation-start))
+                  (when (get-file-buffer file)
+                    (kill-buffer (get-file-buffer file)))
+                  (delete-file file)))))
+
+    (it "builds an HTML5 command"
+      (let ((args (spy-context-args (command-for #'adoc-export-html))))
+        (expect (car args) :to-match "asciidoctor")
+        (expect (car args) :to-match "-b html5")))
+
+    (it "builds a DocBook command"
+      (let ((args (spy-context-args (command-for #'adoc-export-docbook))))
+        (expect (car args) :to-match "-b docbook5")))
+
+    (it "builds a PDF command requiring asciidoctor-pdf"
+      (let ((args (spy-context-args (command-for #'adoc-export-pdf))))
+        (expect (car args) :to-match "-r asciidoctor-pdf")
+        (expect (car args) :to-match "-b pdf")))
+
+    (it "builds an EPUB3 command requiring asciidoctor-epub3"
+      (let ((args (spy-context-args (command-for #'adoc-export-epub))))
+        (expect (car args) :to-match "-r asciidoctor-epub3")
+        (expect (car args) :to-match "-b epub3")))))
+
+(describe "adoc--preview-resolve-backend"
+  (it "passes explicit backends through unchanged"
+    (dolist (backend '(xwidget eww browser))
+      (let ((adoc-preview-backend backend))
+        (expect (adoc--preview-resolve-backend) :to-be backend))))
+
+  (it "auto resolves to eww on a terminal"
+    (let ((adoc-preview-backend 'auto))
+      (spy-on 'display-graphic-p :and-return-value nil)
+      (expect (adoc--preview-resolve-backend) :to-be 'eww)))
+
+  (it "auto resolves to xwidget when graphical with xwidget support"
+    (let ((adoc-preview-backend 'auto))
+      (spy-on 'display-graphic-p :and-return-value t)
+      (cl-letf (((symbol-function 'xwidget-webkit-browse-url) #'ignore))
+        (expect (adoc--preview-resolve-backend) :to-be 'xwidget)))))
+
+(describe "adoc--preview-update"
+  (it "displays the rendered file on success"
+    (spy-on 'adoc--asciidoctor-render-preview :and-return-value "/tmp/x.html")
+    (spy-on 'adoc--preview-display)
+    (adoc--preview-update)
+    (expect 'adoc--preview-display :to-have-been-called-with "/tmp/x.html"))
+
+  (it "does not display anything when the render fails"
+    (spy-on 'adoc--asciidoctor-render-preview :and-return-value nil)
+    (spy-on 'adoc--preview-display)
+    (adoc--preview-update)
+    (expect 'adoc--preview-display :not :to-have-been-called)))
+
+(describe "the asciidoc compilation regexp"
+  ;; The entry is registered in `compilation-error-regexp-alist-alist' by
+  ;; `adoc-mode', so spin up an adoc buffer to populate it.
+  (let (re)
+    (before-all
+      (with-adoc-buffer "= Title\n"
+        (setq re (car (alist-get 'asciidoc 
compilation-error-regexp-alist-alist)))))
+
+    (it "matches modern Asciidoctor errors"
+      (let ((line "asciidoctor: ERROR: doc.adoc: line 5: include file not 
found"))
+        (expect (string-match re line) :to-be 0)
+        (expect (match-string 2 line) :to-equal "doc.adoc")
+        (expect (match-string 3 line) :to-equal "5")))
+
+    (it "matches modern Asciidoctor warnings"
+      (let ((line "asciidoctor: WARNING: doc.adoc: line 1: unterminated table 
block"))
+        (expect (string-match re line) :to-be 0)
+        (expect (match-string 2 line) :to-equal "doc.adoc")
+        (expect (match-string 3 line) :to-equal "1")))
+
+    (it "still matches the legacy Python asciidoc format"
+      (let ((line "asciidoc: WARNING: doc.txt: line 9: missing"))
+        (expect (string-match re line) :to-be 0)
+        (expect (match-string 2 line) :to-equal "doc.txt")
+        (expect (match-string 3 line) :to-equal "9")))))
+
+(provide 'adoc-mode-asciidoctor-test)
+
+;;; adoc-mode-asciidoctor-test.el ends here

Reply via email to