summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MANUAL.txt2
-rw-r--r--data/templates/default.typst90
-rw-r--r--data/templates/definitions.typst18
-rw-r--r--data/templates/template.typst73
-rw-r--r--pandoc.cabal2
-rw-r--r--src/Text/Pandoc/Writers/Typst.hs54
-rw-r--r--test/writer.typst241
7 files changed, 347 insertions, 133 deletions
diff --git a/MANUAL.txt b/MANUAL.txt
index 309204a6a..13c72c9f3 100644
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -481,7 +481,7 @@ header when requesting a document from a URL:
[OPML]: http://dev.opml.org/spec2.html
[OpenDocument]: http://opendocument.xml.org
[ODT]: https://en.wikipedia.org/wiki/OpenDocument
-[Textile]: https://www.promptworks.com/textile
+[Textile]: https://textile-lang.com
[MediaWiki markup]: https://www.mediawiki.org/wiki/Help:Formatting
[DokuWiki markup]: https://www.dokuwiki.org/dokuwiki
[ZimWiki markup]: https://zim-wiki.org/manual/Help/Wiki_Syntax.html
diff --git a/data/templates/default.typst b/data/templates/default.typst
index c6066dd24..11e7b1211 100644
--- a/data/templates/default.typst
+++ b/data/templates/default.typst
@@ -1,59 +1,55 @@
-#set page(
+$definitions.typst()$
+
+$if(template)$
+#import "$template$": conf
+$else$
+$template.typst()$
+$endif$
+
+#show: doc => conf(
+$if(title)$
+ title: [$title$],
+$endif$
+$if(author)$
+ authors: (
+$for(author)$
+$if(author.name)$
+ ( name: [$author.name$],
+ affiliation: [$author.affiliation$],
+ email: [$author.email$] ),
+$else$
+ ( name: [$author$],
+ affiliation: [],
+ email: [] ),
+$endif$
+$endfor$
+ ),
+$endif$
+$if(date)$
+ date: [$date$],
+$endif$
+$if(abstract)$
+ abstract: [$abstract$],
+$endif$
+$if(margin)$
+ margin: ($for(margin/pairs)$$margin.key$: $margin.value$,$endfor$),
+$endif$
$if(papersize)$
paper: "$papersize$",
$endif$
- numbering: "1"
-)
-#set par(justify: true)
-#set text(
-$if(lang)$
- lang: "$lang$",
-$endif$
$if(mainfont)$
- font: "$mainfont$",
+ font: ("$mainfont$",),
$endif$
$if(fontsize)$
- size: $fontsize$,
+ fontsize: $fontsize$,
$endif$
-)
-#set heading(
-$if(numbering)$
- numbering: "$numbering$"
+$if(section-numbering)$
+ sectionnumbering: "$section-numbering$",
$endif$
+ cols: $if(columns)$$columns$$else$1$endif$,
+ doc,
)
-#align(center)[#block(inset: 2em)[
- #text(weight: "bold", size: 18pt)[$title$] \
-$for(author)$
- $author$ \
-$endfor$
-$if(date)$
- $date$
-$endif$
-]]
-
-#let definition(term, ..defs) = [
- #strong(term) \
- #(defs.pos().join("\n"))
-]
-
-#let blockquote(body) = [
- #set text( size: 0.92em )
- #block(inset: (left: 1.5em, top: 0.2em, bottom: 0.2em))[#body]
-]
-
-#let horizontalrule = [
- #line(start: (25%,0%), end: (75%,0%))
-]
-
-#let endnote(num, contents) = [
- #stack(dir: ltr, spacing: 3pt, super[#num], contents)
-]
-
-$if(columns)$
-#show: doc => columns($columns$, doc)
-$endif$
-
$for(header-includes)$
$header-includes$
@@ -71,6 +67,7 @@ $endif$
$body$
+$if(notes)$
#v(1em)
#block[
#horizontalrule
@@ -79,6 +76,7 @@ $body$
$notes$
]
+$endif$
$if(bibliographystyle)$
#set bibliography(style: "$bibliographystyle$")
diff --git a/data/templates/definitions.typst b/data/templates/definitions.typst
new file mode 100644
index 000000000..02fe80f38
--- /dev/null
+++ b/data/templates/definitions.typst
@@ -0,0 +1,18 @@
+// Some definitions presupposed by pandoc's typst output.
+#let definition(term, ..defs) = [
+ #strong(term) \
+ #(defs.pos().join("\n"))
+]
+
+#let blockquote(body) = [
+ #set text( size: 0.92em )
+ #block(inset: (left: 1.5em, top: 0.2em, bottom: 0.2em))[#body]
+]
+
+#let horizontalrule = [
+ #line(start: (25%,0%), end: (75%,0%))
+]
+
+#let endnote(num, contents) = [
+ #stack(dir: ltr, spacing: 3pt, super[#num], contents)
+]
diff --git a/data/templates/template.typst b/data/templates/template.typst
new file mode 100644
index 000000000..29edca969
--- /dev/null
+++ b/data/templates/template.typst
@@ -0,0 +1,73 @@
+#let conf(
+ title: none,
+ authors: none,
+ date: none,
+ abstract: none,
+ cols: 1,
+ margin: (x: 1.25in, y: 1.25in),
+ paper: "us-letter",
+ lang: none,
+ font: none,
+ fontsize: 11pt,
+ sectionnumbering: none,
+ doc,
+) = {
+ set page(
+ paper: paper,
+ margin: margin,
+ numbering: "1",
+ )
+ set par(justify: true)
+ if lang != none {
+ set text(lang: lang)
+ }
+ if font != none {
+ set text(font: font)
+ }
+ if fontsize != none {
+ set text(size: fontsize)
+ }
+ if sectionnumbering != none {
+ set heading(numbering: sectionnumbering)
+ }
+
+ if title != none {
+ align(center)[#block(inset: 2em)[
+ #text(weight: "bold", size: 1.5em)[#title]
+ ]]
+ }
+
+ if authors != none {
+ let count = authors.len()
+ let ncols = calc.min(count, 3)
+ grid(
+ columns: (1fr,) * ncols,
+ row-gutter: 1.5em,
+ ..authors.map(author =>
+ align(center)[
+ #author.name \
+ #author.affiliation \
+ #author.email
+ ]
+ )
+ )
+ }
+
+ if date != none {
+ align(center)[#block(inset: 1em)[
+ #date
+ ]]
+ }
+
+ if abstract != none {
+ block(inset: 2em)[
+ #text(weight: "semibold")[Abstract] #h(1em) #abstract
+ ]
+ }
+
+ if cols == 1 {
+ doc
+ } else {
+ columns(cols, doc)
+ }
+}
diff --git a/pandoc.cabal b/pandoc.cabal
index 6061eec13..044164838 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -96,6 +96,8 @@ data-files:
data/templates/affiliations.jats
data/templates/default.markua
data/templates/default.typst
+ data/templates/definitions.typst
+ data/templates/template.typst
-- translations
data/translations/*.yaml
-- entities
diff --git a/src/Text/Pandoc/Writers/Typst.hs b/src/Text/Pandoc/Writers/Typst.hs
index bcecda035..12364ce37 100644
--- a/src/Text/Pandoc/Writers/Typst.hs
+++ b/src/Text/Pandoc/Writers/Typst.hs
@@ -28,14 +28,14 @@ import Data.Text (Text)
import Data.List (intercalate, intersperse)
import qualified Data.Text as T
import Control.Monad.State ( StateT, evalStateT, gets, modify )
-import Text.Pandoc.Writers.Shared ( metaToContext, defField, toLegacyTable )
+import Text.Pandoc.Writers.Shared ( metaToContext, defField, setField,
+ toLegacyTable, lookupMetaString )
import Text.Pandoc.Shared (isTightList, orderedListMarkers)
import Text.Pandoc.Writers.Math (convertMath)
import qualified Text.TeXMath as TM
import Text.DocLayout
import Text.DocTemplates (renderTemplate)
import Text.Pandoc.Extensions (Extension(..))
-import Control.Monad (zipWithM)
-- | Convert Pandoc to Typst.
writeTypst :: PandocMonad m => WriterOptions -> Pandoc -> m Text
@@ -66,11 +66,14 @@ pandocToTypst options (Pandoc meta blocks) = do
let notes = vsep $ zipWith
(\(num :: Int) cont ->
"#endnote" <> parens (brackets (text (show num))
- <> ", " <> brackets (chomp cont)))
+ <> ", " <> brackets (chomp cont <> cr)))
[1..] noteContents
let context = defField "body" main
$ defField "notes" notes
$ defField "toc" (writerTableOfContents options)
+ $ (case lookupMetaString "lang" meta of
+ "" -> id
+ lang -> setField "lang" $ T.takeWhile (/='-') lang)
$ (if writerNumberSections options
then defField "numbering" ("1.1.1.1.1" :: Text)
else id)
@@ -116,12 +119,27 @@ blockToTypst block =
HorizontalRule ->
return $ blankline <> "#horizontalrule" <> blankline
OrderedList attribs items -> do
- items' <- zipWithM (\marker item ->
- chomp <$> listItemToTypst 3 (literal marker) item)
- (orderedListMarkers attribs) items
- return $ (if isTightList items
+ let addBlock = case attribs of
+ (1, DefaultStyle, DefaultDelim) -> id
+ (1, Decimal, Period) -> id
+ (start, sty, delim) -> \x ->
+ "#block[" $$
+ ("#set enum" <>
+ parens (
+ "numbering: " <>
+ doubleQuoted
+ (head (orderedListMarkers
+ (1, sty, delim))) <>
+ ", start: " <>
+ text (show start) )) $$
+ x $$
+ "]"
+ items' <- mapM (fmap chomp . listItemToTypst 2 ("+ ")) items
+ return $ addBlock
+ (if isTightList items
then vcat items'
- else vsep items') $$ blankline
+ else vsep items')
+ $$ blankline
BulletList items -> do
items' <- mapM (fmap chomp . listItemToTypst 2 "- ") items
return $ (if isTightList items
@@ -208,9 +226,9 @@ inlineToTypst inline =
DisplayMath -> return $ "$ " <> literal r <> " $"
Code (_,cls,_) code -> return $
case cls of
- (lang:_) -> "#raw(lang=" <> doubleQuotes (literal lang) <>
- ", " <> doubleQuotes (literal code) <> ")"
- _ | T.any (=='`') code -> "#raw(" <> doubleQuotes (literal code) <> ")"
+ (lang:_) -> "#raw(lang=" <> doubleQuoted lang <>
+ ", " <> doubleQuoted code <> ")"
+ _ | T.any (=='`') code -> "#raw(" <> doubleQuoted code <> ")"
| otherwise -> "`" <> literal code <> "`"
RawInline fmt str ->
case fmt of
@@ -238,11 +256,11 @@ inlineToTypst inline =
then return $ -- Note: this loses locators, prefix, suffix
"#cite" <> parens
(mconcat $ intersperse ", " $
- map (doubleQuotes . literal . citationId) citations)
+ map (doubleQuoted . citationId) citations)
else inlinesToTypst inlines
Link _attrs inlines (src,_tit) -> do
contents <- inlinesToTypst inlines
- return $ "#link" <> parens (doubleQuotes (literal src)) <>
+ return $ "#link" <> parens (doubleQuoted src) <>
if render Nothing contents == src
then mempty
else nowrap $ brackets contents
@@ -250,7 +268,7 @@ inlineToTypst inline =
let width' = maybe mempty ((", width: " <>) . literal) $ lookup "width" kvs
let height' = maybe mempty ((", height: " <>) . literal) $
lookup "height" kvs
- return $ "#image(" <> doubleQuotes (literal src) <> width' <> height' <> ")"
+ return $ "#image(" <> doubleQuoted src <> width' <> height' <> ")"
Note blocks -> do -- currently typst has no footnotes!
-- TODO create endnotes with manual typesetting
contents <- blocksToTypst blocks
@@ -291,3 +309,11 @@ toLabel ident =
if T.null ident
then mempty
else "#label" <> parens (doubleQuotes (literal ident))
+
+doubleQuoted :: Text -> Doc Text
+doubleQuoted = doubleQuotes . literal . escape
+ where
+ escape = T.concatMap escapeChar
+ escapeChar '\\' = "\\\\"
+ escapeChar '"' = "\\\""
+ escapeChar c = T.singleton c
diff --git a/test/writer.typst b/test/writer.typst
index aa14a59a6..130c53f59 100644
--- a/test/writer.typst
+++ b/test/writer.typst
@@ -1,19 +1,4 @@
-#set page(
- numbering: "1"
-)
-#set par(justify: true)
-#set text(
-)
-#set heading(
-)
-
-#align(center)[#block(inset: 2em)[
- #text(weight: "bold", size: 18pt)[Pandoc Test Suite] \
- John MacFarlane \
- Anonymous \
- July 17, 2006
-]]
-
+// Some definitions presupposed by pandoc's typst output.
#let definition(term, ..defs) = [
#strong(term) \
#(defs.pos().join("\n"))
@@ -31,7 +16,93 @@
#let endnote(num, contents) = [
#stack(dir: ltr, spacing: 3pt, super[#num], contents)
]
-
+#let conf(
+ title: none,
+ authors: none,
+ date: none,
+ abstract: none,
+ cols: 1,
+ margin: (x: 1.25in, y: 1.25in),
+ paper: "us-letter",
+ lang: none,
+ font: none,
+ fontsize: 11pt,
+ sectionnumbering: none,
+ doc,
+) = {
+ set page(
+ paper: paper,
+ margin: margin,
+ numbering: "1",
+ )
+ set par(justify: true)
+ if lang != none {
+ set text(lang: lang)
+ }
+ if font != none {
+ set text(font: font)
+ }
+ if fontsize != none {
+ set text(size: fontsize)
+ }
+ if sectionnumbering != none {
+ set heading(numbering: sectionnumbering)
+ }
+
+ if title != none {
+ align(center)[#block(inset: 2em)[
+ #text(weight: "bold", size: 1.5em)[#title]
+ ]]
+ }
+
+ if authors != none {
+ let count = authors.len()
+ let ncols = calc.min(count, 3)
+ grid(
+ columns: (1fr,) * ncols,
+ row-gutter: 1.5em,
+ ..authors.map(author =>
+ align(center)[
+ #author.name \
+ #author.affiliation \
+ #author.email
+ ]
+ )
+ )
+ }
+
+ if date != none {
+ align(center)[#block(inset: 1em)[
+ #date
+ ]]
+ }
+
+ if abstract != none {
+ block(inset: 2em)[
+ #text(weight: "semibold")[Abstract] #h(1em) #abstract
+ ]
+ }
+
+ if cols == 1 {
+ doc
+ } else {
+ columns(cols, doc)
+ }
+}
+#show: doc => conf(
+ title: [Pandoc Test Suite],
+ authors: (
+ ( name: [John MacFarlane],
+ affiliation: [],
+ email: [] ),
+ ( name: [Anonymous],
+ affiliation: [],
+ email: [] ),
+ ),
+ date: [July 17, 2006],
+ cols: 1,
+ doc,
+)
This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
@@ -97,8 +168,8 @@ sub status {
A list:
-1. item one
-2. item two
++ item one
++ item two
Nested block quotes:
@@ -191,41 +262,41 @@ Minuses loose:
#label("ordered")
Tight:
-1. First
-2. Second
-3. Third
++ First
++ Second
++ Third
and:
-1. One
-2. Two
-3. Three
++ One
++ Two
++ Three
Loose using tabs:
-1. First
++ First
-2. Second
++ Second
-3. Third
++ Third
and using spaces:
-1. One
++ One
-2. Two
++ Two
-3. Three
++ Three
Multiple paragraphs:
-1. Item 1, graf one.
++ Item 1, graf one.
- Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
+ Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.
-2. Item 2.
++ Item 2.
-3. Item 3.
++ Item 3.
== Nested
#label("nested")
@@ -235,24 +306,24 @@ Multiple paragraphs:
Here’s another:
-1. First
-2. Second:
- - Fee
- - Fie
- - Foe
-3. Third
++ First
++ Second:
+ - Fee
+ - Fie
+ - Foe
++ Third
Same thing but with paragraphs:
-1. First
++ First
-2. Second:
++ Second:
- - Fee
- - Fie
- - Foe
+ - Fee
+ - Fie
+ - Foe
-3. Third
++ Third
== Tabs and spaces
#label("tabs-and-spaces")
@@ -266,29 +337,50 @@ Same thing but with paragraphs:
== Fancy list markers
#label("fancy-list-markers")
-(2) begins with 2
-
-(3) and now 3
-
- with a continuation
-
- iv. sublist with roman numerals, starting with 4
- v. more items
- (A) a subsublist
- (B) a subsublist
+#block[
+#set enum(numbering: "(1)", start: 2)
++ begins with 2
+
++ and now 3
+
+ with a continuation
+
+ #block[
+ #set enum(numbering: "i.", start: 4)
+ + sublist with roman numerals, starting with 4
+ + more items
+ #block[
+ #set enum(numbering: "(A)", start: 1)
+ + a subsublist
+ + a subsublist
+ ]
+ ]
+]
Nesting:
-A. Upper Alpha
- I. Upper Roman.
- (6) Decimal start with 6
- c) Lower alpha with paren
+#block[
+#set enum(numbering: "A.", start: 1)
++ Upper Alpha
+ #block[
+ #set enum(numbering: "I.", start: 1)
+ + Upper Roman.
+ #block[
+ #set enum(numbering: "(1)", start: 6)
+ + Decimal start with 6
+ #block[
+ #set enum(numbering: "a)", start: 3)
+ + Lower alpha with paren
+ ]
+ ]
+ ]
+]
Autonumbering:
-1. Autonumber.
-2. More.
- 1. Nested.
++ Autonumber.
++ More.
+ + Nested.
Should not be a list item:
@@ -380,8 +472,8 @@ Blank line after term, indented marker, alternate markers:
#definition[orange][orange fruit
-1. sublist
-2. sublist
++ sublist
++ sublist
]
@@ -674,7 +766,7 @@ Here is an inline note.#super[3]
Notes can go in quotes.#super[4]
]
-1. And in list items.#super[5]
++ And in list items.#super[5]
This paragraph should not be part of the note, as it is not indented.
@@ -685,7 +777,8 @@ This paragraph should not be part of the note, as it is not indented.
#v(3pt) // otherwise first note marker is swallowed, bug?
#endnote([1], [Here is the footnote. It can go anywhere after the footnote
-reference. It need not be placed at the end of the document.])
+reference. It need not be placed at the end of the document.
+])
#endnote([2], [Here’s the long note. This one contains multiple blocks.
@@ -697,13 +790,17 @@ list items).
```
If you want, you can indent every line, but you can also be lazy and just indent
-the first line of each block.])
+the first line of each block.
+])
#endnote([3], [This is #emph[easier] to type. Inline notes may contain
#link("http://google.com")[links] and `]` verbatim characters, as well as
-\[bracketed text\].])
+\[bracketed text\].
+])
-#endnote([4], [In quote.])
+#endnote([4], [In quote.
+])
-#endnote([5], [In list.])
+#endnote([5], [In list.
+])
]