Basic Html Rendering

This commit is contained in:
Nathan McCarty 2025-02-21 05:13:19 -05:00
parent 6c36d6e62a
commit 2ce4579e08
9 changed files with 168 additions and 8 deletions

View file

@ -14,6 +14,7 @@ authors = "Nathan McCarty"
-- packages to add to search path -- packages to add to search path
depends = structures depends = structures
, tailrec
, eff , eff
, refined , refined
, elab-util , elab-util
@ -25,6 +26,7 @@ modules = SSG.Parser.Core
, SSG.Djot.Common , SSG.Djot.Common
, SSG.Djot.Inline , SSG.Djot.Inline
, SSG.Djot.Block , SSG.Djot.Block
, SSG.Djot.Render
, SSG.HTML , SSG.HTML
, SSG.HTML.ElementTypes , SSG.HTML.ElementTypes

47
bin/Djot.ipkg Normal file
View file

@ -0,0 +1,47 @@
package Djot
version = 0.1.0
authors = "Nathan McCarty"
-- maintainers =
-- license =
-- brief =
-- readme =
-- homepage =
-- sourceloc =
-- bugtracker =
-- the Idris2 version required (e.g. langversion >= 0.5.1)
-- langversion
-- packages to add to search path
depends = SSG
-- modules to install
-- modules =
-- main file (i.e. file to load at REPL)
main = Djot
-- name of executable
executable = "djot"
-- opts =
sourcedir = "src"
-- builddir =
-- outputdir =
-- script to run before building
-- prebuild =
-- script to run after building
-- postbuild =
-- script to run after building, before installing
-- preinstall =
-- script to run after installing
-- postinstall =
-- script to run before cleaning
-- preclean =
-- script to run after cleaning
-- postclean =

21
bin/src/Djot.idr Normal file
View file

@ -0,0 +1,21 @@
module Djot
import System
import System.File
import SSG.Djot
import SSG.HTML
main : IO ()
main = do
args <- getArgs
case args of
[_, file] => do
Right contents <- readFile file
| Left err => printLn err
let parsed = djot contents
printLn parsed
putStr . render $ renderHtml parsed
_ => do
putStrLn "?"
exitFailure

View file

@ -4,6 +4,11 @@ path = "."
ipkg = "SSG.ipkg" ipkg = "SSG.ipkg"
test = "test/test.ipkg" test = "test/test.ipkg"
[custom.all.Djot]
type = "local"
path = "bin"
ipkg = "Djot.ipkg"
[custom.all.SSG-test] [custom.all.SSG-test]
type = "local" type = "local"
path = "test" path = "test"

View file

@ -1,4 +1,17 @@
module SSG.Djot module SSG.Djot
import SSG.Parser.Util
import Control.Eff
import public SSG.Djot.Inline as SSG.Djot import public SSG.Djot.Inline as SSG.Djot
import public SSG.Djot.Block as SSG.Djot import public SSG.Djot.Block as SSG.Djot
import public SSG.Djot.Render as SSG.Djot
export
||| Parse a djot document
djot : String -> List Block
djot str =
case runPS blocks str of
Left _ => []
Right x => x

View file

@ -97,6 +97,7 @@ heading = do
-- Overall Block Parser -- -- Overall Block Parser --
-------------------------- --------------------------
export
block : PS Block block : PS Block
block = do block = do
-- eat up any blank lines -- eat up any blank lines
@ -106,6 +107,7 @@ block = do
, paragraph , paragraph
] ]
export
blocks : PS (List Block) blocks : PS (List Block)
blocks = many block blocks = many block

View file

@ -22,7 +22,7 @@ data Inline : Type where
HardLineBreak : Inline HardLineBreak : Inline
SoftLineBreak : Inline SoftLineBreak : Inline
NonBreakingSpace : Inline NonBreakingSpace : Inline
Text : (c : Char) -> Inline Text : (c : String) -> Inline
%runElab derive "Inline" [Show, Eq] %runElab derive "Inline" [Show, Eq]
@ -69,13 +69,13 @@ softLineBreak = do
escapedText : PS Inline escapedText : PS Inline
escapedText = do escapedText = do
c <- escapedChar c <- escapedChar
pure $ Text c pure $ Text (singleton c)
-- Any non-line-ending character can be part of regular text -- Any non-line-ending character can be part of regular text
text : PS Inline text : PS Inline
text = do text = do
c <- nonTerminal c <- nonTerminal
pure $ Text c pure $ Text (singleton c)
--------------------------- ---------------------------
-- Overall Inline Parser -- -- Overall Inline Parser --
@ -113,7 +113,7 @@ inlineFromString : String -> List (Inline)
inlineFromString str with (asList str) inlineFromString str with (asList str)
inlineFromString "" | [] = [] inlineFromString "" | [] = []
inlineFromString (strCons c str) | (c :: x) = inlineFromString (strCons c str) | (c :: x) =
Text c :: inlineFromString str | x Text (singleton c) :: inlineFromString str | x
export export
inlineFromString' : String -> List1 (Inline) inlineFromString' : String -> List1 (Inline)
@ -130,13 +130,13 @@ inlineFromString' str =
inlineTextSmoke : IO Bool inlineTextSmoke : IO Bool
inlineTextSmoke = inlineTextSmoke =
let input = "Hello World!" in let input = "Hello World!" in
golden input (map Text . unpack $ input) (map forget inline) golden input (map (Text . singleton) . unpack $ input) (map forget inline)
-- @@test Escaped Text -- @@test Escaped Text
inlineEscapedSmoke : IO Bool inlineEscapedSmoke : IO Bool
inlineEscapedSmoke = inlineEscapedSmoke =
let input = "Hello\\n\\*World" let input = "Hello\\n\\*World"
ref = inlineFromString "Hello" ++ [Text '\n', Text '*'] ++ inlineFromString "World" ref = inlineFromString "Hello" ++ [Text "\n", Text "*"] ++ inlineFromString "World"
in golden input ref (map forget inline) in golden input ref (map forget inline)
-- @@test Hard Line Break -- @@test Hard Line Break

70
src/SSG/Djot/Render.idr Normal file
View file

@ -0,0 +1,70 @@
module SSG.Djot.Render
import SSG.HTML
import SSG.Djot.Inline
import SSG.Djot.Block
import Data.String
import Data.List1
import Structures.Dependent.DList
export
renderInline : Inline -> (type : String ** Html type)
renderInline HardLineBreak =
(_ ** Void "br" [])
renderInline SoftLineBreak =
(_ ** Text "\n")
renderInline NonBreakingSpace =
(_ ** Text "&nbsp;")
renderInline (Text c) =
(_ ** Text c)
-- BUG: Coverage checker bug here?
partial
combineTexts : (types : List String ** DList _ Html types)
-> (types' : List String ** DList _ Html types')
combineTexts (_ ** []) = (_ ** [])
combineTexts xs@(_ ** (elem :: [])) = xs
combineTexts (_ ** Text content :: (Text str :: rest)) =
combineTexts (_ ** Text (content ++ str) :: rest)
combineTexts (_ ** Text content :: (next :: rest)) =
let (_ ** rest) = combineTexts (_ ** (next :: rest))
in (_ ** Text content :: rest)
combineTexts (_ ** (x :: (next :: rest))) =
let (_ ** rest) = combineTexts (_ ** (next :: rest))
in (_ ** x :: rest)
export
renderInlines : List Inline -> (types : List String ** DList _ Html types)
renderInlines xs = assert_total $
combineTexts . fromList . map renderInline $ xs
headingLevel : HeaderLevel -> (h : String ** IsNormal h)
headingLevel H1 = ("h1" ** IsH1)
headingLevel H2 = ("h2" ** IsH2)
headingLevel H3 = ("h3" ** IsH3)
headingLevel H4 = ("h4" ** IsH4)
headingLevel H5 = ("h5" ** IsH5)
headingLevel H6 = ("h6" ** IsH6)
export
renderBlock : Block -> (type : String ** Html type)
renderBlock (Paragraph contents) =
let (_ ** xs) = renderInlines $ forget contents
in (_ ** Normal "p" [] xs)
renderBlock (Heading level contents) =
let (_ ** xs) = renderInlines $ forget contents
(level ** _ ) = headingLevel level
in (_ ** Normal level [] xs)
export
renderBlocks : List Block -> (types : List String ** DList _ Html types)
renderBlocks xs = fromList $ map renderBlock xs
export
renderHtml : List Block -> Html "html"
renderHtml xs =
let (_ ** xs) = renderBlocks xs
in Normal "html" ["lang" =$ "en"] xs

View file

@ -8,7 +8,7 @@ Decided to rename =Tag= to =Html=, and =Raw= to =Text=, which makes this make se
** TODO Refine =location= in =ParserLocation= ** TODO Refine =location= in =ParserLocation=
** TODO Error messages ** TODO Error messages
** TODO Combinators for predictive parsing ** TODO Combinators for predictive parsing
* Djot [4/42] * Djot [5/42]
:PROPERTIES: :PROPERTIES:
:COOKIE_DATA: recursive :COOKIE_DATA: recursive
:END: :END:
@ -50,7 +50,7 @@ Decided to rename =Tag= to =Html=, and =Raw= to =Text=, which makes this make se
**** TODO Footnote **** TODO Footnote
**** TODO Block attributes **** TODO Block attributes
**** TODO Links to headings **** TODO Links to headings
** TODO Rendering ** DONE Rendering
** TODO Predictive parsing ** TODO Predictive parsing
** TODO Support all types of whitespace ** TODO Support all types of whitespace
*** TODO Escaping *** TODO Escaping