packages feed

readme-lhs 0.1.0.0 → 0.2.0

raw patch · 14 files changed

+1670/−545 lines, 14 filesdep +doctestdep +optparse-genericdep +pandocdep −HUnitdep −attoparsecdep −filepathnew-component:exe:readme-lhs-examplePVP ok

version bump matches the API change (PVP)

Dependencies added: doctest, optparse-generic, pandoc, pandoc-types

Dependencies removed: HUnit, attoparsec, filepath, foldl, optparse-applicative, tasty-hunit

API changes (from Hackage documentation)

- Readme.Lhs: Block :: Section -> [Text] -> Block
- Readme.Lhs: Code :: Section
- Readme.Lhs: Comment :: Section
- Readme.Lhs: Hs :: Format
- Readme.Lhs: Lhs :: Format
- Readme.Lhs: bird :: Parser Block
- Readme.Lhs: data Block
- Readme.Lhs: data Format
- Readme.Lhs: data Section
- Readme.Lhs: instance GHC.Classes.Eq Readme.Lhs.Block
- Readme.Lhs: instance GHC.Classes.Eq Readme.Lhs.Section
- Readme.Lhs: instance GHC.Show.Show Readme.Lhs.Block
- Readme.Lhs: instance GHC.Show.Show Readme.Lhs.Section
- Readme.Lhs: normal :: Parser (Maybe (Section, Section), [Text])
- Readme.Lhs: parse :: Format -> [Text] -> [Block]
- Readme.Lhs: parseHs :: [Text] -> [Block]
- Readme.Lhs: parseLhs :: [Text] -> [Block]
- Readme.Lhs: print :: Format -> [Block] -> [Text]
- Readme.Lhs: printHs :: [Block] -> [Text]
- Readme.Lhs: printLhs :: [Block] -> [Text]
+ Readme.Lhs: GitHubMarkdown :: Flavour
+ Readme.Lhs: LHS :: Flavour
+ Readme.Lhs: code :: Text -> [Text] -> Text -> Block
+ Readme.Lhs: data Flavour
+ Readme.Lhs: output :: Monad m => Text -> Text -> StateT (Map Text Text) m ()
+ Readme.Lhs: para :: Text -> Block
+ Readme.Lhs: plain :: Text -> Block
+ Readme.Lhs: readPandoc :: FilePath -> Flavour -> IO (Either PandocError Pandoc)
+ Readme.Lhs: renderMarkdown :: Flavour -> Pandoc -> Either PandocError Text
+ Readme.Lhs: runOutput :: (FilePath, Flavour) -> (FilePath, Flavour) -> StateT Output IO () -> IO (Either PandocError ())
+ Readme.Lhs: table :: Text -> [Text] -> [Alignment] -> [Int] -> [[Text]] -> Block
+ Readme.Lhs: tweakHaskellCodeBlock :: Block -> Block

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright Tony Day (c) 2016+Copyright Tony Day (c) 2017  All rights reserved. 
− app/Main.hs
@@ -1,39 +0,0 @@-{-# OPTIONS_GHC -Wall #-}-module Main where--import qualified Data.Text as Text-import qualified Data.Text.IO as Text-import Options.Applicative-import Protolude-import Readme.Lhs-import System.FilePath--data Options = Options-    { fileIn :: FilePath-    , fileOut :: FilePath-    } deriving (Show, Eq)--options :: Options.Applicative.Parser Options-options = Options-    <$> (strOption-        (long "in" <> short 'i' <> value "" <> help "file in"))-    <*> (strOption-        (long "out" <> short 'o' <> value "" <> help "file out"))--consume :: Options -> IO ()-consume (Options "" _) = pure ()-consume (Options fi fo) = do-    text <- readFile fi-    let fromHs = ".hs" == takeExtension fi-    let fo' = dropExtension fi ++ (if fromHs then ".lhs" else ".hs")-    withFile (if fo == "" then fo' else fo) WriteMode $ \h -> do-        let f = parse (if fromHs then Hs else Lhs) (Text.lines text)-        mapM_ (Text.hPutStrLn h) (Readme.Lhs.print (if fromHs then Lhs else Hs) f)--main :: IO ()-main = execParser opts >>= consume-  where-    opts = info (helper <*> options)-      ( fullDesc-      <> progDesc "almost isomorph of .lhs and .hs formats"-      <> header "lhs")
+ example.lhs view
@@ -0,0 +1,101 @@+---+pagetitle: readme-lhs+---++[readme-lhs](https://tonyday567.github.io/readme-lhs/index.html) [![Build Status](https://travis-ci.org/tonyday567/readme-lhs.svg)](https://travis-ci.org/tonyday567/readme-lhs)+===++<blockquote cite>+The language in which we express our ideas has a strong influence on our thought processes. ~ Knuth+</blockquote>++This is an example of mixing literate haskell with markdown, and in using Readme.Lhs.  The file is composed of several elements:++- literate haskell. Bird-tracks are used, as the alternative method is latex rather than markdown, which doesn't survive a pandoc round trip.+- markdown. All non bird-tracked lines are considered to be markdown.  It's probably incompatible with haddock, but this may well resolve with adoption of the [literate markdown ghc proposal](https://gitlab.haskell.org/ghc/ghc/wikis/literate-markdown).+- fenced code blocks with an output class, which are used to insert computation results. The fenced code blocks look like:++    \`\`\`{.output .example}+    \`\`\`++[ghc options](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html#flag-reference)+---++> {-# OPTIONS_GHC -Wall #-}++[pragmas](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/lang.html)+------------------------------------------------------------------------------------++> -- doctest doesn't look at the cabal file, so you need pragmas here+> {-# LANGUAGE NoImplicitPrelude #-}+> {-# LANGUAGE OverloadedStrings #-}+> {-# LANGUAGE DataKinds #-}+> {-# LANGUAGE ScopedTypeVariables #-}+> {-# LANGUAGE TypeOperators #-}+> {-# LANGUAGE FlexibleInstances #-}++[libraries](https://www.stackage.org/)+--------------------------------------++-   [protolude](https://www.hackage.org/package/protolude)+-   [readme-lhs](https://www.hackage.org/package/readme-lhs)++> import Protolude+> import Readme.Lhs++code+----++-   [hoogle](https://www.stackage.org/package/hoogle)++> main :: IO ()+> main = do+>   let n = 10+>   let answer = product [1..n::Integer]+>   _ <- runOutput ("example.lhs", LHS) ("readme.md", GitHubMarkdown) $ do+>     output "example1" "Simple example of an output"++```{.output .example1}++```++>     output "example2" (show answer)++10! is equal to:++```{.output .example2}++```++>   pure ()+>++Output that doesn't exist is simply cleared.++``` {.output .example3}+The text inside this code block will be+  cleared on execution.+```++hsfiles writeup+===++A literate-programming friendly; tight work-flow stack template.++other/readme-lhs.hsfiles++other/batteries.hsfiles+---++This is my latest working template, overly influenced by [lexi-lambda's opinionated guide](https://lexi-lambda.github.io/blog/2018/02/10/an-opinionated-guide-to-haskell-in-2018/). The template includes:++- some minor tweaks to protolude+- lens, foldl, formatting & text as must have libraries+- generic-lens-labels++workflow+---++```+stack build --test --exec "$(stack path --local-install-root)/bin/readme-lhs-example" --file-watch+```
+ index.html view
@@ -0,0 +1,81 @@+<meta charset="utf-8"> <link rel="stylesheet" href="other/lhs.css">+<script type="text/javascript" async+  src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML">+</script>+<h1 id="readme-lhs-build-status"><a href="https://tonyday567.github.io/readme-lhs/index.html">readme-lhs</a> <a href="https://travis-ci.org/tonyday567/readme-lhs"><img src="https://travis-ci.org/tonyday567/readme-lhs.svg" alt="Build Status" /></a></h1>+<blockquote cite>+The language in which we express our ideas has a strong influence on our thought processes. ~ Knuth+</blockquote>+<p>A literate-programming friendly; tight work-flow stack template.</p>+<h2 id="otherreadme-lhs.hsfiles">other/readme-lhs.hsfiles</h2>+<pre><code>stack new project-name readme-lhs+cd project-name+stack build+$(stack path --local-install-root)/bin/readme-lhs-example+$(stack path --local-bin)/pandoc -f markdown -i other/header.md readme.md example/example.lhs other/footer.md -t html -o index.html --filter pandoc-include --mathjax</code></pre>+<p>Which:</p>+<ul class="incremental">+<li>runs an executable, which places some output in a markdown file</li>+<li>gathers together the readme.md and the example.lhs into an index.html</li>+</ul>+<h1 id="alternative-templates">alternative templates</h1>+<p>Or grab some of the other templates from this repo:</p>+<h2 id="otherreadme-hs.hsfiles">other/readme-hs.hsfiles</h2>+<p>like the lhs version, but hs based</p>+<h2 id="otherbatteries.hsfiles">other/batteries.hsfiles</h2>+<p>This is my latest working template, overly influenced by <a href="https://lexi-lambda.github.io/blog/2018/02/10/an-opinionated-guide-to-haskell-in-2018/">lexi-lambda's opinionated guide</a>. The template includes:</p>+<ul class="incremental">+<li>some minor tweaks to protolude</li>+<li>lens, foldl, formatting &amp; text as must have libraries</li>+<li>generic-lens-labels</li>+</ul>+<h1 id="code">code</h1>+<h2 id="ghc-options"><a href="https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html#flag-reference">ghc options</a></h2>+<div class="sourceCode"><pre class="sourceCode literate haskell"><code class="sourceCode haskell"><span class="ot">{-# OPTIONS_GHC -Wall #-}</span></code></pre></div>+<h2 id="pragmas"><a href="https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/lang.html">pragmas</a></h2>+<div class="sourceCode"><pre class="sourceCode literate haskell"><code class="sourceCode haskell"><span class="co">-- doctest doesn&#39;t look at the cabal file, so you need pragmas here</span>+<span class="ot">{-# LANGUAGE NoImplicitPrelude #-}</span>+<span class="ot">{-# LANGUAGE OverloadedStrings #-}</span>+<span class="ot">{-# LANGUAGE DataKinds #-}</span>+<span class="ot">{-# LANGUAGE DeriveGeneric #-}</span>+<span class="ot">{-# LANGUAGE ScopedTypeVariables #-}</span>+<span class="ot">{-# LANGUAGE TypeOperators #-}</span>+<span class="ot">{-# LANGUAGE FlexibleInstances #-}</span></code></pre></div>+<h2 id="libraries"><a href="https://www.stackage.org/">libraries</a></h2>+<ul class="incremental">+<li><a href="https://www.stackage.org/package/protolude">protolude</a></li>+<li><a href="https://www.stackage.org/package/optparse-generic">optparse-generic</a></li>+</ul>+<div class="sourceCode"><pre class="sourceCode literate haskell"><code class="sourceCode haskell"><span class="kw">import </span><span class="dt">Protolude</span>+<span class="kw">import </span><span class="dt">Options.Generic</span></code></pre></div>+<h2 id="code-1">code</h2>+<ul class="incremental">+<li><a href="https://www.stackage.org/package/hoogle">hoogle</a></li>+</ul>+<div class="sourceCode"><pre class="sourceCode literate haskell"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Opts</span> w <span class="fu">=</span> <span class="dt">Opts</span>+  {<span class="ot"> number ::</span> w <span class="ot">::</span><span class="fu">:</span> <span class="dt">Maybe</span> <span class="dt">Integer</span> <span class="fu">&lt;?&gt;</span> <span class="st">&quot;The number you want to product to&quot;</span>+  } <span class="kw">deriving</span> (<span class="dt">Generic</span>)++<span class="kw">instance</span> <span class="dt">ParseRecord</span> (<span class="dt">Opts</span> <span class="dt">Wrapped</span>)++<span class="ot">main ::</span> <span class="dt">IO</span> ()+main <span class="fu">=</span> <span class="kw">do</span>+<span class="ot">  o ::</span> <span class="dt">Opts</span> <span class="dt">Unwrapped</span> <span class="ot">&lt;-</span> unwrapRecord <span class="st">&quot;an example app for readme-lhs&quot;</span>+  <span class="kw">let</span> n <span class="fu">=</span> fromMaybe <span class="dv">10</span> (number o)+  <span class="kw">let</span> answer <span class="fu">=</span> product [<span class="dv">1</span><span class="fu">..</span>n]+  putStrLn (show answer <span class="fu">&lt;&gt;</span> <span class="st">&quot; 👍&quot;</span><span class="ot"> ::</span> <span class="dt">Text</span>)+  writeFile <span class="st">&quot;other/answer.md&quot;</span>+    (<span class="st">&quot;$\\prod_{i=1}^{&quot;</span> <span class="fu">&lt;&gt;</span> show n <span class="fu">&lt;&gt;</span> <span class="st">&quot;} i = &quot;</span> <span class="fu">&lt;&gt;</span>+     show answer <span class="fu">&lt;&gt;</span> <span class="st">&quot;$&quot;</span>)</code></pre></div>+<h2 id="output">output</h2>+<p><span class="math inline">\(\prod_{i=1}^{10} i = 3628800\)</span></p>+<h2 id="tests">tests</h2>+<p><a href="https://www.stackage.org/package/doctest">doctest</a></p>+<div class="sourceCode"><pre class="sourceCode literate haskell"><code class="sourceCode haskell"><span class="co">-- | doctests</span>+<span class="co">-- &gt;&gt;&gt; let n = 10</span>+<span class="co">-- &gt;&gt;&gt; product [1..n]</span>+<span class="co">-- 3628800</span></code></pre></div>+<hr />+<div class="footer">+<p>Made with love 'n' care; and <a href="https://haskell-lang.org/">haskell</a>, <a href="https://pandoc.org">pandoc</a>, and <a href="https://docs.haskellstack.org/en/stable/README/">stack</a>.</p>+</div>
+ other/batteries.hsfiles view
@@ -0,0 +1,476 @@+{-# START_FILE .gitattributes #-}+other/* linguist-documentation+index.html linguist-documentation+{-# START_FILE .gitignore #-}+/.stack-work/+TAGS+*.DS_Store+{-# START_FILE .hlint.yaml #-}+- ignore: {name: Eta reduce}+- ignore: {name: Use if}+- ignore: {name: Use first}++# To generate a suitable file for HLint do:+# $ hlint --default > .hlint.yaml+{-# START_FILE .travis.yaml #-}+# This is the simple Travis configuration, which is intended for use+# on applications which do not require cross-platform and+# multiple-GHC-version support. For more information and other+# options, see:+#+# https://docs.haskellstack.org/en/stable/travis_ci/+#+# Copy these contents into the root directory of your Github project in a file+# named .travis.yml++# Use new container infrastructure to enable caching+sudo: false++# Do not choose a language; we provide our own build tools.+language: generic++# Caching so the next build will be fast too.+cache:+  directories:+  - $HOME/.stack++# Ensure necessary system libraries are present+addons:+  apt:+    packages:+      - libgmp-dev++before_install:+# Download and unpack the stack executable+- mkdir -p ~/.local/bin+- export PATH=$HOME/.local/bin:$PATH+- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'++install:+# Build dependencies+- stack --no-terminal --install-ghc test --only-dependencies++script:+# Build the package, its tests, and its docs and run the tests+- stack --no-terminal test --haddock --no-haddock-deps+{-# START_FILE .weeder.yaml #-}+- package:+  - name: {{name}}+  - section:+    - name: test:test+    - message:+      - name: Redundant build-depends entry+      - depends: base+{-# START_FILE LICENSE #-}+Copyright {{author-name}}{{^author-name}}Author name here{{/author-name}} (c) {{year}}{{^year}}2017{{/year}}++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 of {{author-name}}{{^author-name}}Author name here{{/author-name}} nor the names of other+      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 AND CONTRIBUTORS+"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+OWNER OR CONTRIBUTORS 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.+{-# START_FILE Setup.hs #-}+import Distribution.Simple+main = defaultMain+{-# START_FILE package.yaml #-}+name: {{name}}+version: '0.0.0.1'+synopsis: See readme.md+description: See readme.md for description.+category: project+author: {{author-name}}{{^author-name}}Author name here{{/author-name}}+maintainer: {{author-email}}{{^author-email}}example@example.com{{/author-email}}+copyright: {{copyright}}{{^copyright}}{{year}}{{^year}}2018{{/year}} {{authorName}}{{^authorName}}Author name here{{/authorName}}{{/copyright}}+license: BSD3+github: {{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}+extra-source-files:+  - readme.md+  - stack.yaml+dependencies:+  - base >=4.7 && <5+ghc-options:+  - -Wall+  - -Wcompat+  - -Wincomplete-record-updates+  - -Wincomplete-uni-patterns+  - -Wredundant-constraints+library:+  source-dirs: src+  dependencies:+    - data-default+    - flow+    - foldl+    - formatting+    - generic-lens-labels+    - lens+    - protolude+    - text+  ghc-options:+    - -funbox-strict-fields+  exposed-modules:+  - Batterylude+executables:+  {{name}}:+    main: {{name}}.hs+    source-dirs: app+    ghc-options:+      - -funbox-strict-fields+      - -threaded+      - -rtsopts+      - -with-rtsopts=-N+    dependencies:+      - {{name}}+      - optparse-generic+      - protolude+tests:+  test:+    main: test.hs+    source-dirs: test+    dependencies:+      - doctest+      - protolude+{-# START_FILE readme.md #-}+{{name}}+===++[![Build Status](https://travis-ci.org/{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}.svg)](https://travis-ci.org/{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}) [![Hackage](https://img.shields.io/hackage/v/{{name}}.svg)](https://hackage.haskell.org/package/{{name}}) [![lts](https://www.stackage.org/package/{{name}}/badge/lts)](http://stackage.org/lts/package/{{name}}) [![nightly](https://www.stackage.org/package/{{name}}/badge/nightly)](http://stackage.org/nightly/package/{{name}}) ++recipe+---++```+stack build --test --fast --haddock --exec "$(stack path --local-install-root)/bin/{{name}}" --ghc-options=-Werror --file-watch+```++To generate an index.html++```+stack build --exec "$(stack path --local-bin)/pandoc -f markdown -i other/header.md readme.md other/footer.md -t html -o index.html --filter pandoc-include --mathjax"+```++To generate a per-project hoogle++```+stack hoogle -- generate --local++```++To serve hoogle search++```+stack hoogle -- server --local --port=8080+```++- [hoogle](http://localhost:8080/)++reference+---++- [lexi-lambda's opinionated guide](https://lexi-lambda.github.io/blog/2018/02/10/an-opinionated-guide-to-haskell-in-2018/)++- [ghc options](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html#flag-reference)+- [pragmas](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/lang.html)+- [hoogle](https://www.stackage.org/package/hoogle)+- [doctest](https://www.stackage.org/package/doctest)++Included [libraries](https://www.stackage.org/)+---++- [data-default](https://www.stackage.org/package/data-default)+- [foldl](https://www.stackage.org/package/foldl)+- [formatting](https://www.stackage.org/package/formatting)+- [lens](https://www.stackage.org/package/protolude)+- [optparse-generic](https://www.stackage.org/package/optparse-generic)+- [protolude](https://www.stackage.org/package/protolude)+- [text](https://www.stackage.org/package/text)+{-# START_FILE stack.yaml #-}+resolver: nightly-2018-02-17++packages:+  - .++extra-deps:+  # for hoogle+  - http-conduit-2.3.0+  - generic-lens-labels-0.1.0.2+{-# START_FILE app/{{name}}.hs #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# OPTIONS_GHC -Wall #-}++import Options.Generic+import Batterylude++newtype Opts w = Opts+  { numBatteries :: w ::: Maybe Int <?> "number of {{name}} desired"+  } deriving (Generic)++instance ParseRecord (Opts Wrapped)++main :: IO ()+main = do+  o :: Opts Unwrapped <- unwrapRecord "{{name}}"+  let n = fromMaybe (view #countBatteries (def::ConfigBatteries)) (numBatteries o)+  putStrLn ("👍" :: Text)+  putStrLn (statement1 (def |> #countBatteries .~ n))+  statement2++-- | doctests+-- >>> :main+-- 👍+-- There are 99 batteries.+-- This is not a battery.+-- This is an effect of a battery.+--+{-# START_FILE other/footer.md #-}+***++<div class="footer">+Made with love 'n' care; and+[haskell](https://haskell-lang.org/),+[pandoc](https://pandoc.org), and+[stack](https://docs.haskellstack.org/en/stable/README/).+</div>+{-# START_FILE other/header.md #-}+<meta charset="utf-8">+<link rel="stylesheet" href="other/lhs.css">+<script type="text/javascript" async+  src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML">+</script>+{-# START_FILE other/lhs.css #-}+* {+  background: transparent;+  border: 0;+  font-size: 100%;+  margin: 0;+  padding: 0;+  text-decoration: none;+  vertical-align: baseline; }++body {+  background-color: #fafafa;+  color: #3c3c3c;+  font-family: "Lora", "Seravek", sans-serif;+  line-height: 1.5;+  word-wrap: break-word;+  min-width: 200px;+  max-width: 900px;+  margin: 0 auto;+  padding: 3em; }+  body a {+    background-color: transparent;+    color: #3c3c3c;+    border-bottom-style: solid;+    border-bottom-width: 1px;+    border-bottom-color: #969696;+    text-decoration: none; }+    body a:visited {+      border-bottom-style: solid;+      border-bottom-width: 1px;+      border-bottom-color: #bd67c9;+      text-decoration: none; }+      body a:visited:hover {+        opacity: 0.7; }+    body a:hover {+      opacity: 0.7; }+  body h1 {+    font-size: 2em;+    padding-top: 1em;+    padding-bottom: 0.5em; }+  body h2 {+    font-size: 1.5em;+    padding-top: 1em;+    padding-bottom: 0.5em; }+  body h1, body h2 {+    font-family: "Raleway", serif;+    color: #222222; }+    body h1 a, body h2 a {+      background-color: transparent;+      color: #222222;+      text-decoration: none;+      border-bottom-style: solid;+      border-bottom-width: 2px;+      border-bottom-color: #969696; }+      body h1 a:visited, body h2 a:visited {+        opacity: 0.7;+        color: #222222;+        text-decoration: none;+        border-bottom-style: solid;+        border-bottom-width: 2px;+        border-bottom-color: #bd67c9; }+      body h1 a:hover, body h2 a:hover {+        opacity: 0.7;+        text-decoration: none; }+  body blockquote {+    border-left: 0.25rem solid #c8c8c8;+    font-style: italic;+    margin: 0.5rem 0 1rem 0;+    padding: 0 0 0 1rem;+    color: #646464; }+  body .footer {+    color: #888888;+    font-size: 0.75em;+    text-align: right; }+  body hr {+    height: 0;+    margin: 1em 0;+    overflow: hidden;+    background: transparent;+    border: 0;+    border-bottom: 1px solid #c8c8c8; }+  body pre {+    color: #ab1f27;+    background-color: #f5f0f0;+    padding: 0.75em;+    overflow: auto; }+  body ul {+    margin: 0.5rem 0;+    padding-left: 0; }+    body ul li {+      counter-increment: this;+      line-height: 1.313em;+      list-style: none;+      position: relative; }+      body ul li:after {+        color: #646464;+        content: "-";+        left: -1em;+        position: absolute;+        top: 0; }++.sourceCode {+  background-color: whitesmoke;+  color: #284628;+  font-family: "Inconsolata", mono;+  font-size: 1em; }+  .sourceCode .ot, .sourceCode .kw {+    color: #284628; }+  .sourceCode .dt {+    color: #ab1f27; }+  .sourceCode .dv, .sourceCode .st {+    color: #2536d6; }+  .sourceCode .co {+    color: #646464;+    font-style: italic; }+  .sourceCode .fu {+    color: #e347e4; }+{-# START_FILE src/Batterylude.hs #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedLabels #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# OPTIONS_GHC -Wall #-}+{-# OPTIONS_GHC -Wno-unused-top-binds #-}++module Batterylude+  ( module Protolude+  , (<>)+  , (.)+  , id+  , String+  , module Control.Lens+  , module Flow+  , module Data.Default+  , module Formatting+  , statement1+  , statement2+  , ConfigBatteries(ConfigBatteries)+  ) where++import Control.Category ((.), id)+import qualified Control.Foldl as L+import Control.Lens+       hiding (Fold, Strict, Unwrapped, Wrapped, (.>), (<&>), (<.), (<.>),+               (<|), (|>), from, to, uncons, unsnoc)+import Data.Default+import Data.Generics.Labels ()+import Data.Semigroup ((<>))+import qualified Data.Text as Text+import qualified Data.Text.IO as Text+import Flow+import Formatting+import GHC.Base (String)+import Protolude hiding ((%), (.), (<>))++-- | there is invariably a Config for a project+data ConfigBatteries = ConfigBatteries+  { countBatteries :: Int+  , hasBatteries :: Bool+  } deriving (Show, Eq, Generic)++instance Default ConfigBatteries where+  def = ConfigBatteries 99 True++-- | formatting example+statement1 :: ConfigBatteries -> Text+statement1 cfg =+  sformat+    ("There " %text % " " %text % " " %text%".")+    (bool "are" "is" (view #countBatteries cfg == 1))+    (bool "no" (show <| view #countBatteries cfg) (view #hasBatteries cfg))+    (bool "batteries" "battery" (view #countBatteries cfg == 1))++-- | foldl example+statement2 :: IO ()+statement2 = do+  Text.putStrLn <|+    L.fold+      (L.Fold (\x a -> x <> " " <> a) ("This" :: Text) id)+      ["is", "not", "a", "battery."]+  Text.putStrLn <|+    Text.intercalate " " ["This", "is", "an", "effect", "of", "a", "battery."]+{-# START_FILE test/test.hs #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# OPTIONS_GHC -Wall #-}++module Main where++import Protolude+import Test.DocTest++main :: IO ()+main =+    doctest ["app/{{name}}.hs"]
+ other/readme-hs.hsfiles view
@@ -0,0 +1,335 @@+{-# START_FILE app/example.md #-}+{{name}}+===++[![Build Status](https://travis-ci.org/{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}.svg)](https://travis-ci.org/{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}) [![Hackage](https://img.shields.io/hackage/v/{{name}}.svg)](https://hackage.haskell.org/package/{{name}}) [![lts](https://www.stackage.org/package/{{name}}/badge/lts)](http://stackage.org/lts/package/{{name}}) [![nightly](https://www.stackage.org/package/{{name}}/badge/nightly)](http://stackage.org/nightly/package/{{name}}) ++results+---++```include+other/results.md+```++recipe+---++```+stack build --test --exec "$(stack path --local-install-root)/bin/{{name}}" --exec "$(stack path --local-bin)/pandoc -f markdown -i other/header.md app/example.md other/footer.md -t html -o index.html --filter pandoc-include --mathjax" --exec "$(stack path --local-bin)/pandoc -f markdown -i app/example.md -t markdown -o readme.md --filter pandoc-include --mathjax" --file-watch+```++reference+---++- [ghc options](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html#flag-reference)+- [pragmas](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/lang.html)+- [libraries](https://www.stackage.org/)+- [protolude](https://www.stackage.org/package/protolude)+- [optparse-generic](https://www.stackage.org/package/optparse-generic)+- [hoogle](https://www.stackage.org/package/hoogle)+- [doctest](https://www.stackage.org/package/doctest)++{-# START_FILE app/example.hs #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleInstances #-}+{-# OPTIONS_GHC -Wall #-}++import Options.Generic+import Protolude++data Opts w = Opts+  { number :: w ::: Maybe Integer <?> "The number you want to product to"+  } deriving (Generic)++instance ParseRecord (Opts Wrapped)++main :: IO ()+main = do+  o :: Opts Unwrapped <- unwrapRecord "{{name}}"+  let n = fromMaybe 10 (number o)+  let answer = product [1 .. n]+  putStrLn (show answer <> " 👍" :: Text)+  writeFile+    "other/answer.md"+    ("$\\prod_{i=1}^{" <> show n <> "} i = " <> show answer <> "$")++-- | doctests+-- >>> let n = 10+-- >>> product [1..n]+-- 3628800++{-# START_FILE package.yaml #-}+name: {{name}}+version: '0.0.1'+synopsis: See readme.md+description: See readme.md for description.+category: project+author: {{author-name}}{{^author-name}}Author name here{{/author-name}}+maintainer: tonyday567@gmail.com+copyright: {{copyright}}{{^copyright}}{{year}}{{^year}}2017{{/year}} {{authorName}}{{^authorName}}Author name here{{/authorName}}{{/copyright}}+license: BSD3+github: {{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}+extra-source-files:+  - stack.yaml+default-extensions:+  - NegativeLiterals+  - NoImplicitPrelude+  - OverloadedStrings+  - UnicodeSyntax+dependencies:+- base >=4.7 && <5+executables:+  {{name}}:+    main: example.hs+    source-dirs: app+    ghc-options:+      - -funbox-strict-fields+      - -fforce-recomp+      - -threaded+      - -rtsopts+      - -with-rtsopts=-N+    dependencies:+      - protolude+      - optparse-generic+tests:+  test:+    main: test.hs+    source-dirs: test+    dependencies:+    - doctest+    - protolude++{-# START_FILE .gitignore #-}+/.stack-work/+TAGS++{-# START_FILE .gitattributes #-}+other/* linguist-documentation+index.html linguist-documentation++{-# START_FILE Setup.hs #-}+import Distribution.Simple+main = defaultMain++{-# START_FILE LICENSE #-}+Copyright {{author-name}}{{^author-name}}Author name here{{/author-name}} (c) {{year}}{{^year}}2017{{/year}}++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 of {{author-name}}{{^author-name}}Author name here{{/author-name}} nor the names of other+      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 AND CONTRIBUTORS+"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+OWNER OR CONTRIBUTORS 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.++{-# START_FILE .travis.yml #-}+# This is the simple Travis configuration, which is intended for use+# on applications which do not require cross-platform and+# multiple-GHC-version support. For more information and other+# options, see:+#+# https://docs.haskellstack.org/en/stable/travis_ci/+#+# Copy these contents into the root directory of your Github project in a file+# named .travis.yml++# Use new container infrastructure to enable caching+sudo: false++# Do not choose a language; we provide our own build tools.+language: generic++# Caching so the next build will be fast too.+cache:+  directories:+  - $HOME/.stack++# Ensure necessary system libraries are present+addons:+  apt:+    packages:+      - libgmp-dev++before_install:+# Download and unpack the stack executable+- mkdir -p ~/.local/bin+- export PATH=$HOME/.local/bin:$PATH+- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'++install:+# Build dependencies+- stack --no-terminal --install-ghc test --only-dependencies++script:+# Build the package, its tests, and its docs and run the tests+- stack --no-terminal test --haddock --no-haddock-deps++{-# START_FILE other/lhs.css #-}+* {+  background: transparent;+  border: 0;+  font-size: 100%;+  margin: 0;+  padding: 0;+  text-decoration: none;+  vertical-align: baseline; }++body {+  background-color: #fafafa;+  color: #3c3c3c;+  font-family: "Lora", "Seravek", sans-serif;+  line-height: 1.5;+  word-wrap: break-word;+  min-width: 200px;+  max-width: 900px;+  margin: 0 auto;+  padding: 3em; }+  body a {+    background-color: transparent;+    color: #3c3c3c;+    border-bottom-style: solid;+    border-bottom-width: 1px;+    border-bottom-color: #969696;+    text-decoration: none; }+    body a:visited {+      border-bottom-style: solid;+      border-bottom-width: 1px;+      border-bottom-color: #bd67c9;+      text-decoration: none; }+      body a:visited:hover {+        opacity: 0.7; }+    body a:hover {+      opacity: 0.7; }+  body h1 {+    font-size: 2em;+    padding-top: 1em;+    padding-bottom: 0.5em; }+  body h2 {+    font-size: 1.5em;+    padding-top: 1em;+    padding-bottom: 0.5em; }+  body h1, body h2 {+    font-family: "Raleway", serif;+    color: #222222; }+    body h1 a, body h2 a {+      background-color: transparent;+      color: #222222;+      text-decoration: none;+      border-bottom-style: solid;+      border-bottom-width: 2px;+      border-bottom-color: #969696; }+      body h1 a:visited, body h2 a:visited {+        opacity: 0.7;+        color: #222222;+        text-decoration: none;+        border-bottom-style: solid;+        border-bottom-width: 2px;+        border-bottom-color: #bd67c9; }+      body h1 a:hover, body h2 a:hover {+        opacity: 0.7;+        text-decoration: none; }+  body blockquote {+    border-left: 0.25rem solid #c8c8c8;+    font-style: italic;+    margin: 0.5rem 0 1rem 0;+    padding: 0 0 0 1rem;+    color: #646464; }+  body .footer {+    color: #888888;+    font-size: 0.75em;+    text-align: right; }+  body hr {+    height: 0;+    margin: 1em 0;+    overflow: hidden;+    background: transparent;+    border: 0;+    border-bottom: 1px solid #c8c8c8; }+  body pre {+    color: #ab1f27;+    background-color: #f5f0f0;+    padding: 0.75em;+    overflow: auto; }+  body ul {+    margin: 0.5rem 0;+    padding-left: 0; }+    body ul li {+      counter-increment: this;+      line-height: 1.313em;+      list-style: none;+      position: relative; }+      body ul li:after {+        color: #646464;+        content: "-";+        left: -1em;+        position: absolute;+        top: 0; }++.sourceCode {+  background-color: whitesmoke;+  color: #284628;+  font-family: "Inconsolata", mono;+  font-size: 1em; }+  .sourceCode .ot, .sourceCode .kw {+    color: #284628; }+  .sourceCode .dt {+    color: #ab1f27; }+  .sourceCode .dv, .sourceCode .st {+    color: #2536d6; }+  .sourceCode .co {+    color: #646464;+    font-style: italic; }+  .sourceCode .fu {+    color: #e347e4; }++{-# START_FILE other/header.md #-}+<meta charset="utf-8">+<link rel="stylesheet" href="other/lhs.css">+<script type="text/javascript" async+  src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML">+</script>++{-# START_FILE other/footer.md #-}+***++<div class="footer">+Powered by [haskell](https://haskell-lang.org/), [stack](https://docs.haskellstack.org/en/stable/README/) and [pandoc](http://pandoc.org/).+</div>++{-# START_FILE test/test.hs #-}+{-# OPTIONS_GHC -Wall #-}++module Main where++import Protolude+import Test.DocTest++main :: IO ()+main = do+  doctest ["app/example.hs"]
+ other/readme-lhs.hsfiles view
@@ -0,0 +1,359 @@+{-# START_FILE readme.md #-}+{{name}}+===++[![Build Status](https://travis-ci.org/{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}.svg)](https://travis-ci.org/{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}) [![Hackage](https://img.shields.io/hackage/v/{{name}}.svg)](https://hackage.haskell.org/package/{{name}}) [![lts](https://www.stackage.org/package/{{name}}/badge/lts)](http://stackage.org/lts/package/{{name}}) [![nightly](https://www.stackage.org/package/{{name}}/badge/nightly)](http://stackage.org/nightly/package/{{name}}) ++```+stack build --test --exec "$(stack path --local-install-root)/bin/{{name}}" --exec "$(stack path --local-bin)/pandoc -f markdown+lhs -i other/header.md app/example.lhs other/footer.md -t html -o index.html --filter pandoc-include --mathjax" --file-watch+```++{-# START_FILE app/example.lhs #-}+[{{name}}](https://github.com/{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}) example+===++[ghc options](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html#flag-reference)+---++\begin{code}+{-# OPTIONS_GHC -Wall #-}+\end{code}++[pragmas](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/lang.html)+---++\begin{code}+-- doctest doesn't look at the cabal file, so you need pragmas here+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleInstances #-}+\end{code}++[libraries](https://www.stackage.org/)+---++- [protolude](https://www.stackage.org/package/protolude)+- [optparse-generic](https://www.stackage.org/package/optparse-generic)++\begin{code}+import Protolude+import Options.Generic+\end{code}++code+---++- [hoogle](https://www.stackage.org/package/hoogle)++\begin{code}+data Opts w = Opts+  { number :: w ::: Maybe Integer <?> "The number you want to product to"+  } deriving (Generic)++instance ParseRecord (Opts Wrapped)++main :: IO ()+main = do+  o :: Opts Unwrapped <- unwrapRecord "{{name}}"+  let n = fromMaybe 10 (number o)+  let answer = product [1..n]+  putStrLn (show answer <> " 👍" :: Text)+  writeFile "other/answer.md"+    ("$\\prod_{i=1}^{" <> show n <> "} i = " <>+     show answer <> "$")+\end{code}++output+---++```include+other/answer.md+```++tests+---++- [doctest](https://www.stackage.org/package/doctest)++\begin{code}+-- | doctests+-- >>> let n = 10+-- >>> product [1..n]+-- 3628800+\end{code}++{-# START_FILE package.yaml #-}+name: {{name}}+version: '0.0.0.1'+synopsis: See readme.md+description: See readme.md for description.+category: project+author: {{author-name}}{{^author-name}}Author name here{{/author-name}}+maintainer: tonyday567@gmail.com+copyright: {{copyright}}{{^copyright}}{{year}}{{^year}}2017{{/year}} {{authorName}}{{^authorName}}Author name here{{/authorName}}{{/copyright}}+license: BSD3+github: {{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}+extra-source-files:+  - readme.md+  - stack.yaml+default-extensions:+  - NegativeLiterals+  - NoImplicitPrelude+  - OverloadedStrings+  - UnicodeSyntax+dependencies:+  - base >=4.7 && <5+executables:+  {{name}}:+    main: example.lhs+    source-dirs: app+    ghc-options:+      - -funbox-strict-fields+      - -fforce-recomp+      - -threaded+      - -rtsopts+      - -with-rtsopts=-N+    dependencies:+      - protolude+      - optparse-generic+tests:+  test:+    main: test.hs+    source-dirs: test+    dependencies:+      - doctest+      - protolude++{-# START_FILE .gitignore #-}+/.stack-work/+TAGS++{-# START_FILE .gitattributes #-}+other/* linguist-documentation+index.html linguist-documentation++{-# START_FILE Setup.hs #-}+import Distribution.Simple+main = defaultMain++{-# START_FILE LICENSE #-}+Copyright {{author-name}}{{^author-name}}Author name here{{/author-name}} (c) {{year}}{{^year}}2017{{/year}}++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 of {{author-name}}{{^author-name}}Author name here{{/author-name}} nor the names of other+      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 AND CONTRIBUTORS+"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+OWNER OR CONTRIBUTORS 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.++{-# START_FILE .travis.yml #-}+# This is the simple Travis configuration, which is intended for use+# on applications which do not require cross-platform and+# multiple-GHC-version support. For more information and other+# options, see:+#+# https://docs.haskellstack.org/en/stable/travis_ci/+#+# Copy these contents into the root directory of your Github project in a file+# named .travis.yml++# Use new container infrastructure to enable caching+sudo: false++# Do not choose a language; we provide our own build tools.+language: generic++# Caching so the next build will be fast too.+cache:+  directories:+  - $HOME/.stack++# Ensure necessary system libraries are present+addons:+  apt:+    packages:+      - libgmp-dev++before_install:+# Download and unpack the stack executable+- mkdir -p ~/.local/bin+- export PATH=$HOME/.local/bin:$PATH+- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'++install:+# Build dependencies+- stack --no-terminal --install-ghc test --only-dependencies++script:+# Build the package, its tests, and its docs and run the tests+- stack --no-terminal test --haddock --no-haddock-deps++{-# START_FILE other/lhs.css #-}+* {+  background: transparent;+  border: 0;+  font-size: 100%;+  margin: 0;+  padding: 0;+  text-decoration: none;+  vertical-align: baseline; }++body {+  background-color: #fafafa;+  color: #3c3c3c;+  font-family: "Lora", "Seravek", sans-serif;+  line-height: 1.5;+  word-wrap: break-word;+  min-width: 200px;+  max-width: 900px;+  margin: 0 auto;+  padding: 3em; }+  body a {+    background-color: transparent;+    color: #3c3c3c;+    border-bottom-style: solid;+    border-bottom-width: 1px;+    border-bottom-color: #969696;+    text-decoration: none; }+    body a:visited {+      border-bottom-style: solid;+      border-bottom-width: 1px;+      border-bottom-color: #bd67c9;+      text-decoration: none; }+      body a:visited:hover {+        opacity: 0.7; }+    body a:hover {+      opacity: 0.7; }+  body h1 {+    font-size: 2em;+    padding-top: 1em;+    padding-bottom: 0.5em; }+  body h2 {+    font-size: 1.5em;+    padding-top: 1em;+    padding-bottom: 0.5em; }+  body h1, body h2 {+    font-family: "Raleway", serif;+    color: #222222; }+    body h1 a, body h2 a {+      background-color: transparent;+      color: #222222;+      text-decoration: none;+      border-bottom-style: solid;+      border-bottom-width: 2px;+      border-bottom-color: #969696; }+      body h1 a:visited, body h2 a:visited {+        opacity: 0.7;+        color: #222222;+        text-decoration: none;+        border-bottom-style: solid;+        border-bottom-width: 2px;+        border-bottom-color: #bd67c9; }+      body h1 a:hover, body h2 a:hover {+        opacity: 0.7;+        text-decoration: none; }+  body blockquote {+    border-left: 0.25rem solid #c8c8c8;+    font-style: italic;+    margin: 0.5rem 0 1rem 0;+    padding: 0 0 0 1rem;+    color: #646464; }+  body .footer {+    color: #888888;+    font-size: 0.75em;+    text-align: right; }+  body hr {+    height: 0;+    margin: 1em 0;+    overflow: hidden;+    background: transparent;+    border: 0;+    border-bottom: 1px solid #c8c8c8; }+  body pre {+    color: #ab1f27;+    background-color: #f5f0f0;+    padding: 0.75em;+    overflow: auto; }+  body ul {+    margin: 0.5rem 0;+    padding-left: 0; }+    body ul li {+      counter-increment: this;+      line-height: 1.313em;+      list-style: none;+      position: relative; }+      body ul li:after {+        color: #646464;+        content: "-";+        left: -1em;+        position: absolute;+        top: 0; }++.sourceCode {+  background-color: whitesmoke;+  color: #284628;+  font-family: "Inconsolata", mono;+  font-size: 1em; }+  .sourceCode .ot, .sourceCode .kw {+    color: #284628; }+  .sourceCode .dt {+    color: #ab1f27; }+  .sourceCode .dv, .sourceCode .st {+    color: #2536d6; }+  .sourceCode .co {+    color: #646464;+    font-style: italic; }+  .sourceCode .fu {+    color: #e347e4; }++{-# START_FILE other/header.md #-}+<meta charset="utf-8">+<link rel="stylesheet" href="other/lhs.css">+<script type="text/javascript" async+  src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML">+</script>++{-# START_FILE other/footer.md #-}+***++<div class="footer">+Powered by [haskell](https://haskell-lang.org/), [stack](https://docs.haskellstack.org/en/stable/README/) and [pandoc](http://pandoc.org/).+</div>++{-# START_FILE test/test.hs #-}+{-# OPTIONS_GHC -Wall #-}++module Main where++import Protolude+import Test.DocTest++main :: IO ()+main = do+  doctest ["app/example.lhs"]
readme-lhs.cabal view
@@ -1,233 +1,81 @@-name:-  readme-lhs-version:-  0.1.0.0-synopsis:-  See readme.lhs-description:-  See readme.lhs-homepage:-  https://github.com/tonyday567/readme-lhs-license:-  BSD3-license-file:-  LICENSE-author:-  Tony Day-maintainer:-  tonyday567@gmail.com-copyright:-  2016 Tony Day-category:-  Development              -build-type:-  Simple-cabal-version:-  >=1.14+cabal-version: 1.12+name:           readme-lhs+version:        0.2.0+synopsis:       See readme.md+description:    See readme.md for description.+category:       Development+homepage:       https://github.com/tonyday567/readme-lhs#readme+bug-reports:    https://github.com/tonyday567/readme-lhs/issues+author:         Tony Day+maintainer:     tonyday567@gmail.com+copyright:      2016 Tony Day+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    readme.md+    index.html+    stack.yaml+    other/readme-lhs.hsfiles+    other/readme-hs.hsfiles+    other/batteries.hsfiles +source-repository head+  type: git+  location: https://github.com/tonyday567/readme-lhs+ library-  default-language:-    Haskell2010-  ghc-options:   hs-source-dirs:     src-  exposed-modules:-    Readme.Lhs-  build-depends:-    base >= 4.7 && < 5,-    protolude,-    foldl,-    text,-    attoparsec   default-extensions:-    NoImplicitPrelude,-    UnicodeSyntax,-    BangPatterns,-    BinaryLiterals,-    DeriveFoldable,-    DeriveFunctor,-    DeriveGeneric,-    DeriveTraversable,-    DisambiguateRecordFields,-    EmptyCase,-    FlexibleContexts,-    FlexibleInstances,-    FunctionalDependencies,-    GADTSyntax,-    InstanceSigs,-    KindSignatures,-    LambdaCase,-    MonadComprehensions,-    MultiParamTypeClasses,-    MultiWayIf,-    NegativeLiterals,-    OverloadedStrings,-    ParallelListComp,-    PartialTypeSignatures,-    PatternSynonyms,-    RankNTypes,-    RecordWildCards,-    RecursiveDo,-    ScopedTypeVariables,-    TupleSections,-    TypeFamilies,-    TypeOperators--executable lhs-  default-language:-    Haskell2010-  hs-source-dirs:-    app-  main-is:-    Main.hs+    NegativeLiterals+    OverloadedStrings+    UnicodeSyntax   ghc-options:-    -threaded-    -rtsopts-    -with-rtsopts=-N+    -Wall+    -Wcompat+    -Wincomplete-record-updates+    -Wincomplete-uni-patterns+    -Wredundant-constraints   build-depends:-    base >= 4.7 && < 5,-    protolude,-    readme-lhs,-    optparse-applicative,-    filepath,-    text,-    containers-  default-language:-    Haskell2010-  default-extensions:-    NoImplicitPrelude,-    UnicodeSyntax,-    BangPatterns,-    BinaryLiterals,-    DeriveFoldable,-    DeriveFunctor,-    DeriveGeneric,-    DeriveTraversable,-    DisambiguateRecordFields,-    EmptyCase,-    FlexibleContexts,-    FlexibleInstances,-    FunctionalDependencies,-    GADTSyntax,-    InstanceSigs,-    KindSignatures,-    LambdaCase,-    MonadComprehensions,-    MultiParamTypeClasses,-    MultiWayIf,-    NegativeLiterals,-    OverloadedStrings,-    ParallelListComp,-    PartialTypeSignatures,-    PatternSynonyms,-    RankNTypes,-    RecordWildCards,-    RecursiveDo,-    ScopedTypeVariables,-    TupleSections,-    TypeFamilies,-    TypeOperators+    base >=4.7 && <5+    , protolude+    , text+    , pandoc+    , pandoc-types+    , containers+  exposed-modules:+    Readme.Lhs+  other-modules:+  default-language: Haskell2010 -executable readme-  default-language:-    Haskell2010-  ghc-options:+executable readme-lhs-example+  main-is: example.lhs+  other-modules:+      Paths_readme_lhs   hs-source-dirs:-    ./-  main-is:-    readme.lhs+      ./+  default-extensions: NoImplicitPrelude UnicodeSyntax NegativeLiterals OverloadedStrings+  ghc-options: -funbox-strict-fields -fforce-recomp -threaded -rtsopts -with-rtsopts=-N   build-depends:-    base >= 4.7 && < 5,-    protolude,-    text,-    foldl-  default-extensions:-    NoImplicitPrelude,-    UnicodeSyntax,-    BangPatterns,-    BinaryLiterals,-    DeriveFoldable,-    DeriveFunctor,-    DeriveGeneric,-    DeriveTraversable,-    DisambiguateRecordFields,-    EmptyCase,-    FlexibleContexts,-    FlexibleInstances,-    FunctionalDependencies,-    GADTSyntax,-    InstanceSigs,-    KindSignatures,-    LambdaCase,-    MonadComprehensions,-    MultiParamTypeClasses,-    MultiWayIf,-    NegativeLiterals,-    OverloadedStrings,-    ParallelListComp,-    PartialTypeSignatures,-    PatternSynonyms,-    RankNTypes,-    RecordWildCards,-    RecursiveDo,-    ScopedTypeVariables,-    TupleSections,-    TypeFamilies,-    TypeOperators+      base >=4.7 && <5+    , optparse-generic+    , pandoc+    , protolude+    , readme-lhs+  default-language: Haskell2010  test-suite test-  default-language:-    Haskell2010-  type:-    exitcode-stdio-1.0+  type: exitcode-stdio-1.0+  main-is: test.hs+  other-modules:+      Paths_readme_lhs   hs-source-dirs:-    test-  main-is:-    test.lhs+      test+  default-extensions: NoImplicitPrelude UnicodeSyntax NegativeLiterals OverloadedStrings   build-depends:-    base >= 4.7 && < 5,-    protolude,-    tasty,-    HUnit,-    tasty-hunit,-    readme-lhs,-    text-  default-extensions:-    NoImplicitPrelude,-    UnicodeSyntax,-    BangPatterns,-    BinaryLiterals,-    DeriveFoldable,-    DeriveFunctor,-    DeriveGeneric,-    DeriveTraversable,-    DisambiguateRecordFields,-    EmptyCase,-    FlexibleContexts,-    FlexibleInstances,-    FunctionalDependencies,-    GADTSyntax,-    InstanceSigs,-    KindSignatures,-    LambdaCase,-    MonadComprehensions,-    MultiParamTypeClasses,-    MultiWayIf,-    NegativeLiterals,-    OverloadedStrings,-    ParallelListComp,-    PartialTypeSignatures,-    PatternSynonyms,-    RankNTypes,-    RecordWildCards,-    RecursiveDo,-    ScopedTypeVariables,-    TupleSections,-    TypeFamilies,-    TypeOperators--source-repository head-  type:-    git-  location:-    https://github.com/tonyday567/readme-lhs+      base >=4.7 && <5+    , doctest+    , protolude+    , tasty+  default-language: Haskell2010
− readme.lhs
@@ -1,119 +0,0 @@-```include-other/header.md-```--[readme-lhs](https://tonyday567.github.io/readme-lhs/index.html) [![Build Status](https://travis-ci.org/tonyday567/readme-lhs.png)](https://travis-ci.org/tonyday567/readme-lhs)-===-- *starting a literate haskell narrative.*--I've long suffered from procrastination in new projects. The coders equivalent for sharpening pencils is the creation of bespoke, boiler-plate scaffolding as one prevaricates about the guts of the project. I see evidence littered through my old repos - self-obsfucating technical debt encrusted on the interface between the project and RealWorld.--So, starting at the pointy end of a new project, I aligned my workflow with stack, and started looking at a reproducible, exact startup routine.  I followed the path to stack templates and wrote my own (`stack new project-name readme-lhs`), which was kindy accepted.--design------Stripping away optional extras, I went with a minimalist design:--- markdown for all docs.  Anything outside what markdown can do is me being too fancy.-- pandoc for document conversion. `-f markdown+lhs` is a georgeous rendering of a .lhs file. I turn [github pages](https://help.github.com/articles/user-organization-and-project-pages/) on using the User Pages site method for each project I'd like to blog, and render readme.lhs to index.html using pandoc.-- css for styling, but also dealing with github markdown style which is where many users will read your lhs.-- using lhs as a valid haskell artform-- readme.lhs as a general purpose executable, tester, example holder and all-round centralising communication document.-- a long list of the most commonly-used, and mostly-benign language flags, NoImplicitPrelude & UnicodeSyntax.  I call this -XHaskell2016 in private.-- the stack-recommended .travis.yml-- Embedding [Protolude](https://www.stackage.org/package/protolude) as the replacement prelude.--Here's what I threw out:--- haddock. The design space of using markdown as a complete replacement is fresh territory.-- test directory. I looked through my test and example directories and noted the mess in many. I love to test - creating a realistic arbitrary instance is the best way to get to know your data structures - but tests and multiple examples didn't belong in the start-up phase.-- hakyll. For me, markdown created for a separate blogging process is better inside the actual  project as readme's - my hakyll site rots pretty quickly.-- app directory.  The boundary between what the app is and what the library is is very fluid for me, and a source of technical debt as concepts bounce between directories.--I then keep this repo around for phase 2, where a project takes a successful shape and and needs test and app boiler-plate.--Workflow------This design must be monadic cause I seem to get a hyper-efficient workflow for free! The template reproducably installs and runs out of the box, with zero TODO items littered through the structure.--~~~-stack install && readme--...--Copied executables to /Users/tonyday/.local/bin:-- readme-"ok"-~~~--I gather libraries I guess I'm needing, adding to .cabal and imports added to readme.lhs.  Firing up a repl there, I start hacking some code together, saving the good bits to readme.lhs, adding notes and links, and getting some initial learnings coded up in main, so I can eyeball results. I use the following command to build, run, and render an index.html so pushing is also auto-publishing on github.--~~~-stack install && readme && pandoc -f markdown+lhs -i readme.lhs -t html -o index.html --filter pandoc-include --mathjax && pandoc -f markdown+lhs -i readme.lhs -t markdown -o readme.md --filter pandoc-include --mathjax-~~~--todo:--- [ ] can stack --file-watch help?-- [ ] should pandoc be wrapped in the stack version ie `stack exec pandoc --`-- [ ] reproducible build instructions with stack-only environment (travis)--usage------To just use the stack template:--~~~-stack new project-name readme-lhs-cd project-name-stack install-readme-~~~--and it should chirp back a cheery "ok".--The [template file](other/readme-lhs.hsfiles) can always be edited, renamed etc and dropped into a directory, and stack will find it.---lhs-----I use both .lhs and .hs styles, and often need to flip between the two. In particular, hlint didn't always play nice with .lhs, and for a while I needed to flip from .lhs to .hs, run hlint, and then flip back to .lhs.--lhs makes no attempt to account for haddock and will thus not be suitable for most people.--To install and use lhs:--~~~-git clone https://github.com/tonyday567/readme-lhs-cd readme-lhs-stack install-lhs readme.lhs-~~~--code------I tend to stick [protolude](http://www.stephendiehl.com/posts/protolude.html) in most modules, which really cuts down on boiler-plate.--> {-# OPTIONS_GHC -Wall #-}-> {-# OPTIONS_GHC -fno-warn-type-defaults #-}-> import Protolude-> -> main :: IO ()-> main = do->   print "readme-lhs library"->   let fac n = foldr (\x g n' -> g (x*n')) identity [1..n] 1->   writeFile "other/example.md" $->       "$\\prod_{x=1}^{20} x = " <> show (fac 20) <> "$\n"->--Output from the code above appears in this readme.lhs when rendered with pandoc-include (except if you're reading this as the repo readme.md, sorry):--```include-other/example.md-```--
+ readme.md view
@@ -0,0 +1,114 @@+[readme-lhs](https://tonyday567.github.io/readme-lhs/index.html) [![Build Status](https://travis-ci.org/tonyday567/readme-lhs.svg)](https://travis-ci.org/tonyday567/readme-lhs)+================================================================================================================================================================================++<blockquote cite>+The language in which we express our ideas has a strong influence on our+thought processes. \~ Knuth+</blockquote>++This is an example of mixing literate haskell with markdown, and in+using Readme.Lhs. The file is composed of several elements:++-   literate haskell. Bird-tracks are used, as the alternative method is+    latex rather than markdown, which doesn’t survive a pandoc round+    trip.+-   markdown. All non bird-tracked lines are considered to be markdown.+    It’s probably incompatible with haddock, but this may well resolve+    with adoption of the [literate markdown ghc+    proposal](https://gitlab.haskell.org/ghc/ghc/wikis/literate-markdown).+-   fenced code blocks with an output class, which are used to insert+    computation results. The fenced code blocks look like:++    \`\`\`{.output .example} \`\`\`++[ghc options](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html#flag-reference)+--------------------------------------------------------------------------------------------------------++``` haskell+{-# OPTIONS_GHC -Wall #-}+```++[pragmas](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/lang.html)+------------------------------------------------------------------------------------++``` haskell+-- doctest doesn't look at the cabal file, so you need pragmas here+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleInstances #-}+```++[libraries](https://www.stackage.org/)+--------------------------------------++-   [protolude](https://www.hackage.org/package/protolude)+-   [readme-lhs](https://www.hackage.org/package/readme-lhs)++``` haskell+import Protolude+import Readme.Lhs+```++code+----++-   [hoogle](https://www.stackage.org/package/hoogle)++``` haskell+main :: IO ()+main = do+  let n = 10+  let answer = product [1..n::Integer]+  _ <- runOutput ("example.lhs", LHS) ("readme.md", GitHubMarkdown) $ do+    output "example1" "Simple example of an output"+```++``` output+Simple example of an output+```++``` haskell+    output "example2" (show answer)+```++10! is equal to:++``` output+3628800+```++``` haskell+  pure ()+```++Output that doesn’t exist is simply cleared.++``` output+```++hsfiles writeup+===============++A literate-programming friendly; tight work-flow stack template.++other/readme-lhs.hsfiles++other/batteries.hsfiles+-----------------------++This is my latest working template, overly influenced by [lexi-lambda’s+opinionated+guide](https://lexi-lambda.github.io/blog/2018/02/10/an-opinionated-guide-to-haskell-in-2018/).+The template includes:++-   some minor tweaks to protolude+-   lens, foldl, formatting & text as must have libraries+-   generic-lens-labels++workflow+--------++    stack build --exec "$(stack path --local-install-root)/bin/readme-lhs-example" --file-watch
src/Readme/Lhs.hs view
@@ -1,130 +1,134 @@-{-# OPTIONS_GHC -Wall #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoImplicitPrelude #-}+ module Readme.Lhs-  (-      Section(..),-      Block(..),-      Format(..),-      bird,-      normal,-      parseHs,-      printHs,-      parseLhs,-      printLhs,-      parse,-      print+  ( para+  , plain+  , table+  , code+  , Flavour(..)+  , readPandoc+  , renderMarkdown+  , output+  , runOutput+  , tweakHaskellCodeBlock   ) where -import qualified Control.Foldl as L-import qualified Data.Attoparsec.Text as Text-import qualified Data.List as List-import qualified Data.Text as Text-import Protolude hiding (print)+import Protolude+import Data.Text as Text+import Text.Pandoc.Definition+import Text.Pandoc.Options+import Text.Pandoc+import qualified Data.Map as Map -data Section  = Code | Comment deriving (Show, Eq)-data Block = Block Section [Text] deriving (Show, Eq)+type Output = Map Text Text --- starting with .lhs bird style-bird :: Text.Parser Block-bird = do-    (\x -> (Block Code [x])) <$> ("> " *> Text.takeText)-    <|> (\_ -> (Block Code [""])) <$> (">" *> Text.takeText)-    <|> (\x -> (Block Comment [x])) <$> Text.takeText+-- | doctest+-- >>> :set -XOverloadedStrings -parseLhs :: [Text] -> [Block]-parseLhs text = L.fold (L.Fold step begin done) $ Text.parseOnly bird <$> text-  where-    begin = ((Block Code []), [])-    done ((Block _ []),out) = unlit' $ out-    done (block,out) = unlit' $ out <> [block]-    unlit' ss = (\(Block s ts) ->-                   case s of-                     Comment -> (Block s (unlit ts))-                     Code -> (Block s ts)) <$> ss-    step x (Left _) = x-    step ((Block s ts),out) (Right (Block s' ts')) = if-        | s == s' -> ((Block s (ts<>ts')), out)-        | otherwise -> case ts of-            [] -> ((Block s' ts), out)-            _ -> ((Block s' ts'), out <> [(Block s ts)])-    unlit [] = [""]-    unlit [""] = [""]-    unlit xs = if-        | (Protolude.head xs == Just "") && (Protolude.head (reverse xs) == Just "") ->-          List.init $ List.tail xs-        | (Protolude.head xs == Just "") ->-          List.tail xs-        | (Protolude.head (reverse xs) == Just "") ->-          List.init xs-        | otherwise ->-          xs+-- | turn text into a Pandoc Paragraph Block+-- >>> para "hello"+-- Para [Str "hello"]+para :: Text -> Block+para = Para . fmap (Str . Text.unpack) . Text.lines -printLhs :: [Block] -> [Text]-printLhs ss = Protolude.mconcat $-    (\(Block s ts) ->-       case s of-         Code -> ("> " <>) <$> ts-         Comment -> lit ts)-    <$> ss-  where-    lit [] = [""]-    lit [""] = [""]-    lit xs =-        (if (Protolude.head xs == Just "") then [] else [""]) <>-        xs <>-        (if (List.last xs == "") then [] else [""])+-- | turn text into a Pandoc Plain Block+-- >>> plain "hello"+-- Plain [Str "hello"]+plain :: Text -> Block+plain = Plain . fmap (Str . Text.unpack) . Text.lines --- coming from hs--- normal code (.hs) is parsed where lines that are continuation of a section (neither contain clues as to whether code or comment) are output as Nothing, and the clues as to what the current and next section are is encoded as Just (current, next).-normal :: Text.Parser (Maybe (Section, Section), [Text])-normal = do-    -- Nothing represents a continuation of previous section-    (\_ -> (Nothing, [""])) <$> Text.endOfInput <|>-     -- exact matches include line removal-     (\_ -> (Just (Comment, Comment), [])) <$> ("{-" *> Text.endOfInput) <|>-     (\_ -> (Just (Comment, Code), [])) <$> ("-}" *> Text.endOfInput) <|>-     -- single line braced-     (\x -> (Just (Code, Code), ["{-" <> x <> "-}"])) <$>-         ("{-" *> (Text.pack <$> Text.manyTill' Text.anyChar "-}")) <|>-     -- pragmas-     (\x -> (Just (Code, Code), ["{-#" <> x])) <$> ("{-#" *> Text.takeText) <|>-     (\x -> (Just (Code, Code), [x])) <$> (Text.pack <$> Text.manyTill' Text.anyChar "#-}") <|>-     -- braced start of multi-line comment (brace is stripped)-     (\x -> (Just (Comment, Comment), [x])) <$> ("{-" *> Text.takeText) <|>-     -- braced end of multi-line comment (brace is stripped)-     (\x -> (Just (Comment, Code), [x])) <$> (Text.pack <$> Text.manyTill' Text.anyChar "-}") <|>-     -- everything else a continuation and verbatim-     (\x -> (Nothing, [x])) <$> Text.takeText+-- |+-- >>> inline "two\nlines"+-- [Str "two",Str "lines"]+inline :: Text -> [Inline]+inline = fmap (Str . Text.unpack) . Text.lines -parseHs :: [Text] -> [Block]-parseHs text = L.fold (L.Fold step begin done) $ Text.parseOnly normal <$> text-  where-    begin = ((Block Code []), [])-    done ((Block _ []), out) = out-    done (buff, out) = out <> [buff]-    step x (Left _) = x-    step ((Block s ts), out) (Right (Just (this, next), ts')) = if-        | ts<>ts'==[] -> ((Block next []), out)-        | this == s && next == s -> ((Block s (ts<>ts')), out)-        | this /= s -> ((Block this ts'), out <> [(Block s ts)])-        | otherwise -> ((Block next []), out <> [(Block s (ts <> ts'))])-    step ((Block s ts),out) (Right (Nothing, ts')) = if-        | ts<>ts'==[] -> ((Block s []), out)-        | otherwise -> ((Block s (ts<>ts')), out)+-- | table caption headers alignments widths rows+-- >>> table "an example table" ["first column", "second column"] [AlignLeft, AlignRight] [0,0] [["first row", "1"], ["second row", "1000"]]+-- Table [Str "an example table"] [AlignLeft,AlignRight] [0.0,0.0] [[Para [Str "first column"]],[Para [Str "second column"]]] [[[Para [Str "first row"]],[Para [Str "1"]]],[[Para [Str "second row"]],[Para [Str "1000"]]]]+table :: Text -> [Text] -> [Alignment] -> [Int] -> [[Text]] -> Block+table caption hs as ws rs =+      Table+      (inline caption)+      as+      (fromIntegral <$> ws)+      ((:[]) . para <$> hs)+      (fmap ((:[]) . para) <$> rs) -printHs :: [Block] -> [Text]-printHs ss = Protolude.mconcat $-    (\(Block s ts) ->-       case s of-         Code -> ts-         Comment -> ["{-"] <> ts <> ["-}"]) <$> ss+-- | code identifier classes text+-- >>> code "name" ["sourceCode", "literate", "haskell"] "x = 1\n"+-- CodeBlock ("name",["sourceCode","literate","haskell"],[]) "x = 1\n"+code :: Text -> [Text] -> Text -> Block+code name classes =+  CodeBlock (Text.unpack name, Text.unpack <$> classes, []) . Text.unpack --- just in case there are ever other formats (YAML haskell anyone?)-data Format = Lhs | Hs+-- | use LHS when you want to just add output to a *.lhs+-- | use GitHubMarkdown for rendering code and results on github+data Flavour = GitHubMarkdown | LHS -print :: Format -> [Block] -> [Text]-print Lhs f = printLhs f-print Hs f = printHs f+-- | exts LHS is equivalent to 'markdown+lhs'+--  exts GitHubMarkdown is equivalent to 'gfm'+exts :: Flavour -> Extensions+exts LHS = enableExtension Ext_literate_haskell $ getDefaultExtensions "markdown"+exts GitHubMarkdown = githubMarkdownExtensions -parse :: Format -> [Text] -> [Block]-parse Lhs f = parseLhs f-parse Hs f = parseHs f+{- |+literate haskell code blocks comes out of markdown+lhs to native pandoc with the following classes:++["sourceCode","literate","haskell"]++  and then conversion to github flavour gives:++``` sourceCode+```++which doesn't lead to nice code highlighting on github (and elsewhere).  This function tweaks the list so that ["haskell"] is the class, and it all works.++-}+tweakHaskellCodeBlock :: Block -> Block+tweakHaskellCodeBlock (CodeBlock (id', cs, kv) b) =+  CodeBlock (id', bool cs ["haskell"] (Protolude.any ("haskell" ==) cs), kv) b+tweakHaskellCodeBlock x = x++-- | read a file into the pandoc AST+readPandoc :: FilePath -> Flavour -> IO (Either PandocError Pandoc)+readPandoc fp f = do+  t <- liftIO $ readFile fp+  runIO $ readMarkdown (def :: ReaderOptions) { readerExtensions = exts f} t++-- | render a pandoc AST+renderMarkdown :: Flavour -> Pandoc -> Either PandocError Text+renderMarkdown f (Pandoc meta bs) =+  runPure $+  writeMarkdown (def :: WriterOptions) { writerExtensions = exts f}+  (Pandoc meta (tweakHaskellCodeBlock <$> bs))++insertOutput :: Output -> Block -> Block+insertOutput m b = case b of+  (b'@ (CodeBlock (id', classes, kv) _)) ->+    bool b'+    (maybe+     (CodeBlock (id', classes, kv) mempty)+     (\x -> CodeBlock (id', classes, kv) . maybe mempty Text.unpack $ Map.lookup x m)+     (headMay . Protolude.filter ((`elem` classes) . Text.unpack) . Map.keys $ m))+    ("output" `elem` classes)+  b' -> b'++-- | add an output key-value pair to state+output :: (Monad m) => Text -> Text -> StateT (Map Text Text) m ()+output k v = modify (Map.insert k v)++-- | insert outputs into a new file+runOutput+  :: (FilePath, Flavour)+  -> (FilePath, Flavour)+  -> StateT Output IO ()+  -> IO (Either PandocError ())+runOutput (fi, flavi) (fo, flavo) out = do+  m <- execStateT out Map.empty+  p <- readPandoc fi flavi+  let w = do+              p' <- fmap (\(Pandoc meta bs) -> Pandoc meta (insertOutput m <$> bs)) p+              renderMarkdown flavo p'+  either (pure . Left) (\t -> writeFile fo t >> pure (Right ())) w
+ stack.yaml view
@@ -0,0 +1,3 @@+resolver: lts-13.21++
+ test/test.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# OPTIONS_GHC -Wall #-}++module Main where++import Protolude+import Test.DocTest++main :: IO ()+main =+  doctest ["src/Readme/Lhs.hs"]+
− test/test.lhs
@@ -1,50 +0,0 @@-> {-# OPTIONS_GHC -Wall #-}-> module Main where->-> import Protolude hiding (print)->-> import Test.Tasty (TestTree, testGroup, defaultMain)-> import Test.HUnit (Assertion, (@?=))-> import Test.Tasty.HUnit (testCase)-> import qualified Data.Text as Text->-> import Readme.Lhs->--parse . print is almost an isomorphism.--Forgetting whether comment marks were on a new line or embedded in with the comment text lines, and ensuring enough spaces in lhs comment sections to avoid unlit causes some initial style to be lost.--Once having been through these normalisations, however, isomorphism should appear.  print and parse should then satisfy the following laws:--    (parse Lhs . print Lhs) = id -- printid-    -- round about isomorphism-    (print Lhs . parse Lhs) . (print Lhs . parse Lhs) = (print Lhs . parse Lhs) -- parseid--> testPrintid :: Format -> [Block] -> Assertion-> testPrintid s f =->     (parse s . print s) f @?= f->-> testParseid :: Format -> [Text] -> Assertion-> testParseid s ts =->     ((print s . parse s) . (print s . parse s)) ts @?= (print s . parse s) ts->-> tests :: [Text] -> [Text] -> TestTree-> tests tsHs tsLhs = testGroup "Readme.Lhs"->     [ testCase "print parse iso - lhs" (testPrintid Lhs (parse Lhs tsLhs))->     , testCase "parse print pseudo-iso - lhs" (testParseid Lhs tsLhs)->     , testCase "print parse iso - hs" (testPrintid Hs (parse Hs tsHs))->     , testCase "parse print pseudo-iso - hs" (testParseid Hs tsHs)->     ]-> -> main :: IO ()-> main = do->     tsHs <- Text.lines <$> readFile "test/example1.hs"->     tsLhs <- Text.lines <$> readFile "test/example1.lhs"->     defaultMain (tests tsHs tsLhs)->-----