New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parse markdown descriptions #1106
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@byorgey its only in a MVP stage right now, but it already caught this inaccuracy:
parse scenario "data/scenarios/Tutorials/requireinv.yaml": FAIL
test/integration/Main.hs:115:
Aeson exception:
Error in $.objectives[0].goal[0]: 1:8:
|
1 | require
| ^
reserved word 'require' cannot be used as variable name
Because require
is not a command we can not use it on its own. 😄
Thinking about this a bit, maybe I could handle reserved words. It would require (pun intended) a bit more work to highlight them properly later though. 🤔
I think we should not use them for entities though and only use code for valid code snippets.
src/Data/Text/Markdown.hs
Outdated
readTerm txt & \case | ||
Left e -> Left (T.unpack e) | ||
Right Nothing -> Left "empty code" | ||
Right (Just s) -> case processParsedTerm s of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We currently use inline code for types like dir -> cmd unit
.
I think I can solve the type signatures as an alternative parse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we can make a parallel to readTerm
for types, like readType = runParser (fully parseType)
. If readTerm
fails you can just try running readType
too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I turned types to "raw inlines" for now:
`cmd a`{=type}
src/Swarm/TUI/View/Objective.hs
Outdated
titleWidget = maybe (txt "?") withEllipsis textSource | ||
|
||
singleGoalDetails :: GoalEntry -> Widget Name | ||
singleGoalDetails = \case | ||
Goal _gs obj -> displayParagraphs $ obj ^. objectiveGoal | ||
Goal _gs obj -> displayParagraphs . map Markdown.toText $ obj ^. objectiveGoal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to change to properly support the whole markdown text (with code) instead of a list of paragraphs.
I suppose it might make sense to use [[StreamNode]]
as paragraphs so that we can add padding.
src/Data/Text/Markdown.hs
Outdated
fromGeneralNode (CMark.Node p t cs) = case t of | ||
CMark.DOCUMENT -> Node Document <$> mapM fromGeneralNode cs | ||
CMark.PARAGRAPH -> Node Paragraph <$> mapM fromGeneralNode cs | ||
CMark.SOFTBREAK -> leaf $ LeafText "\n" -- ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to https://github.github.com/gfm/#soft-line-breaks it seems like a SOFTBREAK
is what we get at the end of a physical line of parsed text which does not end with two or more spaces. Typically we ignore such breaks and just reflow the text, so I would think we should not generate a LeafText "\n"
here, unless I am misunderstanding something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might need to use a space instead of newline here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: check that spacing is preserved.
src/Data/Text/Markdown.hs
Outdated
readTerm txt & \case | ||
Left e -> Left (T.unpack e) | ||
Right Nothing -> Left "empty code" | ||
Right (Just s) -> case processParsedTerm s of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we can make a parallel to readTerm
for types, like readType = runParser (fully parseType)
. If readTerm
fails you can just try running readType
too.
May be able to reduce likelihood of #1086 by having a autogenerated table of the commands and the tutorials they are introduced in. This work is related to #1106 in that robot commands should be given distinct markup (backticks). ## Demo scripts/play.sh generate pedagogy **Updated:** See [rendered output](https://gist.github.com/kostmo/d4af3a6814e65fc6d455fd34b41552d3). ## New tests scripts/run-tests.sh --test-arguments '--pattern "Pedagogical soundness"' Note that the test for `crash.yaml` is currently failing because the `Give` command (and some others) are utilized in this tutorial without having been mentioned in the description or in earlier tutorials. Additionally, the "bug" described in [this comment](#1089 (comment)) **should** be caught by these tests (i.e. fail the tests) since the embedded `solution` code in the YAML file utilizes the `give` command. That is, if it currently weren't for [this issue](https://github.com/swarm-game/swarm/pull/1186/files#r1152789153).
Co-authored-by: Restyled.io <commits@restyled.io>
Huzzah! 🥳 Turns out CommonMark has a neat extension that allows me to annotate inline code as entities/types/invalid code snippets. @kostmo If it is OK, I would switch from CMark-GFM to CommonMark. AFAIK it was only used in one place and the change was simple one-liner. |
@byorgey @kostmo I rewrote the implementation from CMark-GFM to CommonMark and while it is a bit of a DIY project, I hope it will make reading descriptions a little easier. 🙂 For reference, the markdown highlighting conventions I went with are:
If we want to do something else with any of those cases, they should be easy to grep and replace. |
txtLookups = M.fromList $ map (syntax . constInfo &&& id) commandConsts | ||
allCode = concatMap findCode goalTextParagraphs | ||
filterConst :: Syntax -> [Const] | ||
filterConst sx = mapMaybe toConst $ universe (sx ^. sTerm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kostmo this is one of the little nice things a parsed code gives us. 🤩
Hopefully universe
works just as well as your original implementation, but please check that I did not break it. 😅
Nice! I'm working on a detailed review, hopefully finished later today. |
src/Data/Text/Markdown.hs
Outdated
-- | Get chunks of nodes not exceeding length and broken at word boundary. | ||
-- | ||
-- The split will end when no more nodes (then words) can fit or on 'ParagraphBreak'. | ||
chunksOf :: Int -> [StreamNode] -> [[StreamNode]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a shame we seem to be reimplementing some of the functionality of https://hackage.haskell.org/package/word%2Dwrap ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are doing slightly more - we have annotated chunks of text, which we break while keeping the annotation.
Maybe this could be generalised as some kind of traversal?
Co-Authored-By: Brent Yorgey <byorgey@gmail.com> Co-authored-by: Brent Yorgey <byorgey@gmail.com>
Co-Authored-By: Brent Yorgey <byorgey@gmail.com> Co-authored-by: Brent Yorgey <byorgey@gmail.com>
Co-authored-by: Restyled.io <commits@restyled.io>
🚀 |
@byorgey odd, it looks like if you used old exe with new data. 😕 It worked fir me on the move tutorial, but I did not check alk of them. I will test it with autoplay and add a script to go through all of them. |
Oh, I see, the goal dialog is formatted properly, but the formatting doesn't show up when you look at the description of an entity. |
Document Text -> Document Syntax
)move
- valid swarm code (the easy to write default)wedge
{=entity} - for swarm entitiesunit
{=type} - for swarm typesrequire <a> <b>
{=snippet} - raw snippets for invalid code