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

    Recognise the block ID shorthand [#id]
    
    Modern AsciiDoc assigns a block ID with the shorthand [#id] (optionally
    [#id.role%opt] or [style#id]) rather than only the legacy [[id]] anchor.
    
    Add a block-id-shorthand anchor type so adoc-goto-ref-label and M-. follow
    xrefs to [#id] (and [style#id]) blocks, and a font-lock keyword that
    highlights the id in a pure [#id...] line with adoc-anchor-face.
---
 CHANGELOG.md             |  1 +
 adoc-mode.el             | 19 ++++++++++++++++++-
 doc/spec-compliance.adoc | 27 ++++++++++++++++-----------
 test/adoc-mode-test.el   | 24 ++++++++++++++++++++++++
 4 files changed, 59 insertions(+), 12 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a8a12ae80..03dcc0ec18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
 
 ### New features
 
+- Recognise the modern block ID shorthand `[#id]`. The id in a `[#id]` / 
`[#id.role%opt]` block-attribute line is now highlighted like an anchor 
(`adoc-anchor-face`), and cross-reference following (`adoc-goto-ref-label`, 
`M-.`) jumps to `[#id]` block IDs - including the `[style#id]` form, e.g. 
`[source#id]` - not just `[[id]]` anchors.
 - Highlight checklist items. An unordered list item whose text begins with `[ 
]` (unchecked), `[x]`/`[X]`, or `[*]` (checked) now fontifies the checkbox with 
the new `adoc-checkbox-face` (inherits `font-lock-constant-face`).
 - Honour backslash escapes in inline formatting: a backslash before a 
formatting delimiter (e.g. `\*not bold*`, `\**nor this**`, `` \`nor code` ``) 
now de-emphasises the backslash and leaves the escaped span as literal text 
instead of fontifying it as markup. Previously the unconstrained forms still 
leaked an inner constrained match (`\**x**` highlighted `x`).
 - `fill-paragraph` (and auto-fill) now preserve AsciiDoc hard line breaks: a 
line ending in a space and a `+` is no longer merged with the following line. 
Filling still joins ordinary soft-wrapped lines and indents list-item 
continuations.
diff --git a/adoc-mode.el b/adoc-mode.el
index f1b6427bc3..49b34110e2 100644
--- a/adoc-mode.el
+++ b/adoc-mode.el
@@ -1366,10 +1366,19 @@ this id. If ID is nil, the regexp matches any anchor."
    ((eq type 'inline-general)
     (adoc-re-inline-macro "anchor" id))
 
+   ((eq type 'block-id-shorthand)
+    ;; Modern block ID shorthand on a block attribute line, e.g. [#id],
+    ;; [#id.role%opt] or [style#id].  Group 1 is the id; anything before the
+    ;; `#' is a positional style and anything after is a role/option/attr.
+    (concat "^\\[\\(?:[^][#\n]*\\)#"
+            "\\(" (if id (regexp-quote id) (adoc-re-id)) "\\)"
+            "\\(?:[.%,][^]\n]*\\)?"
+            "\\][ \t]*$"))
+
    ((null type)
     (mapconcat
      (lambda (x) (adoc-re-anchor x id))
-     '(block-id inline-special biblio inline-general)
+     '(block-id block-id-shorthand inline-special biblio inline-general)
      "\\|"))
 
    (t
@@ -2598,6 +2607,14 @@ for multiline constructs to be matched."
          '(0 '(face adoc-meta-face adoc-reserved block-del))
          '(1 '(face adoc-anchor-face adoc-flyspell-ignore t) t) ;; BLOCK-ID
          '(2 'adoc-secondary-text-face t t)) ;; SECONDARY-TEXT
+   ;; block id shorthand on its own line: [#id], [#id.role], [#id.role%opt]
+   (list `(lambda (end)
+            (adoc-kwf-std
+             end
+             "^\\(\\[#\\)\\([-a-zA-Z0-9_]+\\)\\(?:[.%][^]\n]*\\)?\\(\\]\\)[ 
\t]*$"
+             '(0)))
+         '(0 '(face adoc-meta-face adoc-reserved block-del))
+         '(2 '(face adoc-anchor-face adoc-flyspell-ignore t) t)) ;; BLOCK-ID
 
    ;; --- general attribute list block element
    ;; ^\[(?P<attrlist>.*)\]$
diff --git a/doc/spec-compliance.adoc b/doc/spec-compliance.adoc
index f9b24177d8..ae1e4357f4 100644
--- a/doc/spec-compliance.adoc
+++ b/doc/spec-compliance.adoc
@@ -58,8 +58,10 @@ Findings are graded:
 | Medium
 
 | blocks / sections / attributes
-| The modern block-attribute *ID shorthand* `[#id]` (and `[#id.role]`)
-  is not recognised; only the legacy block anchor `[[id]]` is.
+| [.line-through]#The modern block-attribute *ID shorthand* `[#id]` is not
+  recognised.# *FIXED* - `[#id]` is highlighted as an anchor and is
+  navigable; the `.role`/`%opt` shorthands inside an arbitrary attribute
+  list are still not individually faced.
 | Medium
 
 | text
@@ -157,8 +159,8 @@ Findings are graded:
 | -
 
 | Block ID shorthand `[#id]` / `[#id.role]`
-| Not recognised (only `[[id]]`); this is the preferred modern form
-| Medium
+| *Fixed* - highlighted as an anchor and navigable (see `block-id-shorthand`)
+| -
 
 | Hard line breaks (line ending in ` +`)
 | Preserved when filling; `[%hardbreaks]` option not specially handled
@@ -230,8 +232,8 @@ Findings are graded:
 | -
 
 | Custom section ID via `[#id]` shorthand
-| Not recognised (see blocks / attributes)
-| Medium
+| Fixed (see blocks / attributes)
+| -
 
 | Discrete heading, special sections (appendix, bibliography, glossary)
 | Styles are generic attribute lines; titles highlight normally
@@ -315,8 +317,9 @@ Findings are graded:
 | -
 
 | ID/role/option shorthand `[#id.role%opt]`
-| Partial - the attribute list highlights, but `#id` / `.role` / `%opt`
-  shorthands inside it are not individually recognised
+| Partial - a pure `[#id]` line highlights the id as an anchor and is
+  navigable; the `.role` / `%opt` shorthands inside an arbitrary attribute
+  list are still not individually faced
 | Medium
 
 | Counters `{counter:name}`, character-replacement refs
@@ -377,9 +380,11 @@ implements.
 . [x] *Recognise checklist items* (`* [ ]`, `* [x]`, `* [*]`) with a
   dedicated face for the checkbox. Done - `adoc-kw-checkbox` /
   `adoc-checkbox-face`.
-. [ ] *Recognise the block-attribute ID/role/option shorthand* `[#id]`,
-  `[#id.role]`, `[%opt]` on block attribute lines, and treat `[#id]` as a
-  block anchor for `adoc-goto-ref-label` / xref following.
+. [x] *Recognise the block-attribute ID shorthand* `[#id]`. Done -
+  `[#id]` / `[#id.role%opt]` lines highlight the id as an anchor
+  (`block-id-shorthand`) and `adoc-goto-ref-label` follows `[#id]` (and
+  `[style#id]`) targets. Faceting `.role` / `%opt` inside arbitrary
+  attribute lists is left as a smaller follow-up.
 . [ ] *Add modern curved-quote highlighting* `+"`text`"+` and ``'`text`'``.
 . [ ] *Drop or de-emphasise the deprecated `` `text' `` / ``\`\`text''``
   templates* in the menu (and the `+...+` / `++...++` "Monospaced"
diff --git a/test/adoc-mode-test.el b/test/adoc-mode-test.el
index 837040f27f..0d8e8c9e46 100644
--- a/test/adoc-mode-test.el
+++ b/test/adoc-mode-test.el
@@ -1383,6 +1383,30 @@ on top of the `<mark>' default)."
         (should (equal (line-number-at-pos) 3)))
     (kill-buffer "adoc-test")))
 
+(ert-deftest adoctest-test-block-id-shorthand-faces ()
+  ;; the id in a [#id] block-attribute line is highlighted like an anchor
+  (adoctest-faces "block-id-shorthand"
+                  "[#" 'adoc-meta-face "myid" 'adoc-anchor-face "]" 
'adoc-meta-face)
+  (adoctest-faces "block-id-shorthand-role"
+                  "[#" 'adoc-meta-face "myid" 'adoc-anchor-face ".role%open]" 
'adoc-meta-face))
+
+(ert-deftest adoctest-test-goto-block-id-shorthand ()
+  (with-temp-buffer
+    (adoc-mode)
+    (insert "[#sect2]\n"          ;1
+            "== Two\n"            ;2
+            "\n"                  ;3
+            "[source#sid]\n"      ;4
+            "----\n"              ;5
+            "code\n"              ;6
+            "----\n")             ;7
+    ;; the pure shorthand form
+    (adoc-goto-ref-label "sect2")
+    (should (equal (line-number-at-pos) 1))
+    ;; the style+id form is navigable too
+    (adoc-goto-ref-label "sid")
+    (should (equal (line-number-at-pos) 4))))
+
 (defun adoctest-template (template expected)
   "Todo document adoctest-template TEMPLATE EXPECTED."
   (let ((buf-name (concat "adoctest-" (symbol-name template))))

Reply via email to