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

    Prefer neocaml-mode for OCaml code blocks, with fallbacks
    
    Map `ocaml' to neocaml-mode, then tuareg-mode, then caml-mode, so source
    blocks use the modern tree-sitter mode when it is available and degrade
    gracefully otherwise. adoc-code-lang-modes values may now be a single mode
    or a list of candidate modes; adoc-get-lang-mode returns the first that is
    defined.
---
 CHANGELOG.md                     |  4 ++++
 adoc-mode.el                     | 33 +++++++++++++++++++--------------
 test/adoc-mode-font-lock-test.el | 19 +++++++++++++++++++
 3 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 259e2de1ac..eff47a9ea9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
 
 ## main (unreleased)
 
+### Changes
+
+- `[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).
+
 ## 0.9.0 (2026-06-02)
 
 ### New features
diff --git a/adoc-mode.el b/adoc-mode.el
index c5c48ae62c..2d1209e032 100644
--- a/adoc-mode.el
+++ b/adoc-mode.el
@@ -274,22 +274,24 @@ are fontified natively regardless of their size."
     ("ditaa" . artist-mode)
     ("dot" . fundamental-mode)
     ("elisp" . emacs-lisp-mode)
-    ("ocaml" . tuareg-mode)
+    ("ocaml" . (neocaml-mode tuareg-mode caml-mode))
     ("screen" . shell-script-mode)
     ("shell" . sh-mode)
     ("sqlite" . sql-mode)
     )
   "Alist mapping languages to their major mode.
-The key is the language name, the value is the major mode.  For
-many languages this is simple, but for language where this is not
-the case, this variable provides a way to simplify things on the
-user side.  For example, there is no ocaml-mode in Emacs, but the
-mode to use is `tuareg-mode'."
+The key is the language name.  The value is either a single major
+mode or a list of candidate modes tried in order, the first
+defined one being used.  This makes it possible to map a language
+to a preferred mode with fallbacks: for example there is no
+ocaml-mode in Emacs, so `ocaml' maps to `neocaml-mode', then
+`tuareg-mode', then `caml-mode'."
   :group 'adoc
   :type '(repeat
           (cons
            (string "Language name")
-           (symbol "Major mode")))
+           (choice (symbol "Major mode")
+                   (repeat (symbol "Major mode")))))
   :package-version '(adoc-mode . "0.8.0"))
 
 (defcustom adoc-fontify-code-block-default-mode 'prog-mode
@@ -2208,13 +2210,16 @@ TEXTPROPS is an additional plist with textproperties."
 
 (defun adoc-get-lang-mode (lang)
   "Return major mode that should be used for LANG.
-LANG is a string, and the returned major mode is a symbol."
-  (cl-find-if
-   #'fboundp
-   (list (cdr (assoc lang adoc-code-lang-modes))
-         (cdr (assoc (downcase lang) adoc-code-lang-modes))
-         (intern (concat lang "-mode"))
-         (intern (concat (downcase lang) "-mode")))))
+LANG is a string, and the returned major mode is a symbol.  A
+value in `adoc-code-lang-modes' may be a single mode or a list of
+candidate modes; the first one that is defined is used."
+  (cl-flet ((candidates (value) (if (listp value) value (list value))))
+    (cl-find-if
+     #'fboundp
+     (append (candidates (cdr (assoc lang adoc-code-lang-modes)))
+             (candidates (cdr (assoc (downcase lang) adoc-code-lang-modes)))
+             (list (intern (concat lang "-mode"))
+                   (intern (concat (downcase lang) "-mode")))))))
 
 ;; Based on `org-src-font-lock-fontify-block' from org-src.el.
 (defun adoc-fontify-code-block-natively (lang start-block end-block start-src 
end-src)
diff --git a/test/adoc-mode-font-lock-test.el b/test/adoc-mode-font-lock-test.el
index 77c801e68e..b4b6a6e922 100644
--- a/test/adoc-mode-font-lock-test.el
+++ b/test/adoc-mode-font-lock-test.el
@@ -413,6 +413,25 @@
         (expect (adoc-test-face-at-range (match-beginning 0) (1- (match-end 
0)))
                 :to-equal '(adoc-verbatim-face adoc-code-face)))))
 
+  ;; ---- Language -> major mode resolution -----------------------------
+
+  (describe "language mode resolution"
+    (it "uses a single mapped mode"
+      (let ((adoc-code-lang-modes '(("demo" . emacs-lisp-mode))))
+        (expect (adoc-get-lang-mode "demo") :to-equal 'emacs-lisp-mode)))
+
+    (it "tries a list of candidate modes in order, first defined wins"
+      (let ((adoc-code-lang-modes
+             '(("demo" . (adoc-no-such-mode-1 adoc-no-such-mode-2 
emacs-lisp-mode)))))
+        (expect (adoc-get-lang-mode "demo") :to-equal 'emacs-lisp-mode)))
+
+    (it "falls back to <lang>-mode when there is no mapping"
+      (expect (adoc-get-lang-mode "emacs-lisp") :to-equal 'emacs-lisp-mode))
+
+    (it "returns nil when no candidate mode is available"
+      (let ((adoc-code-lang-modes '(("demo" . (adoc-no-such-mode-1 
adoc-no-such-mode-2)))))
+        (expect (adoc-get-lang-mode "demo") :to-be nil))))
+
   ;; ---- Character replacements (display overlays) ---------------------
 
   (describe "character replacements"

Reply via email to