1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-23 23:30:40 +03:00

Refactor html command with extra options (#1725)

This PR redefines the `html` command unifying our previous subcommands
for the HTML backend. You should use the command in the following way to
obtain the same results as before:

- `juvix html src.juvix` -> `juvix html src.juvix --only-source`
- `juvix dev doc src.juvix` -> `juvix html src.juvix`

- Other fixes here include the flag `--non-recursive`, which replaces
the previous behavior in that we now generate all the HTML recursively
by default.
- The flag `--no-print-metadata` is now called `--no-footer` 
- Also, another change introduced by this PR is asset handling; for
example, with our canonical Juvix program,
the new output is organized as follows.

```
juvix html HelloWorld.juvix --only-source && tree html/
Copying assets files to test/html/assets
Writing HelloWorld.html
html/
├── assets
│   ├── css
│   │   ├── linuwial.css
│   │   ├── source-ayu-light.css
│   │   └── source-nord.css
│   ├── images
│   │   ├── tara-magicien.png
│   │   ├── tara-seating.svg
│   │   ├── tara-smiling.png
│   │   ├── tara-smiling.svg
│   │   ├── tara-teaching.png
│   │   └── tara-teaching.svg
│   └── js
│       ├── highlight.js
│       └── tex-chtml.js
└── HelloWorld.html
├── Stdlib.Data.Bool.html
├── Stdlib.Data.List.html
├── Stdlib.Data.Maybe.html
├── Stdlib.Data.Nat.html
├── Stdlib.Data.Ord.html
├── Stdlib.Data.Product.html
├── Stdlib.Data.String.html
├── Stdlib.Function.html
├── Stdlib.Prelude.html
└── Stdlib.System.IO.html
```
In addition, for the vscode-plugin, this PR adds two flags,
`--prefix-assets` and `--prefix-url`, for which one provides input to
help vscode find resource locations and Juvix files.

PS. Make sure to run `make clean` the first time you run `make install`
for the first time.
This commit is contained in:
Jonathan Cubides 2023-01-17 18:11:59 +01:00 committed by GitHub
parent 742a0e53dd
commit 22027f137c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 683 additions and 391 deletions

View File

@ -3,9 +3,8 @@ PREFIX="$(PWD)/.stack-work/prefix"
UNAME := $(shell uname)
HLINTQUIET :=
ASSETS = seating-mascot.051c86a.svg \
Seating_Tara_smiling.svg \
teaching-mascot.f828959.svg
IMAGES = $(shell find assets/images -type f)
ORGFILES = $(shell find docs/org -type f -name '*.org')
MDFILES:=$(patsubst docs/org/%,docs/md/%,$(ORGFILES:.org=.md))
@ -34,6 +33,9 @@ else
THREADS := $(shell echo %NUMBER_OF_PROCESSORS%)
endif
images:
echo $(IMAGES)
all: install
clean: clean-runtime
@ -97,8 +99,8 @@ markdown-files: docs/md/README.md docs/md/changelog.md $(MDFILES)
.PHONY: markdown-docs
markdown-docs: markdown-files
@echo "copying assets ..."
@mkdir -p docs/md/assets
@cp -v $(addprefix assets/,$(ASSETS)) docs/md/assets
@mkdir -p docs/md/assets/images
@cp -v $(IMAGES) docs/md/assets/images/
@mdbook build
.PHONY: serve-docs
@ -191,7 +193,7 @@ fast-build: submodules runtime
.PHONY: runtime
runtime:
cd runtime && make -j 4
cd runtime && make -j 4 -s
# -- Install

View File

@ -26,7 +26,7 @@ alt="pages-build-deployment" /></a>
#+begin_html
<a href="https://github.com/anoma/juvix">
<img align="right" width="300" height="300" alt="Juvix Mascot" src="assets/seating-mascot.051c86a.svg" />
<img align="right" width="300" height="300" alt="Juvix Mascot" src="assets/images/tara-seating.svg" />
</a>
#+end_html

View File

@ -8,7 +8,6 @@ import Commands.Base
import Commands.Dev.Asm qualified as Asm
import Commands.Dev.Core qualified as Core
import Commands.Dev.DisplayRoot qualified as DisplayRoot
import Commands.Dev.Doc qualified as Doc
import Commands.Dev.Highlight qualified as Highlight
import Commands.Dev.Internal qualified as Internal
import Commands.Dev.MiniC qualified as MiniC
@ -23,7 +22,6 @@ runCommand = \case
Highlight opts -> Highlight.runCommand opts
Parse opts -> Parse.runCommand opts
Scope opts -> Scope.runCommand opts
Doc opts -> Doc.runCommand opts
Internal opts -> Internal.runCommand opts
MiniC opts -> MiniC.runCommand opts
Termination opts -> Termination.runCommand opts

View File

@ -1,16 +0,0 @@
module Commands.Dev.Doc where
import Commands.Base
import Commands.Dev.Doc.Options
import Juvix.Compiler.Backend.Html.Translation.FromTyped qualified as Doc
import Juvix.Extra.Process
import System.Process qualified as Process
runCommand :: Members '[Embed IO, App] r => DocOptions -> Sem r ()
runCommand DocOptions {..} = do
ctx <- runPipeline _docInputFile upToInternalTyped
docDir <- someBaseToAbs' (_docOutputDir ^. pathPath)
Doc.compile docDir "proj" ctx
when _docOpen $ case openCmd of
Nothing -> say "Could not recognize the 'open' command for your OS"
Just opencmd -> embed (void (Process.spawnProcess opencmd [toFilePath (docDir <//> Doc.indexFileName)]))

View File

@ -1,28 +0,0 @@
module Commands.Dev.Doc.Options where
import CommonOptions
data DocOptions = DocOptions
{ _docOutputDir :: AppPath Dir,
_docOpen :: Bool,
_docInputFile :: AppPath File
}
deriving stock (Data)
makeLenses ''DocOptions
parseDoc :: Parser DocOptions
parseDoc = do
_docOutputDir <-
parseGenericOutputDir
( value (Rel (relDir "doc"))
<> showDefault
<> help "html output directory"
)
_docOpen <-
switch
( long "open"
<> help "open the documentation after generating it"
)
_docInputFile <- parseInputJuvixFile
pure DocOptions {..}

View File

@ -6,7 +6,6 @@ module Commands.Dev.Options
module Commands.Dev.Parse.Options,
module Commands.Dev.Highlight.Options,
module Commands.Dev.Scope.Options,
module Commands.Dev.Doc.Options,
module Commands.Dev.Termination.Options,
module Commands.Dev.DisplayRoot.Options,
)
@ -15,7 +14,6 @@ where
import Commands.Dev.Asm.Options hiding (Compile)
import Commands.Dev.Core.Options
import Commands.Dev.DisplayRoot.Options
import Commands.Dev.Doc.Options
import Commands.Dev.Highlight.Options
import Commands.Dev.Internal.Options
import Commands.Dev.MiniC.Options
@ -36,7 +34,6 @@ data DevCommand
| Parse ParseOptions
| Scope ScopeOptions
| Termination TerminationCommand
| Doc DocOptions
deriving stock (Data)
parseDevCommand :: Parser DevCommand
@ -50,20 +47,12 @@ parseDevCommand =
commandRuntime,
commandMiniC,
commandParse,
commandDoc,
commandScope,
commandShowRoot,
commandTermination
]
)
commandDoc :: Mod CommandFields DevCommand
commandDoc =
command "doc" $
info
(Doc <$> parseDoc)
(progDesc "Generate documentation")
commandHighlight :: Mod CommandFields DevCommand
commandHighlight =
command "highlight" $

View File

@ -2,13 +2,63 @@ module Commands.Html where
import Commands.Base
import Commands.Html.Options
import Juvix.Compiler.Backend.Html.Translation.FromTyped (JudocArgs (..))
import Juvix.Compiler.Backend.Html.Translation.FromTyped qualified as Html
import Juvix.Compiler.Backend.Html.Translation.FromTyped.Source
( GenSourceHtmlArgs (..),
)
import Juvix.Compiler.Concrete.Pretty qualified as Concrete
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping qualified as Scoper
import Juvix.Extra.Process
import System.Process qualified as Process
runCommand :: Members '[Embed IO, App] r => HtmlOptions -> Sem r ()
runCommand HtmlOptions {..} = do
runGenOnlySourceHtml :: Members '[Embed IO, App] r => HtmlOptions -> Sem r ()
runGenOnlySourceHtml HtmlOptions {..} = do
res <- runPipeline _htmlInputFile upToScoping
let m = head (res ^. Scoper.resultModules)
outDir <- someBaseToAbs' (_htmlOutputDir ^. pathPath)
embed (Html.genHtml Concrete.defaultOptions _htmlRecursive _htmlTheme outDir _htmlPrintMetadata m)
outputDir <- someBaseToAbs' (_htmlOutputDir ^. pathPath)
embed $
Html.genSourceHtml
GenSourceHtmlArgs
{ _genSourceHtmlArgsAssetsDir = _htmlAssetsPrefix,
_genSourceHtmlArgsHtmlKind = Html.HtmlSrc,
_genSourceHtmlArgsParamBase = "",
_genSourceHtmlArgsUrlPrefix = _htmlUrlPrefix,
_genSourceHtmlArgsConcreteOpts = Concrete.defaultOptions,
_genSourceHtmlArgsEntryPoint = m,
_genSourceHtmlArgsOutputDir = outputDir,
_genSourceHtmlArgsNoFooter = _htmlNoFooter,
_genSourceHtmlArgsNonRecursive = _htmlNonRecursive,
_genSourceHtmlArgsTheme = _htmlTheme
}
runCommand :: Members '[Embed IO, App] r => HtmlOptions -> Sem r ()
runCommand HtmlOptions {..}
| _htmlOnlySource = runGenOnlySourceHtml HtmlOptions {..}
| otherwise = do
ctx <- runPipeline _htmlInputFile upToInternalTyped
outputDir <- someBaseToAbs' (_htmlOutputDir ^. pathPath)
Html.genJudocHtml
JudocArgs
{ _judocArgsAssetsPrefix = _htmlAssetsPrefix,
_judocArgsBaseName = "proj",
_judocArgsCtx = ctx,
_judocArgsOutputDir = outputDir,
_judocArgsUrlPrefix = _htmlUrlPrefix,
_judocArgsTheme = _htmlTheme,
_judocArgsNonRecursive = _htmlNonRecursive,
_judocArgsNoFooter = _htmlNoFooter
}
when _htmlOpen $ case openCmd of
Nothing -> say "Could not recognize the 'open' command for your OS"
Just opencmd ->
embed
( void
( Process.spawnProcess
opencmd
[ toFilePath
( outputDir <//> Html.indexFileName
)
]
)
)

View File

@ -1,14 +1,18 @@
module Commands.Html.Options where
import CommonOptions
import Juvix.Compiler.Backend.Html.Data.Theme
import Juvix.Compiler.Backend.Html.Data.Options hiding (HtmlOptions)
data HtmlOptions = HtmlOptions
{ _htmlRecursive :: Bool,
{ _htmlNonRecursive :: Bool,
_htmlOnlySource :: Bool,
_htmlTheme :: Theme,
_htmlOutputDir :: AppPath Dir,
_htmlInputFile :: AppPath File,
_htmlPrintMetadata :: Bool
_htmlNoFooter :: Bool,
_htmlAssetsPrefix :: Text,
_htmlUrlPrefix :: Text,
_htmlOpen :: Bool
}
deriving stock (Data)
@ -16,10 +20,15 @@ makeLenses ''HtmlOptions
parseHtml :: Parser HtmlOptions
parseHtml = do
_htmlRecursive <-
_htmlNonRecursive <-
switch
( long "recursive"
<> help "export imported modules recursively"
( long "non-recursive"
<> help "Export imported modules recursively"
)
_htmlOnlySource <-
switch
( long "only-source"
<> help "Generate only Html for the source code with syntax highlighting"
)
_htmlTheme <-
option
@ -28,26 +37,46 @@ parseHtml = do
<> metavar "THEME"
<> value Ayu
<> showDefault
<> help "selects a theme: ayu (light); nord (dark)"
<> help "Theme for syntax highlighting. Options: ayu (light) and nord (dark)"
<> completeWith (map show allThemes)
)
_htmlOutputDir <-
parseGenericOutputDir
( value (Rel $(mkRelDir "html"))
<> showDefault
<> help "html output directory"
<> help "Html output directory"
<> action "directory"
)
_htmlPrintMetadata <-
_htmlNoFooter <-
switch
( long "print-metadata"
<> help "Add HTML footer with metadata"
( long "no-footer"
<> help "Remove HTML Juvix footer"
)
_htmlAssetsPrefix <-
strOption
( value ""
<> long "prefix-assets"
<> showDefault
<> help "Prefix used for assets's source path"
)
_htmlUrlPrefix <-
strOption
( value ""
<> long "prefix-url"
<> showDefault
<> help "Prefix used for inner Juvix hyperlinks"
)
_htmlOpen <-
switch
( long "open"
<> help "Open the documentation after generating it"
)
_htmlInputFile <- parseInputJuvixFile
pure HtmlOptions {..}
where
allThemes :: [Theme]
allThemes = allElements
parseTheme :: String -> Either String Theme
parseTheme s = case map toLower s of
"nord" -> Right Nord

View File

@ -1,5 +1,3 @@
@import "extra.css";
/* @group Fundamentals */
* { margin: 0; padding: 0 }

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

1
assets/js/tex-chtml.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
#+begin_html
<a href="https://github.com/anoma/juvix">
<img align="right" width="300" height="300" alt="Juvix Mascot" src="../assets/Seating_Tara_smiling.svg" />
<img align="right" width="300" height="300" alt="Juvix Mascot" src="../assets/images/tara-smiling.svg" />
</a>
#+end_html

View File

@ -2,7 +2,7 @@
#+begin_html
<a href="https://github.com/anoma/juvix">
<img align="left" width="200" height="200" alt="Juvix Mascot" src="../assets/teaching-mascot.f828959.svg" />
<img align="left" width="200" height="200" alt="Juvix Mascot" src="../assets/images/tara-teaching.svg" />
</a>
#+end_html

View File

@ -14,7 +14,10 @@ github: anoma/juvix
extra-source-files:
- README.org
- assets/*
- assets/css/*.css
- assets/js/*.js
- assets/images/*.svg
- assets/images/*.png
- juvix-stdlib/juvix.yaml
- juvix-stdlib/**/*.juvix
- runtime/include/**/*.h

View File

@ -1,3 +1,3 @@
module Juvix.Compiler.Backend.Html.Data (module Juvix.Compiler.Backend.Html.Data.Theme) where
module Juvix.Compiler.Backend.Html.Data (module Juvix.Compiler.Backend.Html.Data.Options) where
import Juvix.Compiler.Backend.Html.Data.Theme
import Juvix.Compiler.Backend.Html.Data.Options

View File

@ -0,0 +1,26 @@
module Juvix.Compiler.Backend.Html.Data.Options where
import Juvix.Prelude
data HtmlOptions = HtmlOptions
{ _htmlOptionsKind :: HtmlKind,
_htmlOptionsAssetsPrefix :: Text,
_htmlOptionsUrlPrefix :: Text,
_htmlOptionsOutputDir :: Path Abs Dir,
_htmlOptionsParamBase :: Text,
_htmlOptionsTheme :: Theme,
_htmlOptionsNoFooter :: Bool
}
data Theme
= Nord
| Ayu
deriving stock (Show, Enum, Bounded, Data)
data HtmlKind
= HtmlDoc
| HtmlSrc
| HtmlOnly
deriving stock (Data)
makeLenses ''HtmlOptions

View File

@ -1,14 +0,0 @@
module Juvix.Compiler.Backend.Html.Data.Theme where
import Juvix.Prelude
data Theme
= Nord
| Ayu
deriving stock (Show, Enum, Bounded, Data)
data HtmlKind
= HtmlDoc
| HtmlSrc
| HtmlOnly
deriving stock (Data)

View File

@ -1,26 +1,27 @@
module Juvix.Compiler.Backend.Html.Extra where
import Juvix.Compiler.Backend.Html.Data.Options
import Juvix.Extra.Strings qualified as Str
import Juvix.Extra.Version
import Juvix.Prelude
import Text.Blaze.Html5 as Html hiding (map)
import Text.Blaze.Html5.Attributes qualified as Attr
mathJaxCdn :: Html
mathJaxCdn = script1 <> script2
where
script1 =
script
! Attr.src src1
$ mempty
script2 =
script
! Attr.type_ "text/javascript"
! Attr.id "MathJax-script"
! Attr.src src2
$ mempty
src1 :: AttributeValue
src1 = "https://polyfill.io/v3/polyfill.min.js?features=es6"
src2 :: AttributeValue
src2 = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"
mathJaxCdn :: Members '[Reader HtmlOptions] r => Sem r Html
mathJaxCdn = do
assetsPrefix <- textValue <$> asks (^. htmlOptionsAssetsPrefix)
let script1 =
script
! Attr.src "https://polyfill.io/v3/polyfill.min.js?features=es6"
$ mempty
script2 =
script
! Attr.type_ "text/javascript"
! Attr.id "MathJax-script"
! Attr.src (assetsPrefix <> "assets/js/tex-chtml.js")
$ mempty
return $ script1 <> script2
-- | This is useful fore debugging only. Note that it only works on a server
-- protocol, opening the file from the local system won't work. For that, one
@ -32,40 +33,88 @@ livejs =
! Attr.src "https://livejs.com/live.js"
$ mempty
linuwialCss :: Html
linuwialCss =
link
! Attr.href "assets/linuwial.css"
! Attr.rel "stylesheet"
! Attr.type_ "text/css"
! Attr.title "Linuwial"
cssLink :: Members '[Reader HtmlOptions] r => AttributeValue -> Sem r Html
cssLink css = do
assetsPrefix <- textValue <$> asks (^. htmlOptionsAssetsPrefix)
return $
link
! Attr.href (assetsPrefix <> "assets/css/" <> css)
! Attr.rel "stylesheet"
! Attr.type_ "text/css"
sourceCss :: Html
sourceCss =
link
! Attr.href "assets/source.css"
! Attr.rel "stylesheet"
! Attr.type_ "text/css"
cssLink :: AttributeValue -> Html
cssLink css =
link
! Attr.href css
! Attr.rel "stylesheet"
! Attr.type_ "text/css"
ayuCss :: Html
ayuCss = cssLink "assets/source-ayu-light.css"
nordCss :: Html
nordCss = cssLink "assets/source-nord.css"
highlightJs :: Html
highlightJs =
script
! Attr.src "assets/highlight.js"
! Attr.type_ "text/javascript"
jsLink :: Members '[Reader HtmlOptions] r => AttributeValue -> Sem r Html
jsLink js = do
assetsPrefix <- textValue <$> asks (^. htmlOptionsAssetsPrefix)
return
$ script
! Attr.src (assetsPrefix <> "assets/js/" <> js)
! Attr.type_ "text/javascript"
$ mempty
linuwialCss :: Members '[Reader HtmlOptions] r => Sem r Html
linuwialCss = cssLink "linuwial.css"
ayuCss :: Members '[Reader HtmlOptions] r => Sem r Html
ayuCss = cssLink "source-ayu-light.css"
nordCss :: Members '[Reader HtmlOptions] r => Sem r Html
nordCss = cssLink "source-nord.css"
themeCss :: Members '[Reader HtmlOptions] r => Sem r Html
themeCss = do
theme <- asks (^. htmlOptionsTheme)
case theme of
Ayu -> ayuCss
Nord -> nordCss
highlightJs :: Members '[Reader HtmlOptions] r => Sem r Html
highlightJs = jsLink "highlight.js"
metaUtf8 :: Html
metaUtf8 = meta ! Attr.charset "UTF-8"
taraSmiling :: Members '[Reader HtmlOptions] r => Sem r Html
taraSmiling = do
assetsPrefix <- textValue <$> asks (^. htmlOptionsAssetsPrefix)
return $
Html.a ! Attr.href Str.juvixDotOrg $
Html.img
! Attr.id "tara"
! Attr.src (assetsPrefix <> "assets/images/tara-smiling.svg")
! Attr.alt "Tara"
htmlJuvixFooter ::
Members '[Reader HtmlOptions] r =>
Sem r Html
htmlJuvixFooter = do
noFooter <- asks (^. htmlOptionsNoFooter)
htmlKind <- asks (^. htmlOptionsKind)
tara <- taraSmiling
if
| noFooter -> return mempty
| otherwise -> do
let juvixLinkOrg :: Html
juvixLinkOrg =
a ! Attr.href Str.juvixDotOrg $
toHtml ("Juvix " :: Text)
commitInfo :: Html
commitInfo =
a
! Attr.href
(textValue ("https://github.com/anoma/juvix/commit/" <> shortHash))
$ toHtml versionTag
juvixVersion :: Html
juvixVersion =
toHtml ("Powered by " :: Text)
<> juvixLinkOrg
<> commitInfo
return $
case htmlKind of
HtmlDoc ->
Html.div ! Attr.id "footer" $
p juvixVersion
<> tara
_ -> footer . pre $ juvixVersion

View File

@ -5,7 +5,6 @@ module Juvix.Compiler.Backend.Html.Translation.FromTyped
)
where
import Data.ByteString qualified as BS
import Data.ByteString.Builder qualified as Builder
import Data.HashMap.Strict qualified as HashMap
import Data.Time.Clock
@ -24,21 +23,26 @@ import Juvix.Compiler.Internal.Translation.FromInternal.Analysis.ArityChecking.D
import Juvix.Compiler.Internal.Translation.FromInternal.Analysis.TypeChecking qualified as InternalTyped
import Juvix.Compiler.Internal.Translation.FromInternal.Analysis.TypeChecking.Data.Context
import Juvix.Compiler.Pipeline.EntryPoint
import Juvix.Extra.Paths
import Juvix.Extra.Assets
import Juvix.Extra.Strings qualified as Str
import Juvix.Extra.Version
import Juvix.Prelude
import Juvix.Prelude qualified as Prelude
import Text.Blaze.Html.Renderer.Utf8 qualified as Html
import Text.Blaze.Html5 as Html hiding (map)
import Text.Blaze.Html5.Attributes qualified as Attr
data DocParams = DocParams
{ _docParamBase :: Text,
_docOutputDir :: Path Abs Dir
data JudocArgs = JudocArgs
{ _judocArgsOutputDir :: Path Abs Dir,
_judocArgsBaseName :: Text,
_judocArgsAssetsPrefix :: Text,
_judocArgsUrlPrefix :: Text,
_judocArgsCtx :: InternalTypedResult,
_judocArgsTheme :: Theme,
_judocArgsNonRecursive :: Bool,
_judocArgsNoFooter :: Bool
}
makeLenses ''DocParams
makeLenses ''JudocArgs
data Tree k a = Tree
{ _treeLabel :: a,
@ -70,12 +74,12 @@ indexFileName = $(mkRelFile "index.html")
createIndexFile ::
forall r.
Members '[Reader DocParams, Embed IO, Reader HtmlOptions, Reader EntryPoint] r =>
Members '[Embed IO, Reader HtmlOptions, Reader EntryPoint] r =>
[TopModulePath] ->
Sem r ()
createIndexFile ps = do
outDir <- asks (^. docOutputDir)
indexHtml >>= (template mempty >=> writeHtml (outDir <//> indexFileName))
outputDir <- asks (^. htmlOptionsOutputDir)
indexHtml >>= (template mempty >=> writeHtml (outputDir <//> indexFileName))
where
indexHtml :: Sem r Html
indexHtml = do
@ -85,8 +89,10 @@ createIndexFile ps = do
Html.div ! Attr.id "module-list" $
(p ! Attr.class_ "caption" $ "Modules")
<> tree'
tree :: ModuleTree
tree = indexTree ps
root :: ModuleTree -> Sem r Html
root (Tree _ t) = do
c' <- mconcatMapM (uncurry goChild) (HashMap.toList t)
@ -106,10 +112,13 @@ createIndexFile ps = do
return $
Html.span ! Attr.class_ attrBare $
(a ! Attr.href lnk $ toHtml (prettyText lbl'))
attrBase :: Html.AttributeValue
attrBase = "details-toggle-control details-toggle"
attrBare :: Html.AttributeValue
attrBare = attrBase <> " directory"
node :: Sem r Html
node = do
row' <- nodeRow
@ -127,46 +136,6 @@ createIndexFile ps = do
summary "Subtree"
<> ul (mconcatMap li c')
compile :: Members '[Embed IO] r => Path Abs Dir -> Text -> InternalTypedResult -> Sem r ()
compile dir baseName ctx = runReader params . runReader normTable . runReader entry $ do
copyAssets
mapM_ goTopModule topModules
runReader docHtmlOpts (createIndexFile (map topModulePath (toList topModules)))
where
entry :: EntryPoint
entry = ctx ^. InternalTyped.internalTypedResultEntryPoint
normTable :: InternalTyped.NormalizedTable
normTable = ctx ^. InternalTyped.resultNormalized
mainMod :: Module 'Scoped 'ModuleTop
mainMod =
ctx
^. InternalTyped.resultInternalArityResult
. InternalArity.resultInternalResult
. Internal.resultAbstract
. Abstract.resultScoper
. Scoped.mainModule
copyAssets :: forall s. Members '[Embed IO, Reader DocParams] s => Sem s ()
copyAssets = do
toAssetsDir <- (<//> $(mkRelDir "assets")) <$> asks (^. docOutputDir)
let writeAsset :: (Path Rel File, BS.ByteString) -> Sem s ()
writeAsset (filePath, fileContents) =
Prelude.embed $ BS.writeFile (toFilePath (toAssetsDir <//> filePath)) fileContents
ensureDir toAssetsDir
mapM_ writeAsset assetFiles
where
assetFiles :: [(Path Rel File, BS.ByteString)]
assetFiles = assetsDir
params :: DocParams
params =
DocParams
{ _docParamBase = baseName,
_docOutputDir = dir
}
topModules :: HashMap NameId (Module 'Scoped 'ModuleTop)
topModules = getAllModules mainMod
writeHtml :: Members '[Embed IO] r => Path Abs File -> Html -> Sem r ()
writeHtml f h = Prelude.embed $ do
ensureDir dir
@ -175,94 +144,117 @@ writeHtml f h = Prelude.embed $ do
dir :: Path Abs Dir
dir = parent f
moduleDocPath :: Members '[Reader HtmlOptions, Reader DocParams] r => Module 'Scoped 'ModuleTop -> Sem r (Path Abs File)
genJudocHtml :: Members '[Embed IO] r => JudocArgs -> Sem r ()
genJudocHtml JudocArgs {..} =
runReader htmlOpts . runReader normTable . runReader entry $ do
Prelude.embed (writeAssets _judocArgsOutputDir)
mapM_ goTopModule allModules
createIndexFile (map topModulePath (toList allModules))
where
entry :: EntryPoint
entry = _judocArgsCtx ^. InternalTyped.internalTypedResultEntryPoint
normTable :: InternalTyped.NormalizedTable
normTable = _judocArgsCtx ^. InternalTyped.resultNormalized
mainMod :: Module 'Scoped 'ModuleTop
mainMod =
_judocArgsCtx
^. InternalTyped.resultInternalArityResult
. InternalArity.resultInternalResult
. Internal.resultAbstract
. Abstract.resultScoper
. Scoped.mainModule
htmlOpts :: HtmlOptions
htmlOpts =
HtmlOptions
{ _htmlOptionsKind = HtmlDoc,
_htmlOptionsAssetsPrefix = _judocArgsAssetsPrefix,
_htmlOptionsOutputDir = _judocArgsOutputDir,
_htmlOptionsUrlPrefix = _judocArgsUrlPrefix,
_htmlOptionsParamBase = _judocArgsBaseName,
_htmlOptionsTheme = _judocArgsTheme,
_htmlOptionsNoFooter = _judocArgsNoFooter
}
allModules
| _judocArgsNonRecursive = pure mainMod
| otherwise = toList topModules
topModules :: HashMap NameId (Module 'Scoped 'ModuleTop)
topModules = getAllModules mainMod
moduleDocPath :: Members '[Reader HtmlOptions] r => Module 'Scoped 'ModuleTop -> Sem r (Path Abs File)
moduleDocPath m = do
relPath <- moduleDocRelativePath (m ^. modulePath . S.nameConcrete)
outDir <- asks (^. docOutputDir)
return (outDir <//> relPath)
outputDir <- asks (^. htmlOptionsOutputDir)
return (outputDir <//> relPath)
topModulePath ::
Module 'Scoped 'ModuleTop -> TopModulePath
topModulePath :: Module 'Scoped 'ModuleTop -> TopModulePath
topModulePath = (^. modulePath . S.nameConcrete)
srcHtmlOpts :: HtmlOptions
srcHtmlOpts = HtmlOptions HtmlSrc
docHtmlOpts :: HtmlOptions
docHtmlOpts = HtmlOptions HtmlDoc
template :: forall r. Members '[Reader EntryPoint] r => Html -> Html -> Sem r Html
template :: forall r. Members '[Reader EntryPoint, Reader HtmlOptions] r => Html -> Html -> Sem r Html
template rightMenu' content' = do
mathJax <- mathJaxCdn
ayuTheme <- ayuCss
judocTheme <- linuwialCss
let mhead :: Html
mhead =
Html.head $
title titleStr
<> Html.meta
! Attr.httpEquiv "Content-Type"
! Attr.content "text/html; charset=UTF-8"
<> Html.meta
! Attr.name "viewport"
! Attr.content "width=device-width, initial-scale=1"
<> mathJax
<> livejs
<> ayuTheme
<> judocTheme
titleStr :: Html
titleStr = "Juvix Documentation"
packageHeader :: Sem r Html
packageHeader = do
pkgName' <- toHtml <$> asks (^. entryPointPackage . packageName)
version' <- toHtml <$> asks (^. entryPointPackage . packageVersion . to prettyV)
return $
Html.div ! Attr.id "package-header" $
( Html.span ! Attr.class_ "caption" $
pkgName' <> " - " <> version'
)
<> rightMenu'
mbody :: Sem r Html
mbody = do
bodyHeader' <- packageHeader
footer' <- htmlJuvixFooter
return $
body ! Attr.class_ "js-enabled" $
bodyHeader'
<> content'
<> footer'
body' <- mbody
return (docTypeHtml (mhead <> body'))
where
mhead :: Html
mhead =
Html.head $
title titleStr
<> Html.meta
! Attr.httpEquiv "Content-Type"
! Attr.content "text/html; charset=UTF-8"
<> Html.meta
! Attr.name "viewport"
! Attr.content "width=device-width, initial-scale=1"
<> mathJaxCdn
<> livejs
<> ayuCss
<> linuwialCss
titleStr :: Html
titleStr = "Juvix Documentation"
packageHeader :: Sem r Html
packageHeader = do
pkgName' <- toHtml <$> asks (^. entryPointPackage . packageName)
version' <- toHtml <$> asks (^. entryPointPackage . packageVersion . to prettyV)
return $
Html.div ! Attr.id "package-header" $
( Html.span ! Attr.class_ "caption" $
pkgName' <> " - " <> version'
)
<> rightMenu'
mbody :: Sem r Html
mbody = do
bodyHeader' <- packageHeader
return $
body ! Attr.class_ "js-enabled" $
bodyHeader'
<> content'
<> mfooter
mfooter :: Html
mfooter =
Html.div ! Attr.id "footer" $
p
( "Build by "
<> (Html.a ! Attr.href Str.juvixDotOrg $ "Juvix")
<> " version "
<> toHtml versionDoc
)
<> ( Html.a ! Attr.href Str.juvixDotOrg $
Html.img
! Attr.id "tara"
! Attr.src "assets/Seating_Tara_smiling.svg"
! Attr.alt "Tara"
)
return $ docTypeHtml (mhead <> body')
-- | This function compiles a datalang module into Html documentation.
goTopModule ::
forall r.
Members '[Reader DocParams, Embed IO, Reader EntryPoint, Reader NormalizedTable] r =>
Members '[Reader HtmlOptions, Embed IO, Reader EntryPoint, Reader NormalizedTable] r =>
Module 'Scoped 'ModuleTop ->
Sem r ()
goTopModule m = do
runReader docHtmlOpts $ do
htmlOpts <- ask @HtmlOptions
runReader (htmlOpts {_htmlOptionsKind = HtmlDoc}) $ do
fpath <- moduleDocPath m
Prelude.embed (putStrLn ("processing " <> pack (toFilePath fpath)))
Prelude.embed (putStrLn ("Writing " <> pack (toFilePath fpath)))
docHtml >>= writeHtml fpath
runReader srcHtmlOpts $ do
runReader (htmlOpts {_htmlOptionsKind = HtmlSrc}) $ do
fpath <- moduleDocPath m
srcHtml >>= writeHtml fpath
where
@ -272,7 +264,12 @@ goTopModule m = do
srcHtml :: forall s. Members '[Reader HtmlOptions, Embed IO] s => Sem s Html
srcHtml = do
utc <- Prelude.embed getCurrentTime
return (genModuleHtml defaultOptions HtmlSrc True utc Ayu m)
genModuleHtml
GenModuleHtmlArgs
{ _genModuleHtmlArgsConcreteOpts = defaultOptions,
_genModuleHtmlArgsUTC = utc,
_genModuleHtmlArgsEntryPoint = m
}
docHtml :: forall s. Members '[Reader HtmlOptions, Reader EntryPoint, Reader NormalizedTable] s => Sem s Html
docHtml = do
@ -285,7 +282,7 @@ goTopModule m = do
sourceRef' <- local (set htmlOptionsKind HtmlSrc) (nameIdAttrRef tmp Nothing)
return $
ul ! Attr.id "page-menu" ! Attr.class_ "links" $
li (a ! Attr.href sourceRef' $ "Source")
li (a ! Attr.href sourceRef' $ "Source") -- TODO: review here
<> li (a ! Attr.href (fromString (toFilePath indexFileName)) $ "Index")
content :: Sem s Html
@ -353,11 +350,13 @@ goJudoc (Judoc bs) = mconcatMapM goBlock bs
goBlock = \case
JudocParagraph ls -> Html.p . concatWith (\l r -> l <> " " <> r) <$> mapM goLine (toList ls)
JudocExample e -> goExample e
goLine :: JudocParagraphLine 'Scoped -> Sem r Html
goLine (JudocParagraphLine atoms) = mconcatMapM goAtom (toList atoms)
goExample :: Example 'Scoped -> Sem r Html
goExample ex = do
e' <- ppCodeHtml (ex ^. exampleExpression)
e' <- ppCodeHtml defaultOptions (ex ^. exampleExpression)
norm' <- asks @NormalizedTable (^?! at (ex ^. exampleId) . _Just) >>= ppCodeHtmlInternal
return $
Html.pre ! Attr.class_ "screen" $
@ -366,9 +365,10 @@ goJudoc (Judoc bs) = mconcatMapM goBlock bs
<> e'
<> "\n"
<> norm'
goAtom :: JudocAtom 'Scoped -> Sem r Html
goAtom = \case
JudocExpression e -> ppCodeHtml e
JudocExpression e -> ppCodeHtml defaultOptions e
JudocText txt -> return (toHtml txt)
goStatement :: Members '[Reader HtmlOptions, Reader NormalizedTable] r => Statement 'Scoped -> Sem r Html
@ -381,7 +381,7 @@ goStatement = \case
goOpen :: forall r. Members '[Reader HtmlOptions] r => OpenModule 'Scoped -> Sem r Html
goOpen op
| Public <- op ^. openPublic = noDefHeader <$> ppCodeHtml op
| Public <- op ^. openPublic = noDefHeader <$> ppCodeHtml defaultOptions op
| otherwise = mempty
goAxiom :: forall r. Members '[Reader HtmlOptions, Reader NormalizedTable] r => AxiomDef 'Scoped -> Sem r Html
@ -394,7 +394,7 @@ goAxiom axiom = do
tmp :: TopModulePath
tmp = axiom ^. axiomName . S.nameDefinedIn . S.absTopModulePath
axiomHeader :: Sem r Html
axiomHeader = ppCodeHtml (set axiomDoc Nothing axiom)
axiomHeader = ppCodeHtml defaultOptions (set axiomDoc Nothing axiom)
goInductive :: forall r. Members '[Reader HtmlOptions, Reader NormalizedTable] r => InductiveDef 'Scoped -> Sem r Html
goInductive def = do
@ -409,7 +409,7 @@ goInductive def = do
tmp = def ^. inductiveName . S.nameDefinedIn . S.absTopModulePath
inductiveHeader :: Sem r Html
inductiveHeader =
runReader defaultOptions (ppInductiveSignature def) >>= ppCodeHtml
runReader defaultOptions (ppInductiveSignature def) >>= ppCodeHtml defaultOptions
goConstructors :: forall r. Members '[Reader HtmlOptions, Reader NormalizedTable] r => NonEmpty (InductiveConstructorDef 'Scoped) -> Sem r Html
goConstructors cc = do
@ -432,7 +432,7 @@ goConstructors cc = do
srcPart :: Sem r Html
srcPart = do
sig' <- ppCodeHtml (set constructorDoc Nothing c)
sig' <- ppCodeHtml defaultOptions (set constructorDoc Nothing c)
return $
td ! Attr.class_ "src" $
sig'
@ -469,7 +469,7 @@ goTypeSignature sig = do
uid :: NameId
uid = sig ^. sigName . S.nameId
typeSig :: Sem r Html
typeSig = ppCodeHtml (set sigDoc Nothing sig)
typeSig = ppCodeHtml defaultOptions (set sigDoc Nothing sig)
sourceAndSelfLink :: Members '[Reader HtmlOptions] r => TopModulePath -> NameId -> Sem r Html
sourceAndSelfLink tmp name = do

View File

@ -1,12 +1,11 @@
module Juvix.Compiler.Backend.Html.Translation.FromTyped.Source where
import Data.ByteString qualified as BS
import Data.Text qualified as Text
import Data.Text.IO qualified as Text
import Data.Text.Lazy (toStrict)
import Data.Time.Clock
import Data.Time.Format
import Juvix.Compiler.Backend.Html.Data.Theme
import Juvix.Compiler.Backend.Html.Data.Options
import Juvix.Compiler.Backend.Html.Extra
import Juvix.Compiler.Concrete.Data.ScopedName qualified as S
import Juvix.Compiler.Concrete.Extra
@ -14,8 +13,7 @@ import Juvix.Compiler.Concrete.Language
import Juvix.Compiler.Concrete.Pretty.Base
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.PathResolver
import Juvix.Compiler.Internal.Pretty qualified as Internal
import Juvix.Extra.Paths
import Juvix.Extra.Version
import Juvix.Extra.Assets (writeAssets)
import Juvix.Prelude
import Prettyprinter.Render.Util.SimpleDocTree
import Text.Blaze.Html
@ -23,113 +21,159 @@ import Text.Blaze.Html.Renderer.Text qualified as Html
import Text.Blaze.Html5 as Html hiding (map)
import Text.Blaze.Html5.Attributes qualified as Attr
newtype HtmlOptions = HtmlOptions
{ _htmlOptionsKind :: HtmlKind
}
makeLenses ''HtmlOptions
kindSuffix :: HtmlKind -> String
kindSuffix = \case
HtmlDoc -> ""
HtmlSrc -> "-src"
HtmlOnly -> ""
genHtml :: Options -> Bool -> Theme -> Path Abs Dir -> Bool -> Module 'Scoped 'ModuleTop -> IO ()
genHtml opts recursive theme outputDir printMetadata entry = do
data GenSourceHtmlArgs = GenSourceHtmlArgs
{ _genSourceHtmlArgsConcreteOpts :: Options,
_genSourceHtmlArgsAssetsDir :: Text,
_genSourceHtmlArgsHtmlKind :: HtmlKind,
_genSourceHtmlArgsParamBase :: Text,
_genSourceHtmlArgsUrlPrefix :: Text,
_genSourceHtmlArgsEntryPoint :: Module 'Scoped 'ModuleTop,
_genSourceHtmlArgsOutputDir :: Path Abs Dir,
_genSourceHtmlArgsNonRecursive :: Bool,
_genSourceHtmlArgsNoFooter :: Bool,
_genSourceHtmlArgsTheme :: Theme
}
makeLenses ''GenSourceHtmlArgs
data GenModuleHtmlArgs = GenModuleHtmlArgs
{ _genModuleHtmlArgsConcreteOpts :: Options,
_genModuleHtmlArgsUTC :: UTCTime,
_genModuleHtmlArgsEntryPoint :: Module 'Scoped 'ModuleTop
}
makeLenses ''GenModuleHtmlArgs
data GenModuleTextArgs = GenModuleTextArgs
{ _genModuleTextArgsConcreteOpts :: Options,
_genModuleTextArgsUTC :: UTCTime,
_genModuleTextArgsEntryPoint :: Module 'Scoped 'ModuleTop
}
makeLenses ''GenModuleTextArgs
genSourceHtml :: GenSourceHtmlArgs -> IO ()
genSourceHtml o@GenSourceHtmlArgs {..} = do
let outputDir = _genSourceHtmlArgsOutputDir
ensureDir outputDir
copyAssetFiles
writeAssets outputDir
withCurrentDir outputDir $ do
mapM_ outputModule allModules
where
htmlOptions :: HtmlOptions
htmlOptions =
HtmlOptions
{ _htmlOptionsOutputDir = o ^. genSourceHtmlArgsOutputDir,
_htmlOptionsUrlPrefix = o ^. genSourceHtmlArgsUrlPrefix,
_htmlOptionsAssetsPrefix = o ^. genSourceHtmlArgsAssetsDir,
_htmlOptionsKind = o ^. genSourceHtmlArgsHtmlKind,
_htmlOptionsParamBase = o ^. genSourceHtmlArgsParamBase,
_htmlOptionsTheme = o ^. genSourceHtmlArgsTheme,
_htmlOptionsNoFooter = o ^. genSourceHtmlArgsNoFooter
}
entry = o ^. genSourceHtmlArgsEntryPoint
allModules
| recursive = toList (getAllModules entry)
| otherwise = pure entry
| _genSourceHtmlArgsNonRecursive = pure entry
| otherwise = toList topModules
copyAssetFiles :: IO ()
copyAssetFiles = do
ensureDir toAssetsDir
mapM_ writeAsset assetFiles
where
assetFiles :: [(Path Rel File, BS.ByteString)]
assetFiles = assetsDir
writeAsset :: (Path Rel File, BS.ByteString) -> IO ()
writeAsset (filePath, fileContents) =
BS.writeFile (toFilePath (toAssetsDir <//> filePath)) fileContents
toAssetsDir = outputDir <//> $(mkRelDir "assets")
topModules :: HashMap NameId (Module 'Scoped 'ModuleTop)
topModules = getAllModules entry
outputModule :: Module 'Scoped 'ModuleTop -> IO ()
outputModule m = do
ensureDir (parent htmlFile)
putStrLn $ "Writing " <> pack (toFilePath htmlFile)
let absPath = (htmlOptions ^. htmlOptionsOutputDir) <//> htmlFile
putStrLn $ "Writing " <> pack (toFilePath absPath)
utc <- getCurrentTime
Text.writeFile (toFilePath htmlFile) (genModule opts HtmlOnly printMetadata utc theme m)
Text.writeFile
(toFilePath htmlFile)
( run . runReader htmlOptions $
genModuleText
GenModuleTextArgs
{ _genModuleTextArgsConcreteOpts = o ^. genSourceHtmlArgsConcreteOpts,
_genModuleTextArgsUTC = utc,
_genModuleTextArgsEntryPoint = m
}
)
where
htmlFile :: Path Rel File
htmlFile = relFile (topModulePathToDottedPath (m ^. modulePath . S.nameConcrete) <.> ".html")
genModuleHtml :: Options -> HtmlKind -> Bool -> UTCTime -> Theme -> Module 'Scoped 'ModuleTop -> Html
genModuleHtml opts htmlKind printMetadata utc theme m =
docTypeHtml ! Attr.xmlns "http://www.w3.org/1999/xhtml" $
mhead
<> mbody
<> if printMetadata then infoFooter else mempty
where
themeCss :: Html
themeCss = case theme of
Ayu -> ayuCss
Nord -> nordCss
htmlOpts :: HtmlOptions
htmlOpts =
HtmlOptions
{ _htmlOptionsKind = htmlKind
genModuleText ::
forall r.
Members '[Reader HtmlOptions] r =>
GenModuleTextArgs ->
Sem r Text
genModuleText GenModuleTextArgs {..} = do
outputHtml <-
genModuleHtml $
GenModuleHtmlArgs
{ _genModuleHtmlArgsConcreteOpts = _genModuleTextArgsConcreteOpts,
_genModuleHtmlArgsUTC = _genModuleTextArgsUTC,
_genModuleHtmlArgsEntryPoint = _genModuleTextArgsEntryPoint
}
return . toStrict . Html.renderHtml $ outputHtml
pp :: PrettyCode a => a -> Html
pp = ppCodeHtml' htmlOpts opts
genModuleHtml ::
forall r.
Members '[Reader HtmlOptions] r =>
GenModuleHtmlArgs ->
Sem r Html
genModuleHtml o = do
outHtml <- mhead <> mbody
return $
docTypeHtml ! Attr.xmlns "http://www.w3.org/1999/xhtml" $
outHtml
where
mhead :: Sem r Html
mhead = do
css <- themeCss
js <- highlightJs
return $
metaUtf8
<> css
<> js
prettySrc :: Html
prettySrc =
(pre ! Attr.id "src-content") $
pp m
mheader :: Html
mheader =
Html.div ! Attr.id "package-header" $
(Html.span ! Attr.class_ "caption" $ "")
mhead :: Html
mhead =
metaUtf8
<> themeCss
<> highlightJs
mbody :: Html
mbody :: Sem r Html
mbody =
mheader
<> prettySrc
fold
[ mheader,
prettySrc,
htmlJuvixFooter,
formattedTime
]
infoFooter :: Html
infoFooter =
footer . pre $
toHtml ("Powered by " :: Text)
<> (a ! Attr.href "https://anoma.github.io/juvix" $ toHtml ("Juvix CLI " :: Text))
<> (a ! Attr.href (textValue commitAddress) $ toHtml versionTag)
<> br
<> Html.span (toHtml $ ("Last modified on " :: String) <> formattedTime)
where
commitAddress :: Text
commitAddress = "https://github.com/anoma/juvix/commit/" <> shortHash
formattedTime :: Sem r Html
formattedTime =
return $
Html.span . toHtml $
"Last modified on "
<> formatTime
defaultTimeLocale
"%Y-%m-%d %-H:%M %Z"
(o ^. genModuleHtmlArgsUTC)
formattedTime = formatTime defaultTimeLocale "%Y-%m-%d %-H:%M %Z" utc
prettySrc :: Sem r Html
prettySrc = do
pp <-
ppCodeHtml
(o ^. genModuleHtmlArgsConcreteOpts)
(o ^. genModuleHtmlArgsEntryPoint)
return $ (pre ! Attr.id "src-content") pp
genModule :: Options -> HtmlKind -> Bool -> UTCTime -> Theme -> Module 'Scoped 'ModuleTop -> Text
genModule opts htmlKind printMetadata utc theme =
toStrict
. Html.renderHtml
. genModuleHtml opts htmlKind printMetadata utc theme
mheader :: Sem r Html
mheader =
return $
Html.div ! Attr.id "package-header" $
(Html.span ! Attr.class_ "caption" $ "")
docStream' :: PrettyCode a => Options -> a -> SimpleDocStream Ann
docStream' opts m = layoutPretty defaultLayoutOptions (runPrettyCode opts m)
@ -140,10 +184,14 @@ renderTree = go
ppCodeHtml' :: PrettyCode a => HtmlOptions -> Options -> a -> Html
ppCodeHtml' htmlOpts opts = run . runReader htmlOpts . renderTree . treeForm . docStream' opts
ppCodeHtml :: (Members '[Reader HtmlOptions] r, PrettyCode a) => a -> Sem r Html
ppCodeHtml x = do
ppCodeHtml ::
(Members '[Reader HtmlOptions] r, PrettyCode a) =>
Options ->
a ->
Sem r Html
ppCodeHtml opts x = do
o <- ask
return (ppCodeHtml' o defaultOptions x)
return (ppCodeHtml' o opts x)
ppCodeHtmlInternal :: (Members '[Reader HtmlOptions] r, Internal.PrettyCode a) => a -> Sem r Html
ppCodeHtmlInternal x = do
@ -225,4 +273,9 @@ moduleDocRelativePath m = do
nameIdAttrRef :: Members '[Reader HtmlOptions] r => TopModulePath -> Maybe S.NameId -> Sem r AttributeValue
nameIdAttrRef tp s = do
pth <- toFilePath <$> moduleDocRelativePath tp
return (fromString pth <> preEscapedToValue '#' <>? (nameIdAttr <$> s))
prefixUrl <- unpack <$> asks (^. htmlOptionsUrlPrefix)
return $
fromString prefixUrl
<> fromString pth
<> preEscapedToValue '#'
<>? (nameIdAttr <$> s)

View File

@ -11,13 +11,16 @@ topModulePathToRelativePath ext suffix joinpath mp = relFile relFilePath
where
relDirPath :: FilePath
relDirPath = foldr (joinpath . toPath) mempty (mp ^. modulePathDir)
relFilePath :: FilePath
relFilePath = addExt (relDirPath `joinpath'` toPath (mp ^. modulePathName) <> suffix)
joinpath' :: FilePath -> FilePath -> FilePath
joinpath' l r
| null l = r
| otherwise = joinpath l r
addExt = (<.> ext)
toPath :: Symbol -> FilePath
toPath s = unpack (s ^. symbolText)

View File

@ -278,16 +278,15 @@ goFunctionDef (f, sym) = do
mkBody :: Sem r Node
mkBody
| nPatterns == 0 = runReader initIndexTable (goExpression (f ^. Internal.funDefClauses . _head1 . Internal.clauseBody))
| otherwise =
( do
let values :: [Node]
values = mkVar Info.empty <$> vs
indexTable :: IndexTable
indexTable = IndexTable {_indexTableVarsNum = nPatterns, _indexTableVars = mempty}
ms <- mapM (runReader indexTable . goFunctionClause) (f ^. Internal.funDefClauses)
let match = mkMatch' (fromList values) (toList ms)
return $ foldr (\_ n -> mkLambda' n) match vs
)
| otherwise = do
let values :: [Node]
values = mkVar Info.empty <$> vs
indexTable :: IndexTable
indexTable = IndexTable {_indexTableVarsNum = nPatterns, _indexTableVars = mempty}
ms <- mapM (runReader indexTable . goFunctionClause) (f ^. Internal.funDefClauses)
let match = mkMatch' (fromList values) (toList ms)
return $ foldr (\_ n -> mkLambda' n) match vs
-- Assumption: All clauses have the same number of patterns
nPatterns :: Int
nPatterns = length (f ^. Internal.funDefClauses . _head1 . Internal.clausePatterns)

49
src/Juvix/Extra/Assets.hs Normal file
View File

@ -0,0 +1,49 @@
module Juvix.Extra.Assets
( module Juvix.Extra.Assets,
)
where
import Data.ByteString qualified as BS
import Juvix.Extra.Paths
import Juvix.Prelude.Base
import Juvix.Prelude.Path
data AssetKind
= Css
| Js
| Images
assetsDirByKind :: AssetKind -> [(Path Rel File, ByteString)]
assetsDirByKind k = map (first relFile) $
case k of
Css -> $(cssDirQ)
Js -> $(jsDirQ)
Images -> $(imagesDirQ)
absDirAssetsByKind :: Path Abs Dir -> AssetKind -> Path Abs Dir
absDirAssetsByKind baseDir k = baseDir <//> $(mkRelDir "assets") <//> dir
where
dir :: Path Rel Dir
dir = case k of
Css -> $(mkRelDir "css")
Js -> $(mkRelDir "js")
Images -> $(mkRelDir "images")
assetsWithAbsPathAndContent :: Path Abs Dir -> [(Path Abs File, ByteString)]
assetsWithAbsPathAndContent baseDir =
[ (absPath, content)
| kind <- [Css, Js, Images],
(relPart, content) <- assetsDirByKind kind,
let absPath = absDirAssetsByKind baseDir kind <//> relPart
]
writeAssets :: Path Abs Dir -> IO ()
writeAssets baseDir = do
putStrLn $ "Copying assets files to " <> pack (toFilePath baseDir)
mapM_ writeAssetFile (assetsWithAbsPathAndContent baseDir)
where
writeAssetFile :: (Path Abs File, ByteString) -> IO ()
writeAssetFile (p, content) = do
let dirFile = parent p
createDirIfMissing True dirFile
BS.writeFile (toFilePath p) content

View File

@ -15,6 +15,15 @@ relToProject r = $(projectPath) <//> r
assetsDir :: [(Path Rel File, ByteString)]
assetsDir = map (first relFile) $(assetsDirQ)
cssDir :: [(Path Rel File, ByteString)]
cssDir = map (first relFile) $(cssDirQ)
jsDir :: [(Path Rel File, ByteString)]
jsDir = map (first relFile) $(jsDirQ)
imagesDir :: [(Path Rel File, ByteString)]
imagesDir = map (first relFile) $(imagesDirQ)
-- | Given a relative file from the root of the project, checks that the file
-- exists and returns the absolute path
mkProjFile :: Path Rel File -> Q Exp

View File

@ -7,6 +7,15 @@ import Language.Haskell.TH.Syntax
assetsDirQ :: Q Exp
assetsDirQ = FE.makeRelativeToProject "assets" >>= FE.embedDir
cssDirQ :: Q Exp
cssDirQ = FE.makeRelativeToProject "assets/css" >>= FE.embedDir
jsDirQ :: Q Exp
jsDirQ = FE.makeRelativeToProject "assets/js" >>= FE.embedDir
imagesDirQ :: Q Exp
imagesDirQ = FE.makeRelativeToProject "assets/images" >>= FE.embedDir
projectFilePath :: Q Exp
projectFilePath = FE.makeRelativeToProject "." >>= lift

View File

@ -191,5 +191,5 @@ tests =
$(mkRelDir "Internal")
$(mkRelFile "Synonyms.juvix")
]
<> [ compilationTest t | t <- Compilation.tests, t ^. Compilation.name `notElem` ["Self-application"]
<> [ compilationTest t | t <- Compilation.tests, t ^. Compilation.name /= "Self-application"
]

View File

@ -7,9 +7,9 @@ tests:
- bash
script: |
cd milestone/ValidityPredicates
juvix html SimpleFungibleToken.juvix
juvix html SimpleFungibleToken.juvix --only-source
cat html/SimpleFungibleToken.html
stdout:
stdout:
contains:
<!DOCTYPE HTML>
exit-status: 0
@ -20,12 +20,13 @@ tests:
- bash
script: |
rm -rf html
juvix html milestone/ValidityPredicates/SimpleFungibleToken.juvix --output-dir=html
juvix html milestone/ValidityPredicates/SimpleFungibleToken.juvix --only-source --output-dir=html --non-recursive
[ -d html/assets ]
[ -f html/SimpleFungibleToken.html ]
stdout:
equals: |
Writing SimpleFungibleToken.html
stdout:
matches: |
Copying assets files to .*
Writing .*SimpleFungibleToken.html
exit-status: 0
- name: recursive-generation
@ -34,9 +35,7 @@ tests:
- bash
script: |
rm -rf html
juvix html milestone/ValidityPredicates/SimpleFungibleToken.juvix --output-dir=html --recursive
[ -d html/assets ]
[ -f html/SimpleFungibleToken.html ]
juvix html milestone/ValidityPredicates/SimpleFungibleToken.juvix --only-source --output-dir=html
(ls html | wc -l)
cd html
[ -f Stdlib.Data.Ord.html ]
@ -54,10 +53,94 @@ tests:
[ -f Stdlib.Prelude.html ]
[ -f Anoma.Base.html ]
[ -f SimpleFungibleToken.html ]
[ -f assets/highlight.js ]
[ -f assets/source-ayu-light.css ]
[ -f assets/source-nord.css ]
stdout:
[ -f assets/css/source-ayu-light.css ]
[ -f assets/css/source-nord.css ]
[ -f assets/images/tara-magicien.png ]
[ -f assets/images/tara-seating.svg ]
[ -f assets/images/tara-smiling.png ]
[ -f assets/images/tara-smiling.svg ]
[ -f assets/images/tara-teaching.png ]
[ -f assets/images/tara-teaching.svg ]
[ -f assets/js/highlight.js ]
[ -f assets/js/tex-chtml.js ]
stdout:
contains: |
Writing SimpleFungibleToken.html
SimpleFungibleToken.html
exit-status: 0
- name: judoc-assets
command:
shell:
- bash
script: |
rm -rf html
juvix html milestone/ValidityPredicates/SimpleFungibleToken.juvix --output-dir=html
(ls html | wc -l)
cd html
[ -f Stdlib.Data.Ord.html ]
[ -f Stdlib.Data.String.html ]
[ -f Stdlib.Data.Nat.html ]
[ -f Stdlib.System.IO.html ]
[ -f Stdlib.Function.html ]
[ -f Stdlib.Data.List.html ]
[ -f Stdlib.Data.String.Ord.html ]
[ -f Stdlib.Data.Product.html ]
[ -f Data.Int.Ops.html ]
[ -f Stdlib.Data.Maybe.html ]
[ -f Data.Int.html ]
[ -f Stdlib.Data.Bool.html ]
[ -f Stdlib.Prelude.html ]
[ -f Anoma.Base.html ]
[ -f SimpleFungibleToken.html ]
[ -f assets/css/source-ayu-light.css ]
[ -f assets/css/source-nord.css ]
[ -f assets/css/linuwial.css ]
[ -f assets/images/tara-magicien.png ]
[ -f assets/images/tara-seating.svg ]
[ -f assets/images/tara-smiling.png ]
[ -f assets/images/tara-smiling.svg ]
[ -f assets/images/tara-teaching.png ]
[ -f assets/images/tara-teaching.svg ]
[ -f assets/js/highlight.js ]
[ -f assets/js/tex-chtml.js ]
stdout:
contains: |
SimpleFungibleToken.html
exit-status: 0
- name: non-recursive-generation
command:
shell:
- bash
script: |
rm -rf html
juvix html milestone/ValidityPredicates/SimpleFungibleToken.juvix --output-dir=html --non-recursive
(ls html | wc -l)
cd html
[ -d assets ]
[ -f SimpleFungibleToken.html ]
stdout:
matches: |
Copying assets files to .*
Writing .*SimpleFungibleToken.html
4
exit-status: 0
- name: non-recursive-generation-only-source
command:
shell:
- bash
script: |
rm -rf html
juvix html milestone/ValidityPredicates/SimpleFungibleToken.juvix --output-dir=html --non-recursive --only-source
(ls html | wc -l)
cd html
[ -d assets/ ]
[ -f SimpleFungibleToken.html ]
stdout:
matches: |
Copying assets files to .*
Writing .*SimpleFungibleToken.html
2
exit-status: 0