Browse Source

Allow control of span linking

Amélia Liao 2 years ago
parent
commit
296e68025b
6 changed files with 106 additions and 19 deletions
  1. +5
    -1
      .gitignore
  2. +28
    -2
      README.md
  3. +9
    -3
      example/example.html
  4. +8
    -2
      example/example.lagda.md
  5. +9
    -3
      example/example.md
  6. +47
    -8
      src/Main.hs

+ 5
- 1
.gitignore View File

@ -1,2 +1,6 @@
/.stack-work /.stack-work
/agda-reference-filter
/agda-reference-filter
/example/Agda*.html
/example/*.agdai
/example/*.css

+ 28
- 2
README.md View File

@ -4,9 +4,35 @@ A Pandoc filter for linking Agda identifiers in inline code blocks.
## Usage ## Usage
Compile your literate Agda file to Markdown (use `--html-highlight=auto`), then `pandoc --filter agda-reference-filter -i output.md -o output.html` to compile the Markdown to HTML. Inline code spans that are exactly the same as an identifier present in the raw HTML emitted by Agda (that is - either a definition or a reference) will be linked to the same place that Agda linked that identifier to.
The filter operates on Markdown files generated by Agda's built-in
literate programming support (use `--html-highlight=auto` to keep the
Markdown), then call Pandoc with the filter:
```bash ```bash
agda --html-highlight=auto --html example.lagda.md agda --html-highlight=auto --html example.lagda.md
pandoc --filter agda-reference-filter -i example.md -o example.html pandoc --filter agda-reference-filter -i example.md -o example.html
```
```
The input file will be scanned, in source order, to build a variable
name - HTML element association.
Only the first reference is counted: if you have two identifiers called
`go`, then `` `go` `` in Markdown will link to the first.
### Controlling whether spans are linked
Code spans in Markdown are only linked if they have the `agda` - **case
insensitive** - class. In Pandoc syntax, you can attach a class to a
code span like so:
```
`List`{.agda}
```
If you want a span to have the `agda` class but for it not to be linked,
add the `nolink` class.
### Controlling what spans are linked to
If a span has the `ident` attribute, then the value of that attribute
will be used as the identifier to link to instead of the span text.

+ 9
- 3
example/example.html View File

@ -1,4 +1,10 @@
<p>This is a literate Agda file. This span - <span class="Agda"><a href="example.html#104" class="Record">span</a></span> - will be linked to the record below:</p>
<pre class="Agda"><a id="97" class="Keyword">record</a> <a id="span"></a><a id="104" href="example.html#104" class="Record">span</a> <a id="109" class="Symbol">:</a> <a id="111" class="PrimitiveType">Set</a> <a id="115" class="Keyword">where</a>
<a id="123" class="Keyword">constructor</a> <a id="hey-look"></a><a id="135" href="example.html#135" class="InductiveConstructor">hey-look</a>
<p>This is a literate Agda file.</p>
<p>Here’s some inline code:</p>
<ul class="incremental">
<li>This is a link to the record below: <pre class="Agda"><a href="example.html#224" class="Record">Record</a></pre></li>
<li>This is not: <code>Record</code></li>
<li>This is a link with alternate text: <pre class="Agda"><a href="example.html#224" class="Record">also a link</a></pre></li>
</ul>
<pre class="Agda"><a id="217" class="Keyword">record</a> <a id="Record"></a><a id="224" href="example.html#224" class="Record">Record</a> <a id="231" class="Symbol">:</a> <a id="233" class="PrimitiveType">Set</a> <a id="237" class="Keyword">where</a>
<a id="245" class="Keyword">constructor</a> <a id="hey-look"></a><a id="257" href="example.html#257" class="InductiveConstructor">hey-look</a>
</pre> </pre>

+ 8
- 2
example/example.lagda.md View File

@ -1,6 +1,12 @@
This is a literate Agda file. This span - `span` - will be linked to the record below:
This is a literate Agda file.
Here's some inline code:
- This is a link to the record below: `Record`{.agda}
- This is not: `Record`
- This is a link with alternate text: `also a link`{.agda ident=Record}
```agda ```agda
record span : Set where
record Record : Set where
constructor hey-look constructor hey-look
``` ```

+ 9
- 3
example/example.md View File

@ -1,5 +1,11 @@
This is a literate Agda file. This span - `span` - will be linked to the record below:
This is a literate Agda file.
<pre class="Agda"><a id="97" class="Keyword">record</a> <a id="span"></a><a id="104" href="example.html#104" class="Record">span</a> <a id="109" class="Symbol">:</a> <a id="111" class="PrimitiveType">Set</a> <a id="115" class="Keyword">where</a>
<a id="123" class="Keyword">constructor</a> <a id="hey-look"></a><a id="135" href="example.html#135" class="InductiveConstructor">hey-look</a>
Here's some inline code:
- This is a link to the record below: `Record`{.agda}
- This is not: `Record`
- This is a link with alternate text: `also a link`{.agda ident=Record}
<pre class="Agda"><a id="217" class="Keyword">record</a> <a id="Record"></a><a id="224" href="example.html#224" class="Record">Record</a> <a id="231" class="Symbol">:</a> <a id="233" class="PrimitiveType">Set</a> <a id="237" class="Keyword">where</a>
<a id="245" class="Keyword">constructor</a> <a id="hey-look"></a><a id="257" href="example.html#257" class="InductiveConstructor">hey-look</a>
</pre> </pre>

+ 47
- 8
src/Main.hs View File

@ -25,23 +25,62 @@ linkDocument (Pandoc meta blocks) =
let hm = parseSymbolRefs blocks let hm = parseSymbolRefs blocks
in Pandoc meta (walk (link hm) blocks) in Pandoc meta (walk (link hm) blocks)
link :: HashMap Text Text -> Inline -> Inline
link hm (Code attrs xs)
| Just sp <- HashMap.lookup xs hm = RawInline (Format "html") sp
link :: HashMap Text Reference -> Inline -> Inline
link hm inline@(Code (_, classes, kv) text)
| isToBeLinked =
case HashMap.lookup identifier hm of
Just ref -> RawInline "html" (renderReference ref text)
Nothing -> inline
where
classes' = map T.toLower classes
isToBeLinked = ("agda" `elem` classes')
&& ("nolink" `notElem` classes')
identifier =
case lookup "ident" kv of
Just id -> id
_ -> text
link _ x = x link _ x = x
parseSymbolRefs :: [Block] -> HashMap Text Text
renderReference :: Reference -> Text -> Text
renderReference (Reference href cls) t =
renderTags [ TagOpen "pre" [("class", "Agda")]
, TagOpen "a" [("href", href), ("class", cls)]
, TagText t
, TagClose "a"
, TagClose "pre"
]
data Reference =
Reference { refHref :: Text
, refClass :: Text
}
deriving (Eq, Show)
parseSymbolRefs :: [Block] -> HashMap Text Reference
parseSymbolRefs = go mempty . concat . mapMaybe getHTML where parseSymbolRefs = go mempty . concat . mapMaybe getHTML where
getHTML :: Block -> Maybe ([Tag Text])
getHTML (RawBlock (Format x) xs) getHTML (RawBlock (Format x) xs)
| x == "html" = Just (parseTags (T.unpack xs))
| x == "html" = Just (parseTags xs)
getHTML _ = Nothing getHTML _ = Nothing
go map (TagOpen "a" meta:TagText t:TagClose "a":xs)
| Just id <- lookup "id" meta, Just cls <- lookup "class" meta
= go (HashMap.insert (T.pack t) (T.pack (renderTags tags)) map) xs
go :: HashMap Text Reference -> [Tag Text] -> HashMap Text Reference
go map (TagOpen a meta:TagText t:TagClose a':xs)
| a == "a"
, a' == a
, Just id <- lookup "id" meta
, Just cls <- lookup "class" meta
, Just href <- lookup "href" meta
= go (addIfNotPresent t (Reference href cls) map) xs
| otherwise = go map xs | otherwise = go map xs
where where
tags = [ TagOpen "span" [("class", "Agda")], TagOpen "a" meta', TagText t, TagClose "a", TagClose "span" ] tags = [ TagOpen "span" [("class", "Agda")], TagOpen "a" meta', TagText t, TagClose "a", TagClose "span" ]
meta' = filter ((/= "id") . fst) meta meta' = filter ((/= "id") . fst) meta
go map (_:xs) = go map xs go map (_:xs) = go map xs
go map [] = map go map [] = map
addIfNotPresent :: Text -> v -> HashMap Text v -> HashMap Text v
addIfNotPresent = HashMap.insertWith (\_ old -> old)

Loading…
Cancel
Save