mirror of
https://github.com/unisonweb/unison.git
synced 2024-11-14 07:51:12 +03:00
7d213d8798
Embedded evaluation type can't include the evaluated result, since that won't be recomputed when the dependencies are updated. Correct approach is to use the watch cache when evaluating embedded expressions in a doc.
528 lines
13 KiB
Plaintext
528 lines
13 KiB
Plaintext
{-
|
|
- [x] Debug the lexer/parser combination
|
|
- [x] Implement display logic for doc type (Unison side)
|
|
- [ ] Add to IOSource
|
|
- [ ] Implement display logic for new doc type in DisplayValues
|
|
- [ ] Write illustrative transcript (and possibly separate tests)
|
|
- [ ] Review with Simon, Rúnar, to see if we're missing any elements
|
|
- [ ] PR writeup
|
|
- [ ] (Later) Pretty-printer should reverse the syntax
|
|
- [ ] (Later) docs command should look for foo.doc if nothing is linked, or just have it do: display foo.doc
|
|
- [ ] (Later) Top level types should allow anon doc blocks
|
|
- [ ] (Later) Remove backticks syntax
|
|
- [ ] (Later) Instant docs preview
|
|
- [ ] (Later) Remove old doc, rename Doc2 to Doc
|
|
-}
|
|
|
|
id x = x
|
|
|
|
unique[fb488e55e66e2492c2946388e4e846450701db04] type Doc2.Term = Term Any
|
|
|
|
Doc2.term : 'a -> Doc2.Term
|
|
Doc2.term a = Doc2.Term.Term (Any a)
|
|
|
|
unique[da70bff6431da17fa515f3d18ded11852b6a745f] type Doc2.SpecialForm
|
|
= Source [Either Link.Type Doc2.Term]
|
|
| Example Nat Doc2.Term
|
|
| Link (Either Link.Type Doc2.Term)
|
|
| Signature [Doc2.Term]
|
|
| InlineSignature Doc2.Term
|
|
| Eval Doc2.Term
|
|
| InlineEval Doc2.Term
|
|
| Embed Any
|
|
| InlineEmbed Any
|
|
|
|
unique[b7a4fb87e34569319591130bf3ec6e24c9955b6a] type Doc2
|
|
= Word Text
|
|
| Code Doc2
|
|
| CodeBlock Text Doc2
|
|
| Bold Doc2
|
|
| Italic Doc2
|
|
| Strikethrough Doc2
|
|
-- style {{ myclass }} mydoc
|
|
| Style Doc2 Doc2
|
|
| Blockquote Doc2
|
|
| Blankline
|
|
| SectionBreak
|
|
| Aside (Optional Doc2) Doc2
|
|
-- callout icon content
|
|
| Callout (Optional Doc2) Doc2
|
|
| Folded Boolean Doc2 Doc2
|
|
| Paragraph [Doc2]
|
|
| BulletedList [Doc2]
|
|
| NumberedList Nat [Doc2]
|
|
| Section Doc2 [Doc2]
|
|
| NamedLink Doc2 Doc2
|
|
| Special Doc2.SpecialForm
|
|
| Docs [Doc2]
|
|
|
|
unique[d7b2ced8c08b2c6e54050d1f5acedef3395f293d] type Pretty.Annotated w txt
|
|
= Empty
|
|
| Group w (Pretty.Annotated w txt)
|
|
| Lit w txt
|
|
| Wrap w (Pretty.Annotated w txt)
|
|
| OrElse w (Pretty.Annotated w txt) (Pretty.Annotated w txt)
|
|
-- Indent _ initialIndent indentAfterNewline p prefixes the first
|
|
-- line of `p` with `initialIndent`, and subsequent lines by `indentAfterNewline`.
|
|
| Indent w (Pretty.Annotated w txt) (Pretty.Annotated w txt) (Pretty.Annotated w txt)
|
|
| Append w [Pretty.Annotated w txt]
|
|
|
|
type Pretty txt = Pretty (Pretty.Annotated () txt)
|
|
|
|
Pretty.get = cases Pretty p -> p
|
|
|
|
Pretty.map : (txt ->{g} txt2) ->{} Pretty txt ->{g} Pretty txt2
|
|
Pretty.map f p =
|
|
go = cases
|
|
Empty -> Empty
|
|
Group _ p -> Group () (go p)
|
|
Lit _ t -> Lit () (f t)
|
|
Wrap _ p -> Wrap () (go p)
|
|
OrElse _ p1 p2 -> OrElse () (go p1) (go p2)
|
|
Indent _ i0 iN p -> Indent () (go i0) (go iN) (go p)
|
|
-- Append _ ps -> Append () (List.map go ps)
|
|
Pretty (go (Pretty.get p))
|
|
|
|
Pretty.empty : Pretty txt
|
|
Pretty.empty = Pretty Empty
|
|
|
|
{- A group adds a level of breaking. Layout tries not to break a group
|
|
unless needed to fit in available width. Breaking is done "outside in".
|
|
|
|
(a | b) <> (c | d) will try (a <> c)
|
|
then (b <> d)
|
|
|
|
(a | b) <> group (c | d) will try (a <> c)
|
|
then (b <> c)
|
|
then (b <> d)
|
|
-}
|
|
Pretty.group : Pretty txt -> Pretty txt
|
|
Pretty.group p = Pretty (Group () (Pretty.get p))
|
|
|
|
-- Create a leaf-level `Pretty` that cannot be broken.
|
|
Pretty.lit : txt -> Pretty txt
|
|
Pretty.lit txt = Pretty (Lit () txt)
|
|
|
|
-- Turn on wrapping for `p`, which means that it inserts
|
|
-- softbreaks (either a space or a newline) between each
|
|
-- subgroup or leaf.
|
|
-- wrap (lit a <> lit b <> group c) ==
|
|
-- wrap (lit a <> group (orElse (lit " ") (lit "\n")
|
|
Pretty.wrap : Pretty txt -> Pretty txt
|
|
Pretty.wrap p = Pretty (Wrap () (Pretty.get p))
|
|
|
|
-- If `p1` fits on the current line at its preferred width,
|
|
-- it will be chosen, otherwise `p2` is chosen.
|
|
Pretty.orElse : Pretty txt -> Pretty txt -> Pretty txt
|
|
Pretty.orElse p1 p2 = Pretty (OrElse () (Pretty.get p1) (Pretty.get p2))
|
|
|
|
-- Prefixes all lines of `p` by `by`.
|
|
Pretty.indent : Pretty txt -> Pretty txt -> Pretty txt
|
|
Pretty.indent by p = Pretty (Indent () (Pretty.get by) (Pretty.get by) (Pretty.get p))
|
|
|
|
-- Prefixes the first line of `p` with `initialIndent`, and
|
|
-- subsequent lines by `indentAfterNewline`.
|
|
Pretty.indent' : Pretty txt -> Pretty txt -> Pretty txt -> Pretty txt
|
|
Pretty.indent' initialIndent indentAfterNewline p =
|
|
Pretty (Indent () (Pretty.get initialIndent)
|
|
(Pretty.get indentAfterNewline)
|
|
(Pretty.get p))
|
|
|
|
Pretty.append : Pretty txt -> Pretty txt -> Pretty txt
|
|
Pretty.append p1 p2 =
|
|
use Pretty.Annotated Empty Append
|
|
match (Pretty.get p1, Pretty.get p2) with
|
|
(_, Empty) -> p1
|
|
(Empty, _) -> p2
|
|
(Append _ ps1, Append _ ps2) -> Pretty (Append () (ps1 List.++ ps2))
|
|
(Append _ ps1, p2) -> Pretty (Append () (ps1 :+ p2))
|
|
(p1, Append _ ps2) -> Pretty (Append () (p1 +: ps2))
|
|
(p1,p2) -> Pretty (Append () [p1,p2])
|
|
|
|
Pretty.join : [Pretty txt] -> Pretty txt
|
|
Pretty.join =
|
|
go acc = cases [] -> acc
|
|
h +: t -> go (append acc h) t
|
|
go Pretty.empty
|
|
|
|
Pretty.sepBy : Pretty txt -> [Pretty txt] -> Pretty txt
|
|
Pretty.sepBy sep ps =
|
|
go acc insertSep = cases
|
|
[] -> acc
|
|
ps | insertSep -> go (append acc sep) false ps
|
|
h +: t -> go (append acc h) true t
|
|
go Pretty.empty false ps
|
|
|
|
syntax.doc.docs = cases [d] -> d
|
|
ds -> Docs ds
|
|
syntax.doc.word = Word
|
|
syntax.doc.bold = Doc2.Bold
|
|
syntax.doc.italic = Italic
|
|
syntax.doc.strikethrough = Strikethrough
|
|
syntax.doc.paragraph = Paragraph
|
|
syntax.doc.embedTermLink tm =
|
|
guid = "b7a4fb87e34569319591130bf3ec6e24"
|
|
Right (Doc2.term tm)
|
|
syntax.doc.embedTypeLink typ =
|
|
guid = "b7a4fb87e34569319591130bf3ec6e24"
|
|
Left typ
|
|
syntax.doc.source t = Special (Source t)
|
|
syntax.doc.signature ts = Special (Signature ts)
|
|
syntax.doc.inlineSignature t = Special (InlineSignature t)
|
|
syntax.doc.inlineEval e = Special (InlineEval (Doc2.term e))
|
|
syntax.doc.embedSignatureLink tm =
|
|
guid = "d9a4fb87e34569319591130bf3ec6e24"
|
|
Doc2.term tm
|
|
syntax.doc.code c = Code c
|
|
syntax.doc.codeBlock typ c = CodeBlock typ (word c)
|
|
syntax.doc.verbatim c = CodeBlock "raw" c
|
|
syntax.doc.evalBlock d = Special (Eval (Doc2.term d))
|
|
syntax.doc.eval a = Special (InlineEval (Doc2.term a))
|
|
syntax.doc.example n a = Special (Example n (Doc2.term a))
|
|
syntax.doc.link t = Special (Link t)
|
|
syntax.doc.transclude d =
|
|
guid = "b7a4fb87e34569319591130bf3ec6e24"
|
|
d
|
|
syntax.doc.namedLink = NamedLink
|
|
syntax.doc.bulletedList = BulletedList
|
|
syntax.doc.numberedList = NumberedList
|
|
syntax.doc.section = Section
|
|
|
|
unique[e25bc44d251ae0301517ad0bd02cbd294161dc89] type ConsoleText
|
|
= Plain Text
|
|
| Foreground ANSI.Color ConsoleText
|
|
| Background ANSI.Color ConsoleText
|
|
| Bold ConsoleText
|
|
| Underline ConsoleText
|
|
| Invert ConsoleText
|
|
|
|
unique[de2e0ee924578939213c950dfd8e0ba1047703ae] type ANSI.Color
|
|
= Black | Red | Green | Yellow | Blue | Magenta | Cyan | White
|
|
| BrightBlack | BrightRed | BrightGreen | BrightYellow | BrightBlue
|
|
| BrightMagenta | BrightCyan | BrightWhite
|
|
|
|
List.map : (a ->{g} b) ->{} [a] ->{g} [b]
|
|
List.map f as =
|
|
go acc = cases
|
|
[] -> acc
|
|
h +: t -> go (acc :+ f h) t
|
|
go [] as
|
|
|
|
Either.mapRight : (a -> b) -> Either e a -> Either e b
|
|
Either.mapRight f = cases
|
|
Right a -> Right (f a)
|
|
Left e -> Left e
|
|
|
|
syntax.doc.formatConsole : Doc2 -> Pretty (Either SpecialForm ConsoleText)
|
|
syntax.doc.formatConsole d =
|
|
lit t = Pretty.lit (Right (Plain t))
|
|
p1 <> p2 = Pretty.append p1 p2
|
|
nl = lit "\n"
|
|
map f p = Pretty.map (mapRight f) p
|
|
go = cases
|
|
Word t -> lit t
|
|
Code d -> lit "`" <> go d <> lit "`"
|
|
CodeBlock typ d ->
|
|
lit "``` " <> lit typ <> nl <>
|
|
go d <> nl <>
|
|
lit "```"
|
|
Italic d -> lit "*" <> go d <> lit "*"
|
|
Strikethrough d -> lit "~~" <> go d <> lit "~~"
|
|
Doc2.Bold d -> map ConsoleText.Bold (go d)
|
|
Style _ d -> go d
|
|
Blockquote d -> Pretty.indent (lit "> ") (go d)
|
|
Blankline -> lit "\n\n"
|
|
SectionBreak -> lit "܍"
|
|
Aside None d -> Pretty.indent (lit " | ") (go d)
|
|
Aside (Some title) d ->
|
|
Pretty.indent (lit " | ") (go (Doc2.Bold title) <> nl <> nl <> go d)
|
|
Callout icon d -> go (Aside icon d) --
|
|
Folded _ _closed open -> go open
|
|
Paragraph ds -> Pretty.wrap (Pretty.join (List.map go ds))
|
|
BulletedList ds ->
|
|
item d = Pretty.indent' (lit "* ") (lit " ") (go d)
|
|
items = List.map item ds
|
|
Pretty.sepBy nl items
|
|
NumberedList n ds ->
|
|
dot = ". "
|
|
w = Text.size (Nat.toText (n + List.size ds)) + size dot
|
|
num n = lit (Text.alignRightWith w ?\s (Nat.toText n Text.++ dot))
|
|
indent = lit (Text.repeat w " ")
|
|
item : Nat -> Doc2 -> Pretty (Either SpecialForm ConsoleText)
|
|
item n d = Pretty.indent' (num n) indent (go d)
|
|
items n acc = cases [] -> acc
|
|
d +: ds -> items (n+1) (acc :+ item n d) ds
|
|
Pretty.sepBy nl (items n [] ds)
|
|
Section title ds ->
|
|
t = Pretty.indent' (lit "# ") (lit " ") (go (Doc2.Bold title))
|
|
subs = List.map (d -> Pretty.indent (lit " ") (go d)) ds
|
|
Pretty.sepBy (nl <> nl) (t +: subs)
|
|
Docs ds -> Pretty.join (List.map go ds)
|
|
NamedLink name _target -> map ConsoleText.Underline (go name)
|
|
Special sf -> Pretty.lit (Left sf)
|
|
go d
|
|
|
|
doc1 = {{
|
|
|
|
# Unison documentation format
|
|
|
|
The syntax tries to be close to markdown.
|
|
|
|
## Basic formatting
|
|
|
|
Paragraphs are separated by one or more blanklines. There's syntax for bold, italics, and strikethrough text:
|
|
|
|
'''
|
|
_italics_ or *italics*
|
|
|
|
**bold text** or __moar bold text__
|
|
|
|
~~striken text~~
|
|
|
|
''some code''
|
|
|
|
[The Unison website](https://unisonweb.org)
|
|
|
|
A link to a term: {Some}. A link to a type {type List}.
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
_italics_ or *italics*
|
|
|
|
**bold text** or __moar bold text__
|
|
|
|
~~stricken text~~
|
|
|
|
''some code''
|
|
|
|
[The Unison website](https://unisonweb.org)
|
|
|
|
A link to a term: {Some}. A link to a type {type List}.
|
|
|
|
### Escaping formatting
|
|
|
|
If you want the text.
|
|
|
|
'''
|
|
{{ syntax.doc.word "__not bold__"}}
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
{{ syntax.doc.word "__not bold__" }}
|
|
|
|
If you have some inline text you want to leave unparsed and have it render in a monospace font, do:
|
|
|
|
'''
|
|
An example of bold text syntax: ''__some bold text__''
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
An example of bold text syntax: ''__some bold text__''
|
|
|
|
## Sections and subsections
|
|
|
|
'''
|
|
# Section title!
|
|
|
|
Sections consist of section titles followed by zero or more paragraphs or other section elements (such as subsections).
|
|
|
|
## Subsection title
|
|
|
|
* Item 1
|
|
* Item 2
|
|
|
|
## An empty subsection!
|
|
|
|
### Subsection 2.1
|
|
|
|
Some deeply nested content in subsection 2.1
|
|
'''
|
|
|
|
Sections start with a title, then zero or more documents, separated by blanklines. Sections whose title starts with ''##'' are subsections of sections whose title starts with one ''#''. Sections may be nested arbitrarily.
|
|
|
|
## Lists
|
|
|
|
### Bulleted lists
|
|
|
|
Bulleted lists can use ''+'', ''-'', or ''*'' for the bullets. They can be nested, to any depth:
|
|
|
|
'''
|
|
+ A
|
|
+ B
|
|
+ C
|
|
- C1
|
|
* C2
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
+ A
|
|
+ B
|
|
+ C
|
|
- C1
|
|
* C2
|
|
|
|
### Numbered lists
|
|
|
|
'''
|
|
1. A
|
|
2. B
|
|
3. C
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
1. A
|
|
2. B
|
|
3. C
|
|
|
|
The first number of the list determines the starting number in the rendered output. The other numbers are ignored:
|
|
|
|
'''
|
|
10. A
|
|
99. B
|
|
102. C
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
10. A
|
|
99. B
|
|
102. C
|
|
|
|
Numbered lists can be nested as well, and combined with bulleted lists:
|
|
|
|
'''
|
|
1. Wake up.
|
|
+ What am I doing here?
|
|
+ In this nested list.
|
|
2. Take shower.
|
|
3. Get dressed.
|
|
'''
|
|
|
|
1. Wake up.
|
|
+ What am I doing here?
|
|
+ In this nested list.
|
|
2. Take shower.
|
|
3. Get dressed.
|
|
|
|
## Evaluation
|
|
|
|
'''
|
|
Expressions can be evaluated inline, for instance @eval{1 + 1}.
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
Expressions can be evaluated inline, for instance @eval{1 + 1}.
|
|
|
|
Blocks of code can be evaluated as well, for instance:
|
|
|
|
'''
|
|
```
|
|
id x = x
|
|
|
|
id 99
|
|
```
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
```
|
|
id x = x
|
|
|
|
id 99
|
|
```
|
|
|
|
## Including Unison source code
|
|
|
|
'''
|
|
@source{ type Optional, id }
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
@source{ type Optional, id }
|
|
|
|
You can also render just the signatures of a collection of terms:
|
|
|
|
'''
|
|
@signatures{ id, Some, None }
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
@signatures{ id, Some, None }
|
|
|
|
You can reference a signature inline, like so
|
|
|
|
'''
|
|
An inline signature @signature{id}.
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
An inline signature @signature{id}.
|
|
|
|
## Including other documents
|
|
|
|
'''
|
|
"And what is the use of a book," thought {{name}}, "without pictures or conversations?"
|
|
|
|
* [The documentation]({{baseUrl}}/docs)
|
|
'''
|
|
|
|
"And what is the use of a book," thought {{name}}, "without pictures or conversations?"
|
|
|
|
## Non-unison code blocks
|
|
|
|
A code block with no syntax highlighting starts with at least two {{ code (word "'") }} characters, and is terminated by the same number of {{ code (word "'") }} characters.
|
|
|
|
''''
|
|
'''
|
|
Not formatted. Rendered as a code block with no syntax highlighting.
|
|
'''
|
|
''''
|
|
|
|
Renders as:
|
|
|
|
'''
|
|
Not formatted. Rendered as a code block with no syntax highlighting.
|
|
'''
|
|
|
|
You can use triple (or greater) backticks plus a language name for blocks with syntax highlighting.
|
|
|
|
'''
|
|
``` Haskell
|
|
-- A fenced code block which isn't parsed by Unison
|
|
reverse = foldl (flip (:)) []
|
|
```
|
|
|
|
``` Scala
|
|
// A fenced code block which isn't parsed by Unison
|
|
def reverse[A](xs: List[A]) =
|
|
xs.foldLeft(Nil : List[A])((acc,a) => a +: acc)
|
|
```
|
|
'''
|
|
|
|
Renders as:
|
|
|
|
``` Haskell
|
|
-- A fenced code block which isn't parsed by Unison
|
|
reverse = foldl (flip (:)) []
|
|
```
|
|
|
|
``` Scala
|
|
// A fenced code block which isn't parsed by Unison
|
|
def reverse[A](xs: List[A]) =
|
|
xs.foldLeft(Nil : List[A])((acc,a) => a +: acc)
|
|
```
|
|
}}
|
|
|
|
name = {{ Alice }}
|
|
baseUrl = {{ https://www.unisonweb.org }}
|
|
|