summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Smedegaard <dr@jones.dk>2025-03-16 19:28:29 +0100
committerJonas Smedegaard <dr@jones.dk>2025-03-16 19:28:29 +0100
commit0664e64525ebd2f8a78f9040f249eb69a9fb038c (patch)
tree09780c75f974ea0003f3079c50e6f2e07ada812b
parentc8ef87f9c167e6eb83dee73a76d806e9b3c59f6b (diff)
add draft filter plugin
-rw-r--r--_extensions/ruc-play/semantic-markdown/_extension.yaml6
-rw-r--r--_extensions/ruc-play/semantic-markdown/semantic-markdown.lua129
-rw-r--r--example/example.qmd20
3 files changed, 155 insertions, 0 deletions
diff --git a/_extensions/ruc-play/semantic-markdown/_extension.yaml b/_extensions/ruc-play/semantic-markdown/_extension.yaml
new file mode 100644
index 0000000..76b9a7a
--- /dev/null
+++ b/_extensions/ruc-play/semantic-markdown/_extension.yaml
@@ -0,0 +1,6 @@
+name: semantic-markdown
+author: Jonas Smedegaard
+version: 0.0.1
+contributes:
+ filters:
+ - semantic-markdown.lua
diff --git a/_extensions/ruc-play/semantic-markdown/semantic-markdown.lua b/_extensions/ruc-play/semantic-markdown/semantic-markdown.lua
new file mode 100644
index 0000000..f17f309
--- /dev/null
+++ b/_extensions/ruc-play/semantic-markdown/semantic-markdown.lua
@@ -0,0 +1,129 @@
+--- semantic-markdown - Pandoc plugin to process semantic hints
+---
+--- SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
+--- SPDX-License-Identifier: GPL-3.0-or-later
+---
+--- simple example
+---
+--- ```
+--- "A [map]{foaf:depiction} is not the territory"
+--- | || |
+--- | |brace_open brace_close
+--- | bracket_close
+--- bracket_open
+---
+--- TODO: complex example with nesting and mixed-use enclosure
+---
+--- ["[Ceci]{foaf:depiction} n'est pas une pipe"{lang=fr dc:Text}
+--- | | || |
+--- | | |brace_open brace_close
+--- | | bracket_close
+--- | bracket_open
+--- ```
+---
+--- * v0.0.1
+--- * initial release
+---
+--- @version 0.0.1
+--- @see <https://source.jones.dk/semantic-markdown/about/>
+--- @see <https://moodle.ruc.dk/course/view.php?id=23505>
+
+-- TODO: maybe use topdown traversal
+-- * order of declaring annotations might matter (but should not)
+-- * might enable simpler functions and/or faster processing
+-- @see <https://pandoc.org/lua-filters.html#topdown-traversal>
+
+-- ensure stable character classes independent of system locale
+-- @see <https://pandoc.org/lua-filters.html#common-pitfalls>
+os.setlocale 'C'
+
+-- TODO: support Unicode
+-- @see <https://www.lua.org/manual/5.4/manual.html#6.5>
+--- qnameLong - RDF/turtle QName with prefix and name as set of chars
+--- @see <https://www.w3.org/TeamSubmission/turtle/#name>
+local _nameStartChar = "A-Z_a-z"
+local _nameChar = _nameStartChar.."-0-9"
+local _name = "[".._nameStartChar.."][".._nameChar.."]*"
+local _prefixName = "[".._nameStartChar.."_-][".._nameChar.."]*"
+local qnameLong = _prefixName..":".._name
+
+--- qnamePrefixed - RDF/turtle QName with only prefix as set of chars
+local qnamePrefixed = _prefixName..":"
+
+--- qnameLocal - RDF/turtle QName with only name as set of chars
+local qnameLocal = ":".._name
+
+--- qnameDefault - RDF/turtle QName without prefix or name as char
+local qnameDefault = ":"
+
+-- TODO: qname - RDF/turtle QName as `LPeg.re` regex object
+-- TODO: test and replace above qname* patterns
+-- @see <https://pandoc.org/lua-filters.html#global-variables>
+--local qname_re = re.compile("(".._prefixName..")?:(".._name..")?")
+
+-- TODO: process Blocks (vocabulary blocks first)
+
+--- Extract and strip semantic annotations from inlines
+---
+--- This function is a Pandoc hook executed for each Inlines object
+--- when iterating through its Abstract Syntax Tree (AST) of a document.
+---
+--- @param inlines Markdown with semantic annotations as Inlines
+--- @returns Markdown stripped of semantic annotations as Inlines
+--- @see <https://pandoc.org/lua-filters.html#type-inline>
+function Inlines (inlines)
+
+ -- positions of enclosure markers
+ local bracket_open, bracket_close, brace_open, brace_close
+
+ -- maintain states across inlines
+ local bracketed, braced, has_hints
+
+ local new_inlines = {}
+
+ for i, el in ipairs(inlines) do
+
+ -- only string inlines can alter state
+ if el.t ~= 'Str' then
+ table.insert(new_inlines, el)
+ goto continue
+ end
+
+ -- unenclosed
+ if not (bracketed or braced) then
+ _, bracket_open = string.find(el.text, "%[")
+ if bracket_open then
+ bracketed = true
+ end
+ end
+
+ -- enters a bracket enclosure
+ -- TODO: maybe support nested bracket enclosure
+ if bracketed and not braced then
+ _, bracket_close, s = string.find(el.text, "^([^%[%]}]*)%]{",
+ bracket_open)
+ if bracket_close then
+ braced = true
+ table.insert(new_inlines, pandoc.Str(s))
+ end
+ end
+
+ -- (ignore space-delimited enclosures: not in spec for inlines)
+
+ -- completes a brace enclosure
+ -- TODO: support mixed-use enclosure (non-qname enclosure content)
+ -- TODO: cover qnamePrefix and qnameLocal and qnameDefault
+ if braced then
+ _, brace_close = string.find(el.text, "^"..qnameLong.."}",
+ bracket_close)
+ if brace_close then
+ has_hints = true
+ -- TODO: call same function with remains of Str
+ end
+ end
+ ::continue::
+ end
+ if has_hints then
+ return pandoc.Inlines {new_inlines}
+ end
+end
diff --git a/example/example.qmd b/example/example.qmd
new file mode 100644
index 0000000..57e03b5
--- /dev/null
+++ b/example/example.qmd
@@ -0,0 +1,20 @@
+---
+title: "Test Document"
+format:
+ html:
+ minimal: true
+filters:
+ - semantic-markdown
+---
+
+My name is
+[Manu Sporny]{:name}
+and you can give me a ring via
+[1-800-555-0199]{:telephone}.
+![](http://manu.sporny.org/images/manu.png){:image}
+My favorite animal is the [Liger]{ov:preferredAnimal}.
+{=<#manu> .:Person}
+
+{schema}: @default
+
+{ov}: http://open.vocab.org/terms/