diff --git a/src/SSG/Djot/Inline.idr b/src/SSG/Djot/Inline.idr index 19b07ed..824221a 100644 --- a/src/SSG/Djot/Inline.idr +++ b/src/SSG/Djot/Inline.idr @@ -33,7 +33,6 @@ data Inline : Type where -- Combine adjacent `Text`s in the parsed output combineTexts : List1 Inline -> Eval (List1 Inline) -combineTexts xs@(Text c ::: []) = pure xs combineTexts (Text c ::: (Text d :: xs)) = combineTexts (Text (c ++ d) ::: xs) combineTexts (x ::: tail) = do @@ -49,6 +48,23 @@ combineTexts (x ::: tail) = do rest <- combineTexts' ys pure $ y :: rest +-- Combine adjacent soft line breaks into one +combineSoftBreaks : List1 Inline -> Eval (List1 Inline) +combineSoftBreaks (SoftLineBreak ::: (SoftLineBreak :: xs)) = + combineSoftBreaks (SoftLineBreak ::: xs) +combineSoftBreaks (head ::: tail) = do + tail <- combineSoftBreaks' tail + pure $ head ::: tail + where + combineSoftBreaks' : List Inline -> Eval (List Inline) + combineSoftBreaks' [] = pure [] + combineSoftBreaks' (x :: []) = pure [x] + combineSoftBreaks' (SoftLineBreak :: (SoftLineBreak :: xs)) = + combineSoftBreaks' (SoftLineBreak :: xs) + combineSoftBreaks' (x :: xs) = do + rest <- combineSoftBreaks' xs + pure $ x :: rest + -- Remove a trailing soft line break from a list of inlines removeTrailingSoftBreak : List1 Inline -> Eval (List1 Inline) removeTrailingSoftBreak (head ::: tail) = do @@ -66,6 +82,7 @@ removeTrailingSoftBreak (head ::: tail) = do postProcess : List1 Inline -> List1 Inline postProcess xs = eval $ do xs <- combineTexts xs + xs <- combineSoftBreaks xs xs <- removeTrailingSoftBreak xs pure xs @@ -91,6 +108,8 @@ nbsp = do softLineBreak : PS Inline softLineBreak = do + -- Slurp up any horizontal whitespace before the line break + _ <- spaces _ <- lineEnding -- Check to see if the next line is empty, if it is, we are at the end of the inline -- content, go ahead and bail @@ -98,6 +117,17 @@ softLineBreak = do Nothing <- tryMaybe blankLine | Just _ => throw "End of inline" load state + -- Slurp up any horizontal whitespace after the line break + _ <- spaces + pure $ SoftLineBreak + +escapedNewLine : PS Inline +escapedNewLine = do + -- Slurp up any horizontal whitespace before the line break + _ <- spaces + _ <- thisString "\\n" + -- Slurp up any horizontal whitespace after the line break + _ <- spaces pure $ SoftLineBreak --------------------- @@ -124,19 +154,15 @@ text = do -- Overall Inline Parser -- --------------------------- -inlineElementsNoNewlines : PS Inline -inlineElementsNoNewlines = oneOfE "" [ - nbsp - , escapedText - -- Text is last so that anything can superseed it - , text - ] - inlineElement : PS Inline inlineElement = oneOfE "" [ hardLineBreak , softLineBreak - , inlineElementsNoNewlines + , escapedNewLine + , nbsp + , escapedText + -- Text is last so that anything can superseed it + , text ] export diff --git a/src/SSG/Djot/Render.idr b/src/SSG/Djot/Render.idr index d9a4a58..b218f6b 100644 --- a/src/SSG/Djot/Render.idr +++ b/src/SSG/Djot/Render.idr @@ -9,6 +9,7 @@ import Data.String import Data.List1 import Data.List +import Control.Monad.Eval import Structures.Dependent.DList -- Maybe because specifically Soft line breaks don't generate any html of their @@ -24,10 +25,27 @@ renderInline NonBreakingSpace = renderInline (Text c) = Just (_ ** Text c) +combineTexts : (types : List String ** DList _ Html types) + -> Eval (types : List String ** DList _ Html types) +combineTexts (_ ** []) = pure (_ ** []) +-- We do a little bit of magic insert of whitespace, so we have some special handling for +-- nbsps to not insert spaces around them +combineTexts (_ ** (Text c :: Text " " :: Text " " :: rest)) = + combineTexts (_ ** Text (c ++ " ") :: Text " " :: rest) +combineTexts (_ ** (Text c :: Text " " :: Text d :: rest)) = + combineTexts (_ ** Text (c ++ " " ++ d) :: rest) +combineTexts (_ ** (Text c :: Text " " :: rest)) = + combineTexts (_ ** Text (c ++ " ") :: rest) +combineTexts (_ ** (Text c :: Text d :: rest)) = + combineTexts (_ ** Text (c ++ " " ++ d) :: rest) +combineTexts (_ ** (elem :: rest)) = do + (_ ** rest) <- combineTexts (_ ** rest) + pure $ (_ ** elem :: rest) + export renderInlines : List Inline -> (types : List String ** DList _ Html types) renderInlines xs = - fromList . catMaybes . map renderInline $ xs + eval . combineTexts . fromList . catMaybes . map renderInline $ xs headingLevel : HeaderLevel -> (h : String ** IsNormal h) headingLevel H1 = ("h1" ** IsH1) diff --git a/test/djot-to-html/002-linebreaks-and-nbsp/Main.idr b/test/djot-to-html/002-linebreaks-and-nbsp/Main.idr new file mode 100644 index 0000000..97d8771 --- /dev/null +++ b/test/djot-to-html/002-linebreaks-and-nbsp/Main.idr @@ -0,0 +1,16 @@ +module Main + +import SSG.Djot +import SSG.HTML + +import System +import System.File + +main : IO () +main = do + Right contents <- readFile "test.dj" + | Left err => do + printLn err + exitFailure + let parsed = djot contents + putStr . render . renderHtml $ parsed diff --git a/test/djot-to-html/002-linebreaks-and-nbsp/expected b/test/djot-to-html/002-linebreaks-and-nbsp/expected new file mode 100644 index 0000000..d344ee1 --- /dev/null +++ b/test/djot-to-html/002-linebreaks-and-nbsp/expected @@ -0,0 +1,26 @@ + + + +

A paragraph with a normal newline in the middle of it

+

+ A paragraph with a hard line break +
+ in the middle of it +

+

+ A paragraph with a hard line break +
+ in the middle of it with extra spaces +

+

+ A paragraph with a hard line break +
+ in the middle of it with no spaces +

+

A paragraph with an explicit soft line break in the middle of it

+

Multiple soft breaks should coalesce into one

+

Same should apply when mixing explicit and implied soft breaks

+

An escaped space should render as a nonbreaking space

+

We also want to test  multiple   nonbreaking    spaces     in a row

+ + \ No newline at end of file diff --git a/test/djot-to-html/002-linebreaks-and-nbsp/run b/test/djot-to-html/002-linebreaks-and-nbsp/run new file mode 100644 index 0000000..6b5ab53 --- /dev/null +++ b/test/djot-to-html/002-linebreaks-and-nbsp/run @@ -0,0 +1,6 @@ +rm -rf build/ + +flock "$1" pack -q install-deps test.ipkg +pack -q run test.ipkg + +rm -rf build/ diff --git a/test/djot-to-html/002-linebreaks-and-nbsp/test.dj b/test/djot-to-html/002-linebreaks-and-nbsp/test.dj new file mode 100644 index 0000000..24e3421 --- /dev/null +++ b/test/djot-to-html/002-linebreaks-and-nbsp/test.dj @@ -0,0 +1,22 @@ +A paragraph with a normal newline +in the middle of it + +A paragraph with a hard line break \ +in the middle of it + +A paragraph with a hard line break \ +in the middle of it with extra spaces + +A paragraph with a hard line break \ +in the middle of it with no spaces + +A paragraph with an explicit soft line break \n in the middle of it + +Multiple soft breaks should coalesce \n\n\n into one + +Same should apply when mixing explicit \n +and implied soft breaks + +An escaped space\ should render as a nonbreaking space + +We also want to test\ \ multiple\ \ \ nonbreaking\ \ \ \ spaces\ \ \ \ \ in a row diff --git a/test/djot-to-html/002-linebreaks-and-nbsp/test.ipkg b/test/djot-to-html/002-linebreaks-and-nbsp/test.ipkg new file mode 100644 index 0000000..0efef9e --- /dev/null +++ b/test/djot-to-html/002-linebreaks-and-nbsp/test.ipkg @@ -0,0 +1,7 @@ +package a-test + +depends = SSG + +main = Main + +executable = test