From 7745fbba4be701cb6bbae0d26cb19eac90798c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAnar?= Date: Wed, 22 Sep 2021 11:07:29 -0400 Subject: [PATCH 1/3] Fix emphasis roundtrip in docs --- parser-typechecker/src/Unison/Lexer.hs | 66 ++++---- parser-typechecker/src/Unison/TermPrinter.hs | 11 +- unison-src/transcripts-round-trip/main.md | 18 ++ .../transcripts-round-trip/main.output.md | 158 ++++++++++++------ 4 files changed, 170 insertions(+), 83 deletions(-) diff --git a/parser-typechecker/src/Unison/Lexer.hs b/parser-typechecker/src/Unison/Lexer.hs index cf6bc3b23..3c0349ddb 100644 --- a/parser-typechecker/src/Unison/Lexer.hs +++ b/parser-typechecker/src/Unison/Lexer.hs @@ -342,22 +342,30 @@ lexemes' eof = P.optional space >> do isPrefixOf "}}" word || all (== '#') word - wordy ok = wrap "syntax.docWord" . tok . fmap Textual . P.try $ do - let end = P.lookAhead $ void docClose - <|> void docOpen - <|> void (CP.satisfy isSpace) - <|> void (CP.satisfy (not . ok)) - word <- P.someTill (CP.satisfy (\ch -> not (isSpace ch) && ok ch)) end - guard (not $ reserved word) + wordy closing = wrap "syntax.docWord" . tok . fmap Textual . P.try $ do + let end = + P.lookAhead + $ void docClose + <|> void docOpen + <|> void (CP.satisfy isSpace) + <|> void closing + word <- P.manyTill (CP.satisfy (\ch -> not (isSpace ch))) end + guard (not $ reserved word || null word) pure word - leafy ok = groupy ok gs - where - gs = link <|> externalLink <|> exampleInline <|> expr - <|> boldOrItalicOrStrikethrough ok <|> verbatim - <|> atDoc <|> wordy ok + -- escaped :: P Char + -- escaped = char '\\' *> P.choice (map char codes) + -- where + -- codes = + -- ['\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '#', '+', '-', '.', '!'] - leaf = leafy (const True) + leafy closing = groupy closing gs + where + gs = link <|> externalLink <|> exampleInline <|> expr + <|> boldOrItalicOrStrikethrough closing <|> verbatim + <|> atDoc <|> wordy closing + + leaf = leafy mzero atDoc = src <|> evalInline <|> signature <|> signatureInline where @@ -403,9 +411,9 @@ lexemes' eof = P.optional space >> do signatureLink = wrap "syntax.docEmbedSignatureLink" $ tok (symbolyId <|> wordyId) <* CP.space - groupy ok p = do + groupy closing p = do (start,p,stop) <- positioned p - after <- P.optional . P.try $ leafy ok + after <- P.optional . P.try $ leafy closing pure $ case after of Nothing -> p Just after -> @@ -486,28 +494,30 @@ lexemes' eof = P.optional space >> do verbatim <- tok $ Textual . trim <$> P.someTill CP.anyChar ([] <$ lit fence) pure (name <> verbatim) - boldOrItalicOrStrikethrough ok = do - let start = some (CP.satisfy (== '*')) <|> some (CP.satisfy (== '_')) <|> some (CP.satisfy (== '~')) - name s = if take 1 s == "~" then "syntax.docStrikethrough" - else if length s > 1 then "syntax.docBold" - else "syntax.docItalic" - (end,ch) <- P.try $ do - end@(ch:_) <- start + boldOrItalicOrStrikethrough closing = do + let start = + some (CP.satisfy (== '*')) <|> some (CP.satisfy (== '_')) <|> some + (CP.satisfy (== '~')) + name s = if take 1 s == "~" + then "syntax.docStrikethrough" + else if length s > 1 then "syntax.docBold" else "syntax.docItalic" + end <- P.try $ do + end <- start P.lookAhead (CP.satisfy (not . isSpace)) - pure (end,ch) - wrap (name end) . wrap "syntax.docParagraph" $ - join <$> P.someTill (leafy (\c -> ok c && c /= ch) <* nonNewlineSpaces) - (lit end) + pure end + wrap (name end) . wrap "syntax.docParagraph" $ join <$> P.someTill + (leafy (closing <|> (void $ lit end)) <* nonNewlineSpaces) + (lit end) externalLink = P.label "hyperlink (example: [link name](https://destination.com))" $ wrap "syntax.docNamedLink" $ do _ <- lit "[" - p <- leafies (/= ']') + p <- leafies (void $ char ']') _ <- lit "]" _ <- lit "(" target <- wrap "syntax.docGroup" . wrap "syntax.docJoin" $ - link <|> fmap join (P.some (expr <|> wordy (/= ')'))) + link <|> fmap join (P.some (expr <|> wordy (char ')'))) _ <- lit ")" pure (p <> target) diff --git a/parser-typechecker/src/Unison/TermPrinter.hs b/parser-typechecker/src/Unison/TermPrinter.hs index 644214deb..c381253c9 100644 --- a/parser-typechecker/src/Unison/TermPrinter.hs +++ b/parser-typechecker/src/Unison/TermPrinter.hs @@ -1342,7 +1342,16 @@ prettyDoc2 ppe ac tm = case tm of (toDocItalic ppe -> Just d) -> PP.group $ "*" <> rec d <> "*" (toDocBold ppe -> Just d) -> - PP.group $ "__" <> rec d <> "__" + let inner = rec d + numUnderscores = + case + filter (\s -> take 2 s == "__") + $ group (PP.toPlainUnbroken $ PP.syntaxToColor inner) + of + [] -> 2 + x -> 1 + (maximum $ map length x) + underscores = replicate numUnderscores '_' + in PP.group $ PP.string underscores <> inner <> PP.string underscores (toDocStrikethrough ppe -> Just d) -> PP.group $ "~~" <> rec d <> "~~" (toDocGroup ppe -> Just d) -> diff --git a/unison-src/transcripts-round-trip/main.md b/unison-src/transcripts-round-trip/main.md index cf18aaec7..43e6fcffa 100644 --- a/unison-src/transcripts-round-trip/main.md +++ b/unison-src/transcripts-round-trip/main.md @@ -152,3 +152,21 @@ foo = .> load scratch.u ``` +## Emphasis in docs inserts the right number of underscores + +Regression test for https://github.com/unisonweb/unison/issues/2408 + +```unison:hide +myDoc = {{ **my text** __my text__ **MY_TEXT** ___MY__TEXT___ }} +``` + +```ucm +.> add +.> edit myDoc +.> undo +``` + +``` ucm +.> load scratch.u +``` + diff --git a/unison-src/transcripts-round-trip/main.output.md b/unison-src/transcripts-round-trip/main.output.md index c933dddec..ff6919692 100644 --- a/unison-src/transcripts-round-trip/main.output.md +++ b/unison-src/transcripts-round-trip/main.output.md @@ -34,15 +34,15 @@ x = 1 + 1 most recent, along with the command that got us there. Try: `fork 2 .old` - `fork #pqvd5behc2 .old` to make an old namespace + `fork #bt17giel42 .old` to make an old namespace accessible again, - `reset-root #pqvd5behc2` to reset the root namespace and + `reset-root #bt17giel42` to reset the root namespace and its history to that of the specified namespace. - 1. #8rn1an5gj8 : add - 2. #pqvd5behc2 : builtins.mergeio + 1. #agadr8gg6g : add + 2. #bt17giel42 : builtins.mergeio 3. #sjg2v58vn2 : (initial reflogged namespace) .> reset-root 2 @@ -116,17 +116,17 @@ Without the above stanza, the `edit` will send the definition to the most recent most recent, along with the command that got us there. Try: `fork 2 .old` - `fork #pqvd5behc2 .old` to make an old namespace + `fork #bt17giel42 .old` to make an old namespace accessible again, - `reset-root #pqvd5behc2` to reset the root namespace and + `reset-root #bt17giel42` to reset the root namespace and its history to that of the specified namespace. - 1. #dbvse9969b : add - 2. #pqvd5behc2 : reset-root #pqvd5behc2 - 3. #8rn1an5gj8 : add - 4. #pqvd5behc2 : builtins.mergeio + 1. #rhf1s808fb : add + 2. #bt17giel42 : reset-root #bt17giel42 + 3. #agadr8gg6g : add + 4. #bt17giel42 : builtins.mergeio 5. #sjg2v58vn2 : (initial reflogged namespace) .> reset-root 2 @@ -191,19 +191,19 @@ f x = let most recent, along with the command that got us there. Try: `fork 2 .old` - `fork #pqvd5behc2 .old` to make an old namespace + `fork #bt17giel42 .old` to make an old namespace accessible again, - `reset-root #pqvd5behc2` to reset the root namespace and + `reset-root #bt17giel42` to reset the root namespace and its history to that of the specified namespace. - 1. #clsum27pr1 : add - 2. #pqvd5behc2 : reset-root #pqvd5behc2 - 3. #dbvse9969b : add - 4. #pqvd5behc2 : reset-root #pqvd5behc2 - 5. #8rn1an5gj8 : add - 6. #pqvd5behc2 : builtins.mergeio + 1. #gj5agagj7s : add + 2. #bt17giel42 : reset-root #bt17giel42 + 3. #rhf1s808fb : add + 4. #bt17giel42 : reset-root #bt17giel42 + 5. #agadr8gg6g : add + 6. #bt17giel42 : builtins.mergeio 7. #sjg2v58vn2 : (initial reflogged namespace) .> reset-root 2 @@ -273,21 +273,21 @@ h xs = match xs with most recent, along with the command that got us there. Try: `fork 2 .old` - `fork #pqvd5behc2 .old` to make an old namespace + `fork #bt17giel42 .old` to make an old namespace accessible again, - `reset-root #pqvd5behc2` to reset the root namespace and + `reset-root #bt17giel42` to reset the root namespace and its history to that of the specified namespace. - 1. #acngtb04a8 : add - 2. #pqvd5behc2 : reset-root #pqvd5behc2 - 3. #clsum27pr1 : add - 4. #pqvd5behc2 : reset-root #pqvd5behc2 - 5. #dbvse9969b : add - 6. #pqvd5behc2 : reset-root #pqvd5behc2 - 7. #8rn1an5gj8 : add - 8. #pqvd5behc2 : builtins.mergeio + 1. #3igmh2it4p : add + 2. #bt17giel42 : reset-root #bt17giel42 + 3. #gj5agagj7s : add + 4. #bt17giel42 : reset-root #bt17giel42 + 5. #rhf1s808fb : add + 6. #bt17giel42 : reset-root #bt17giel42 + 7. #agadr8gg6g : add + 8. #bt17giel42 : builtins.mergeio 9. #sjg2v58vn2 : (initial reflogged namespace) .> reset-root 2 @@ -353,23 +353,23 @@ foo n _ = n most recent, along with the command that got us there. Try: `fork 2 .old` - `fork #pqvd5behc2 .old` to make an old namespace + `fork #bt17giel42 .old` to make an old namespace accessible again, - `reset-root #pqvd5behc2` to reset the root namespace and + `reset-root #bt17giel42` to reset the root namespace and its history to that of the specified namespace. - 1. #j32i1remee : add - 2. #pqvd5behc2 : reset-root #pqvd5behc2 - 3. #acngtb04a8 : add - 4. #pqvd5behc2 : reset-root #pqvd5behc2 - 5. #clsum27pr1 : add - 6. #pqvd5behc2 : reset-root #pqvd5behc2 - 7. #dbvse9969b : add - 8. #pqvd5behc2 : reset-root #pqvd5behc2 - 9. #8rn1an5gj8 : add - 10. #pqvd5behc2 : builtins.mergeio + 1. #jsnoueu9le : add + 2. #bt17giel42 : reset-root #bt17giel42 + 3. #3igmh2it4p : add + 4. #bt17giel42 : reset-root #bt17giel42 + 5. #gj5agagj7s : add + 6. #bt17giel42 : reset-root #bt17giel42 + 7. #rhf1s808fb : add + 8. #bt17giel42 : reset-root #bt17giel42 + 9. #agadr8gg6g : add + 10. #bt17giel42 : builtins.mergeio 11. #sjg2v58vn2 : (initial reflogged namespace) .> reset-root 2 @@ -432,25 +432,25 @@ foo = most recent, along with the command that got us there. Try: `fork 2 .old` - `fork #pqvd5behc2 .old` to make an old namespace + `fork #bt17giel42 .old` to make an old namespace accessible again, - `reset-root #pqvd5behc2` to reset the root namespace and + `reset-root #bt17giel42` to reset the root namespace and its history to that of the specified namespace. - 1. #o6r7803627 : add - 2. #pqvd5behc2 : reset-root #pqvd5behc2 - 3. #j32i1remee : add - 4. #pqvd5behc2 : reset-root #pqvd5behc2 - 5. #acngtb04a8 : add - 6. #pqvd5behc2 : reset-root #pqvd5behc2 - 7. #clsum27pr1 : add - 8. #pqvd5behc2 : reset-root #pqvd5behc2 - 9. #dbvse9969b : add - 10. #pqvd5behc2 : reset-root #pqvd5behc2 - 11. #8rn1an5gj8 : add - 12. #pqvd5behc2 : builtins.mergeio + 1. #vbmanbqtlh : add + 2. #bt17giel42 : reset-root #bt17giel42 + 3. #jsnoueu9le : add + 4. #bt17giel42 : reset-root #bt17giel42 + 5. #3igmh2it4p : add + 6. #bt17giel42 : reset-root #bt17giel42 + 7. #gj5agagj7s : add + 8. #bt17giel42 : reset-root #bt17giel42 + 9. #rhf1s808fb : add + 10. #bt17giel42 : reset-root #bt17giel42 + 11. #agadr8gg6g : add + 12. #bt17giel42 : builtins.mergeio 13. #sjg2v58vn2 : (initial reflogged namespace) .> reset-root 2 @@ -470,3 +470,53 @@ foo = foo : Text ``` +## Emphasis in docs inserts the right number of underscores + +Regression test for https://github.com/unisonweb/unison/issues/2408 + +```unison +myDoc = {{ **my text** __my text__ **MY_TEXT** ___MY__TEXT___ }} +``` + +```ucm +.> add + + ⍟ I've added these definitions: + + myDoc : Doc2 + +.> edit myDoc + + ☝️ + + I added these definitions to the top of + /Users/runar/work/unison/scratch.u + + myDoc : Doc2 + myDoc = + {{ __my text__ __my text__ __MY_TEXT__ ___MY__TEXT___ }} + + You can edit them there, then do `update` to replace the + definitions currently in this namespace. + +.> undo + + Here are the changes I undid + + Added definitions: + + 1. myDoc : Doc2 + +``` +```ucm +.> load scratch.u + + I found and typechecked these definitions in scratch.u. If you + do an `add` or `update`, here's how your codebase would + change: + + ⍟ These new definitions are ok to `add`: + + myDoc : Doc2 + +``` From 49ea7731fd7ae2069e151b36ba6f7db87058878a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAnar?= Date: Wed, 22 Sep 2021 15:23:53 -0400 Subject: [PATCH 2/3] Changes to doc basic formatting syntax. * Allow ~~ to contain ~ * Make ** bold and __ italic --- parser-typechecker/src/Unison/Lexer.hs | 2 +- parser-typechecker/src/Unison/TermPrinter.hs | 33 ++++++++++++------- unison-src/transcripts-round-trip/main.md | 2 +- .../transcripts-round-trip/main.output.md | 7 ++-- .../doc.md.files/syntax.u | 6 ++-- .../transcripts-using-base/doc.output.md | 8 ++--- 6 files changed, 35 insertions(+), 23 deletions(-) diff --git a/parser-typechecker/src/Unison/Lexer.hs b/parser-typechecker/src/Unison/Lexer.hs index 3c0349ddb..90180949e 100644 --- a/parser-typechecker/src/Unison/Lexer.hs +++ b/parser-typechecker/src/Unison/Lexer.hs @@ -500,7 +500,7 @@ lexemes' eof = P.optional space >> do (CP.satisfy (== '~')) name s = if take 1 s == "~" then "syntax.docStrikethrough" - else if length s > 1 then "syntax.docBold" else "syntax.docItalic" + else if take 1 s == "*" then "syntax.docBold" else "syntax.docItalic" end <- P.try $ do end <- start P.lookAhead (CP.satisfy (not . isSpace)) diff --git a/parser-typechecker/src/Unison/TermPrinter.hs b/parser-typechecker/src/Unison/TermPrinter.hs index c381253c9..ddeb27c2c 100644 --- a/parser-typechecker/src/Unison/TermPrinter.hs +++ b/parser-typechecker/src/Unison/TermPrinter.hs @@ -1311,6 +1311,16 @@ prettyDoc2 ppe ac tm = case tm of S.DocDelimiter "}}" bail tm = brace (pretty0 ppe ac tm) + -- Finds the longest run of a character and return a run one longer than that + oneMore c inner = replicate num c + where + num = + case + filter (\s -> take 2 s == "__") + $ group (PP.toPlainUnbroken $ PP.syntaxToColor inner) + of + [] -> 2 + x -> 1 + (maximum $ map length x) go :: Width -> Term3 v PrintAnnotation -> Pretty SyntaxText go hdr = \case (toDocTransclude ppe -> Just d) -> @@ -1336,24 +1346,23 @@ prettyDoc2 ppe ac tm = case tm of (toDocWord ppe -> Just t) -> PP.text t (toDocCode ppe -> Just d) -> - PP.group ("''" <> rec d <> "''") + let inner = rec d + quotes = oneMore '\'' inner + in PP.group $ PP.string quotes <> inner <> PP.string quotes (toDocJoin ppe -> Just ds) -> foldMap rec ds (toDocItalic ppe -> Just d) -> - PP.group $ "*" <> rec d <> "*" + let inner = rec d + underscores = oneMore '_' inner + in PP.group $ PP.string underscores <> inner <> PP.string underscores (toDocBold ppe -> Just d) -> let inner = rec d - numUnderscores = - case - filter (\s -> take 2 s == "__") - $ group (PP.toPlainUnbroken $ PP.syntaxToColor inner) - of - [] -> 2 - x -> 1 + (maximum $ map length x) - underscores = replicate numUnderscores '_' - in PP.group $ PP.string underscores <> inner <> PP.string underscores + stars = oneMore '*' inner + in PP.group $ PP.string stars <> inner <> PP.string stars (toDocStrikethrough ppe -> Just d) -> - PP.group $ "~~" <> rec d <> "~~" + let inner = rec d + quotes = oneMore '~' inner + in PP.group $ PP.string quotes <> inner <> PP.string quotes (toDocGroup ppe -> Just d) -> PP.group $ rec d (toDocColumn ppe -> Just ds) -> diff --git a/unison-src/transcripts-round-trip/main.md b/unison-src/transcripts-round-trip/main.md index 43e6fcffa..0cfd4d50e 100644 --- a/unison-src/transcripts-round-trip/main.md +++ b/unison-src/transcripts-round-trip/main.md @@ -157,7 +157,7 @@ foo = Regression test for https://github.com/unisonweb/unison/issues/2408 ```unison:hide -myDoc = {{ **my text** __my text__ **MY_TEXT** ___MY__TEXT___ }} +myDoc = {{ **my text** __my text__ **MY_TEXT** ___MY__TEXT___ ~~MY~TEXT~~ **MY*TEXT** }} ``` ```ucm diff --git a/unison-src/transcripts-round-trip/main.output.md b/unison-src/transcripts-round-trip/main.output.md index ff6919692..cb37d5fd6 100644 --- a/unison-src/transcripts-round-trip/main.output.md +++ b/unison-src/transcripts-round-trip/main.output.md @@ -475,7 +475,7 @@ foo = Regression test for https://github.com/unisonweb/unison/issues/2408 ```unison -myDoc = {{ **my text** __my text__ **MY_TEXT** ___MY__TEXT___ }} +myDoc = {{ **my text** __my text__ **MY_TEXT** ___MY__TEXT___ ~~MY~TEXT~~ **MY*TEXT** }} ``` ```ucm @@ -494,7 +494,10 @@ myDoc = {{ **my text** __my text__ **MY_TEXT** ___MY__TEXT___ }} myDoc : Doc2 myDoc = - {{ __my text__ __my text__ __MY_TEXT__ ___MY__TEXT___ }} + {{ + **my text** __my text__ **MY_TEXT** ___MY__TEXT___ + ~~MY~TEXT~~ **MY*TEXT** + }} You can edit them there, then do `update` to replace the definitions currently in this namespace. diff --git a/unison-src/transcripts-using-base/doc.md.files/syntax.u b/unison-src/transcripts-using-base/doc.md.files/syntax.u index 10b9b0292..a34ac8d50 100644 --- a/unison-src/transcripts-using-base/doc.md.files/syntax.u +++ b/unison-src/transcripts-using-base/doc.md.files/syntax.u @@ -5,7 +5,7 @@ basicFormatting = {{ Paragraphs are separated by one or more blanklines. Sections have a title and 0 or more paragraphs or other section elements. - Text can be __bold__, *italicized*, ~~strikethrough~~, or + Text can be **bold**, __italicized__, ~~strikethrough~~, or ''monospaced''. You can link to Unison terms, types, and external URLs: @@ -20,7 +20,7 @@ basicFormatting = {{ This is useful for creating documents programmatically or just including other documents. - *Next up:* {lists} + __Next up:__ {lists} }} lists = {{ @@ -168,7 +168,7 @@ This is an aside. {{ docAside {{ Some extra detail that doesn't belong in main t docBlockquote {{ "And what is the use of a book," thought Alice, "without pictures or conversation?" - *Lewis Carroll, Alice's Adventures in Wonderland* }} + _Lewis Carroll, Alice's Adventures in Wonderland_ }} }} {{ docTooltip {{Hover over me}} {{Extra detail}} }} diff --git a/unison-src/transcripts-using-base/doc.output.md b/unison-src/transcripts-using-base/doc.output.md index badb23bba..d8699b61f 100644 --- a/unison-src/transcripts-using-base/doc.output.md +++ b/unison-src/transcripts-using-base/doc.output.md @@ -113,8 +113,8 @@ and the rendered output using `display`: Sections have a title and 0 or more paragraphs or other section elements. - Text can be __bold__, *italicized*, ~~strikethrough~~, or - ''monospaced''. + Text can be **bold**, __italicized__, ~~strikethrough~~, + or ''monospaced''. You can link to Unison terms, types, and external URLs: @@ -129,7 +129,7 @@ and the rendered output using `display`: useful for creating documents programmatically or just including other documents. - *Next up:* {lists} + __Next up:__ {lists} }} .> display basicFormatting @@ -469,7 +469,7 @@ and the rendered output using `display`: "And what is the use of a book," thought Alice, "without pictures or conversation?" - *Lewis Carroll, Alice's Adventures in Wonderland* + __Lewis Carroll, Alice's Adventures in Wonderland__ }} }} {{ docTooltip {{ Hover over me }} {{ Extra detail }} }} From 671397661a5f0905e24bf41d7989c797cd021455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAnar?= Date: Wed, 22 Sep 2021 15:26:17 -0400 Subject: [PATCH 3/3] Remove commented-out code --- parser-typechecker/src/Unison/Lexer.hs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/parser-typechecker/src/Unison/Lexer.hs b/parser-typechecker/src/Unison/Lexer.hs index 90180949e..38fb22de1 100644 --- a/parser-typechecker/src/Unison/Lexer.hs +++ b/parser-typechecker/src/Unison/Lexer.hs @@ -353,12 +353,6 @@ lexemes' eof = P.optional space >> do guard (not $ reserved word || null word) pure word - -- escaped :: P Char - -- escaped = char '\\' *> P.choice (map char codes) - -- where - -- codes = - -- ['\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '#', '+', '-', '.', '!'] - leafy closing = groupy closing gs where gs = link <|> externalLink <|> exampleInline <|> expr