1
1
mirror of https://github.com/srid/ema.git synced 2024-12-01 15:13:36 +03:00

markdown helper gone

This commit is contained in:
Sridhar Ratnakumar 2022-02-04 19:33:00 -05:00
parent cabae54a23
commit f65e2b1b73
5 changed files with 11 additions and 151 deletions

View File

@ -6,6 +6,7 @@
- Helpers
- `Ema.Helpers.PathTree` moved to separate package *pathtree*.
- `Ema.Helpers.FileSystem` moved to separate package *unionmount*.
- `Ema.Helpers.Markdown` moved to separate package *commonmark-simple*.
## 0.4.0.0 -- 2022-01-19

View File

@ -1,10 +1,10 @@
---
order: 5
---
# Helpers
# Howto
Beyond the model and route types, Ema leaves it up to you as to how to develop your site. The following are not *required* when using Ema; nevertheless they are useful inasmuch as they capture common patterns in writing a good static site:
Beyond the model and route types, Ema leaves it up to you as to how to develop your site. Here are some common aspects of writing a static site:
* [Blaze](guide/helpers/blaze.md) -- [We recommend--but not mandate--Tailwind for CSS and blaze-html as HTML DSL]{.item-intro}
* [Blaze HTML DSL](guide/helpers/blaze.md) -- [Use blaze-html with Tailwind CSS]{.item-intro}
* [Working with files](guide/helpers/filesystem.md) -- [Use `unionmount` to support hot-reload on files]{.item-intro}
* [Converting Markdown](guide/helpers/markdown.md) -- [Pointers on how to work with Markdown files]{.item-intro}

View File

@ -8,14 +8,15 @@ There are quite a few packages to convert Markdown to HTML,
- [Pandoc](https://hackage.haskell.org/package/pandoc) -- [Supports formats other than Markdown]{.item-intro}
- [commonmark-hs](https://github.com/jgm/commonmark-hs) -- [Lightweight parser by the same author of Pandoc]{.item-intro}
- [commonmark-simple](https://hackage.haskell.org/package/commonmark-simple-0.1.0.0) -- [Simpler interface to the above, with frontmatter support]{.item-intro}
- [mmark](https://github.com/mmark-md/mmark) -- [*Strict* Markdown parser]{.item-intro}
## Helper
## `commonmark-simple`
Ema provides a helper to parse Markdown files with YAML frontmatter, using commonmark-hs. If you are parsing front matter, you can use any type that has a [`FromYAML`](https://hackage.haskell.org/package/HsYAML-0.2.1.0/docs/Data-YAML.html#t:FromYAML) instance.
`commonmark-simple` uses commonmark-hs to provide a simpler API, along with front matter support. If you are parsing front matter, you can use any type that has a [`FromYAML`](https://hackage.haskell.org/package/HsYAML-0.2.1.0/docs/Data-YAML.html#t:FromYAML) instance.
```haskell
import qualified Ema.Helper.Markdown as Markdown
import qualified Commonmark.Simple as CS
-- Front matter metadata can be any type with a `FromYAML` instance
--
@ -24,10 +25,10 @@ import qualified Ema.Helper.Markdown as Markdown
type Metadata = Map Text Text
-- Returns `Either Text (Metadata, Pandoc)`
Markdown.parseMarkdownWithFrontMatter @Metadata
CS.parseMarkdownWithFrontMatter @Metadata
"test.md" "Hello *world*"
```
The template repo, as well as [Emanote](https://github.com/srid/emanote) (used to generate this site), uses this helper to parse Markdown files into Pandoc AST. Consult [the template repo's source code](https://github.com/srid/ema-template/blob/master/src/Main.hs) for details.
Note that with Ema you can get [hot reload](concepts/hot-reload.md) support for your Markdown files using [filesystem notifications](guide/helpers/filesystem.md).
Note that with Ema you can get [hot reload](concepts/hot-reload.md) support for your Markdown files using [the `unionmount` package](guide/helpers/filesystem.md).

View File

@ -1,6 +1,6 @@
cabal-version: 2.4
name: ema
version: 0.5.2.0
version: 0.5.3.0
license: AGPL-3.0-only
copyright: 2021 Sridhar Ratnakumar
maintainer: srid@srid.ca
@ -68,15 +68,6 @@ library
build-depends:
, blaze-html
, blaze-markup
, commonmark
, commonmark-extensions
, commonmark-pandoc
, megaparsec
, pandoc-types
, parsec
, parser-combinators
, time
, yaml
if flag(with-examples)
build-depends: time
@ -139,7 +130,6 @@ library
if (flag(with-helpers) || flag(with-examples))
exposed-modules:
Ema.Helper.Blaze
Ema.Helper.Markdown
other-modules:
Ema.App

View File

@ -1,132 +0,0 @@
-- | Helper to deal with Markdown files
--
-- TODO: Publish this eventually to Hackage, along with wiki-link stuff from
-- emanote (maybe as separate package).
module Ema.Helper.Markdown
( -- Parsing
-- TODO: Publish to Hackage as commonmark-pandoc-simple?
parseMarkdownWithFrontMatter,
parseMarkdown,
fullMarkdownSpec,
-- Utilities
plainify,
)
where
import Commonmark qualified as CM
import Commonmark.Extensions qualified as CE
import Commonmark.Pandoc qualified as CP
import Control.Monad.Combinators (manyTill)
import Data.Aeson (FromJSON)
import Data.Yaml qualified as Y
import Text.Megaparsec qualified as M
import Text.Megaparsec.Char qualified as M
import Text.Pandoc.Builder qualified as B
import Text.Pandoc.Definition (Pandoc (..))
import Text.Pandoc.Walk qualified as W
-- | Parse a Markdown file using commonmark-hs with all extensions enabled
parseMarkdownWithFrontMatter ::
forall meta m il bl.
( FromJSON meta,
m ~ Either CM.ParseError,
bl ~ CP.Cm () B.Blocks,
il ~ CP.Cm () B.Inlines
) =>
CM.SyntaxSpec m il bl ->
-- | Path to file associated with this Markdown
FilePath ->
-- | Markdown text to parse
Text ->
Either Text (Maybe meta, Pandoc)
parseMarkdownWithFrontMatter spec fn s = do
(mMeta, markdown) <- partitionMarkdown fn s
mMetaVal <- first show $ (Y.decodeEither' . encodeUtf8) `traverse` mMeta
blocks <- first show $ join $ CM.commonmarkWith @(Either CM.ParseError) spec fn markdown
let doc = Pandoc mempty $ B.toList . CP.unCm @() @B.Blocks $ blocks
pure (mMetaVal, doc)
parseMarkdown :: FilePath -> Text -> Either Text Pandoc
parseMarkdown fn s = do
cmBlocks <- first show $ join $ CM.commonmarkWith @(Either CM.ParseError) fullMarkdownSpec fn s
let blocks = B.toList . CP.unCm @() @B.Blocks $ cmBlocks
pure $ Pandoc mempty blocks
type SyntaxSpec' m il bl =
( Monad m,
CM.IsBlock il bl,
CM.IsInline il,
Typeable m,
Typeable il,
Typeable bl,
CE.HasEmoji il,
CE.HasStrikethrough il,
CE.HasPipeTable il bl,
CE.HasTaskList il bl,
CM.ToPlainText il,
CE.HasFootnote il bl,
CE.HasMath il,
CE.HasDefinitionList il bl,
CE.HasDiv bl,
CE.HasQuoted il,
CE.HasSpan il
)
-- | GFM + official commonmark extensions
fullMarkdownSpec ::
SyntaxSpec' m il bl =>
CM.SyntaxSpec m il bl
fullMarkdownSpec =
mconcat
[ CE.gfmExtensions,
CE.fancyListSpec,
CE.footnoteSpec,
CE.mathSpec,
CE.smartPunctuationSpec,
CE.definitionListSpec,
CE.attributesSpec,
CE.rawAttributeSpec,
CE.fencedDivSpec,
CE.bracketedSpanSpec,
CE.autolinkSpec,
CM.defaultSyntaxSpec,
-- as the commonmark documentation states, pipeTableSpec should be placed after
-- fancyListSpec and defaultSyntaxSpec to avoid bad results when parsing
-- non-table lines
CE.pipeTableSpec
]
-- | Identify metadata block at the top, and split it from markdown body.
--
-- FIXME: https://github.com/srid/neuron/issues/175
partitionMarkdown :: FilePath -> Text -> Either Text (Maybe Text, Text)
partitionMarkdown =
parse (M.try splitP <|> fmap (Nothing,) M.takeRest)
where
separatorP :: M.Parsec Void Text ()
separatorP =
void $ M.string "---" <* M.eol
splitP :: M.Parsec Void Text (Maybe Text, Text)
splitP = do
separatorP
a <- toText <$> manyTill M.anySingle (M.try $ M.eol *> separatorP)
b <- M.takeRest
pure (Just a, b)
parse :: M.Parsec Void Text a -> String -> Text -> Either Text a
parse p fn s =
first (toText . M.errorBundlePretty) $
M.parse (p <* M.eof) fn s
-- | Convert Pandoc AST inlines to raw text.
plainify :: [B.Inline] -> Text
plainify = W.query $ \case
B.Str x -> x
B.Code _attr x -> x
B.Space -> " "
B.SoftBreak -> " "
B.LineBreak -> " "
B.RawInline _fmt s -> s
B.Math _mathTyp s -> s
-- Ignore the rest of AST nodes, as they are recursively defined in terms of
-- `Inline` which `W.query` will traverse again.
_ -> ""