packages feed

mmark-cli (empty) → 0.0.1.0

raw patch · 6 files changed

+647/−0 lines, 6 filesdep +aesondep +basedep +bytestringsetup-changed

Dependencies added: aeson, base, bytestring, directory, gitrev, lucid, megaparsec, mmark, mmark-ext, optparse-applicative, skylighting, stache, text, unordered-containers

Files

+ CHANGELOG.md view
@@ -0,0 +1,3 @@+## MMark CLI 0.0.1.0++* Initial release.
+ LICENSE.md view
@@ -0,0 +1,28 @@+Copyright © 2018 Mark Karpov++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice,+  this list of conditions and the following disclaimer.++* Redistributions in binary form must reproduce the above copyright+  notice, this list of conditions and the following disclaimer in the+  documentation and/or other materials provided with the distribution.++* Neither the name Mark Karpov nor the names of contributors may be used to+  endorse or promote products derived from this software without specific+  prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS “AS IS” AND ANY EXPRESS+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN+NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,315 @@+# MMark CLI++[![License BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg)](http://opensource.org/licenses/BSD-3-Clause)+[![Hackage](https://img.shields.io/hackage/v/mmark-cli.svg?style=flat)](https://hackage.haskell.org/package/mmark-cli)+[![Stackage Nightly](http://stackage.org/package/mmark-cli/badge/nightly)](http://stackage.org/nightly/package/mmark-cli)+[![Stackage LTS](http://stackage.org/package/mmark-cli/badge/lts)](http://stackage.org/lts/package/mmark-cli)+[![Build Status](https://travis-ci.org/mmark-md/mmark-cli.svg?branch=master)](https://travis-ci.org/mmark-md/mmark-cli)++* [Templates](#tepmlates)+* [Extensions](#extensions)+  * [Comment paragraph](#comment-paragraph)+  * [Font Awesome](#font-awesome)+  * [Kbd tags](#kbd-tags)+  * [Link targets](#link-targets)+  * [Email obfuscation](#email-obfuscation)+  * [Punctuation prettifier](#punctuation-prettifier)+  * [Skylighting](#skylighting)+  * [Table of contents](#table-of-contents)+* [Contribution](#contribution)+* [License](#license)++This is a command line application serving as an interface to MMark markdown+processor.++```+mmark—command line interface to MMark markdown processor++Usage: mmark [-v|--version] [-i|--ifile IFILE] [-o|--ofile OFILE] [-j|--json]+             [-t|--template FILE] [--ext-comment PREFIX] [--ext-font-awesome]+             [--ext-kbd] [--ext-link-target] [--ext-obfuscate-email CLASS]+             [--ext-punctuation] [--ext-skylighting] [--ext-toc RANGE]+  Command line interface to MMark markdown processor++Available options:+  -h,--help                Show this help text+  -v,--version             Print version of the program+  -i,--ifile IFILE         Read markdown source from this file (otherwise read+                           from stdin)+  -o,--ofile OFILE         Save rendered HTML document to this file (otherwise+                           write to stdout)+  -j,--json                Output parse errors and result in JSON format+  -t,--template FILE       Use the template located at this path+  --ext-comment PREFIX     Remove paragraphs that start with the given prefix+  --ext-font-awesome       Enable support for inserting font awesome icons+  --ext-kbd                Enable support for wrapping things in kbd tags+  --ext-link-target        Enable support for specifying link targets+  --ext-obfuscate-email CLASS+                           Obfuscate email addresses assigning the specified+                           class+  --ext-punctuation        Enable punctuation prettifier+  --ext-skylighting        Enable syntax highlighting of code snippets with+                           Skylighting+  --ext-toc RANGE          Enable generation of table of contents using the+                           supplied range of headers to include, e.g. "1-6" or+                           "2-4"+```++## Templates++By using the `--template` argument, it's possible to create a standalone+HTML page. The templating system we use is+[Mustache](https://mustache.github.io/mustache.5.html), as implemented by+the [stache](https://hackage.haskell.org/package/stache) library. The+library conforms to the version 1.1.3 of the official [Mustache+specification](https://github.com/mustache/spec), but does not implement+lambdas (which is an optional feature is the specification) for simplify and+other technical reasons we won't touch here.++If markdown source file has a YAML section, its contents will be provided as+context for rendering of the template. In addition to that, a new top-level+value bound to the variable named `output` will be available. That variable+contains the HTML rendition of markdown document. It's best to interpolate+it without HTML escaping, like so: `{{& output }}`.++## Extensions++Here we list how to use the available extensions. The extensions come from+the [`mmark-ext`](https://hackage.haskell.org/package/mmark-ext) package.++### Comment paragraph++* Option: `--ext-comment PREFIX`++This extension removes paragraphs that start with the given `PREFIX`. For+example:++```+$ mmark --ext-comment REM+First.++REM Second.++Third.+----------------------- Control-D+<p>First.</p>+<p>Third.</p>+```++### Font awesome++* Option: `--ext-font-awesome`++This allows to turn autolinks with `fa` scheme into font awesome icons:++```+$ mmark --ext-font-awesome+Here is the user icon: <fa:user>.++A more interesting example: <fa:quote-left/3x/pull-left/border>.+----------------------- Control-D+<p>Here is the user icon: <span class="fa fa-user"></span>.</p>+<p>A more interesting example:+  <span class="fa fa-quote-left fa-3x fa-pull-left fa-border"></span>.+</p>+```++In general, all path components in URIs that go after the name of icon will+be prefixed with `"fa-"` and added as classes, so you can do a lot of fancy+stuff, see <http://fontawesome.io/examples/>.++### Kbd tags++* Option: `--ext-kbd`++Introduce kbd tags into resulting HTML document by wrapping content in links+with URL with kbd scheme. For example:++```+$ mmark --ext-kbd+To enable that mode press [Ctrl+A][kbd].++[kbd]: kbd:+----------------------- Control-D+<p>To enable that mode press <kbd>Ctrl+A</kbd>.</p>+```++The use of reference-style links seems more aesthetically pleasant to the+author, but you can of course do something like this instead:++```+To enable that mode press [Ctrl+A](kbd:).+```++### Link targets++* Option: `--ext-link-target`++When title of a link starts with the word `"_blank"`, `"_self"`,+`"_parent"`, or `"_top"`, it's stripped from title (as well as all+whitespace after it) and added as the value of target attribute of the+resulting link. For example:++```+$ mmark --ext-kbd+This [link](/url '_blank My title') opens in new tab.+----------------------- Control-D+<p>This <a href="/url" title="My title" target="_blank">link</a>+opens in new tab.</p>+```++### Email obfuscation++* Option: `--obfuscate-email CLASS`++This extension makes email addresses in autolinks be rendered as something+like this:++```+[mark@arch ~]$ mmark --ext-obfuscate-email protected-email+Send all your spam to <someone@example.org>, if you can!+----------------------- Control-D+<p>Send all your spam to+  <a href="javascript:void(0)"+     class="protected-email"+     data-email="someone@example.org">+  Enable JavaScript to see this email</a>, if you can!+</p>+```++You'll also need to include jQuery and this bit of JS code for the magic to+work:++```java-script+$(document).ready(function () {+    $(".protected-email").each(function () {+        var item = $(this);+        var email = item.data('email');+        item.attr('href', 'mailto:' + email);+        item.html(email);+    });+});+```++### Punctuation prettifier++* Option: `--ext-punctuation`++This makes MMark prettify punctuation (only affects plain text in inlines),+the effect is the following:++* Replace `...` with ellipsis `…`+* Replace `---` with em-dash `—`+* Replace `--` with en-dash `–`+* Replace `"` with left double quote `“` when previous character was a space+  character, otherwise replace it with right double quote `”`+* Replace `'` with left single quote `‘` when previous character was a space+  character, otherwise replace it with right single quote `’` aka apostrophe++For example (not sure this is the correct punctuation to use here, but it+demonstrates the effect):++```+[mark@arch ~]$ mmark --ext-punctuation+Something---we don't know what, happened...+----------------------- Control-D+<p>Something—we don’t know what, happened…</p>+```++### Skylighting++* Option: `--ext-skylighting`++Use the [skylighting](https://hackage.haskell.org/package/skylighting)+package to render code blocks with info strings that result in a successful+lookup from syntax table that comes with the library.++The resulting markup is wrapped with spans as described in the docs for+[`formatHtmlInline`](https://hackage.haskell.org/package/skylighting/docs/Skylighting-Format-HTML.html#v:formatHtmlInline).++Example:++````+[mark@arch ~]$ mmark --ext-skylighting+Some Haskell:++```haskell+main :: IO ()+main = return ()+```+----------------------- Control-D+<p>Some Haskell:</p>+<div class="sourceCode">+  <pre class="sourceCode">+    <code class="sourceCode">+      <a class="sourceLine" id="1" data-line-number="1">+        <span class="ot">main ::</span> <span class="dt">IO</span> ()+      </a>+      <a class="sourceLine" id="2" data-line-number="2">main <span class="fu">=</span> return ()</a>+    </code>+  </pre>+</div>+````++### Table of contents++* Option: `--ext-toc RANGE`++Replace the code block with info string `"toc"` by table of contents+assembled from headings with levels from `N` to `M`, where `N-M` is `RANGE`.++For example:++````+[mark@arch ~]$ mmark --ext-toc 2-4+# Story of my life++```toc+```++## Charpter 1++Foo.++## Chapter 2++Bar.++### Something++Baz.+----------------------- Control-D+<h1 id="story-of-my-life">Story of my life</h1>+<ul>+<li>+<a href="#charpter-1">Charpter 1</a>+</li>+<li>+<a href="#chapter-2">Chapter 2</a>+<ul>+<li>+<a href="#something">Something</a>+</li>+</ul>+</li>+</ul>+<h2 id="charpter-1">Charpter 1</h2>+<p>Foo.</p>+<h2 id="chapter-2">Chapter 2</h2>+<p>Bar.</p>+<h3 id="something">Something</h3>+<p>Baz.</p>+````++## Contribution++Issues, bugs, and questions may be reported in [the GitHub issue tracker for+this project](https://github.com/mmark-md/mmark-cli/issues).++Pull requests are also welcome and will be reviewed quickly.++## License++Copyright © 2018 Mark Karpov++Distributed under BSD 3 clause license.
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main (main) where++import Distribution.Simple++main :: IO ()+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,246 @@+{-# LANGUAGE CPP               #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE TemplateHaskell   #-}+{-# LANGUAGE TupleSections     #-}++module Main (main) where++import Control.Applicative+import Control.Monad+import Data.Aeson ((.=), Value (..))+import Data.List (intercalate)+import Data.List.NonEmpty (NonEmpty (..))+import Data.Text (Text)+import Data.Version (showVersion)+import Data.Void+import Development.GitRev+import Options.Applicative hiding (ParseError)+import Paths_mmark_cli (version)+import Skylighting (defaultFormatOpts)+import System.Directory (makeAbsolute)+import System.Exit (exitFailure)+import Text.MMark (MMarkErr)+import Text.Megaparsec (Parsec, ParseError, SourcePos (..))+import qualified Data.Aeson                  as Aeson+import qualified Data.ByteString.Lazy.Char8  as BL+import qualified Data.HashMap.Strict         as HM+import qualified Data.Text                   as T+import qualified Data.Text.IO                as T+import qualified Data.Text.Lazy              as TL+import qualified Lucid                       as L+import qualified Text.MMark                  as MMark+import qualified Text.MMark.Extension.Common as Ext+import qualified Text.Megaparsec             as M+import qualified Text.Megaparsec.Char        as MC+import qualified Text.Megaparsec.Char.Lexer  as MCL+import qualified Text.Mustache               as U++-- | Entry point of the program.++main :: IO ()+main = do+  Opts {..} <- execParser optsParserInfo+  (mdFileName, mdInput) <-+    case optInputFile of+      Nothing -> ("<stdin>",) <$> T.getContents+      Just file -> do+        absFile <- makeAbsolute file+        (absFile,) <$> T.readFile absFile+  case MMark.parse mdFileName mdInput of+    Left errs -> do+      if optJson+        then (BL.putStrLn . Aeson.encode . parseErrorsJson) errs+        else putStr (MMark.parseErrorsPretty mdInput errs)+      exitFailure+    Right doc -> do+      let exts = mconcat+            [ g optExtComment               Ext.commentParagraph+            , f optExtFontAwesome           Ext.fontAwesome+            , f optExtKbd                   Ext.kbd+            , f optExtLinkTarget            Ext.linkTarget+            , g optExtObfuscateEmail        Ext.obfuscateEmail+            , f optExtPunctuationPrettifier Ext.punctuationPrettifier+            , f optExtSkylighting           Ext.skylighting defaultFormatOpts+            , g optExtToc $ \(from,to) ->+               Ext.toc "toc" . MMark.runScanner doc . Ext.tocScanner $ \x ->+                 from <= x && x <= to+            ]+          f p x = if p then x else mempty+          g p x = maybe mempty x p+          applyTemplate tfile output = do+            t <- U.compileMustacheFile tfile+            return . TL.toStrict . U.renderMustache t $+              case MMark.projectYaml doc of+                Just (Object m) -> Object $+                  HM.insert "output" (String output) m+                _ -> Aeson.object+                  [ "output" .= output+                  ]+      htmlOutput <- maybe return applyTemplate optTemplate+        . TL.toStrict+        . L.renderText+        . MMark.render+        . MMark.useExtension exts+        $ doc+      if optJson+        then maybe BL.putStrLn BL.writeFile optOutputFile $+               Aeson.encode (htmlDocJson htmlOutput)+        else maybe T.putStr T.writeFile optOutputFile htmlOutput++----------------------------------------------------------------------------+-- Command line options parsing++-- | Command line options.++data Opts = Opts+  { optInputFile  :: !(Maybe FilePath)+    -- ^ File from which to read input (otherwise use stdin)+  , optOutputFile :: !(Maybe FilePath)+    -- ^ File to which to save output (otherwise use stdout)+  , optJson :: !Bool+    -- ^ Whether to output JSON+  , optTemplate :: !(Maybe FilePath)+    -- ^ Use the template located at this path++  , optExtComment :: !(Maybe Text)+    -- ^ Enable extension: 'Ext.commentParagraph'+  , optExtFontAwesome :: !Bool+    -- ^ Enable extension: 'Ext.fontAwesome'+  , optExtKbd :: !Bool+    -- ^ Enable extension: 'Ext.kbd'+  , optExtLinkTarget :: !Bool+    -- ^ Enable extension: 'Ext.linkTarget'+  , optExtObfuscateEmail :: !(Maybe Text)+    -- ^ Enable extension: 'Ext.obfuscateEmail'+  , optExtPunctuationPrettifier :: !Bool+    -- ^ Enable extension: 'Ext.punctuationPrettifier'+  , optExtSkylighting :: !Bool+    -- ^ Enable extension: 'Ext.skylighting'+  , optExtToc :: !(Maybe (Int, Int))+    -- ^ Enable extension: 'Ext.toc'+  }++optsParserInfo :: ParserInfo Opts+optsParserInfo = info (helper <*> ver <*> optsParser) . mconcat $+  [ fullDesc+  , progDesc "Command line interface to MMark markdown processor"+  , header   "mmark—command line interface to MMark markdown processor"+  ]+  where+    ver :: Parser (a -> a)+    ver = infoOption verStr . mconcat $+      [ long  "version"+      , short 'v'+      , help  "Print version of the program"+      ]+    verStr = intercalate "\n"+      [ unwords+        [ "mmark"+        , showVersion version+        , $gitBranch+        , $gitHash+        ]+      , "using mmark     (library) " ++ VERSION_mmark+      , "using mmark-ext (library) " ++ VERSION_mmark_ext+      ]++optsParser :: Parser Opts+optsParser = Opts+  <$> (optional . strOption . mconcat)+    [ long    "ifile"+    , short   'i'+    , metavar "IFILE"+    , help    "Read markdown source from this file (otherwise read from stdin)"+    ]+  <*> (optional . strOption . mconcat)+    [ long    "ofile"+    , short   'o'+    , metavar "OFILE"+    , help    "Save rendered HTML document to this file (otherwise write to stdout)"+    ]+  <*> (switch . mconcat)+    [ long    "json"+    , short   'j'+    , help    "Output parse errors and result in JSON format"+    ]+  <*> (optional . strOption . mconcat)+    [ long    "template"+    , short   't'+    , metavar "FILE"+    , help    "Use the template located at this path"+    ]+  <*> (optional . fmap T.pack . strOption . mconcat)+    [ long    "ext-comment"+    , metavar "PREFIX"+    , help    "Remove paragraphs that start with the given prefix"+    ]+  <*> (switch . mconcat)+    [ long    "ext-font-awesome"+    , help    "Enable support for inserting font awesome icons"+    ]+  <*> (switch . mconcat)+    [ long    "ext-kbd"+    , help    "Enable support for wrapping things in kbd tags"+    ]+  <*> (switch . mconcat)+    [ long    "ext-link-target"+    , help    "Enable support for specifying link targets"+    ]+  <*> (optional . fmap T.pack . strOption . mconcat)+    [ long    "ext-obfuscate-email"+    , metavar "CLASS"+    , help    "Obfuscate email addresses assigning the specified class"+    ]+  <*> (switch . mconcat)+    [ long    "ext-punctuation"+    , help    "Enable punctuation prettifier"+    ]+  <*> (switch . mconcat)+    [ long    "ext-skylighting"+    , help    "Enable syntax highlighting of code snippets with Skylighting"+    ]+  <*> (optional . option parseRange . mconcat)+    [ long    "ext-toc"+    , metavar "RANGE"+    , help    ("Enable generation of table of contents using the supplied "+      ++       "range of headers to include, e.g. \"1-6\" or \"2-4\"")+    ]++----------------------------------------------------------------------------+-- Helpers++-- | Represent the given collection of parse errors as 'Value'.++parseErrorsJson :: NonEmpty (ParseError Char MMarkErr) -> Value+parseErrorsJson = Aeson.toJSON . fmap parseErrorObj+  where+    parseErrorObj :: ParseError Char MMarkErr -> Value+    parseErrorObj err = let (SourcePos {..}:|_) = M.errorPos err in Aeson.object+      [ "file"   .= sourceName+      , "line"   .= M.unPos sourceLine+      , "column" .= M.unPos sourceColumn+      , "text"   .= M.parseErrorTextPretty err+      ]++-- | Represent the given rendered HTML document as 'Aeson.Value'.++htmlDocJson :: Text -> Value+htmlDocJson html = Aeson.object+  [ "html" .= html+  ]++-- | Parse a range as two positive numbers separated by a hyphen.++parseRange :: ReadM (Int, Int)+parseRange = eitherReader $ \s ->+  case M.parse p "" s of+    Left err -> Left (M.parseErrorTextPretty err)+    Right x  -> Right x+  where+    p :: Parsec Void String (Int, Int)+    p = do+      from <- MCL.decimal+      void (MC.char '-')+      to   <- MCL.decimal+      return (from, to)
+ mmark-cli.cabal view
@@ -0,0 +1,49 @@+name:                 mmark-cli+version:              0.0.1.0+cabal-version:        >= 1.18+tested-with:          GHC==8.0.2, GHC==8.2.2+license:              BSD3+license-file:         LICENSE.md+author:               Mark Karpov <markkarpov92@gmail.com>+maintainer:           Mark Karpov <markkarpov92@gmail.com>+homepage:             https://github.com/mmark-md/mmark-cli+bug-reports:          https://github.com/mmark-md/mmark-cli/issues+category:             Categories+synopsis:             Description+build-type:           Simple+description:          Description.+extra-doc-files:      CHANGELOG.md+                    , README.md++source-repository head+  type:               git+  location:           https://github.com/mmark-md/mmark-cli.git++flag dev+  description:        Turn on development settings.+  manual:             True+  default:            False++executable mmark+  main-is:            Main.hs+  hs-source-dirs:     app+  build-depends:      aeson            >= 0.11  && < 1.3+                    , base             >= 4.9   && < 5.0+                    , bytestring       >= 0.9.2 && < 0.11+                    , directory        >= 1.2.2 && < 1.4+                    , gitrev           >= 1.3   && < 1.4+                    , lucid            >= 2.6   && < 3.0+                    , megaparsec       >= 6.4   && < 7.0+                    , mmark            >= 0.0.4 && < 0.1+                    , mmark-ext        >= 0.1   && < 0.2+                    , optparse-applicative >= 0.14 && < 0.15+                    , skylighting      >= 0.5   && < 0.6+                    , stache           >= 1.2   && < 1.3+                    , text             >= 0.2   && < 1.3+                    , unordered-containers >= 0.2.5 && < 0.3+  other-modules:      Paths_mmark_cli+  if flag(dev)+    ghc-options:      -Wall -Werror+  else+    ghc-options:      -O2 -Wall+  default-language:   Haskell2010