Skip to content

Commit f14a032

Browse files
committed
Allow using Pandoc filter in LaTeX commands
1 parent b28e5be commit f14a032

File tree

6 files changed

+108
-127
lines changed

6 files changed

+108
-127
lines changed

.github/workflows/ci-ubuntu.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ on:
2424
########################################################################
2525

2626
env:
27-
IDRIS2_COMMIT: 9e84b153bd3d7d5a63ec9e6a9adfa47a067ea172
27+
IDRIS2_COMMIT: e4431891e915c6866a6eea18046dcb3bcdfa8d89
2828
COLLIE_COMMIT: ed2eda5e04fbd02a7728e915d396e14cc7ec298e
29-
IDRALL_COMMIT: 62a455894b1db5134c8b56d31aadb31d483a4b2c
29+
IDRALL_COMMIT: 86d84e44f7e2d07e597ca10b7d0a3451992b5605
3030
SCHEME: scheme
3131

3232
########################################################################
@@ -61,6 +61,7 @@ jobs:
6161
sudo apt-get update
6262
sudo apt-get install -y chezscheme
6363
sudo apt-get install -y texlive texlive-fonts-extra
64+
sudo apt-get install -y pandoc
6465
6566
- name: Install Idris2 & its API
6667
if: steps.cache-idris2.outputs.cache-hit != 'true'

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
.PHONY: project src install test doc clean
22

3-
project: build/exec/katla
3+
project: build/exec/katla build/exec/katla-pandoc
44

55
src: src/**/*.idr
66

77
build/exec/katla: src
88
idris2 --build katla.ipkg
99

10-
build/exec/katla-pandoc: .PHONY
10+
build/exec/katla-pandoc:
1111
idris2 --build katla-pandoc.ipkg
1212

1313
install: build/exec/katla build/exec/katla-pandoc

src/Katla/Pandoc.idr

Lines changed: 50 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -161,36 +161,39 @@ checkCode dir packages snippets = do
161161
| (msg, err) => die $ "Error checking Idris code (exit code: \{show err})\n" ++ msg
162162
pure ()
163163

164+
addPandocHeaderIncludes : List String -> JSON -> JSON
165+
addPandocHeaderIncludes newHeaders doc = do
166+
let newHeaders = map (\newHeader => JObject [
167+
("t", JString "MetaBlocks"),
168+
("c", JArray [JObject [
169+
("t", JString "RawBlock"),
170+
("c", JArray [JString "tex", JString newHeader])
171+
]])
172+
]) newHeaders
173+
update (Just . update (Just . update (Just . (\case
174+
JArray existingHeaders => JArray $ existingHeaders ++ newHeaders
175+
existingHeader => JArray $ existingHeader :: newHeaders) .
176+
maybe (JArray []) id) "c" .
177+
maybe (JObject [("t", JString "MetaList")]) id) "header-includes" .
178+
maybe (JObject []) id) "meta" doc
179+
164180
covering
165181
addKatlaHeader : JSON -> IO JSON
166182
addKatlaHeader doc = do
167183
(katlaHeader, 0) <- run "katla latex preamble"
168184
| (_, err) => die "Error getting Katla header (exit code: \{show err})"
169185

170-
let pandocKatlaHeader = JObject [
171-
("t", JString "MetaBlocks"),
172-
("c", JArray [JObject [
173-
("t", JString "RawBlock"),
174-
("c", JArray [JString "tex", JString katlaHeader])
175-
]])
176-
]
177-
178-
pure $ update (Just . update (Just . update (Just . (\case
179-
JArray xs => JArray $ pandocKatlaHeader :: xs
180-
json => json) .
181-
maybe (JArray []) id) "c" .
182-
maybe (JObject [("t", JString "MetaList")]) id) "header-includes" .
183-
maybe (JObject []) id) "meta" doc
186+
pure $ addPandocHeaderIncludes [katlaHeader] doc
184187

185188
covering
186-
formatSnippet : (dir : String) -> Snippet -> (start : Nat) -> (len : Nat) -> IO JSON
187-
formatSnippet dir snippet start len = do
189+
formatSnippet : (dir : String) -> Snippet -> (snippetName : String) -> (start : Nat) -> (len : Nat) -> IO (Maybe String, JSON)
190+
formatSnippet dir snippet snippetName start len = do
188191
let False = snippet.hide
189-
| True => pure $ JObject [("t", JString "Para"), ("c", JArray [])]
192+
| True => pure (Nothing, JObject [("t", JString "Para"), ("c", JArray [])])
190193

191194
let katlaCmd = case snippet.displayType of
192-
Block => "katla latex macro KatlaSnippet \{dir}/\{snippet.file}.idr build/ttc/*/\{dir}/\{snippet.file}.ttm \{show start} 0 \{show len}"
193-
Inline => "katla latex macro inline KatlaSnippet \{dir}/\{snippet.file}.idr build/ttc/*/\{dir}/\{snippet.file}.ttm \{show start} 0 \{show $ 1 + len} \{show $ 8 + length snippet.code}"
195+
Block => "katla latex macro \{snippetName} \{dir}/\{snippet.file}.idr build/ttc/*/\{dir}/\{snippet.file}.ttm \{show start} 0 \{show len}"
196+
Inline => "katla latex macro inline \{snippetName} \{dir}/\{snippet.file}.idr build/ttc/*/\{dir}/\{snippet.file}.ttm \{show start} 0 \{show $ 1 + len} \{show $ 8 + length snippet.code}"
194197
(out, 0) <- run katlaCmd
195198
| (_, err) => die "Error running Katla (exit code: \{show err})"
196199

@@ -199,13 +202,10 @@ formatSnippet dir snippet start len = do
199202
Decls => out
200203
Expr _ => dedent out
201204

202-
pure $ JObject [
205+
pure (Just out, JObject [
203206
("t", JString $ case snippet.displayType of Block => "RawBlock"; Inline => "RawInline"),
204-
("c", JArray [
205-
JString "tex",
206-
JString $ "\\let\\KatlaSnippet\\relax{}" ++ out ++ "\\KatlaSnippet{}"
207-
])
208-
]
207+
("c", JArray [ JString "tex", JString "\\\{snippetName}{}"])
208+
])
209209
where
210210
katlaIndent : String
211211
katlaIndent = "\\KatlaSpace{}\\KatlaSpace{}\\KatlaSpace{}\\KatlaSpace{}"
@@ -223,13 +223,31 @@ formatSnippet dir snippet start len = do
223223

224224
covering
225225
addKatlaSnippets : (dir : String) -> List Snippet -> List (Nat, Nat) -> JSON -> IO JSON
226-
addKatlaSnippets dir snippets ranges json = do
227-
evalStateT ranges $ traverseSnippets (\snippet => do
228-
Just (start, len) <- gets head'
229-
| Nothing => die "katla-pandoc internal error"
230-
modify (\case [] => []; _ :: xs => xs)
231-
lift $ formatSnippet dir snippet start len
232-
) json
226+
addKatlaSnippets dir snippets ranges doc = do
227+
((headers, _), doc) <- runStateT (the (SnocList String) [<], ranges) $ traverseSnippets (\snippet => do
228+
(headers, (start, len) :: rest) <- get {stateType = (SnocList String, List (Nat, Nat))}
229+
| _ => die "katla-pandoc internal error"
230+
231+
snippetName <- lift genName
232+
(newHeader, json) <- lift $ formatSnippet dir snippet snippetName start len
233+
234+
put (
235+
case newHeader of Nothing => headers; Just newHeader => headers :< newHeader,
236+
rest
237+
)
238+
239+
pure json
240+
) doc
241+
242+
pure $ addPandocHeaderIncludes (cast headers) doc
243+
where
244+
alpha : List Char
245+
alpha = unpack "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
246+
247+
genName : IO String
248+
genName = do
249+
suffix <- for (replicate 6 ()) $ \() => rndSelect alpha
250+
pure "KatlaSnippet\{pack suffix}"
233251

234252
covering
235253
main : IO ()

tests/examples/pandoc/Source.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,31 @@ x : Nat
2424
x = 1 + 2
2525
```
2626

27+
And here's a code block in a \LaTeX{} figure environment:
28+
29+
```{=latex}
30+
\newcommand\myfig[2]{
31+
\begin{figure}[h]
32+
\centering
33+
#2
34+
\caption{#1}
35+
\end{figure}
36+
}
37+
```
38+
39+
```{=latex}
40+
\myfig{Definition of $y$}{
41+
```
42+
43+
```idr
44+
y : Nat
45+
y = x + 3
46+
```
47+
48+
```{=latex}
49+
}
50+
```
51+
2752
We can use namespaces by adding the `namespace` attribute, such as to provide alternate definitions for functions. Consider this function signature:
2853

2954
```{.idr namespace="A"}

tests/examples/pandoc/run

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
PATH="../../../build/exec:$PATH"
2+
13
rm -rf temp build
24

35
mkdir temp
46

57
# Test Katla pandoc
6-
pandoc ./Source.md --filter "$1-pandoc" -o temp/source.tex
8+
pandoc ./Source.md --filter "$1-pandoc" --to=latex | sed 's/KatlaSnippet[[:alpha:]]\+/KatlaSnippet/g' > temp/source.tex
79
pandoc ./Source.md --filter "$1-pandoc" -o temp/source.pdf
810
diff source-expected.tex temp/source.tex >> output

tests/examples/pandoc/source-expected.tex

Lines changed: 25 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -15,132 +15,74 @@ \section{Basic Usage}\label{basic-usage}}
1515

1616
We can use all Idris 2 features. Here's an example code block:
1717

18-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerbatim[#1]{KatlaSnippet}}
19-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
20-
\IdrisFunction{x}\KatlaSpace{}\IdrisKeyword{:}\KatlaSpace{}\IdrisType{Nat}\KatlaNewline{}
21-
\IdrisFunction{x}\KatlaSpace{}\IdrisKeyword{=}\KatlaSpace{}\IdrisData{1}\KatlaSpace{}\IdrisFunction{+}\KatlaSpace{}\IdrisData{2}\KatlaNewline{}
22-
\end{SaveVerbatim}
2318
\KatlaSnippet{}
2419

20+
And here's a code block in a \LaTeX{} figure environment:
21+
22+
\newcommand\myfig[2]{
23+
\begin{figure}[h]
24+
\centering
25+
#2
26+
\caption{#1}
27+
\end{figure}
28+
}
29+
30+
\myfig{Definition of $y$}{
31+
32+
\KatlaSnippet{}
33+
34+
}
35+
2536
We can use namespaces by adding the \texttt{namespace} attribute, such
2637
as to provide alternate definitions for functions. Consider this
2738
function signature:
2839

29-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerbatim[#1]{KatlaSnippet}}
30-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
31-
\IdrisFunction{f}\KatlaSpace{}\IdrisKeyword{:}\KatlaSpace{}\IdrisType{Vect}\KatlaSpace{}\IdrisBound{n}\KatlaSpace{}\IdrisBound{a}\KatlaSpace{}\IdrisKeyword{\KatlaDash{}>}\KatlaSpace{}\IdrisType{Vect}\KatlaSpace{}\IdrisKeyword{(}\IdrisBound{n}\KatlaSpace{}\IdrisFunction{+}\KatlaSpace{}\IdrisBound{n}\IdrisKeyword{)}\KatlaSpace{}\IdrisBound{a}\KatlaNewline{}
32-
\end{SaveVerbatim}
3340
\KatlaSnippet{}
3441

35-
Here's one implementation for
36-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
37-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
38-
\IdrisFunction{f}\KatlaNewline{}
39-
\end{SaveVerbatim}
40-
\KatlaSnippet{}:
41-
42-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerbatim[#1]{KatlaSnippet}}
43-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
44-
\IdrisFunction{f}\KatlaSpace{}\IdrisBound{xs}\KatlaSpace{}\IdrisKeyword{=}\KatlaSpace{}\IdrisBound{xs}\KatlaSpace{}\IdrisFunction{++}\KatlaSpace{}\IdrisBound{xs}\KatlaNewline{}
45-
\end{SaveVerbatim}
42+
Here's one implementation for \KatlaSnippet{}:
43+
4644
\KatlaSnippet{}
4745

4846
By repeating the signature in a different namespace, in a hidden code
4947
block, I can give an alternate definition:
5048

51-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerbatim[#1]{KatlaSnippet}}
52-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
53-
\IdrisFunction{f}\KatlaSpace{}\IdrisBound{xs}\KatlaSpace{}\IdrisKeyword{=}\KatlaSpace{}\IdrisBound{xs}\KatlaSpace{}\IdrisFunction{++}\KatlaSpace{}\IdrisFunction{reverse}\KatlaSpace{}\IdrisBound{xs}\KatlaNewline{}
54-
\end{SaveVerbatim}
5549
\KatlaSnippet{}
5650

5751
\hypertarget{inline-code}{%
5852
\section{Inline Code}\label{inline-code}}
5953

6054
As well as block code, we can have inline code, like
61-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
62-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
63-
\IdrisFunction{the}\KatlaSpace{}\IdrisType{Nat}\KatlaSpace{}\IdrisData{3}\KatlaNewline{}
64-
\end{SaveVerbatim}
65-
\KatlaSnippet{}. Here's another:
66-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
67-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
68-
\IdrisData{1}\KatlaSpace{}\IdrisFunction{+}\KatlaSpace{}\IdrisData{2}\KatlaNewline{}
69-
\end{SaveVerbatim}
70-
\KatlaSnippet{}. We can also call the function we previously defined:
71-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
72-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
73-
\IdrisFunction{f}\KatlaSpace{}\IdrisData{[1,}\KatlaSpace{}\IdrisData{2,}\KatlaSpace{}\IdrisData{3]}\KatlaNewline{}
74-
\end{SaveVerbatim}
75-
\KatlaSnippet{}.
55+
\KatlaSnippet{}. Here's another: \KatlaSnippet{}. We can
56+
also call the function we previously defined: \KatlaSnippet{}.
7657

7758
By default, a code block is interpreted as top-level Idris 2
7859
declarations, while inline code is interpreted as an expression. But we
7960
can switch it up if we wish.
8061

8162
By using the \texttt{decls} class, we can write an inline declaration:
82-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
83-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
84-
\IdrisFunction{g}\KatlaSpace{}\IdrisKeyword{:}\KatlaSpace{}\IdrisType{Nat}\KatlaSpace{}\IdrisKeyword{\KatlaDash{}>}\KatlaSpace{}\IdrisType{Nat}\KatlaNewline{}
85-
\end{SaveVerbatim}
8663
\KatlaSnippet{}.
8764

8865
By using the \texttt{expr} class, we can write a block expression:
8966

90-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerbatim[#1]{KatlaSnippet}}
91-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
92-
\IdrisData{[}\KatlaNewline{}
93-
\KatlaSpace{}\KatlaSpace{}\KatlaSpace{}\KatlaSpace{}\IdrisData{1,}\KatlaNewline{}
94-
\KatlaSpace{}\KatlaSpace{}\KatlaSpace{}\KatlaSpace{}\IdrisData{2,}\KatlaNewline{}
95-
\KatlaSpace{}\KatlaSpace{}\KatlaSpace{}\KatlaSpace{}\IdrisData{3}\KatlaNewline{}
96-
\IdrisData{]}\KatlaNewline{}
97-
\end{SaveVerbatim}
9867
\KatlaSnippet{}
9968

10069
\hypertarget{types}{%
10170
\section{Types}\label{types}}
10271

10372
Sometimes, Idris 2 cannot infer the type of an expression. Is
104-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
105-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
106-
\IdrisData{[1,}\KatlaSpace{}\IdrisData{2,}\KatlaSpace{}\IdrisData{3]}\KatlaNewline{}
107-
\end{SaveVerbatim}
108-
\KatlaSnippet{} a
109-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
110-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
111-
\IdrisType{List}\KatlaSpace{}\IdrisType{Nat}\KatlaNewline{}
112-
\end{SaveVerbatim}
113-
\KatlaSnippet{}, or a
114-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
115-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
116-
\IdrisType{Vect}\KatlaSpace{}\IdrisData{3}\KatlaSpace{}\IdrisType{Integer}\KatlaNewline{}
117-
\end{SaveVerbatim}
118-
\KatlaSnippet{}? We can use the \texttt{type} attribute to tell Idris 2
119-
which one it should be.
73+
\KatlaSnippet{} a \KatlaSnippet{}, or a
74+
\KatlaSnippet{}? We can use the \texttt{type} attribute to tell
75+
Idris 2 which one it should be.
12076

12177
\hypertarget{multiple-files}{%
12278
\section{Multiple Files}\label{multiple-files}}
12379

12480
If you need an import to \emph{not} be available, namespaces are not
12581
enough. We can use the \texttt{file} attribute to put snippets in
126-
separate files. For example, the signature of
127-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
128-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
129-
\IdrisFunction{f}\KatlaNewline{}
130-
\end{SaveVerbatim}
131-
\KatlaSnippet{} fails to compile if we use a new file, that hasn't
132-
imported
133-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerb[#1]{KatlaSnippet}}
134-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
135-
\IdrisType{Vect}\KatlaNewline{}
136-
\end{SaveVerbatim}
82+
separate files. For example, the signature of \KatlaSnippet{}
83+
fails to compile if we use a new file, that hasn't imported
13784
\KatlaSnippet{}.
13885

139-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerbatim[#1]{KatlaSnippet}}
140-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
141-
\IdrisKeyword{failing}\KatlaSpace{}\IdrisData{"Undefined\KatlaSpace{}name\KatlaSpace{}Vect."}\KatlaNewline{}
142-
\KatlaSpace{}\KatlaSpace{}\KatlaSpace{}\KatlaSpace{}\IdrisFunction{f}\KatlaSpace{}\IdrisKeyword{:}\KatlaSpace{}Vect\KatlaSpace{}n\KatlaSpace{}a\KatlaSpace{}\IdrisKeyword{\KatlaDash{}>}\KatlaSpace{}Vect\KatlaSpace{}\IdrisKeyword{(}n\KatlaSpace{}+\KatlaSpace{}n\IdrisKeyword{)}\KatlaSpace{}a\KatlaNewline{}
143-
\end{SaveVerbatim}
14486
\KatlaSnippet{}
14587

14688
\hypertarget{packages}{%
@@ -150,11 +92,4 @@ \section{Packages}\label{packages}}
15092
using the \texttt{idris2-packages} key. For example, adding
15193
\texttt{contrib} allows us to use the \texttt{Language.JSON} module.
15294

153-
\let\KatlaSnippet\relax{}\newcommand\KatlaSnippet[1][]{\UseVerbatim[#1]{KatlaSnippet}}
154-
\begin{SaveVerbatim}[commandchars=\\\{\}]{KatlaSnippet}
155-
\IdrisKeyword{import}\KatlaSpace{}\IdrisModule{Language.JSON}\KatlaNewline{}
156-
\KatlaNewline{}
157-
\IdrisFunction{x}\KatlaSpace{}\IdrisKeyword{:}\KatlaSpace{}\IdrisType{Maybe}\KatlaSpace{}\IdrisType{JSON}\KatlaNewline{}
158-
\IdrisFunction{x}\KatlaSpace{}\IdrisKeyword{=}\KatlaSpace{}\IdrisFunction{parse}\KatlaSpace{}\IdrisData{\#"\{"x":\KatlaSpace{}1,\KatlaSpace{}"y":\KatlaSpace{}2\}"\#}\KatlaNewline{}
159-
\end{SaveVerbatim}
16095
\KatlaSnippet{}

0 commit comments

Comments
 (0)