mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-23 16:28:02 +03:00
530 lines
13 KiB
Plaintext
530 lines
13 KiB
Plaintext
{-
|
|
- [x] Debug the lexer/parser combination
|
|
- [x] Implement display logic for doc type (Unison side)
|
|
- [x] Add to IOSource
|
|
- [x] Implement display logic for new doc type in DisplayValues
|
|
- [x] (Later) docs command should look for foo.doc if nothing is linked, or just have it do: display foo.doc
|
|
- [x] (Later) Instant docs preview
|
|
- [x] Review with Simon, Rúnar, to see if we're missing any elements
|
|
- [x] Add missing element types to syntax tree
|
|
- [ ] Write illustrative transcript (and possibly separate tests)
|
|
- [ ] PR writeup
|
|
- [ ] (Later) `data DisplayObject b a = BuiltinObject b | MissingObject ShortHash | UserObject a`
|
|
- [ ] (Later) Pretty-printer should reverse the syntax
|
|
- [ ] (Later) Top level types should allow anon doc blocks
|
|
- [ ] (Later) Remove backticks syntax
|
|
- [ ] (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 named link to the ''List'' 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 }}
|
|
|