literatex (empty) → 0.1.0.0
raw patch · 28 files changed
+7684/−0 lines, 28 filesdep +ansi-wl-pprintdep +basedep +bytestringsetup-changed
Dependencies added: ansi-wl-pprint, base, bytestring, conduit, filepath, literatex, optparse-applicative, tasty, tasty-hunit, text, ttc, unliftio
Files
- CHANGELOG.md +31/−0
- LICENSE +21/−0
- README.md +366/−0
- Setup.hs +2/−0
- app/LibOA.hs +122/−0
- app/Main.hs +210/−0
- examples/highlevel.lhs +41/−0
- examples/lowlevel.hs +36/−0
- literatex.cabal +138/−0
- src/LiterateX.hs +531/−0
- src/LiterateX/Parser.hs +193/−0
- src/LiterateX/Renderer.hs +216/−0
- src/LiterateX/SourceDefaults.hs +70/−0
- src/LiterateX/Types.hs +23/−0
- src/LiterateX/Types/CodeLanguage.hs +60/−0
- src/LiterateX/Types/SourceFormat.hs +72/−0
- src/LiterateX/Types/SourceLine.hs +30/−0
- src/LiterateX/Types/TargetFormat.hs +115/−0
- test/LiterateX/Test/API.hs +367/−0
- test/LiterateX/Test/SourceFormat.hs +24/−0
- test/LiterateX/Test/SourceFormat/DoubleDash.hs +871/−0
- test/LiterateX/Test/SourceFormat/DoubleSlash.hs +827/−0
- test/LiterateX/Test/SourceFormat/Hash.hs +740/−0
- test/LiterateX/Test/SourceFormat/LispSemicolons.hs +837/−0
- test/LiterateX/Test/SourceFormat/LiterateHaskell.hs +696/−0
- test/LiterateX/Test/SourceFormat/Percent.hs +860/−0
- test/LiterateX/Test/TargetFormat.hs +167/−0
- test/Spec.hs +18/−0
+ CHANGELOG.md view
@@ -0,0 +1,31 @@+# `literatex-haskell` Changelog++This project follows the [Haskell package versioning policy][PVP], with+versions in `A.B.C.D` format. `A` may be incremented arbitrarily for+non-technical reasons, but [semantic versioning][SemVer] is otherwise+followed, where `A.B` is the major version, `C` is the minor version, and `D`+is the patch version. Initial development uses versions `0.0.0.D`, for which+every version is considered breaking.++[PVP]: <https://pvp.haskell.org/>+[SemVer]: <https://semver.org/>++The format of this changelog is based on [Keep a Changelog][KaC], with the+following conventions:++* Level-two heading `Unreleased` is used to track changes that have not been+ released.+* Other level-two headings specify the release in `A.B.C.D (YYYY-MM-DD)`+ format, with newer versions above older versions.+* Level-three headings are used to categorize changes as follows:+ 1. Breaking+ 2. Non-Breaking+* Changes are listed in arbitrary order and present tense.++[KaC]: <https://keepachangelog.com/en/1.0.0/>++## 0.1.0.0 (2021-05-26)++### Breaking++* Initial public release
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License++Copyright (c) 2021 Travis Cardwell++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,366 @@+# LiterateX++[](https://www.repostatus.org/#active)+[](https://github.com/ExtremaIS/literatex-haskell/actions)+[](https://hackage.haskell.org/package/literatex)+[](https://stackage.org/package/literatex)+[](https://stackage.org/nightly/package/literatex)++++* [Overview](#overview)+* [Source Formats](#source-formats)+ * [Double-Dash Comments](#double-dash-comments)+ * [Double-Slash Comments](#double-slash-comments)+ * [Hash Comments](#hash-comments)+ * [Lisp Semicolon Comments](#lisp-semicolon-comments)+ * [Literate Haskell](#literate-haskell)+ * [Percent Comments](#percent-comments)+* [CLI](#cli)+ * [Requirements](#requirements)+ * [Installation](#installation)+ * [Installation From Source](#installation-from-source)+ * [`.deb` Package Installation](#deb-package-installation)+ * [`.rpm` Package Installation](#rpm-package-installation)+ * [Usage](#usage)+* [Library](#library)+* [Related Work](#related-work)+* [Project](#project)+ * [Links](#links)+ * [Releases](#releases)+ * [Contribution](#contribution)+ * [License](#license)++## Overview++LiterateX transforms literate source code to Markdown. Write documentation in+Markdown format in the comments of source code, and LiterateX can transform+the file to Markdown, optionally including the source code with syntax+highlighting and line numbers. Many [source formats](#source-formats) are+supported, and the following target formats are supported:++* [Pandoc Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown)+* [GitHub Flavored Markdown](https://github.github.com/gfm/)++LiterateX can be used to document code that is particularly important or+difficult to understand. For example, documentation can be written in the SQL+file that defines the schema for a complex database. LiterateX can translate+the `.sql` file to a Markdown file, which can then be converted to HTML, PDF,+or even EPUB with [Pandoc][].++[Pandoc]: <https://pandoc.org/>++LiterateX can also be used in the publishing of blog entries, magazine+articles, or books. Use the [command-line utility](#cli) or integrate the+Haskell [library](#library) into your own software.++LiterateX has support for **source code rules**, comment lines that are used+to visually separate sections of source code. Since source code rules are+only used to make the source code easier to scan quickly, they are ignored+(treated as a blank line) when translating to Markdown.++LiterateX also has support for [shebang][] lines at the start of the file.+They can be ignored so that they do not precede the documentation.++[shebang]: <https://en.wikipedia.org/wiki/Shebang_(Unix)>++## Source Formats++LiterateX supports a number of source formats. With the exception of+[literate Haskell](#literate-haskell), documentation is written in line+comments in the source language. Note that multi-line comments are treated as+code, not documentation.++### Double-Dash Comments++Documentation is parsed from lines that begin with two dashes immediately+followed by a space (`-- `). Lines that only contain two dashes are treated+as blank lines in the documentation. Lines that contain three or more dashes+are treated as source code rules and are ignored.++``` haskell+-- # Haskell Example+--+-- Executables are implemented using a `Main` module that exposes a function+-- named `main`.++module Main (main) where++-- The `main` function is run when the program is executed.++main :: IO ()+main = putStrLn "Hello!"++-- This simple example just prints "Hello!" to the screen.+```++Languages that use double-dash comments include the following:++* [Elm](https://elm-lang.org/)+* [Haskell](https://www.haskell.org/)+* [Idris](https://www.idris-lang.org/)+* [Lua](http://www.lua.org/)+* [SQL](https://en.wikipedia.org/wiki/SQL)++### Double-Slash Comments++Documentation is parsed from lines that begin with two slashes immediately+followed by a space (`// `). Lines that only contain two slashes are treated+as blank lines in the documentation. Lines that contain three or more slashes+are treated as source code rules and are ignored.++``` rust+// # Rust Example+//+// The `main` function is run when the program is executed.++fn main() {+ println!("Hello!");+}++// This simple example just prints "Hello!" to the screen.+```++Languages that use double-slash comments include the following:++* [C][]+* [CSS](https://en.wikipedia.org/wiki/CSS)+* [Go](https://golang.org/)+* [Java](https://www.java.com/)+* [JavaScript](https://en.wikipedia.org/wiki/JavaScript)+* [Kotlin](https://kotlinlang.org/)+* [PHP](https://www.php.net/)+* [Rust](https://www.rust-lang.org/)+* [Scala](https://www.scala-lang.org/)+* [TypeScript](https://www.typescriptlang.org/)++[C]: <https://en.wikipedia.org/wiki/C_(programming_language)>++### Hash Comments++Documentation is parsed from lines that begin with a hash character+immediately followed by a space (`# `). Lines that only contain a hash+character are treated as blank lines in the documentation. Lines that contain+two or more hash characters are treated as source code rules and are ignored.++``` python+# # Python Example+#+# A quick-and-dirty Python script can include commands at the top level!++print("Hello!")++# This simple example just prints "Hello!" to the screen.+```++Languages that use hash comments include the following:++* [Bash](https://www.gnu.org/software/bash/)+* [Elixir](https://elixir-lang.org/)+* [Perl](https://www.perl.org/)+* [Python](https://www.python.org/)+* [R](https://www.r-project.org/)+* [Ruby](https://www.ruby-lang.org/)++### Lisp Semicolon Comments++Lisp languages use a semicolon (`;`) for line comments, but there is a+special convention to use a different number of semicolons according to the+context. Documentation is parsed from lines that begin with one to four+semicolons immediately followed by a space (`; `, `;; `, `;;; `, or `;;;; `).+Lines that only contain one to four semicolons are treated as blank lines in+the documentation. Lines that contain more than four semicolons are treated+as source code rules and are ignored.++``` scheme+; # Racket Example+;+; Racket programs must declare the language to use.++#lang racket/base++; Racket can also include commands at the top level!++(println "Hello!")++; This simple example just prints "Hello!" to the screen.+```++Languages that use Lisp semicolon comments include the following:++* [Clojure](https://clojure.org/)+* [Common Lisp](https://common-lisp.net/)+* [Racket](https://racket-lang.org/)+* [Scheme][]++[Scheme]: <https://en.wikipedia.org/wiki/Scheme_(programming_language)>++### Literate Haskell++[GHC](https://www.haskell.org/ghc/) has special support for+[literate programming](https://wiki.haskell.org/Literate_programming). With+this source format, documentation is not written in comments. Instead, lines+that contain source code are prefixes with a greater-than sign and a space+(`> `).++Note that this source format does not support source code rules.++``` lhaskell+# Literate Haskell Example++Executables are implemented using a `Main` module that exposes a function+named `main`.++> module Main (main) where++The `main` function is run when the program is executed.++> main :: IO ()+> main = putStrLn "Hello!"++This simple example just prints "Hello!" to the screen.+```++### Percent Comments++Documentation is parsed from lines that begin with a percent character+immediately followed by a space (`% `). Lines that only contain a percent+character are treated as blank lines in the documentation. Lines that contain+two or more percent characters are treated as source code rules and are+ignored.++``` erlang+% # Erlang Example+%+% Programs are implemented using a `main` module that exports a `start/0`+% function.++-module(main).+-export([start/0]).++% The `start` function is run when the program is executed.++start() -> io.fwrite("Hello!\n").++% This simple example just prints "Hello!" to the screen.+```++Languages that use percent comments include the following:++* [Erlang](https://www.erlang.org/)+* [LaTeX](https://www.latex-project.org/)++## CLI++LiterateX may be used via a command-line utility named `literatex`.++### Requirements++`literatex` has only been tested on Linux. It *might* work on Windows and+macOS.++### Installation++#### Installation From Source++`literatex` can be built from source using [Stack][]. For example, you can+install the latest release (to `/usr/local` on Linux) as follows:++```+$ git clone https://github.com/ExtremaIS/literatex-haskell.git+$ cd literatex-haskell+$ make+$ sudo make install+```++[Stack]: <https://www.haskellstack.org>++#### `.deb` Package Installation++Check the [Releases][] page for `.deb` packages.++#### `.rpm` Package Installation++Check the [Releases][] page for `.rpm` packages.++[Releases]: <https://github.com/ExtremaIS/literatex-haskell/releases>++### Usage++See the [`literatex` man page](doc/literatex.1.md) for usage information.++## Library++The [LiterateX Haskell library][] provides an API for integrating LiterateX+functionality in your own software.++[LiterateX Haskell library]: <https://hackage.haskell.org/package/literatex>++## Related Work++[Literate programming][] is a style of programming introduced by+[Donald Knuth][] in which [the main idea][] is "to regard a program as a+communication to human beings rather than as a set of instructions to a+computer." LiterateX is faithful to this idea in that it is used for+communication to human beings. Note, however, that LiterateX does *not*+support another core aspect of Knuth's literate programming: the ability to+write source code in the order best for human understanding. Since LiterateX+transforms actual source code files, the source code has to be written in+whatever order is required by the language. Those interested in writing code+in different order are encouraged to check out [noweb][] and [CWEB][].++[Literate programming]: <https://en.wikipedia.org/wiki/Literate_programming>+[Donald Knuth]: <https://en.wikipedia.org/wiki/Donald_Knuth>+[the main idea]: <https://www-cs-faculty.stanford.edu/~knuth/cweb.html>+[noweb]: <https://en.wikipedia.org/wiki/Noweb>+[CWEB]: <https://en.wikipedia.org/wiki/CWEB>++The [lhs2tex][] utility is used to work with literate Haskell and LaTeX.++[lhs2tex]: <https://github.com/kosmikus/lhs2tex>++The [src2md][] utility, written in Common Lisp, also supports multiple source+formats. It outputs Markdown that includes HTML, which limits the usefulness+of the Markdown.++[src2md]: <https://git.sr.ht/~aerique/src2markup>++The [extract-documentation-comments][] utility, written in JavaScript,+extracts documentation from multi-line JavaScript comments.++[extract-documentation-comments]: <https://github.com/Anadian/extract-documentation-comments#readme>++[mlp.clj][], written in Clojure, is a [babashka][] script that transforms+literate Clojure source code to Markdown, including HTML. The author uses it+to implement a [live preview][] of literate Clojure documentation while using+the [Notepad++][] (Windows editor).++[mlp.clj]: <https://github.com/linpengcheng/ClojureBoxNpp/blob/master/Notepad%2B%2B/tools/clj/mlp.clj>+[babashka]: <https://github.com/babashka/babashka#readme>+[live preview]: <https://github.com/linpengcheng/ClojureBoxNpp/tree/master/Notepad%2B%2B/plugins/Config/PreviewHTML>+[Notepad++]: <https://notepad-plus-plus.org/>++## Project++### Links++* GitHub: <https://github.com/ExtremaIS/literatex-haskell>++### Releases++All releases are tagged in the `main` branch. Release tags are signed using+the+[`security@extrema.is` GPG key](http://keys.gnupg.net/pks/lookup?op=vindex&fingerprint=on&search=0x1D484E4B4705FADF).++### Contribution++Issues and feature requests are tracked on GitHub:+<https://github.com/ExtremaIS/literatex-haskell/issues>++Issues may also be submitted via email to <bugs@extrema.is>.++### License++This project is released under the+[MIT License](https://opensource.org/licenses/MIT) as specified in the+[`LICENSE`](LICENSE) file.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/LibOA.hs view
@@ -0,0 +1,122 @@+------------------------------------------------------------------------------+-- |+-- Module : LibOA+-- Description : supplementary functions for optparse-applicative+-- Copyright : Copyright (c) 2019-2021 Travis Cardwell+-- License : MIT+--+-- This is a collection of functions that I often use with+-- @optparse-applicative@. I do not feel that it is worth maintaining yet+-- another helper package on Hackage, so I just copy the code to different+-- projects as required. If the library grows to a substantial size or others+-- with to use it, I will reconsider.+--+-- Revision: 2021-04-04+------------------------------------------------------------------------------++{-# LANGUAGE CPP #-}++module LibOA+ ( -- * Options+ -- $Options+ helper+ , versioner+ -- * Utilities+ , commands+ -- * Help+ , (<||>)+ , section+ , table+ , vspace+ ) where++-- https://hackage.haskell.org/package/ansi-wl-pprint+import qualified Text.PrettyPrint.ANSI.Leijen as Doc+import Text.PrettyPrint.ANSI.Leijen (Doc)++-- https://hackage.haskell.org/package/base+import qualified Data.List as List+#if !MIN_VERSION_base (4,11,0)+import Data.Monoid ((<>))+#endif++-- https://hackage.haskell.org/package/optparse-applicative+import qualified Options.Applicative as OA+import qualified Options.Applicative.Common as OAC+import qualified Options.Applicative.Types as OAT++------------------------------------------------------------------------------+-- $Options+--+-- Option descriptions are not capitalized.++-- | A hidden @-h@ / @--help@ option that always fails, showing the help+--+-- This is the same as 'OA.helper' except that it has a different help+-- message.+helper :: OA.Parser (a -> a)+#if MIN_VERSION_optparse_applicative (0,16,0)+helper = OA.option helpReader $ mconcat+ [ OA.short 'h'+ , OA.long "help"+ , OA.help "show this help text"+ , OA.hidden+ ]+ where+ helpReader = do+ potentialCommand <- OAT.readerAsk+ OA.readerAbort $ OA.ShowHelpText (Just potentialCommand)+#else+helper = OA.abortOption OA.ShowHelpText $ mconcat+ [ OA.short 'h'+ , OA.long "help"+ , OA.help "show help and exit"+ , OA.hidden+ ]+#endif++-- | A hidden @--version@ option that always fails, showing the version+versioner+ :: String -- ^ version string+ -> OA.Parser (a -> a)+versioner verStr = OA.infoOption verStr $ mconcat+ [ OA.long "version"+ , OA.help "show version and exit"+ , OA.hidden+ ]++------------------------------------------------------------------------------+-- $Utilities++-- | Get a list of commands for a parser+commands :: OA.Parser a -> [String]+commands =+ let go _ opt = case OAT.optMain opt of+ OAT.CmdReader _ cmds _ -> reverse cmds+ _otherReader -> []+ in concat . OAC.mapParser go++------------------------------------------------------------------------------+-- $Help++-- | Insert a blank line between two documents+(<||>) :: Doc -> Doc -> Doc+d1 <||> d2 = d1 <> Doc.line <> Doc.line <> d2+infixr 5 <||>++-- | Create a section with a title and indented body+section :: String -> Doc -> Doc+section title = (Doc.text title Doc.<$$>) . Doc.indent 2++-- | Create a two-column table+table :: [(String, String)] -> Doc+table rows =+ let width = 1 + maximum (map (length . fst) rows)+ in Doc.vcat+ [ Doc.fillBreak width (Doc.text l) Doc.<+> Doc.text r+ | (l, r) <- rows+ ]++-- | Vertically space documents with blank lines between them+vspace :: [Doc] -> Doc+vspace = mconcat . List.intersperse (Doc.line <> Doc.line)
+ app/Main.hs view
@@ -0,0 +1,210 @@+------------------------------------------------------------------------------+-- |+-- Module : Main+-- Description : literatex command-line utility+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+------------------------------------------------------------------------------++{-# LANGUAGE RecordWildCards #-}++module Main (main) where++-- https://hackage.haskell.org/package/ansi-wl-pprint+import Text.PrettyPrint.ANSI.Leijen (Doc)++-- https://hackage.haskell.org/package/base+import Control.Applicative (optional)+import System.Exit (ExitCode(ExitFailure), exitWith)+import System.IO (hPutStrLn, stderr, stdin, stdout)++-- https://hackage.haskell.org/package/optparse-applicative+import qualified Options.Applicative as OA++-- https://hackage.haskell.org/package/ttc+import qualified Data.TTC as TTC++-- (literatex)+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.SourceDefaults as SourceDefaults+import LiterateX.Types (CodeLanguage, SourceFormat, TargetFormat)+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.TargetFormat as TargetFormat++-- (literatex:executable)+import qualified LibOA++------------------------------------------------------------------------------+-- $Defaults++defaultTargetFormat :: TargetFormat+defaultTargetFormat = TargetFormat.PandocMarkdown++------------------------------------------------------------------------------+-- $Options++data Options+ = Options+ { formatOpt :: !(Maybe SourceFormat)+ , rendererOpts :: !Renderer.Options+ , noHighlightOpt :: !Bool+ , inputOpt :: !(Maybe FilePath)+ , outputOpt :: !(Maybe FilePath)+ }++sourceFormatOption :: OA.Parser SourceFormat+sourceFormatOption = OA.option (OA.eitherReader TTC.parse) $ mconcat+ [ OA.long "source"+ , OA.short 's'+ , OA.metavar "SOURCE"+ , OA.help "source format"+ ]++targetFormatOption :: OA.Parser TargetFormat+targetFormatOption = OA.option (OA.eitherReader TTC.parse) $ mconcat+ [ OA.long "target"+ , OA.short 't'+ , OA.metavar "TARGET"+ , OA.value defaultTargetFormat+ , OA.showDefaultWith TTC.render+ , OA.help "target format"+ ]++languageOption :: OA.Parser CodeLanguage+languageOption = OA.option (OA.eitherReader TTC.parse) $ mconcat+ [ OA.long "language"+ , OA.short 'l'+ , OA.metavar "LANGUAGE"+ , OA.help "code language"+ ]++ignoreShebangOption :: OA.Parser Bool+ignoreShebangOption = OA.switch $ mconcat+ [ OA.long "ignore-shebang"+ , OA.help "ignore shebangs"+ ]++noCodeOption :: OA.Parser Bool+noCodeOption = OA.switch $ mconcat+ [ OA.long "no-code"+ , OA.help "do not display code"+ ]++noNumbersOption :: OA.Parser Bool+noNumbersOption = OA.switch $ mconcat+ [ OA.long "no-numbers"+ , OA.help "do not number code lines"+ ]++renderOptions :: OA.Parser Renderer.Options+renderOptions = Renderer.Options+ <$> targetFormatOption+ <*> optional languageOption+ <*> ignoreShebangOption+ <*> fmap not noCodeOption+ <*> fmap not noNumbersOption++noHighlightOption :: OA.Parser Bool+noHighlightOption = OA.switch $ mconcat+ [ OA.long "no-highlight"+ , OA.help "do not highlight code"+ ]++inputOption :: OA.Parser FilePath+inputOption = OA.strOption $ mconcat+ [ OA.long "input"+ , OA.short 'i'+ , OA.metavar "FILE"+ , OA.help "input file (default: STDIN)"+ ]++outputOption :: OA.Parser FilePath+outputOption = OA.strOption $ mconcat+ [ OA.long "output"+ , OA.short 'o'+ , OA.metavar "FILE"+ , OA.help "output file (default: STDOUT)"+ ]++options :: OA.Parser Options+options = Options+ <$> optional sourceFormatOption+ <*> renderOptions+ <*> noHighlightOption+ <*> optional inputOption+ <*> optional outputOption++------------------------------------------------------------------------------+-- $Library++errorExit :: String -> IO a+errorExit message = do+ hPutStrLn stderr $ "error: " ++ message+ exitWith $ ExitFailure 1++------------------------------------------------------------------------------+-- $Main++main :: IO ()+main = do+ Options{..} <- OA.execParser pinfo+ let defaultOpts = SourceDefaults.defaultsFor =<< inputOpt+ format <- case (formatOpt, defaultOpts, inputOpt) of+ (Just format, _, _) -> pure format+ (Nothing, Just (format, _), _) -> pure format+ (Nothing, Nothing, Just{}) ->+ errorExit "source format not specified and unknown input filename"+ (Nothing, Nothing, Nothing) ->+ errorExit "source format not specified and no input filename"+ let codeLanguage = Renderer.codeLanguage rendererOpts+ opts = rendererOpts+ { Renderer.codeLanguage =+ case (noHighlightOpt, codeLanguage, defaultOpts) of+ (True, _, _) -> Nothing+ (False, opt@Just{}, _) -> opt+ (False, Nothing, Just (_, lang)) -> Just lang+ (False, Nothing, Nothing) -> Nothing+ }+ case (inputOpt, outputOpt) of+ (Just input, Just output) ->+ LiterateX.transformFileToFile format opts input output+ (Just input, Nothing) ->+ LiterateX.transformFileToHandle format opts input stdout+ (Nothing, Just output) ->+ LiterateX.transformHandleToFile format opts stdin output+ (Nothing, Nothing) ->+ LiterateX.transformHandleToHandle format opts stdin stdout+ where+ pinfo :: OA.ParserInfo Options+ pinfo+ = OA.info+ (LibOA.helper <*> LibOA.versioner LiterateX.version <*> options)+ $ mconcat+ [ OA.fullDesc+ , OA.progDesc "transform literate source code to Markdown"+ , OA.failureCode 2+ , OA.footerDoc . Just $ LibOA.vspace+ [ sourceFormatHelp+ , targetFormatHelp+ , defaultsHelp+ ]+ ]++ sourceFormatHelp :: Doc+ sourceFormatHelp = LibOA.section "SOURCE options:" $ LibOA.table+ [ (TTC.render format, SourceFormat.describe format)+ | format <- SourceFormat.list+ ]++ targetFormatHelp :: Doc+ targetFormatHelp = LibOA.section "TARGET options:" $ LibOA.table+ [ (TTC.render format, TargetFormat.describe format)+ | format <- TargetFormat.list+ ]++ defaultsHelp :: Doc+ defaultsHelp = LibOA.section "Default options:" $ LibOA.table+ [ (ext, TTC.render lang ++ " (" ++ TTC.render format ++ ")")+ | (ext, (format, lang)) <- SourceDefaults.extensionDefaults+ ]
+ examples/highlevel.lhs view
@@ -0,0 +1,41 @@+LiterateX High-Level Example+============================++This is a simple example of using the [LiterateX][] high-level API to+transform Haskell source code to [Pandoc Markdown][].++[LiterateX]: <https://github.com/ExtremaIS/literatex-haskell#readme>+[Pandoc Markdown]: <https://pandoc.org/MANUAL.html#pandocs-markdown>++Code+----++When executed, this example program reads this source code and transforms it+to Markdown, writing the output to `STDOUT`. Note that the path is+hard-coded, so be sure to execute the program from the project directory.++The `OverloadedStrings` extension is used to set the code language below.++> {-# LANGUAGE OverloadedStrings #-}+>+> module Main (main) where++Imports from [base](https://hackage.haskell.org/package/base):++> import System.IO (stdout)++Imports from [literatex](https://hackage.haskell.org/package/literatex):++> import qualified LiterateX+> import qualified LiterateX.Renderer as Renderer+> import qualified LiterateX.Types.SourceFormat as SourceFormat++The `main` function is just a call to `LiterateX.transformFileToHandle` with+appropriate options.++> main :: IO ()+> main = LiterateX.transformFileToHandle+> SourceFormat.LiterateHaskell+> (Renderer.defaultOptionsFor "haskell")+> "examples/highlevel.lhs"+> stdout
+ examples/lowlevel.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++-- https://hackage.haskell.org/package/base+import System.IO (stdout)++-- https://hackage.haskell.org/package/literatex+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.Types.SourceFormat as SourceFormat++------------------------------------------------------------------------------++demo :: String+demo = unlines+ [ "-- Demo"+ , "-- ===="+ , "--"+ , "-- This source code is embedded in the example, but it could come from"+ , "-- a database or API call."+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++------------------------------------------------------------------------------++main :: IO ()+main = LiterateX.runIO+ SourceFormat.DoubleDash+ (Renderer.defaultOptionsFor "haskell")+ (LiterateX.sourceString demo)+ (LiterateX.sinkHandle stdout)
+ literatex.cabal view
@@ -0,0 +1,138 @@+name: literatex+version: 0.1.0.0+category: Utils+synopsis: transform literate source code to Markdown+description:+ This package provides a library as well as a command-line utility that+ transforms literate source code to Markdown. Please see the README on+ GitHub at <https://github.com/ExtremaIS/literatex-haskell#readme>.++homepage: https://github.com/ExtremaIS/literatex-haskell#readme+bug-reports: https://github.com/ExtremaIS/literatex-haskell/issues+author: Travis Cardwell <travis.cardwell@extrema.is>+maintainer: Travis Cardwell <travis.cardwell@extrema.is>+copyright: Copyright (c) 2021 Travis Cardwell+license: MIT+license-file: LICENSE++cabal-version: 1.24+build-type: Simple+tested-with:+ GHC ==8.2.2+ || ==8.4.4+ || ==8.6.5+ || ==8.8.4+ || ==8.10.4+ || ==9.0.1++extra-source-files:+ CHANGELOG.md+ README.md++source-repository head+ type: git+ location: https://github.com/ExtremaIS/literatex-haskell.git++flag examples+ description: build examples+ default: False++flag write-hie+ description: write .hie files+ default: False++library+ hs-source-dirs: src+ exposed-modules:+ LiterateX+ , LiterateX.Parser+ , LiterateX.Renderer+ , LiterateX.SourceDefaults+ , LiterateX.Types+ , LiterateX.Types.CodeLanguage+ , LiterateX.Types.SourceFormat+ , LiterateX.Types.SourceLine+ , LiterateX.Types.TargetFormat+ other-modules:+ Paths_literatex+ build-depends:+ base >=4.7 && <5+ , bytestring >=0.10.8 && <0.12+ , conduit >=1.3 && <1.4+ , text >=1.2.3 && <1.3+ , ttc >=0.4 && <0.5+ , unliftio >=0.2 && <0.3+ default-language: Haskell2010+ default-extensions:+ OverloadedStrings+ if flag(write-hie)+ ghc-options: -Wall -fwrite-ide-info -hiedir=.hie+ else+ ghc-options: -Wall++executable literatex+ hs-source-dirs: app+ main-is: Main.hs+ other-modules:+ LibOA+ build-depends:+ ansi-wl-pprint >=0.6 && <0.7+ , base+ , optparse-applicative >=0.14 && <0.17+ , literatex+ , ttc+ default-language: Haskell2010+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N++executable example-highlevel+ if flag(examples)+ buildable: True+ else+ buildable: False+ hs-source-dirs: examples+ main-is: highlevel.lhs+ build-depends:+ base+ , literatex+ default-language: Haskell2010+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N++executable example-lowlevel+ if flag(examples)+ buildable: True+ else+ buildable: False+ hs-source-dirs: examples+ main-is: lowlevel.hs+ build-depends:+ base+ , literatex+ default-language: Haskell2010+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N++test-suite literatex-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ other-modules:+ LiterateX.Test.API+ , LiterateX.Test.SourceFormat+ , LiterateX.Test.SourceFormat.DoubleDash+ , LiterateX.Test.SourceFormat.DoubleSlash+ , LiterateX.Test.SourceFormat.Hash+ , LiterateX.Test.SourceFormat.LispSemicolons+ , LiterateX.Test.SourceFormat.LiterateHaskell+ , LiterateX.Test.SourceFormat.Percent+ , LiterateX.Test.TargetFormat+ build-depends:+ base+ , bytestring+ , filepath+ , literatex+ , tasty+ , tasty-hunit+ , text+ , ttc+ , unliftio+ default-language: Haskell2010+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
+ src/LiterateX.hs view
@@ -0,0 +1,531 @@+------------------------------------------------------------------------------+-- |+-- Module : LiterateX+-- Description : API+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+--+-- This module provides high-level as well as low-level API functions for+-- transforming literate source code.+------------------------------------------------------------------------------++{-# LANGUAGE FlexibleInstances #-}++module LiterateX+ ( -- * Constants+ version+ -- * API+ -- ** High-Level+ -- $HighLevelAPI+ , transformTextToText+ , transformTextToHandle+ , transformTextToFile+ , transformHandleToText+ , transformHandleToHandle+ , transformHandleToFile+ , transformFileToText+ , transformFileToHandle+ , transformFileToFile+ -- ** Low-Level+ -- $LowLevelAPI+ , runPure+ , runIO+ , runResource+ -- *** Producers+ , sourceString+ , sourceText+ , sourceLazyText+ , sourceByteString+ , sourceLazyByteString+ , sourceHandle+ , sourceFile+ -- *** Consumers+ , sinkString+ , sinkText+ , sinkLazyText+ , sinkByteString+ , sinkLazyByteString+ , sinkHandle+ , sinkFile+ -- *** Transformers+ , transform+ ) where++-- https://hackage.haskell.org/package/base+import Control.Monad.IO.Class (MonadIO)+import Data.Version (showVersion)+import System.IO (Handle)++-- https://hackage.haskell.org/package/bytestring+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BSL++-- https://hackage.haskell.org/package/conduit+import qualified Conduit as C+import Data.Conduit ((.|))+import qualified Data.Conduit.Combinators as CC+import qualified Data.Conduit.List as CL++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import qualified Data.Text.Encoding.Error as TEE+import qualified Data.Text.Lazy as TL++-- https://hackage.haskell.org/package/unliftio+import UnliftIO (MonadUnliftIO)++-- (literatex)+import qualified LiterateX.Parser as Parser+import qualified LiterateX.Renderer as Renderer+import LiterateX.Types (SourceFormat)++-- (literatex:cabal)+import qualified Paths_literatex as Project++------------------------------------------------------------------------------+-- $Constants++-- | LiterateX version string (\"@literatex-haskell X.X.X@\")+version :: String+version = "literatex-haskell " ++ showVersion Project.version++------------------------------------------------------------------------------+-- $HighLevelAPI+--+-- This high-level API provides functions for transforming literate source+-- code. These functions provide support for transforming from/to lazy+-- 'TL.Text', 'Handle's, and files.+--+-- Example usage:+--+-- @+-- {-\# LANGUAGE OverloadedStrings \#-}+--+-- module Main (main) where+--+-- -- https://hackage.haskell.org/package/literatex+-- import qualified LiterateX+-- import qualified LiterateX.Renderer as Renderer+-- import qualified LiterateX.Types.SourceFormat as SourceFormat+--+-- main :: IO ()+-- main = LiterateX.transformFileToFile+-- SourceFormat.LiterateHaskell+-- (Renderer.defaultOptionsFor "haskell")+-- "demo.lhs"+-- "demo.md"+-- @++-- | Transform from lazy 'TL.Text' to lazy 'TL.Text'+--+-- @since 0.0.1.0+transformTextToText+ :: SourceFormat+ -> Renderer.Options+ -> TL.Text+ -> TL.Text+transformTextToText sourceFormat rendererOpts source =+ runPure sourceFormat rendererOpts (sourceLazyText source) sinkLazyText++-- | Transform from lazy 'TL.Text' to a 'Handle'+--+-- @since 0.0.1.0+transformTextToHandle+ :: MonadIO m+ => SourceFormat+ -> Renderer.Options+ -> TL.Text+ -> Handle+ -> m ()+transformTextToHandle sourceFormat rendererOpts source target =+ runIO sourceFormat rendererOpts+ (sourceLazyText source)+ (sinkHandle target)++-- | Transform from lazy 'TL.Text' to a file+--+-- @since 0.0.1.0+transformTextToFile+ :: MonadUnliftIO m+ => SourceFormat+ -> Renderer.Options+ -> TL.Text+ -> FilePath+ -> m ()+transformTextToFile sourceFormat rendererOpts source target =+ runResource sourceFormat rendererOpts+ (sourceLazyText source)+ (sinkFile target)++-- | Transform from a 'Handle' to lazy 'TL.Text'+--+-- @since 0.0.1.0+transformHandleToText+ :: MonadIO m+ => SourceFormat+ -> Renderer.Options+ -> Handle+ -> m TL.Text+transformHandleToText sourceFormat rendererOpts source =+ runIO sourceFormat rendererOpts (sourceHandle source) sinkLazyText++-- | Transform from a 'Handle' to a 'Handle'+--+-- @since 0.0.1.0+transformHandleToHandle+ :: MonadIO m+ => SourceFormat+ -> Renderer.Options+ -> Handle+ -> Handle+ -> m ()+transformHandleToHandle sourceFormat rendererOpts source target =+ runIO sourceFormat rendererOpts (sourceHandle source) (sinkHandle target)++-- | Transform from a 'Handle' to a file+--+-- @since 0.0.1.0+transformHandleToFile+ :: MonadUnliftIO m+ => SourceFormat+ -> Renderer.Options+ -> Handle+ -> FilePath+ -> m ()+transformHandleToFile sourceFormat rendererOpts source target =+ runResource sourceFormat rendererOpts+ (sourceHandle source)+ (sinkFile target)++-- | Transform from a file to lazy 'TL.Text'+--+-- @since 0.0.1.0+transformFileToText+ :: MonadUnliftIO m+ => SourceFormat+ -> Renderer.Options+ -> FilePath+ -> m TL.Text+transformFileToText sourceFormat rendererOpts source =+ runResource sourceFormat rendererOpts (sourceFile source) sinkLazyText++-- | Transform from a file to a 'Handle'+--+-- @since 0.0.1.0+transformFileToHandle+ :: MonadUnliftIO m+ => SourceFormat+ -> Renderer.Options+ -> FilePath+ -> Handle+ -> m ()+transformFileToHandle sourceFormat rendererOpts source target =+ runResource sourceFormat rendererOpts+ (sourceFile source)+ (sinkHandle target)++-- | Transform from a file to a file+--+-- @since 0.0.1.0+transformFileToFile+ :: MonadUnliftIO m+ => SourceFormat+ -> Renderer.Options+ -> FilePath+ -> FilePath+ -> m ()+transformFileToFile sourceFormat rendererOpts source target =+ runResource sourceFormat rendererOpts+ (sourceFile source)+ (sinkFile target)++------------------------------------------------------------------------------+-- $LowLevelAPI+--+-- This low-level API provides more control over transforming literate source+-- code, using "Conduit". The 'transform' transformer implements the+-- transformation, transforming lines of input 'T.Text' to lines of output+-- 'T.Text'. Various producers are provided to produce lines of input+-- 'T.Text' from common sources, and various consumers are provided to consume+-- lines of output 'T.Text' to common sinks. These can be used separately if+-- necessary, but some run functions are provided for common usage.+--+-- Example usage:+--+-- @+-- {-\# LANGUAGE OverloadedStrings \#-}+--+-- module Main (main) where+--+-- -- https://hackage.haskell.org/package/base+-- import System.IO (stdout)+--+-- -- https://hackage.haskell.org/package/literatex+-- import qualified LiterateX+-- import qualified LiterateX.Renderer as Renderer+-- import qualified LiterateX.Types.SourceFormat as SourceFormat+--+-- main :: IO ()+-- main = do+-- let demoBS = "..."+-- LiterateX.runIO+-- SourceFormat.LiterateHaskell+-- (Renderer.defaultOptionsFor "haskell")+-- (LiterateX.sourceByteString demoBS)+-- (LiterateX.sinkHandle stdout)+-- @++-- | Run a pure LiterateX transformation+--+-- This function works with the following input line producers:+--+-- * 'sourceString'+-- * 'sourceText'+-- * 'sourceLazyText'+-- * 'sourceByteString'+-- * 'sourceLazyByteString'+--+-- This function works with the following output line consumers:+--+-- * 'sinkString'+-- * 'sinkText'+-- * 'sinkLazyText'+-- * 'sinkByteString'+-- * 'sinkLazyByteString'+--+-- @since 0.0.1.0+runPure+ :: SourceFormat+ -> Renderer.Options+ -> C.ConduitT () T.Text C.Identity () -- ^ input line producer+ -> C.ConduitT T.Text C.Void C.Identity r -- ^ output line consumer+ -> r+runPure sourceFormat rendererOpts source sink = C.runConduitPure $+ source .| transform sourceFormat rendererOpts .| sink++-- | Run a LiterateX transformation using IO+--+-- This function works with the following input line producers:+--+-- * 'sourceString'+-- * 'sourceText'+-- * 'sourceLazyText'+-- * 'sourceByteString'+-- * 'sourceLazyByteString'+-- * 'sourceHandle'+--+-- This function works with the following output line consumers:+--+-- * 'sinkString'+-- * 'sinkText'+-- * 'sinkLazyText'+-- * 'sinkByteString'+-- * 'sinkLazyByteString'+-- * 'sinkHandle'+--+-- @since 0.0.1.0+runIO+ :: MonadIO m+ => SourceFormat+ -> Renderer.Options+ -> C.ConduitT () T.Text m () -- ^ input line producer+ -> C.ConduitT T.Text C.Void m r -- ^ output line consumer+ -> m r+runIO sourceFormat rendererOpts source sink = C.runConduit $+ source .| transform sourceFormat rendererOpts .| sink++-- | Run a LiterateX transformation using resource management+--+-- This function works with the following input line producers:+--+-- * 'sourceString'+-- * 'sourceText'+-- * 'sourceLazyText'+-- * 'sourceByteString'+-- * 'sourceLazyByteString'+-- * 'sourceHandle'+-- * 'sourceFile'+--+-- This function works with the following output line consumers:+--+-- * 'sinkString'+-- * 'sinkText'+-- * 'sinkLazyText'+-- * 'sinkByteString'+-- * 'sinkLazyByteString'+-- * 'sinkHandle'+-- * 'sinkFile'+--+-- @since 0.0.1.0+runResource+ :: MonadUnliftIO m+ => SourceFormat+ -> Renderer.Options+ -> C.ConduitT () T.Text (C.ResourceT m) () -- ^ input line producer+ -> C.ConduitT T.Text C.Void (C.ResourceT m) r -- ^ output line consumer+ -> m r+runResource sourceFormat rendererOpts source sink = C.runConduitRes $+ source .| transform sourceFormat rendererOpts .| sink++------------------------------------------------------------------------------+-- $Producers++-- | Produce input lines from a 'String' source+--+-- @since 0.0.1.0+sourceString+ :: Monad m+ => String+ -> C.ConduitT i T.Text m ()+sourceString = CC.yieldMany . map T.pack . lines++-- | Produce input lines from a 'T.Text' source+--+-- @since 0.0.1.0+sourceText+ :: Monad m+ => T.Text+ -> C.ConduitT i T.Text m ()+sourceText source = C.yield source .| CC.linesUnbounded++-- | Produce input lines from a lazy 'TL.Text' source+--+-- @since 0.0.1.0+sourceLazyText+ :: Monad m+ => TL.Text+ -> C.ConduitT i T.Text m ()+sourceLazyText source = CC.sourceLazy source .| CC.linesUnbounded++-- | Produce input lines from a 'BS.ByteString' source+--+-- @since 0.0.1.0+sourceByteString+ :: Monad m+ => BS.ByteString+ -> C.ConduitT i T.Text m ()+sourceByteString source =+ C.yield source .| CC.linesUnboundedAscii .| decodeUtf8LinesLenient++-- | Produce input lines from a lazy 'BS.ByteString' source+--+-- @since 0.0.1.0+sourceLazyByteString+ :: Monad m+ => BSL.ByteString+ -> C.ConduitT i T.Text m ()+sourceLazyByteString source =+ CC.sourceLazy source .| CC.linesUnboundedAscii .| decodeUtf8LinesLenient++-- | Produce input lines from a 'Handle' source+--+-- @since 0.0.1.0+sourceHandle+ :: MonadIO m+ => Handle+ -> C.ConduitT i T.Text m ()+sourceHandle source =+ CC.sourceHandle source .| CC.linesUnboundedAscii .| decodeUtf8LinesLenient++-- | Produce input lines from a file source+--+-- @since 0.0.1.0+sourceFile+ :: C.MonadResource m+ => FilePath+ -> C.ConduitT i T.Text m ()+sourceFile source =+ CC.sourceFile source .| CC.linesUnboundedAscii .| decodeUtf8LinesLenient++------------------------------------------------------------------------------+-- $Consumers++-- | Consume output lines, returning a 'String'+--+-- @since 0.0.1.0+sinkString+ :: Monad m+ => C.ConduitT T.Text o m String+sinkString = fmap TL.unpack $ CC.unlines .| CC.sinkLazy++-- | Consume output lines, returning 'T.Text'+--+-- @since 0.0.1.0+sinkText+ :: Monad m+ => C.ConduitT T.Text o m T.Text+sinkText = fmap TL.toStrict $ CC.unlines .| CC.sinkLazy++-- | Consume output lines, returning lazy 'T.Text'+--+-- @since 0.0.1.0+sinkLazyText+ :: Monad m+ => C.ConduitT T.Text o m TL.Text+sinkLazyText = CC.unlines .| CC.sinkLazy++-- | Consume output lines, returning a 'BS.ByteString'+--+-- @since 0.0.1.0+sinkByteString+ :: Monad m+ => C.ConduitT T.Text o m BS.ByteString+sinkByteString =+ fmap BSL.toStrict $ CC.unlines .| CC.encodeUtf8 .| CC.sinkLazy++-- | Consume output lines, returning a lazy 'BS.ByteString'+--+-- @since 0.0.1.0+sinkLazyByteString+ :: Monad m+ => C.ConduitT T.Text o m BSL.ByteString+sinkLazyByteString = CC.unlines .| CC.encodeUtf8 .| CC.sinkLazy++-- | Consume output lines, writing to a 'Handle'+--+-- @since 0.0.1.0+sinkHandle+ :: MonadIO m+ => Handle+ -> C.ConduitT T.Text o m ()+sinkHandle target = CC.encodeUtf8 .| CC.unlinesAscii .| CC.sinkHandle target++-- | Consume output lines, writing to a file+--+-- @since 0.0.1.0+sinkFile+ :: C.MonadResource m+ => FilePath+ -> C.ConduitT T.Text o m ()+sinkFile target = CC.encodeUtf8 .| CC.unlinesAscii .| CC.sinkFile target++------------------------------------------------------------------------------+-- $Transformers++-- | Transform input lines to output lines+--+-- @since 0.0.1.0+transform+ :: Monad m+ => SourceFormat+ -> Renderer.Options+ -> C.ConduitT T.Text T.Text m ()+transform sourceFormat rendererOpts+ = Parser.parse sourceFormat+ .| CL.concatMapAccum (\x n -> (n + 1, [(n, x)])) 1+ .| Renderer.render rendererOpts++------------------------------------------------------------------------------+-- $Internal++-- | Decode UTF-8 'BS.ByteString' lines to 'T.Text'+--+-- Note that 'CC.decodeUtf8Lenient' decodes UTF-8 streams and therefore+-- discards empty strings. This version decodes UTF-8 lines and does not+-- discard empty lines.+decodeUtf8LinesLenient+ :: Monad m+ => C.ConduitT BS.ByteString T.Text m ()+decodeUtf8LinesLenient =+ C.awaitForever $ C.yield . TE.decodeUtf8With TEE.lenientDecode
+ src/LiterateX/Parser.hs view
@@ -0,0 +1,193 @@+------------------------------------------------------------------------------+-- |+-- Module : LiterateX.Parser+-- Description : source parser+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+--+-- This module implements the source parser.+------------------------------------------------------------------------------++{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-}++module LiterateX.Parser+ ( -- * API+ parse+ ) where++-- https://hackage.haskell.org/package/base+import Control.Monad (guard)+import Data.Maybe (fromMaybe)++-- https://hackage.haskell.org/package/conduit+import qualified Data.Conduit as C+import Data.Conduit (ConduitT)++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import Data.Text (Text)++-- (literatex)+import LiterateX.Types (SourceFormat, SourceLine)+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.SourceLine as SourceLine++------------------------------------------------------------------------------+-- $API++-- | Create a "Conduit" transformer that parses the specified source format+--+-- The transformer consumes lines of the input and produces a 'SourceLine' for+-- each line of input.+--+-- @since 0.0.1.0+parse+ :: Monad m+ => SourceFormat+ -> ConduitT Text SourceLine m ()+parse = parseSourceLines . parserFunctionsFor++------------------------------------------------------------------------------+-- $Internal++-- | Parser functions that determine how input is parsed+data ParserFunctions+ = ParserFunctions+ { isCodeBlank :: !(Text -> Bool)+ , isDocBlank :: !(Text -> Bool)+ , isRule :: !(Text -> Bool)+ , getDoc :: !(Text -> Maybe Text)+ , getCode :: !(Text -> Text)+ }++------------------------------------------------------------------------------++-- | Get the parser functions for the specified source format+parserFunctionsFor :: SourceFormat -> ParserFunctions+parserFunctionsFor = \case+ SourceFormat.DoubleDash -> lineCommentParserFunctions '-' 2+ SourceFormat.DoubleSlash -> lineCommentParserFunctions '/' 2+ SourceFormat.Hash -> lineCommentParserFunctions '#' 1+ SourceFormat.LiterateHaskell -> literateHaskellParserFunctions+ SourceFormat.Percent -> lineCommentParserFunctions '%' 1+ SourceFormat.LispSemicolons -> lispCommentParserFunctions++------------------------------------------------------------------------------++-- | Get parser functions for source with line-based comments+lineCommentParserFunctions+ :: Char -- ^ comment character+ -> Int -- ^ number of comment characters to create line comment+ -> ParserFunctions+lineCommentParserFunctions char count = ParserFunctions{..}+ where+ docBlank :: Text+ docBlank = T.pack $ replicate count char++ prefixLen :: Int+ prefixLen = count + 1++ prefix :: Text+ prefix = T.pack $ replicate count char ++ " "++ isCodeBlank :: Text -> Bool+ isCodeBlank = T.null++ isDocBlank :: Text -> Bool+ isDocBlank = (== docBlank)++ isRule :: Text -> Bool+ isRule line = T.length line > count && T.all (== char) line++ getDoc :: Text -> Maybe Text+ getDoc line = do+ let (linePrefix, lineSuffix) = T.splitAt prefixLen line+ guard $ linePrefix == prefix+ pure lineSuffix++ getCode :: Text -> Text+ getCode = id++------------------------------------------------------------------------------++-- | Get parser functions for source with Lisp-style comments+--+-- Lisp-style comments begin with one or more semicolons.+lispCommentParserFunctions :: ParserFunctions+lispCommentParserFunctions = ParserFunctions{..}+ where+ isCodeBlank :: Text -> Bool+ isCodeBlank = T.null++ isDocBlank :: Text -> Bool+ isDocBlank line =+ let len = T.length line+ in len >= 1 && len <= 4 && T.all (== ';') line++ isRule :: Text -> Bool+ isRule line = T.length line > 4 && T.all (== ';') line++ getDoc :: Text -> Maybe Text+ getDoc line = do+ let (linePrefix, (sep, lineSuffix)) = T.splitAt 1 <$> T.breakOn " " line+ guard $ not (T.null linePrefix) && T.all (== ';') linePrefix+ guard $ sep == " "+ pure lineSuffix++ getCode :: Text -> Text+ getCode = id++------------------------------------------------------------------------------++-- | Get parser functions for parsing literate Haskell+literateHaskellParserFunctions :: ParserFunctions+literateHaskellParserFunctions = ParserFunctions{..}+ where+ isCodeBlank :: Text -> Bool+ isCodeBlank = (== ">")++ isDocBlank :: Text -> Bool+ isDocBlank = T.null++ isRule :: Text -> Bool+ isRule = const False++ getDoc :: Text -> Maybe Text+ getDoc line+ | "> " `T.isPrefixOf` line = Nothing+ | otherwise = Just line++ getCode :: Text -> Text+ getCode line = fromMaybe line $ T.stripPrefix "> " line++------------------------------------------------------------------------------++-- | Create a "Conduit" transformer for the specified parser functions+--+-- This function produces a 'SourceLine' for each line of input. A+-- 'SourceLine.Shebang' can only be produced on the first line. Note that the+-- order that the parser functions are used is significant; the parser+-- functions are written for this order.+parseSourceLines+ :: Monad m+ => ParserFunctions+ -> ConduitT Text SourceLine m ()+parseSourceLines ParserFunctions{..} = do+ mLine <- C.await+ case mLine of+ Just line -> do+ C.yield $ if "#!" `T.isPrefixOf` line+ then SourceLine.Shebang line+ else parse' line+ C.awaitForever $ C.yield . parse'+ Nothing -> return ()+ where+ parse' :: Text -> SourceLine+ parse' line+ | isCodeBlank line = SourceLine.CodeBlank+ | isDocBlank line = SourceLine.DocBlank+ | isRule line = SourceLine.Rule+ | otherwise = case (getDoc line, getCode line) of+ (Just doc, _code) -> SourceLine.Doc doc+ (Nothing, code) -> SourceLine.Code code
+ src/LiterateX/Renderer.hs view
@@ -0,0 +1,216 @@+------------------------------------------------------------------------------+-- |+-- Module : LiterateX.Renderer+-- Description : target renderer+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+--+-- This module implements the target renderer.+------------------------------------------------------------------------------++{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++module LiterateX.Renderer+ ( -- * Types+ Options(..)+ -- * API+ , defaultOptions+ , defaultOptionsFor+ , render+ ) where++-- https://hackage.haskell.org/package/base+import Control.Monad (replicateM_)++-- https://hackage.haskell.org/package/conduit+import qualified Data.Conduit as C+import Data.Conduit (ConduitT)++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import Data.Text (Text)++-- (literatex)+import LiterateX.Types (CodeLanguage, SourceLine, TargetFormat)+import qualified LiterateX.Types.SourceLine as SourceLine+import qualified LiterateX.Types.TargetFormat as TargetFormat++------------------------------------------------------------------------------+-- $Types++-- | Renderer options determine how output is rendered+--+-- @since 0.0.1.0+data Options+ = Options+ { targetFormat :: !TargetFormat+ , codeLanguage :: !(Maybe CodeLanguage)+ , ignoreShebang :: !Bool -- ^ 'True' to ignore shebangs+ , renderCode :: !Bool -- ^ 'True' to render code+ , numberCodeLines :: !Bool -- ^ 'True' to number code lines+ }+ deriving Show++------------------------------------------------------------------------------+-- $API++-- | Default options+--+-- * @targetFormat@: 'TargetFormat.PandocMarkdown'+-- * @codeLanguage@: 'Nothing'+-- * @ignoreShebang@: 'True'+-- * @renderCode@: 'True'+-- * @numberCodeLines@: 'True'+--+-- @since 0.0.1.0+defaultOptions :: Options+defaultOptions = Options+ { targetFormat = TargetFormat.PandocMarkdown+ , codeLanguage = Nothing+ , ignoreShebang = True+ , renderCode = True+ , numberCodeLines = True+ }++-- | Default options for the specified code language+--+-- @since 0.0.1.0+defaultOptionsFor :: CodeLanguage -> Options+defaultOptionsFor lang = defaultOptions+ { codeLanguage = Just lang+ }++-- | Create a "Conduit" transformer that renders using the specified options+--+-- The transformer consumes 'SourceLine' values annotated with the line number+-- and produces lines of output.+--+-- @since 0.0.1.0+render+ :: forall m. Monad m+ => Options+ -> ConduitT (Int, SourceLine) Text m ()+render Options{..} = C.await >>= sStart+ where+ -- Start state+ sStart+ :: Maybe (Int, SourceLine)+ -> ConduitT (Int, SourceLine) Text m ()+ sStart (Just (lineNum, sourceLine)) = case sourceLine of+ -- render shebang if enabled, otherwise skip+ SourceLine.Shebang line+ | renderCode && not ignoreShebang -> do+ C.yield $ startShebang lineNum+ C.yield line+ C.yield endCode+ C.await >>= sBlank+ | otherwise -> C.await >>= sStart+ -- start rendering documentation+ SourceLine.Doc line -> do+ C.yield line+ C.await >>= sDoc+ -- start rendering code if enabled, otherwise skip+ SourceLine.Code line+ | renderCode -> do+ C.yield $ startCode lineNum+ C.yield line+ C.await >>= sCode 0+ | otherwise -> C.await >>= sStart+ -- skip blank lines and rules+ _BlankOrRule -> C.await >>= sStart+ sStart Nothing = return ()++ -- Code state+ sCode+ :: Int -- ^ number of pending (code) blank lines+ -> Maybe (Int, SourceLine)+ -> ConduitT (Int, SourceLine) Text m ()+ sCode !numBlanks (Just (_lineNum, sourceLine)) = case sourceLine of+ -- render any pending blank lines and code+ SourceLine.Code line -> do+ replicateM_ numBlanks $ C.yield T.empty+ C.yield line+ C.await >>= sCode 0+ -- increment number of pending blank lines+ SourceLine.CodeBlank -> C.await >>= sCode (numBlanks + 1)+ -- end code, add blank line, start rendering documentation+ SourceLine.Doc line -> do+ C.yield endCode+ C.yield T.empty+ C.yield line+ C.await >>= sDoc+ -- end code, enter blank state+ SourceLine.DocBlank -> do+ C.yield endCode+ C.await >>= sBlank+ -- end code, enter blank state+ SourceLine.Rule -> do+ C.yield endCode+ C.await >>= sBlank+ -- shebang only possible on first line (seen in start state)+ SourceLine.Shebang _line -> error "impossible: Shebang in sCode"+ sCode _numBlanks Nothing = C.yield endCode++ -- Documentation state+ sDoc+ :: Maybe (Int, SourceLine)+ -> ConduitT (Int, SourceLine) Text m ()+ sDoc (Just (lineNum, sourceLine)) = case sourceLine of+ -- render documentation+ SourceLine.Doc line -> do+ C.yield line+ C.await >>= sDoc+ -- start rendering code if enabled, otherwise enter blank state+ SourceLine.Code line+ | renderCode -> do+ C.yield T.empty+ C.yield $ startCode lineNum+ C.yield line+ C.await >>= sCode 0+ | otherwise -> C.await >>= sBlank+ -- shebang only possible on first line (seen in start state)+ SourceLine.Shebang _line -> error "impossible: Shebang in sDoc"+ -- blank lines and rules transition to blank state+ _BlankOrRule -> C.await >>= sBlank+ sDoc Nothing = return ()++ -- Blank state+ sBlank+ :: Maybe (Int, SourceLine)+ -> ConduitT (Int, SourceLine) Text m ()+ sBlank (Just (lineNum, sourceLine)) = case sourceLine of+ -- start rendering code if enabled, otherwise skip+ SourceLine.Code line+ | renderCode -> do+ C.yield T.empty+ C.yield $ startCode lineNum+ C.yield line+ C.await >>= sCode 0+ | otherwise -> C.await >>= sBlank+ -- render blank line, start rendering documentation+ SourceLine.Doc line -> do+ C.yield T.empty+ C.yield line+ C.await >>= sDoc+ -- shebang only possible on first line (seen in start state)+ SourceLine.Shebang _line -> error "impossible: Shebang in sBlank"+ -- skip additional blank lines and rules+ _BlankOrRule -> C.await >>= sBlank+ sBlank Nothing = return ()++ -- start code line for code starting at given line number+ startCode :: Int -> Text+ startCode =+ TargetFormat.mkBeginCode targetFormat codeLanguage numberCodeLines++ -- shebang start code line does not use syntax highlighting+ startShebang :: Int -> Text+ startShebang =+ TargetFormat.mkBeginCode targetFormat Nothing numberCodeLines++ -- end code line+ endCode :: Text+ endCode = TargetFormat.mkEndCode targetFormat+{-# ANN render ("HLint: ignore Reduce duplication" :: String) #-}
+ src/LiterateX/SourceDefaults.hs view
@@ -0,0 +1,70 @@+------------------------------------------------------------------------------+-- |+-- Module : LiterateX.SourceDefaults+-- Description : default options by source extension+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+--+-- This module provides some default options for various sources.+------------------------------------------------------------------------------++module LiterateX.SourceDefaults+ ( -- * API+ defaultsFor+ , extensionDefaults+ ) where++-- https://hackage.haskell.org/package/base+import Data.List (find, isSuffixOf)++-- (literatex)+import LiterateX.Types (CodeLanguage, SourceFormat)+import qualified LiterateX.Types.SourceFormat as SourceFormat++------------------------------------------------------------------------------+-- $API++-- | Get the default source format and code language for the given filename+--+-- @since 0.0.1.0+defaultsFor :: FilePath -> Maybe (SourceFormat, CodeLanguage)+defaultsFor path =+ fmap snd . flip find extensionDefaults $ flip isSuffixOf path . fst++------------------------------------------------------------------------------++-- | List of default options for various filename extensions+--+-- @since 0.0.1.0+extensionDefaults :: [(String, (SourceFormat, CodeLanguage))]+extensionDefaults =+ [ (".c", (SourceFormat.DoubleSlash, "c"))+ , (".clj", (SourceFormat.LispSemicolons, "clojure"))+ , (".css", (SourceFormat.DoubleSlash, "css"))+ , (".elm", (SourceFormat.DoubleDash, "elm"))+ , (".erl", (SourceFormat.Percent, "erlang"))+ , (".ex", (SourceFormat.Hash, "elixir"))+ , (".exs", (SourceFormat.Hash, "elixir"))+ , (".go", (SourceFormat.DoubleSlash, "go"))+ , (".hs", (SourceFormat.DoubleDash, "haskell"))+ , (".idr", (SourceFormat.DoubleDash, "idris"))+ , (".java", (SourceFormat.DoubleSlash, "java"))+ , (".js", (SourceFormat.DoubleSlash, "javascript"))+ , (".kt", (SourceFormat.DoubleSlash, "kotlin"))+ , (".lhs", (SourceFormat.LiterateHaskell, "haskell"))+ , (".lisp", (SourceFormat.LispSemicolons, "commonlisp"))+ , (".lua", (SourceFormat.DoubleDash, "lua"))+ , (".php", (SourceFormat.DoubleSlash, "php"))+ , (".pl", (SourceFormat.Hash, "perl"))+ , (".py", (SourceFormat.Hash, "python"))+ , (".r", (SourceFormat.Hash, "r"))+ , (".rb", (SourceFormat.Hash, "ruby"))+ , (".rkt", (SourceFormat.LispSemicolons, "scheme"))+ , (".rs", (SourceFormat.DoubleSlash, "rust"))+ , (".sc", (SourceFormat.DoubleSlash, "scala"))+ , (".scm", (SourceFormat.LispSemicolons, "scheme"))+ , (".sh", (SourceFormat.Hash, "bash"))+ , (".sql", (SourceFormat.DoubleDash, "sql"))+ , (".tex", (SourceFormat.Percent, "latex"))+ , (".ts", (SourceFormat.DoubleSlash, "typescript"))+ ]
+ src/LiterateX/Types.hs view
@@ -0,0 +1,23 @@+------------------------------------------------------------------------------+-- |+-- Module : LiterateX.Types+-- Description : type re-exports for convenience+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+--+-- The type modules are generally imported qualified, so the types are+-- re-exported by this module for convenience.+------------------------------------------------------------------------------++module LiterateX.Types+ ( module LiterateX.Types.CodeLanguage+ , module LiterateX.Types.SourceFormat+ , module LiterateX.Types.SourceLine+ , module LiterateX.Types.TargetFormat+ ) where++-- (literatex)+import LiterateX.Types.CodeLanguage (CodeLanguage)+import LiterateX.Types.SourceFormat (SourceFormat)+import LiterateX.Types.SourceLine (SourceLine)+import LiterateX.Types.TargetFormat (TargetFormat)
+ src/LiterateX/Types/CodeLanguage.hs view
@@ -0,0 +1,60 @@+------------------------------------------------------------------------------+-- |+-- Module : LiterateX.Types.CodeLanguage+-- Description : source code language type+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+------------------------------------------------------------------------------++module LiterateX.Types.CodeLanguage+ ( -- * Type+ CodeLanguage+ ) where++-- https://hackage.haskell.org/package/base+import Control.Monad (when)+import Data.Bifunctor (first)+import Data.Char (isSpace)+import Data.String (IsString(fromString))++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import Data.Text (Text)++-- https://hackage.haskell.org/package/ttc+import qualified Data.TTC as TTC++------------------------------------------------------------------------------+-- $Type++-- | Source code language+--+-- This string is used for syntax highlighting of source code.+--+-- When using Pandoc Markdown, run the following command to see a list of+-- supported languages:+--+-- @+-- \$ pandoc --list-highlight-languages+-- @+--+-- When using GitHub Flavored Markdown, check the following file for supported+-- languages:+--+-- <https://github.com/github/linguist/blob/master/lib/linguist/languages.yml>+--+-- @since 0.0.1.0+newtype CodeLanguage = CodeLanguage { unCodeLanguage :: Text }+ deriving (Eq, Ord, Show)++instance IsString CodeLanguage where+ fromString = either error id . TTC.parse++instance TTC.Parse CodeLanguage where+ parse = TTC.asT $ \t -> first TTC.fromS $ do+ when (T.null t) $ Left "invalid code language: empty"+ when (T.any isSpace t) $ Left "invalid code language: contains whitespace"+ return $ CodeLanguage t++instance TTC.Render CodeLanguage where+ render = TTC.fromT . unCodeLanguage
+ src/LiterateX/Types/SourceFormat.hs view
@@ -0,0 +1,72 @@+------------------------------------------------------------------------------+-- |+-- Module : LiterateX.Types.SourceFormat+-- Description : source format type+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+------------------------------------------------------------------------------++{-# LANGUAGE LambdaCase #-}++module LiterateX.Types.SourceFormat+ ( -- * Type+ SourceFormat(..)+ -- * API+ , describe+ , list+ ) where++-- https://hackage.haskell.org/package/ttc+import qualified Data.TTC as TTC++------------------------------------------------------------------------------+-- $Type++-- | Source format+--+-- This sum type defines the supported source formats.+--+-- @since 0.0.1.0+data SourceFormat+ = DoubleDash -- ^ \-- comments+ | DoubleSlash -- ^ // comments+ | Hash -- ^ # comments+ | LispSemicolons -- ^ Lisp semicolon comments+ | LiterateHaskell -- ^ literate Haskell+ | Percent -- ^ % comments+ deriving (Bounded, Enum, Eq, Ord, Show)++instance TTC.Parse SourceFormat where+ parse = TTC.parseEnum' "source format" True False++instance TTC.Render SourceFormat where+ render = TTC.fromS . \case+ DoubleDash -> "ddash"+ DoubleSlash -> "dslash"+ Hash -> "hash"+ LispSemicolons -> "lisp"+ LiterateHaskell -> "lhs"+ Percent -> "percent"++------------------------------------------------------------------------------+-- $API++-- | Get a description of a source format+--+-- @since 0.0.1.0+describe :: SourceFormat -> String+describe = \case+ DoubleDash -> "-- comments"+ DoubleSlash -> "// comments"+ Hash -> "# comments"+ LispSemicolons -> "Lisp semicolon comments"+ LiterateHaskell -> "literate Haskell"+ Percent -> "% comments"++------------------------------------------------------------------------------++-- | List of all supported source formats+--+-- @since 0.0.1.0+list :: [SourceFormat]+list = [minBound ..]
+ src/LiterateX/Types/SourceLine.hs view
@@ -0,0 +1,30 @@+------------------------------------------------------------------------------+-- |+-- Module : LiterateX.Types.SourceLine+-- Description : source line type+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+------------------------------------------------------------------------------++module LiterateX.Types.SourceLine+ ( -- * Type+ SourceLine(..)+ ) where++-- https://hackage.haskell.org/package/text+import Data.Text (Text)++------------------------------------------------------------------------------+-- $Type++-- | Parsed source line+--+-- @since 0.0.1.0+data SourceLine+ = Shebang !Text -- ^ script shebang on first line+ | CodeBlank -- ^ code blank line+ | DocBlank -- ^ documentation blank line+ | Rule -- ^ comment rule used to organize source code+ | Doc !Text -- ^ documentation line+ | Code !Text -- ^ code line+ deriving Show
+ src/LiterateX/Types/TargetFormat.hs view
@@ -0,0 +1,115 @@+------------------------------------------------------------------------------+-- |+-- Module : LiterateX.Types.TargetFormat+-- Description : target format type+-- Copyright : Copyright (c) 2021 Travis Cardwell+-- License : MIT+------------------------------------------------------------------------------++{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module LiterateX.Types.TargetFormat+ ( -- * Type+ TargetFormat(..)+ -- * API+ , describe+ , list+ , mkEndCode+ , mkBeginCode+ ) where++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import Data.Text (Text)++-- https://hackage.haskell.org/package/ttc+import qualified Data.TTC as TTC++-- (literatex)+import LiterateX.Types.CodeLanguage (CodeLanguage)++------------------------------------------------------------------------------+-- $Type++-- | Target format+--+-- This sum type defines the supported target formats.+--+-- @since 0.0.1.0+data TargetFormat+ = PandocMarkdown+ | GitHubFlavoredMarkdown+ deriving (Bounded, Enum, Eq, Ord, Show)++instance TTC.Parse TargetFormat where+ parse = TTC.parseEnum' "target format" True False++instance TTC.Render TargetFormat where+ render = TTC.fromS . \case+ PandocMarkdown -> "pandoc"+ GitHubFlavoredMarkdown -> "github"++------------------------------------------------------------------------------+-- $API++-- | Get a description of a target format+--+-- @since 0.0.1.0+describe :: TargetFormat -> String+describe = \case+ PandocMarkdown -> "Pandoc Markdown"+ GitHubFlavoredMarkdown -> "GitHub Flavored Markdown"++------------------------------------------------------------------------------++-- | List of all supported target formats+--+-- @since 0.0.1.0+list :: [TargetFormat]+list = [minBound ..]++------------------------------------------------------------------------------++-- | Make line in the target format to end a block of source code+--+-- @since 0.0.1.0+mkEndCode+ :: TargetFormat+ -> Text+mkEndCode _anyFormat = "```"++------------------------------------------------------------------------------++-- | Make line in the target format to begin a block of code+--+-- Note that this function is written to indicate how it is used. Given the+-- target format, optional code language, and line numbering flag, this+-- function returns a function that takes a line number and returns a line.+--+-- @since 0.0.1.0+mkBeginCode+ :: TargetFormat+ -> Maybe CodeLanguage+ -> Bool -- ^ 'True' to number code lines+ -> (Int -> Text) -- ^ make line for code starting at specified line number+mkBeginCode PandocMarkdown (Just lang) True = \lineNum -> T.concat+ [ "``` {.", TTC.render lang, " .numberSource startFrom=\""+ , TTC.renderWithShow lineNum, "\"}"+ ]+mkBeginCode GitHubFlavoredMarkdown (Just lang) True = \lineNum -> T.concat+ [ "``` ", TTC.render lang, " startline=", TTC.renderWithShow lineNum+ ]+mkBeginCode PandocMarkdown (Just lang) False = const $ T.concat+ [ "```", TTC.render lang+ ]+mkBeginCode GitHubFlavoredMarkdown (Just lang) False = const $ T.concat+ [ "``` ", TTC.render lang+ ]+mkBeginCode PandocMarkdown Nothing True = \lineNum -> T.concat+ [ "``` {.numberSource startFrom=\"", TTC.renderWithShow lineNum, "\"}"+ ]+mkBeginCode GitHubFlavoredMarkdown Nothing True = \lineNum -> T.concat+ [ "``` startline=", TTC.renderWithShow lineNum+ ]+mkBeginCode _anyFormat Nothing False = const "```"
+ test/LiterateX/Test/API.hs view
@@ -0,0 +1,367 @@+{-# LANGUAGE OverloadedStrings #-}++module LiterateX.Test.API (tests) where++-- https://hackage.haskell.org/package/bytestring+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BSL++-- https://hackage.haskell.org/package/filepath+import System.FilePath ((</>))++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL++-- https://hackage.haskell.org/package/ttc+import qualified Data.TTC as TTC++-- https://hackage.haskell.org/package/unliftio+import qualified UnliftIO.IO as IO+import UnliftIO.Temporary (withSystemTempDirectory)++-- (literatex)+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.TargetFormat as TargetFormat++------------------------------------------------------------------------------++sourceS :: String+sourceS = unlines+ [ "#!/usr/bin/env python"+ , ""+ , "# # Example Python Program"+ , "#"+ , "# This is an example program."+ , ""+ , ""+ , "######################################################################"+ , ""+ , "# ## Function `greet`"+ , "#"+ , "# This function prints a greeting."+ , "def greet(name: str) -> None:"+ , " if name == '':"+ , " print('Hello!')"+ , " return"+ , ""+ , " print(f'Hello {name}!')"+ , ""+ , ""+ , "if __name__ == '__main__':"+ , " greet()"+ ]++sourceT :: T.Text+sourceT = TTC.fromS sourceS++sourceTL :: TL.Text+sourceTL = TTC.fromS sourceS++sourceBS :: BS.ByteString+sourceBS = TTC.fromS sourceS++sourceBSL :: BSL.ByteString+sourceBSL = TTC.fromS sourceS++------------------------------------------------------------------------------++targetS :: String+targetS = unlines+ [ "# Example Python Program"+ , ""+ , "This is an example program."+ , ""+ , "## Function `greet`"+ , ""+ , "This function prints a greeting."+ , ""+ , "``` {.python .numberSource startFrom=\"13\"}"+ , "def greet(name: str) -> None:"+ , " if name == '':"+ , " print('Hello!')"+ , " return"+ , ""+ , " print(f'Hello {name}!')"+ , ""+ , ""+ , "if __name__ == '__main__':"+ , " greet()"+ , "```"+ ]++targetT :: T.Text+targetT = TTC.fromS targetS++targetTL :: TL.Text+targetTL = TTC.fromS targetS++targetBS :: BS.ByteString+targetBS = TTC.fromS targetS++targetBSL :: BSL.ByteString+targetBSL = TTC.fromS targetS++------------------------------------------------------------------------------++withSourceHandle+ :: String -- ^ content+ -> (IO.Handle -> IO a)+ -> IO a+withSourceHandle content action =+ withSystemTempDirectory "literatex-test-" $ \tmpDirPath -> do+ let sourcePath = tmpDirPath </> "source"+ writeFile sourcePath content+ IO.withFile sourcePath IO.ReadMode action++------------------------------------------------------------------------------++withTargetHandle+ :: (IO.Handle -> IO ())+ -> IO String+withTargetHandle action =+ withSystemTempDirectory "literatex-test-" $ \tmpDirPath -> do+ let targetPath = tmpDirPath </> "target"+ IO.withFile targetPath IO.WriteMode action+ readFile targetPath++------------------------------------------------------------------------------++withSourceFile+ :: String -- ^ content+ -> (FilePath -> IO a)+ -> IO a+withSourceFile content action =+ withSystemTempDirectory "literatex-test-" $ \tmpDirPath -> do+ let sourcePath = tmpDirPath </> "source"+ writeFile sourcePath content+ action sourcePath++------------------------------------------------------------------------------++withTargetFile+ :: (FilePath -> IO ())+ -> IO String+withTargetFile action =+ withSystemTempDirectory "literatex-test-" $ \tmpDirPath -> do+ let targetPath = tmpDirPath </> "target"+ action targetPath+ readFile targetPath++------------------------------------------------------------------------------++rendererOpts :: Renderer.Options+rendererOpts = Renderer.Options+ { Renderer.targetFormat = TargetFormat.PandocMarkdown+ , Renderer.codeLanguage = Just "python"+ , Renderer.ignoreShebang = True+ , Renderer.renderCode = True+ , Renderer.numberCodeLines = True+ }++------------------------------------------------------------------------------++testTransformTextToText :: TestTree+testTransformTextToText = testCase "transformTextToText" $+ targetTL @=?+ LiterateX.transformTextToText SourceFormat.Hash rendererOpts sourceTL++------------------------------------------------------------------------------++testTransformTextToHandle :: TestTree+testTransformTextToHandle = testCase "transformTextToHandle" $ do+ result <- withTargetHandle $+ LiterateX.transformTextToHandle SourceFormat.Hash rendererOpts sourceTL+ targetS @=? result++------------------------------------------------------------------------------++testTransformTextToFile :: TestTree+testTransformTextToFile = testCase "transformTextToFile" $ do+ result <- withTargetFile $+ LiterateX.transformTextToFile SourceFormat.Hash rendererOpts sourceTL+ targetS @=? result++------------------------------------------------------------------------------++testTransformHandleToText :: TestTree+testTransformHandleToText = testCase "transformHandleToText" $ do+ result <- withSourceHandle sourceS $+ LiterateX.transformHandleToText SourceFormat.Hash rendererOpts+ targetTL @=? result++------------------------------------------------------------------------------++testTransformHandleToHandle :: TestTree+testTransformHandleToHandle = testCase "transformHandleToHandle" $ do+ result <- withSourceHandle sourceS $ withTargetHandle .+ LiterateX.transformHandleToHandle SourceFormat.Hash rendererOpts+ targetS @=? result++------------------------------------------------------------------------------++testTransformHandleToFile :: TestTree+testTransformHandleToFile = testCase "transformHandleToFile" $ do+ result <- withSourceHandle sourceS $ withTargetFile .+ LiterateX.transformHandleToFile SourceFormat.Hash rendererOpts+ targetS @=? result++------------------------------------------------------------------------------++testTransformFileToText :: TestTree+testTransformFileToText = testCase "transformFileToText" $ do+ result <- withSourceFile sourceS $+ LiterateX.transformFileToText SourceFormat.Hash rendererOpts+ targetTL @=? result++------------------------------------------------------------------------------++testTransformFileToHandle :: TestTree+testTransformFileToHandle = testCase "transformFileToHandle" $ do+ result <- withSourceFile sourceS $ withTargetHandle .+ LiterateX.transformFileToHandle SourceFormat.Hash rendererOpts+ targetS @=? result++------------------------------------------------------------------------------++testTransformFileToFile :: TestTree+testTransformFileToFile = testCase "transformFileToFile" $ do+ result <- withSourceFile sourceS $ withTargetFile .+ LiterateX.transformFileToFile SourceFormat.Hash rendererOpts+ targetS @=? result++------------------------------------------------------------------------------++testRunPure :: TestTree+testRunPure = testGroup "runPure"+ [ testCase "sourceString" $+ targetTL @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceString sourceS)+ LiterateX.sinkLazyText+ , testCase "sourceText" $+ targetTL @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceText sourceT)+ LiterateX.sinkLazyText+ , testCase "sourceLazyText" $+ targetTL @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceLazyText sourceTL)+ LiterateX.sinkLazyText+ , testCase "sourceByteString" $+ targetTL @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceByteString sourceBS)+ LiterateX.sinkLazyText+ , testCase "sourceLazyByteString" $+ targetTL @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceLazyByteString sourceBSL)+ LiterateX.sinkLazyText+ , testCase "sinkString" $+ targetS @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceLazyText sourceTL)+ LiterateX.sinkString+ , testCase "sinkText" $+ targetT @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceLazyText sourceTL)+ LiterateX.sinkText+ , testCase "sinkLazyText" $+ targetTL @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceLazyText sourceTL)+ LiterateX.sinkLazyText+ , testCase "sinkByteString" $+ targetBS @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceLazyText sourceTL)+ LiterateX.sinkByteString+ , testCase "sinkLazyByteString" $+ targetBSL @=? LiterateX.runPure SourceFormat.Hash rendererOpts+ (LiterateX.sourceLazyText sourceTL)+ LiterateX.sinkLazyByteString+ ]++------------------------------------------------------------------------------++testRunIO :: TestTree+testRunIO = testGroup "runIO"+ [ testCase "TextToHandle" $ do+ result <- withTargetHandle $ \target ->+ LiterateX.runIO SourceFormat.Hash rendererOpts+ (LiterateX.sourceLazyText sourceTL)+ (LiterateX.sinkHandle target)+ targetS @=? result+ , testCase "HandleToText" $ do+ result <- withSourceHandle sourceS $ \source ->+ LiterateX.runIO SourceFormat.Hash rendererOpts+ (LiterateX.sourceHandle source)+ LiterateX.sinkLazyText+ targetTL @=? result+ , testCase "HandleToHandle" $ do+ result <- withSourceHandle sourceS $ \source ->+ withTargetHandle $ \target ->+ LiterateX.runIO SourceFormat.Hash rendererOpts+ (LiterateX.sourceHandle source)+ (LiterateX.sinkHandle target)+ targetS @=? result+ ]++------------------------------------------------------------------------------++testRunResource :: TestTree+testRunResource = testGroup "runResource"+ [ testCase "TextToFile" $ do+ result <- withTargetFile $ \target ->+ LiterateX.runResource SourceFormat.Hash rendererOpts+ (LiterateX.sourceLazyText sourceTL)+ (LiterateX.sinkFile target)+ targetS @=? result+ , testCase "HandleToFile" $ do+ result <- withSourceHandle sourceS $ \source ->+ withTargetFile $ \target ->+ LiterateX.runResource SourceFormat.Hash rendererOpts+ (LiterateX.sourceHandle source)+ (LiterateX.sinkFile target)+ targetS @=? result+ , testCase "FileToText" $ do+ result <- withSourceFile sourceS $ \source ->+ LiterateX.runResource SourceFormat.Hash rendererOpts+ (LiterateX.sourceFile source)+ LiterateX.sinkLazyText+ targetTL @=? result+ , testCase "FileToHandle" $ do+ result <- withSourceFile sourceS $ \source ->+ withTargetHandle $ \target ->+ LiterateX.runResource SourceFormat.Hash rendererOpts+ (LiterateX.sourceFile source)+ (LiterateX.sinkHandle target)+ targetS @=? result+ , testCase "FileToFile" $ do+ result <- withSourceFile sourceS $ \source ->+ withTargetFile $ \target ->+ LiterateX.runResource SourceFormat.Hash rendererOpts+ (LiterateX.sourceFile source)+ (LiterateX.sinkFile target)+ targetS @=? result+ ]++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "LiterateX.Test.API"+ [ testTransformTextToText+ , testTransformTextToHandle+ , testTransformTextToFile+ , testTransformHandleToText+ , testTransformHandleToHandle+ , testTransformHandleToFile+ , testTransformFileToText+ , testTransformFileToHandle+ , testTransformFileToFile+ , testRunPure+ , testRunIO+ , testRunResource+ ]
+ test/LiterateX/Test/SourceFormat.hs view
@@ -0,0 +1,24 @@+module LiterateX.Test.SourceFormat (tests) where++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- (literatex:test)+import qualified LiterateX.Test.SourceFormat.DoubleDash+import qualified LiterateX.Test.SourceFormat.DoubleSlash+import qualified LiterateX.Test.SourceFormat.Hash+import qualified LiterateX.Test.SourceFormat.LispSemicolons+import qualified LiterateX.Test.SourceFormat.LiterateHaskell+import qualified LiterateX.Test.SourceFormat.Percent++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "LiterateX.Test.SourceFormat"+ [ LiterateX.Test.SourceFormat.DoubleDash.tests+ , LiterateX.Test.SourceFormat.DoubleSlash.tests+ , LiterateX.Test.SourceFormat.Hash.tests+ , LiterateX.Test.SourceFormat.LispSemicolons.tests+ , LiterateX.Test.SourceFormat.LiterateHaskell.tests+ , LiterateX.Test.SourceFormat.Percent.tests+ ]
+ test/LiterateX/Test/SourceFormat/DoubleDash.hs view
@@ -0,0 +1,871 @@+{-# LANGUAGE OverloadedStrings #-}++module LiterateX.Test.SourceFormat.DoubleDash (tests) where++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy (Text)++-- (literatex)+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.TargetFormat as TargetFormat++------------------------------------------------------------------------------++rendererOpts :: Renderer.Options+rendererOpts = Renderer.Options+ { Renderer.targetFormat = TargetFormat.PandocMarkdown+ , Renderer.codeLanguage = Just "haskell"+ , Renderer.ignoreShebang = True+ , Renderer.renderCode = True+ , Renderer.numberCodeLines = True+ }++run' :: Text -> Renderer.Options -> Text+run' = flip $ LiterateX.transformTextToText SourceFormat.DoubleDash++run :: Text -> Text+run source = run' source rendererOpts++------------------------------------------------------------------------------++sourceStartShebangDoc :: Text+sourceStartShebangDoc = TL.unlines+ [ "#!/usr/bin/env stack"+ , ""+ , "-- This results in warnings!"+ , ""+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetStartShebangDocIgnore :: Text+targetStartShebangDocIgnore = TL.unlines+ [ "This results in warnings!"+ , ""+ , "``` {.haskell .numberSource startFrom=\"5\"}"+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++targetStartShebangDocNoIgnore :: Text+targetStartShebangDocNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env stack"+ , "```"+ , ""+ , "This results in warnings!"+ , ""+ , "``` {.haskell .numberSource startFrom=\"5\"}"+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++targetStartShebangDocNoCode :: Text+targetStartShebangDocNoCode = TL.unlines+ [ "This results in warnings!"+ ]++testStartShebangDoc :: TestTree+testStartShebangDoc = testGroup "startShebangDoc"+ [ testCase "Ignore" $+ targetStartShebangDocIgnore @=? run sourceStartShebangDoc+ , testCase "NoIgnore" $+ targetStartShebangDocNoIgnore @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangDocNoCode @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartShebangCode :: Text+sourceStartShebangCode = TL.unlines+ [ "#!/usr/bin/env stack"+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , ""+ , "-- Test"+ ]++targetStartShebangCodeIgnore :: Text+targetStartShebangCodeIgnore = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"2\"}"+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoIgnore :: Text+targetStartShebangCodeNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env stack"+ , "```"+ , ""+ , "``` {.haskell .numberSource startFrom=\"2\"}"+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoCode :: Text+targetStartShebangCodeNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangCode :: TestTree+testStartShebangCode = testGroup "startShebangCode"+ [ testCase "Ignore" $+ targetStartShebangCodeIgnore @=? run sourceStartShebangCode+ , testCase "NoIgnore" $+ targetStartShebangCodeNoIgnore @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangCodeNoCode @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartDoc :: Text+sourceStartDoc = TL.unlines+ [ "-- Test"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetStartDoc :: Text+targetStartDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"3\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testStartDoc :: TestTree+testStartDoc = testCase "startDoc" $+ targetStartDoc @=? run sourceStartDoc++------------------------------------------------------------------------------++sourceStartCode :: Text+sourceStartCode = TL.unlines+ [ "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , ""+ , "-- Test"+ ]++targetStartCode :: Text+targetStartCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testStartCode :: TestTree+testStartCode = testCase "startCode" $+ targetStartCode @=? run sourceStartCode++------------------------------------------------------------------------------++sourceStartDocBlank :: Text+sourceStartDocBlank = TL.unlines+ [ "--"+ , "-- Test"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetStartDocBlank :: Text+targetStartDocBlank = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"4\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testStartDocBlank :: TestTree+testStartDocBlank = testCase "startDocBlank" $+ targetStartDocBlank @=? run sourceStartDocBlank++------------------------------------------------------------------------------++sourceStartCodeBlank :: Text+sourceStartCodeBlank = TL.unlines+ [ ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , ""+ , "-- Test"+ ]++targetStartCodeBlank :: Text+targetStartCodeBlank = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"2\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testStartCodeBlank :: TestTree+testStartCodeBlank = testCase "startCodeBlank" $+ targetStartCodeBlank @=? run sourceStartCodeBlank++------------------------------------------------------------------------------++sourceStartRuleDoc :: Text+sourceStartRuleDoc = TL.unlines+ [ "----------------------------------------------------------------------"+ , "-- Test"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetStartRuleDoc :: Text+targetStartRuleDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"4\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testStartRuleDoc :: TestTree+testStartRuleDoc = testCase "startRuleDoc" $+ targetStartRuleDoc @=? run sourceStartRuleDoc++------------------------------------------------------------------------------++sourceStartRuleCode :: Text+sourceStartRuleCode = TL.unlines+ [ "----------------------------------------------------------------------"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , ""+ , "-- Test"+ ]++targetStartRuleCode :: Text+targetStartRuleCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"3\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testStartRuleCode :: TestTree+testStartRuleCode = testCase "startRuleCode" $+ targetStartRuleCode @=? run sourceStartRuleCode++------------------------------------------------------------------------------++sourceCodeDoc :: Text+sourceCodeDoc = TL.unlines+ [ "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "-- Test"+ ]++targetCodeDoc :: Text+targetCodeDoc = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testCodeDoc :: TestTree+testCodeDoc = testCase "codeDoc" $+ targetCodeDoc @=? run sourceCodeDoc++------------------------------------------------------------------------------++sourceCodeCodeBlanksCode :: Text+sourceCodeCodeBlanksCode = TL.unlines+ [ "module Main (main) where"+ , ""+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetCodeCodeBlanksCode :: Text+targetCodeCodeBlanksCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testCodeCodeBlanksCode :: TestTree+testCodeCodeBlanksCode = testCase "codeCodeBlanksCode" $+ targetCodeCodeBlanksCode @=? run sourceCodeCodeBlanksCode++------------------------------------------------------------------------------++sourceCodeCodeBlanksDoc :: Text+sourceCodeCodeBlanksDoc = TL.unlines+ [ "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , ""+ , ""+ , "-- Test"+ ]++targetCodeCodeBlanksDoc :: Text+targetCodeCodeBlanksDoc = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testCodeCodeBlanksDoc :: TestTree+testCodeCodeBlanksDoc = testCase "codeCodeBlanksDoc" $+ targetCodeCodeBlanksDoc @=? run sourceCodeCodeBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksDoc :: Text+sourceCodeDocBlanksDoc = TL.unlines+ [ "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "--"+ , "--"+ , "-- Test"+ ]++targetCodeDocBlanksDoc :: Text+targetCodeDocBlanksDoc = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testCodeDocBlanksDoc :: TestTree+testCodeDocBlanksDoc = testCase "codeDocBlanksDoc" $+ targetCodeDocBlanksDoc @=? run sourceCodeDocBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksCode :: Text+sourceCodeDocBlanksCode = TL.unlines+ [ "module Main (main) where"+ , "--"+ , "--"+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetCodeDocBlanksCode :: Text+targetCodeDocBlanksCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , "```"+ , ""+ , "``` {.haskell .numberSource startFrom=\"4\"}"+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testCodeDocBlanksCode :: TestTree+testCodeDocBlanksCode = testCase "codeDocBlanksCode" $+ targetCodeDocBlanksCode @=? run sourceCodeDocBlanksCode++------------------------------------------------------------------------------++sourceCodeRuleCode :: Text+sourceCodeRuleCode = TL.unlines+ [ "module Main (main) where"+ , "----------------------------------------------------------------------"+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetCodeRuleCode :: Text+targetCodeRuleCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , "```"+ , ""+ , "``` {.haskell .numberSource startFrom=\"3\"}"+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testCodeRuleCode :: TestTree+testCodeRuleCode = testCase "codeRuleCode" $+ targetCodeRuleCode @=? run sourceCodeRuleCode++------------------------------------------------------------------------------++sourceCodeRuleDoc :: Text+sourceCodeRuleDoc = TL.unlines+ [ "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "----------------------------------------------------------------------"+ , "-- Test"+ ]++targetCodeRuleDoc :: Text+targetCodeRuleDoc = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testCodeRuleDoc :: TestTree+testCodeRuleDoc = testCase "codeRuleDoc" $+ targetCodeRuleDoc @=? run sourceCodeRuleDoc++------------------------------------------------------------------------------++sourceDocCode :: Text+sourceDocCode = TL.unlines+ [ "-- Test"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetDocCode :: Text+targetDocCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"2\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testDocCode :: TestTree+testDocCode = testCase "docCode" $+ targetDocCode @=? run sourceDocCode++------------------------------------------------------------------------------++sourceDocDocBlanksDoc :: Text+sourceDocDocBlanksDoc = TL.unlines+ [ "-- one"+ , "--"+ , "--"+ , "-- two"+ ]++targetDocDocBlanksDoc :: Text+targetDocDocBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocDocBlanksDoc :: TestTree+testDocDocBlanksDoc = testCase "docDocBlanksDoc" $+ targetDocDocBlanksDoc @=? run sourceDocDocBlanksDoc++------------------------------------------------------------------------------++sourceDocDocBlanksCode :: Text+sourceDocDocBlanksCode = TL.unlines+ [ "-- Test"+ , "--"+ , "--"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetDocDocBlanksCode :: Text+targetDocDocBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"4\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testDocDocBlanksCode :: TestTree+testDocDocBlanksCode = testCase "docDocBlanksCode" $+ targetDocDocBlanksCode @=? run sourceDocDocBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksCode :: Text+sourceDocCodeBlanksCode = TL.unlines+ [ "-- Test"+ , ""+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetDocCodeBlanksCode :: Text+targetDocCodeBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"4\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testDocCodeBlanksCode :: TestTree+testDocCodeBlanksCode = testCase "docCodeBlanksCode" $+ targetDocCodeBlanksCode @=? run sourceDocCodeBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksDoc :: Text+sourceDocCodeBlanksDoc = TL.unlines+ [ "-- one"+ , ""+ , ""+ , "-- two"+ ]++targetDocCodeBlanksDoc :: Text+targetDocCodeBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocCodeBlanksDoc :: TestTree+testDocCodeBlanksDoc = testCase "docCodeBlanksDoc" $+ targetDocCodeBlanksDoc @=? run sourceDocCodeBlanksDoc++------------------------------------------------------------------------------++sourceDocRuleDoc :: Text+sourceDocRuleDoc = TL.unlines+ [ "-- one"+ , "----------------------------------------------------------------------"+ , "-- two"+ ]++targetDocRuleDoc :: Text+targetDocRuleDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocRuleDoc :: TestTree+testDocRuleDoc = testCase "docRuleDoc" $+ targetDocRuleDoc @=? run sourceDocRuleDoc++------------------------------------------------------------------------------++sourceDocRuleCode :: Text+sourceDocRuleCode = TL.unlines+ [ "-- Test"+ , "----------------------------------------------------------------------"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetDocRuleCode :: Text+targetDocRuleCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"3\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testDocRuleCode :: TestTree+testDocRuleCode = testCase "docRuleCode" $+ targetDocRuleCode @=? run sourceDocRuleCode++------------------------------------------------------------------------------++sourceEndDoc :: Text+sourceEndDoc = TL.unlines+ [ "-- Test"+ ]++targetEndDoc :: Text+targetEndDoc = TL.unlines+ [ "Test"+ ]++testEndDoc :: TestTree+testEndDoc = testCase "endDoc" $+ targetEndDoc @=? run sourceEndDoc++------------------------------------------------------------------------------++sourceEndDocBlanks :: Text+sourceEndDocBlanks = TL.unlines+ [ "--"+ , "--"+ ]++targetEndDocBlanks :: Text+targetEndDocBlanks = ""++testEndDocBlanks :: TestTree+testEndDocBlanks = testCase "endDocBlanks" $+ targetEndDocBlanks @=? run sourceEndDocBlanks++------------------------------------------------------------------------------++sourceEndCode :: Text+sourceEndCode = TL.unlines+ [ "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ ]++targetEndCode :: Text+targetEndCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testEndCode :: TestTree+testEndCode = testCase "endCode" $+ targetEndCode @=? run sourceEndCode++------------------------------------------------------------------------------++sourceEndCodeBlanks :: Text+sourceEndCodeBlanks = TL.unlines+ [ "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , ""+ , ""+ ]++targetEndCodeBlanks :: Text+targetEndCodeBlanks = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testEndCodeBlanks :: TestTree+testEndCodeBlanks = testCase "endCodeBlanks" $+ targetEndCodeBlanks @=? run sourceEndCodeBlanks++------------------------------------------------------------------------------++sourceEmpty :: Text+sourceEmpty = ""++sourceOnlyRule :: Text+sourceOnlyRule = "-----------------------------------------------------------"++sourceOnlyDocBlanks :: Text+sourceOnlyDocBlanks = TL.unlines+ [ "--"+ , "--"+ ]++sourceOnlyCodeBlanks :: Text+sourceOnlyCodeBlanks = TL.unlines+ [ ""+ , ""+ ]++targetEmpty :: Text+targetEmpty = ""++testEmpty :: TestTree+testEmpty = testCase "empty" $+ targetEmpty @=? run sourceEmpty++testOnlyRule :: TestTree+testOnlyRule = testCase "onlyRule" $+ targetEmpty @=? run sourceOnlyRule++testOnlyDocBlanks :: TestTree+testOnlyDocBlanks = testCase "onlyDocBlanks" $+ targetEmpty @=? run sourceOnlyDocBlanks++testOnlyCodeBlanks :: TestTree+testOnlyCodeBlanks = testCase "onlyCodeBlanks" $+ targetEmpty @=? run sourceOnlyCodeBlanks++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "DoubleDash"+ [ testStartShebangDoc+ , testStartShebangCode+ , testStartDoc+ , testStartCode+ , testStartDocBlank+ , testStartCodeBlank+ , testStartRuleDoc+ , testStartRuleCode+ , testCodeDoc+ , testCodeCodeBlanksCode+ , testCodeCodeBlanksDoc+ , testCodeDocBlanksDoc+ , testCodeDocBlanksCode+ , testCodeRuleCode+ , testCodeRuleDoc+ , testDocCode+ , testDocDocBlanksDoc+ , testDocDocBlanksCode+ , testDocCodeBlanksCode+ , testDocCodeBlanksDoc+ , testDocRuleDoc+ , testDocRuleCode+ , testEndDoc+ , testEndDocBlanks+ , testEndCode+ , testEndCodeBlanks+ , testEmpty+ , testOnlyRule+ , testOnlyDocBlanks+ , testOnlyCodeBlanks+ ]
+ test/LiterateX/Test/SourceFormat/DoubleSlash.hs view
@@ -0,0 +1,827 @@+{-# LANGUAGE OverloadedStrings #-}++module LiterateX.Test.SourceFormat.DoubleSlash (tests) where++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy (Text)++-- (literatex)+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.TargetFormat as TargetFormat++------------------------------------------------------------------------------++rendererOpts :: Renderer.Options+rendererOpts = Renderer.Options+ { Renderer.targetFormat = TargetFormat.PandocMarkdown+ , Renderer.codeLanguage = Just "rust"+ , Renderer.ignoreShebang = True+ , Renderer.renderCode = True+ , Renderer.numberCodeLines = True+ }++run' :: Text -> Renderer.Options -> Text+run' = flip $ LiterateX.transformTextToText SourceFormat.DoubleSlash++run :: Text -> Text+run source = run' source rendererOpts++------------------------------------------------------------------------------++sourceStartShebangDoc :: Text+sourceStartShebangDoc = TL.unlines+ [ "#!/usr/bin/env run-cargo-script"+ , ""+ , "// Test"+ , ""+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ ]++targetStartShebangDocIgnore :: Text+targetStartShebangDocIgnore = TL.unlines+ [ "Test"+ , ""+ , "``` {.rust .numberSource startFrom=\"5\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++targetStartShebangDocNoIgnore :: Text+targetStartShebangDocNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env run-cargo-script"+ , "```"+ , ""+ , "Test"+ , ""+ , "``` {.rust .numberSource startFrom=\"5\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++targetStartShebangDocNoCode :: Text+targetStartShebangDocNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangDoc :: TestTree+testStartShebangDoc = testGroup "startShebangDoc"+ [ testCase "Ignore" $+ targetStartShebangDocIgnore @=? run sourceStartShebangDoc+ , testCase "NoIgnore" $+ targetStartShebangDocNoIgnore @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangDocNoCode @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartShebangCode :: Text+sourceStartShebangCode = TL.unlines+ [ "#!/usr/bin/env run-cargo-script"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , ""+ , "// Test"+ ]++targetStartShebangCodeIgnore :: Text+targetStartShebangCodeIgnore = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"2\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoIgnore :: Text+targetStartShebangCodeNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env run-cargo-script"+ , "```"+ , ""+ , "``` {.rust .numberSource startFrom=\"2\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoCode :: Text+targetStartShebangCodeNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangCode :: TestTree+testStartShebangCode = testGroup "startShebangCode"+ [ testCase "Ignore" $+ targetStartShebangCodeIgnore @=? run sourceStartShebangCode+ , testCase "NoIgnore" $+ targetStartShebangCodeNoIgnore @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangCodeNoCode @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartDoc :: Text+sourceStartDoc = TL.unlines+ [ "// Test"+ , ""+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ ]++targetStartDoc :: Text+targetStartDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.rust .numberSource startFrom=\"3\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++testStartDoc :: TestTree+testStartDoc = testCase "startDoc" $+ targetStartDoc @=? run sourceStartDoc++------------------------------------------------------------------------------++sourceStartCode :: Text+sourceStartCode = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , ""+ , "// Test"+ ]++targetStartCode :: Text+targetStartCode = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ , ""+ , "Test"+ ]++testStartCode :: TestTree+testStartCode = testCase "startCode" $+ targetStartCode @=? run sourceStartCode++------------------------------------------------------------------------------++sourceStartDocBlank :: Text+sourceStartDocBlank = TL.unlines+ [ "//"+ , "// Test"+ , ""+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ ]++targetStartDocBlank :: Text+targetStartDocBlank = TL.unlines+ [ "Test"+ , ""+ , "``` {.rust .numberSource startFrom=\"4\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++testStartDocBlank :: TestTree+testStartDocBlank = testCase "startDocBlank" $+ targetStartDocBlank @=? run sourceStartDocBlank++------------------------------------------------------------------------------++sourceStartCodeBlank :: Text+sourceStartCodeBlank = TL.unlines+ [ ""+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , ""+ , "// Test"+ ]++targetStartCodeBlank :: Text+targetStartCodeBlank = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"2\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ , ""+ , "Test"+ ]++testStartCodeBlank :: TestTree+testStartCodeBlank = testCase "startCodeBlank" $+ targetStartCodeBlank @=? run sourceStartCodeBlank++------------------------------------------------------------------------------++sourceStartRuleDoc :: Text+sourceStartRuleDoc = TL.unlines+ [ "//////////////////////////////////////////////////////////////////////"+ , "// Test"+ , ""+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ ]++targetStartRuleDoc :: Text+targetStartRuleDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.rust .numberSource startFrom=\"4\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++testStartRuleDoc :: TestTree+testStartRuleDoc = testCase "startRuleDoc" $+ targetStartRuleDoc @=? run sourceStartRuleDoc++------------------------------------------------------------------------------++sourceStartRuleCode :: Text+sourceStartRuleCode = TL.unlines+ [ "//////////////////////////////////////////////////////////////////////"+ , ""+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , ""+ , "// Test"+ ]++targetStartRuleCode :: Text+targetStartRuleCode = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"3\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ , ""+ , "Test"+ ]++testStartRuleCode :: TestTree+testStartRuleCode = testCase "startRuleCode" $+ targetStartRuleCode @=? run sourceStartRuleCode++------------------------------------------------------------------------------++sourceCodeDoc :: Text+sourceCodeDoc = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "// Test"+ ]++targetCodeDoc :: Text+targetCodeDoc = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ , ""+ , "Test"+ ]++testCodeDoc :: TestTree+testCodeDoc = testCase "codeDoc" $+ targetCodeDoc @=? run sourceCodeDoc++------------------------------------------------------------------------------++sourceCodeCodeBlanksCode :: Text+sourceCodeCodeBlanksCode = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello...\");"+ , ""+ , ""+ , " println!(\"world!\");"+ , "}"+ ]++targetCodeCodeBlanksCode :: Text+targetCodeCodeBlanksCode = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello...\");"+ , ""+ , ""+ , " println!(\"world!\");"+ , "}"+ , "```"+ ]++testCodeCodeBlanksCode :: TestTree+testCodeCodeBlanksCode = testCase "codeCodeBlanksCode" $+ targetCodeCodeBlanksCode @=? run sourceCodeCodeBlanksCode++------------------------------------------------------------------------------++sourceCodeCodeBlanksDoc :: Text+sourceCodeCodeBlanksDoc = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , ""+ , ""+ , "// Test"+ ]++targetCodeCodeBlanksDoc :: Text+targetCodeCodeBlanksDoc = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ , ""+ , "Test"+ ]++testCodeCodeBlanksDoc :: TestTree+testCodeCodeBlanksDoc = testCase "codeCodeBlanksDoc" $+ targetCodeCodeBlanksDoc @=? run sourceCodeCodeBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksDoc :: Text+sourceCodeDocBlanksDoc = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "//"+ , "//"+ , "// Test"+ ]++targetCodeDocBlanksDoc :: Text+targetCodeDocBlanksDoc = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ , ""+ , "Test"+ ]++testCodeDocBlanksDoc :: TestTree+testCodeDocBlanksDoc = testCase "codeDocBlanksDoc" $+ targetCodeDocBlanksDoc @=? run sourceCodeDocBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksCode :: Text+sourceCodeDocBlanksCode = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello...\");"+ , "//"+ , "//"+ , " println!(\"world!\");"+ , "}"+ ]++targetCodeDocBlanksCode :: Text+targetCodeDocBlanksCode = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello...\");"+ , "```"+ , ""+ , "``` {.rust .numberSource startFrom=\"5\"}"+ , " println!(\"world!\");"+ , "}"+ , "```"+ ]++testCodeDocBlanksCode :: TestTree+testCodeDocBlanksCode = testCase "codeDocBlanksCode" $+ targetCodeDocBlanksCode @=? run sourceCodeDocBlanksCode++------------------------------------------------------------------------------++sourceCodeRuleCode :: Text+sourceCodeRuleCode = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello...\");"+ , "//////////////////////////////////////////////////////////////////////"+ , " println!(\"world!\");"+ , "}"+ ]++targetCodeRuleCode :: Text+targetCodeRuleCode = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello...\");"+ , "```"+ , ""+ , "``` {.rust .numberSource startFrom=\"4\"}"+ , " println!(\"world!\");"+ , "}"+ , "```"+ ]++testCodeRuleCode :: TestTree+testCodeRuleCode = testCase "codeRuleCode" $+ targetCodeRuleCode @=? run sourceCodeRuleCode++------------------------------------------------------------------------------++sourceCodeRuleDoc :: Text+sourceCodeRuleDoc = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "//////////////////////////////////////////////////////////////////////"+ , "// Test"+ ]++targetCodeRuleDoc :: Text+targetCodeRuleDoc = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ , ""+ , "Test"+ ]++testCodeRuleDoc :: TestTree+testCodeRuleDoc = testCase "codeRuleDoc" $+ targetCodeRuleDoc @=? run sourceCodeRuleDoc++------------------------------------------------------------------------------++sourceDocCode :: Text+sourceDocCode = TL.unlines+ [ "// Test"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ ]++targetDocCode :: Text+targetDocCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.rust .numberSource startFrom=\"2\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++testDocCode :: TestTree+testDocCode = testCase "docCode" $+ targetDocCode @=? run sourceDocCode++------------------------------------------------------------------------------++sourceDocDocBlanksDoc :: Text+sourceDocDocBlanksDoc = TL.unlines+ [ "// one"+ , "//"+ , "//"+ , "// two"+ ]++targetDocDocBlanksDoc :: Text+targetDocDocBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocDocBlanksDoc :: TestTree+testDocDocBlanksDoc = testCase "docDocBlanksDoc" $+ targetDocDocBlanksDoc @=? run sourceDocDocBlanksDoc++------------------------------------------------------------------------------++sourceDocDocBlanksCode :: Text+sourceDocDocBlanksCode = TL.unlines+ [ "// Test"+ , "//"+ , "//"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ ]++targetDocDocBlanksCode :: Text+targetDocDocBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.rust .numberSource startFrom=\"4\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++testDocDocBlanksCode :: TestTree+testDocDocBlanksCode = testCase "docDocBlanksCode" $+ targetDocDocBlanksCode @=? run sourceDocDocBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksCode :: Text+sourceDocCodeBlanksCode = TL.unlines+ [ "// Test"+ , ""+ , ""+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ ]++targetDocCodeBlanksCode :: Text+targetDocCodeBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.rust .numberSource startFrom=\"4\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++testDocCodeBlanksCode :: TestTree+testDocCodeBlanksCode = testCase "docCodeBlanksCode" $+ targetDocCodeBlanksCode @=? run sourceDocCodeBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksDoc :: Text+sourceDocCodeBlanksDoc = TL.unlines+ [ "// one"+ , ""+ , ""+ , "// two"+ ]++targetDocCodeBlanksDoc :: Text+targetDocCodeBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocCodeBlanksDoc :: TestTree+testDocCodeBlanksDoc = testCase "docCodeBlanksDoc" $+ targetDocCodeBlanksDoc @=? run sourceDocCodeBlanksDoc++------------------------------------------------------------------------------++sourceDocRuleDoc :: Text+sourceDocRuleDoc = TL.unlines+ [ "// one"+ , "//////////////////////////////////////////////////////////////////////"+ , "// two"+ ]++targetDocRuleDoc :: Text+targetDocRuleDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocRuleDoc :: TestTree+testDocRuleDoc = testCase "docRuleDoc" $+ targetDocRuleDoc @=? run sourceDocRuleDoc++------------------------------------------------------------------------------++sourceDocRuleCode :: Text+sourceDocRuleCode = TL.unlines+ [ "// Test"+ , "//////////////////////////////////////////////////////////////////////"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ ]++targetDocRuleCode :: Text+targetDocRuleCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.rust .numberSource startFrom=\"3\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++testDocRuleCode :: TestTree+testDocRuleCode = testCase "docRuleCode" $+ targetDocRuleCode @=? run sourceDocRuleCode++------------------------------------------------------------------------------++sourceEndDoc :: Text+sourceEndDoc = TL.unlines+ [ "// Test"+ ]++targetEndDoc :: Text+targetEndDoc = TL.unlines+ [ "Test"+ ]++testEndDoc :: TestTree+testEndDoc = testCase "endDoc" $+ targetEndDoc @=? run sourceEndDoc++------------------------------------------------------------------------------++sourceEndDocBlanks :: Text+sourceEndDocBlanks = TL.unlines+ [ "//"+ , "//"+ ]++targetEndDocBlanks :: Text+targetEndDocBlanks = ""++testEndDocBlanks :: TestTree+testEndDocBlanks = testCase "endDocBlanks" $+ targetEndDocBlanks @=? run sourceEndDocBlanks++------------------------------------------------------------------------------++sourceEndCode :: Text+sourceEndCode = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ ]++targetEndCode :: Text+targetEndCode = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++testEndCode :: TestTree+testEndCode = testCase "endCode" $+ targetEndCode @=? run sourceEndCode++------------------------------------------------------------------------------++sourceEndCodeBlanks :: Text+sourceEndCodeBlanks = TL.unlines+ [ "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , ""+ , ""+ ]++targetEndCodeBlanks :: Text+targetEndCodeBlanks = TL.unlines+ [ "``` {.rust .numberSource startFrom=\"1\"}"+ , "fn main() {"+ , " println!(\"Hello!\");"+ , "}"+ , "```"+ ]++testEndCodeBlanks :: TestTree+testEndCodeBlanks = testCase "endCodeBlanks" $+ targetEndCodeBlanks @=? run sourceEndCodeBlanks++------------------------------------------------------------------------------++sourceEmpty :: Text+sourceEmpty = ""++sourceOnlyRule :: Text+sourceOnlyRule = "///////////////////////////////////////////////////////////"++sourceOnlyDocBlanks :: Text+sourceOnlyDocBlanks = TL.unlines+ [ "//"+ , "//"+ ]++sourceOnlyCodeBlanks :: Text+sourceOnlyCodeBlanks = TL.unlines+ [ ""+ , ""+ ]++targetEmpty :: Text+targetEmpty = ""++testEmpty :: TestTree+testEmpty = testCase "empty" $+ targetEmpty @=? run sourceEmpty++testOnlyRule :: TestTree+testOnlyRule = testCase "onlyRule" $+ targetEmpty @=? run sourceOnlyRule++testOnlyDocBlanks :: TestTree+testOnlyDocBlanks = testCase "onlyDocBlanks" $+ targetEmpty @=? run sourceOnlyDocBlanks++testOnlyCodeBlanks :: TestTree+testOnlyCodeBlanks = testCase "onlyCodeBlanks" $+ targetEmpty @=? run sourceOnlyCodeBlanks++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "DoubleSlash"+ [ testStartShebangDoc+ , testStartShebangCode+ , testStartDoc+ , testStartCode+ , testStartDocBlank+ , testStartCodeBlank+ , testStartRuleDoc+ , testStartRuleCode+ , testCodeDoc+ , testCodeCodeBlanksCode+ , testCodeCodeBlanksDoc+ , testCodeDocBlanksDoc+ , testCodeDocBlanksCode+ , testCodeRuleCode+ , testCodeRuleDoc+ , testDocCode+ , testDocDocBlanksDoc+ , testDocDocBlanksCode+ , testDocCodeBlanksCode+ , testDocCodeBlanksDoc+ , testDocRuleDoc+ , testDocRuleCode+ , testEndDoc+ , testEndDocBlanks+ , testEndCode+ , testEndCodeBlanks+ , testEmpty+ , testOnlyRule+ , testOnlyDocBlanks+ , testOnlyCodeBlanks+ ]
+ test/LiterateX/Test/SourceFormat/Hash.hs view
@@ -0,0 +1,740 @@+{-# LANGUAGE OverloadedStrings #-}++module LiterateX.Test.SourceFormat.Hash (tests) where++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy (Text)++-- (literatex)+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.TargetFormat as TargetFormat++------------------------------------------------------------------------------++rendererOpts :: Renderer.Options+rendererOpts = Renderer.Options+ { Renderer.targetFormat = TargetFormat.PandocMarkdown+ , Renderer.codeLanguage = Just "python"+ , Renderer.ignoreShebang = True+ , Renderer.renderCode = True+ , Renderer.numberCodeLines = True+ }++run' :: Text -> Renderer.Options -> Text+run' = flip $ LiterateX.transformTextToText SourceFormat.Hash++run :: Text -> Text+run source = run' source rendererOpts++------------------------------------------------------------------------------++sourceStartShebangDoc :: Text+sourceStartShebangDoc = TL.unlines+ [ "#!/usr/bin/env python"+ , ""+ , "# Test"+ , ""+ , "print('Hello!')"+ ]++targetStartShebangDocIgnore :: Text+targetStartShebangDocIgnore = TL.unlines+ [ "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"5\"}"+ , "print('Hello!')"+ , "```"+ ]++targetStartShebangDocNoIgnore :: Text+targetStartShebangDocNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env python"+ , "```"+ , ""+ , "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"5\"}"+ , "print('Hello!')"+ , "```"+ ]++targetStartShebangDocNoCode :: Text+targetStartShebangDocNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangDoc :: TestTree+testStartShebangDoc = testGroup "startShebangDoc"+ [ testCase "Ignore" $+ targetStartShebangDocIgnore @=? run sourceStartShebangDoc+ , testCase "NoIgnore" $+ targetStartShebangDocNoIgnore @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangDocNoCode @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartShebangCode :: Text+sourceStartShebangCode = TL.unlines+ [ "#!/usr/bin/env python"+ , ""+ , "print('Hello!')"+ , ""+ , "# Test"+ ]++targetStartShebangCodeIgnore :: Text+targetStartShebangCodeIgnore = TL.unlines+ [ "``` {.python .numberSource startFrom=\"3\"}"+ , "print('Hello!')"+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoIgnore :: Text+targetStartShebangCodeNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env python"+ , "```"+ , ""+ , "``` {.python .numberSource startFrom=\"3\"}"+ , "print('Hello!')"+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoCode :: Text+targetStartShebangCodeNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangCode :: TestTree+testStartShebangCode = testGroup "startShebangCode"+ [ testCase "Ignore" $+ targetStartShebangCodeIgnore @=? run sourceStartShebangCode+ , testCase "NoIgnore" $+ targetStartShebangCodeNoIgnore @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangCodeNoCode @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartDoc :: Text+sourceStartDoc = TL.unlines+ [ "# Test"+ , ""+ , "print('Hello!')"+ ]++targetStartDoc :: Text+targetStartDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"3\"}"+ , "print('Hello!')"+ , "```"+ ]++testStartDoc :: TestTree+testStartDoc = testCase "startDoc" $+ targetStartDoc @=? run sourceStartDoc++------------------------------------------------------------------------------++sourceStartCode :: Text+sourceStartCode = TL.unlines+ [ "print('Hello!')"+ , ""+ , "# Test"+ ]++targetStartCode :: Text+targetStartCode = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('Hello!')"+ , "```"+ , ""+ , "Test"+ ]++testStartCode :: TestTree+testStartCode = testCase "startCode" $+ targetStartCode @=? run sourceStartCode++------------------------------------------------------------------------------++sourceStartDocBlank :: Text+sourceStartDocBlank = TL.unlines+ [ "#"+ , "# Test"+ , ""+ , "print('Hello!')"+ ]++targetStartDocBlank :: Text+targetStartDocBlank = TL.unlines+ [ "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"4\"}"+ , "print('Hello!')"+ , "```"+ ]++testStartDocBlank :: TestTree+testStartDocBlank = testCase "startDocBlank" $+ targetStartDocBlank @=? run sourceStartDocBlank++------------------------------------------------------------------------------++sourceStartCodeBlank :: Text+sourceStartCodeBlank = TL.unlines+ [ ""+ , "print('Hello!')"+ , ""+ , "# Test"+ ]++targetStartCodeBlank :: Text+targetStartCodeBlank = TL.unlines+ [ "``` {.python .numberSource startFrom=\"2\"}"+ , "print('Hello!')"+ , "```"+ , ""+ , "Test"+ ]++testStartCodeBlank :: TestTree+testStartCodeBlank = testCase "startCodeBlank" $+ targetStartCodeBlank @=? run sourceStartCodeBlank++------------------------------------------------------------------------------++sourceStartRuleDoc :: Text+sourceStartRuleDoc = TL.unlines+ [ "######################################################################"+ , "# Test"+ , ""+ , "print('Hello!')"+ ]++targetStartRuleDoc :: Text+targetStartRuleDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"4\"}"+ , "print('Hello!')"+ , "```"+ ]++testStartRuleDoc :: TestTree+testStartRuleDoc = testCase "startRuleDoc" $+ targetStartRuleDoc @=? run sourceStartRuleDoc++------------------------------------------------------------------------------++sourceStartRuleCode :: Text+sourceStartRuleCode = TL.unlines+ [ "######################################################################"+ , ""+ , "print('Hello!')"+ , ""+ , "# Test"+ ]++targetStartRuleCode :: Text+targetStartRuleCode = TL.unlines+ [ "``` {.python .numberSource startFrom=\"3\"}"+ , "print('Hello!')"+ , "```"+ , ""+ , "Test"+ ]++testStartRuleCode :: TestTree+testStartRuleCode = testCase "startRuleCode" $+ targetStartRuleCode @=? run sourceStartRuleCode++------------------------------------------------------------------------------++sourceCodeDoc :: Text+sourceCodeDoc = TL.unlines+ [ "print('one')"+ , "# Test"+ ]++targetCodeDoc :: Text+targetCodeDoc = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('one')"+ , "```"+ , ""+ , "Test"+ ]++testCodeDoc :: TestTree+testCodeDoc = testCase "codeDoc" $+ targetCodeDoc @=? run sourceCodeDoc++------------------------------------------------------------------------------++sourceCodeCodeBlanksCode :: Text+sourceCodeCodeBlanksCode = TL.unlines+ [ "print('one')"+ , ""+ , ""+ , "print('two')"+ ]++targetCodeCodeBlanksCode :: Text+targetCodeCodeBlanksCode = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('one')"+ , ""+ , ""+ , "print('two')"+ , "```"+ ]++testCodeCodeBlanksCode :: TestTree+testCodeCodeBlanksCode = testCase "codeCodeBlanksCode" $+ targetCodeCodeBlanksCode @=? run sourceCodeCodeBlanksCode++------------------------------------------------------------------------------++sourceCodeCodeBlanksDoc :: Text+sourceCodeCodeBlanksDoc = TL.unlines+ [ "print('one')"+ , ""+ , ""+ , "# Test"+ ]++targetCodeCodeBlanksDoc :: Text+targetCodeCodeBlanksDoc = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('one')"+ , "```"+ , ""+ , "Test"+ ]++testCodeCodeBlanksDoc :: TestTree+testCodeCodeBlanksDoc = testCase "codeCodeBlanksDoc" $+ targetCodeCodeBlanksDoc @=? run sourceCodeCodeBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksDoc :: Text+sourceCodeDocBlanksDoc = TL.unlines+ [ "print('one')"+ , "#"+ , "#"+ , "# Test"+ ]++targetCodeDocBlanksDoc :: Text+targetCodeDocBlanksDoc = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('one')"+ , "```"+ , ""+ , "Test"+ ]++testCodeDocBlanksDoc :: TestTree+testCodeDocBlanksDoc = testCase "codeDocBlanksDoc" $+ targetCodeDocBlanksDoc @=? run sourceCodeDocBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksCode :: Text+sourceCodeDocBlanksCode = TL.unlines+ [ "print('one')"+ , "#"+ , "#"+ , "print('two')"+ ]++targetCodeDocBlanksCode :: Text+targetCodeDocBlanksCode = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('one')"+ , "```"+ , ""+ , "``` {.python .numberSource startFrom=\"4\"}"+ , "print('two')"+ , "```"+ ]++testCodeDocBlanksCode :: TestTree+testCodeDocBlanksCode = testCase "codeDocBlanksCode" $+ targetCodeDocBlanksCode @=? run sourceCodeDocBlanksCode++------------------------------------------------------------------------------++sourceCodeRuleCode :: Text+sourceCodeRuleCode = TL.unlines+ [ "print('one')"+ , "######################################################################"+ , "print('two')"+ ]++targetCodeRuleCode :: Text+targetCodeRuleCode = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('one')"+ , "```"+ , ""+ , "``` {.python .numberSource startFrom=\"3\"}"+ , "print('two')"+ , "```"+ ]++testCodeRuleCode :: TestTree+testCodeRuleCode = testCase "codeRuleCode" $+ targetCodeRuleCode @=? run sourceCodeRuleCode++------------------------------------------------------------------------------++sourceCodeRuleDoc :: Text+sourceCodeRuleDoc = TL.unlines+ [ "print('one')"+ , "######################################################################"+ , "# Test"+ ]++targetCodeRuleDoc :: Text+targetCodeRuleDoc = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('one')"+ , "```"+ , ""+ , "Test"+ ]++testCodeRuleDoc :: TestTree+testCodeRuleDoc = testCase "codeRuleDoc" $+ targetCodeRuleDoc @=? run sourceCodeRuleDoc++------------------------------------------------------------------------------++sourceDocCode :: Text+sourceDocCode = TL.unlines+ [ "# Test"+ , "print('one')"+ ]++targetDocCode :: Text+targetDocCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"2\"}"+ , "print('one')"+ , "```"+ ]++testDocCode :: TestTree+testDocCode = testCase "docCode" $+ targetDocCode @=? run sourceDocCode++------------------------------------------------------------------------------++sourceDocDocBlanksDoc :: Text+sourceDocDocBlanksDoc = TL.unlines+ [ "# one"+ , "#"+ , "#"+ , "# two"+ ]++targetDocDocBlanksDoc :: Text+targetDocDocBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocDocBlanksDoc :: TestTree+testDocDocBlanksDoc = testCase "docDocBlanksDoc" $+ targetDocDocBlanksDoc @=? run sourceDocDocBlanksDoc++------------------------------------------------------------------------------++sourceDocDocBlanksCode :: Text+sourceDocDocBlanksCode = TL.unlines+ [ "# Test"+ , "#"+ , "#"+ , "print('Hello!')"+ ]++targetDocDocBlanksCode :: Text+targetDocDocBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"4\"}"+ , "print('Hello!')"+ , "```"+ ]++testDocDocBlanksCode :: TestTree+testDocDocBlanksCode = testCase "docDocBlanksCode" $+ targetDocDocBlanksCode @=? run sourceDocDocBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksCode :: Text+sourceDocCodeBlanksCode = TL.unlines+ [ "# Test"+ , ""+ , ""+ , "print('Hello!')"+ ]++targetDocCodeBlanksCode :: Text+targetDocCodeBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"4\"}"+ , "print('Hello!')"+ , "```"+ ]++testDocCodeBlanksCode :: TestTree+testDocCodeBlanksCode = testCase "docCodeBlanksCode" $+ targetDocCodeBlanksCode @=? run sourceDocCodeBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksDoc :: Text+sourceDocCodeBlanksDoc = TL.unlines+ [ "# one"+ , ""+ , ""+ , "# two"+ ]++targetDocCodeBlanksDoc :: Text+targetDocCodeBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocCodeBlanksDoc :: TestTree+testDocCodeBlanksDoc = testCase "docCodeBlanksDoc" $+ targetDocCodeBlanksDoc @=? run sourceDocCodeBlanksDoc++------------------------------------------------------------------------------++sourceDocRuleDoc :: Text+sourceDocRuleDoc = TL.unlines+ [ "# one"+ , "######################################################################"+ , "# two"+ ]++targetDocRuleDoc :: Text+targetDocRuleDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocRuleDoc :: TestTree+testDocRuleDoc = testCase "docRuleDoc" $+ targetDocRuleDoc @=? run sourceDocRuleDoc++------------------------------------------------------------------------------++sourceDocRuleCode :: Text+sourceDocRuleCode = TL.unlines+ [ "# Test"+ , "######################################################################"+ , "print('Hello!')"+ ]++targetDocRuleCode :: Text+targetDocRuleCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"3\"}"+ , "print('Hello!')"+ , "```"+ ]++testDocRuleCode :: TestTree+testDocRuleCode = testCase "docRuleCode" $+ targetDocRuleCode @=? run sourceDocRuleCode++------------------------------------------------------------------------------++sourceEndDoc :: Text+sourceEndDoc = TL.unlines+ [ "# Test"+ ]++targetEndDoc :: Text+targetEndDoc = TL.unlines+ [ "Test"+ ]++testEndDoc :: TestTree+testEndDoc = testCase "endDoc" $+ targetEndDoc @=? run sourceEndDoc++------------------------------------------------------------------------------++sourceEndDocBlanks :: Text+sourceEndDocBlanks = TL.unlines+ [ "#"+ , "#"+ ]++targetEndDocBlanks :: Text+targetEndDocBlanks = ""++testEndDocBlanks :: TestTree+testEndDocBlanks = testCase "endDocBlanks" $+ targetEndDocBlanks @=? run sourceEndDocBlanks++------------------------------------------------------------------------------++sourceEndCode :: Text+sourceEndCode = TL.unlines+ [ "print('Hello!')"+ ]++targetEndCode :: Text+targetEndCode = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('Hello!')"+ , "```"+ ]++testEndCode :: TestTree+testEndCode = testCase "endCode" $+ targetEndCode @=? run sourceEndCode++------------------------------------------------------------------------------++sourceEndCodeBlanks :: Text+sourceEndCodeBlanks = TL.unlines+ [ "print('Hello!')"+ , ""+ , ""+ ]++targetEndCodeBlanks :: Text+targetEndCodeBlanks = TL.unlines+ [ "``` {.python .numberSource startFrom=\"1\"}"+ , "print('Hello!')"+ , "```"+ ]++testEndCodeBlanks :: TestTree+testEndCodeBlanks = testCase "endCodeBlanks" $+ targetEndCodeBlanks @=? run sourceEndCodeBlanks++------------------------------------------------------------------------------++sourceEmpty :: Text+sourceEmpty = ""++sourceOnlyRule :: Text+sourceOnlyRule = "###########################################################"++sourceOnlyDocBlanks :: Text+sourceOnlyDocBlanks = TL.unlines+ [ "#"+ , "#"+ ]++sourceOnlyCodeBlanks :: Text+sourceOnlyCodeBlanks = TL.unlines+ [ ""+ , ""+ ]++targetEmpty :: Text+targetEmpty = ""++testEmpty :: TestTree+testEmpty = testCase "empty" $+ targetEmpty @=? run sourceEmpty++testOnlyRule :: TestTree+testOnlyRule = testCase "onlyRule" $+ targetEmpty @=? run sourceOnlyRule++testOnlyDocBlanks :: TestTree+testOnlyDocBlanks = testCase "onlyDocBlanks" $+ targetEmpty @=? run sourceOnlyDocBlanks++testOnlyCodeBlanks :: TestTree+testOnlyCodeBlanks = testCase "onlyCodeBlanks" $+ targetEmpty @=? run sourceOnlyCodeBlanks++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "Hash"+ [ testStartShebangDoc+ , testStartShebangCode+ , testStartDoc+ , testStartCode+ , testStartDocBlank+ , testStartCodeBlank+ , testStartRuleDoc+ , testStartRuleCode+ , testCodeDoc+ , testCodeCodeBlanksCode+ , testCodeCodeBlanksDoc+ , testCodeDocBlanksDoc+ , testCodeDocBlanksCode+ , testCodeRuleCode+ , testCodeRuleDoc+ , testDocCode+ , testDocDocBlanksDoc+ , testDocDocBlanksCode+ , testDocCodeBlanksCode+ , testDocCodeBlanksDoc+ , testDocRuleDoc+ , testDocRuleCode+ , testEndDoc+ , testEndDocBlanks+ , testEndCode+ , testEndCodeBlanks+ , testEmpty+ , testOnlyRule+ , testOnlyDocBlanks+ , testOnlyCodeBlanks+ ]
+ test/LiterateX/Test/SourceFormat/LispSemicolons.hs view
@@ -0,0 +1,837 @@+{-# LANGUAGE OverloadedStrings #-}++module LiterateX.Test.SourceFormat.LispSemicolons (tests) where++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy (Text)++-- (literatex)+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.TargetFormat as TargetFormat++------------------------------------------------------------------------------++rendererOpts :: Renderer.Options+rendererOpts = Renderer.Options+ { Renderer.targetFormat = TargetFormat.PandocMarkdown+ , Renderer.codeLanguage = Just "scheme"+ , Renderer.ignoreShebang = True+ , Renderer.renderCode = True+ , Renderer.numberCodeLines = True+ }++run' :: Text -> Renderer.Options -> Text+run' = flip $ LiterateX.transformTextToText SourceFormat.LispSemicolons++run :: Text -> Text+run source = run' source rendererOpts++------------------------------------------------------------------------------++sourceStartShebangDoc :: Text+sourceStartShebangDoc = TL.unlines+ [ "#!/usr/bin/env racket"+ , ""+ , "; Test"+ , ""+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ ]++targetStartShebangDocIgnore :: Text+targetStartShebangDocIgnore = TL.unlines+ [ "Test"+ , ""+ , "``` {.scheme .numberSource startFrom=\"5\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++targetStartShebangDocNoIgnore :: Text+targetStartShebangDocNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env racket"+ , "```"+ , ""+ , "Test"+ , ""+ , "``` {.scheme .numberSource startFrom=\"5\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++targetStartShebangDocNoCode :: Text+targetStartShebangDocNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangDoc :: TestTree+testStartShebangDoc = testGroup "startShebangDoc"+ [ testCase "Ignore" $+ targetStartShebangDocIgnore @=? run sourceStartShebangDoc+ , testCase "NoIgnore" $+ targetStartShebangDocNoIgnore @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangDocNoCode @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartShebangCode :: Text+sourceStartShebangCode = TL.unlines+ [ "#!/usr/bin/env racket"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , ""+ , "; Test"+ ]++targetStartShebangCodeIgnore :: Text+targetStartShebangCodeIgnore = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"2\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoIgnore :: Text+targetStartShebangCodeNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env racket"+ , "```"+ , ""+ , "``` {.scheme .numberSource startFrom=\"2\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoCode :: Text+targetStartShebangCodeNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangCode :: TestTree+testStartShebangCode = testGroup "startShebangCode"+ [ testCase "Ignore" $+ targetStartShebangCodeIgnore @=? run sourceStartShebangCode+ , testCase "NoIgnore" $+ targetStartShebangCodeNoIgnore @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangCodeNoCode @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartDoc :: Text+sourceStartDoc = TL.unlines+ [ "; Test"+ , ""+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ ]++targetStartDoc :: Text+targetStartDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.scheme .numberSource startFrom=\"3\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++testStartDoc :: TestTree+testStartDoc = testCase "startDoc" $+ targetStartDoc @=? run sourceStartDoc++------------------------------------------------------------------------------++sourceStartCode :: Text+sourceStartCode = TL.unlines+ [ "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , ""+ , "; Test"+ ]++targetStartCode :: Text+targetStartCode = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ , ""+ , "Test"+ ]++testStartCode :: TestTree+testStartCode = testCase "startCode" $+ targetStartCode @=? run sourceStartCode++------------------------------------------------------------------------------++sourceStartDocBlank :: Text+sourceStartDocBlank = TL.unlines+ [ ";"+ , "; Test"+ , ""+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ ]++targetStartDocBlank :: Text+targetStartDocBlank = TL.unlines+ [ "Test"+ , ""+ , "``` {.scheme .numberSource startFrom=\"4\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++testStartDocBlank :: TestTree+testStartDocBlank = testCase "startDocBlank" $+ targetStartDocBlank @=? run sourceStartDocBlank++------------------------------------------------------------------------------++sourceStartCodeBlank :: Text+sourceStartCodeBlank = TL.unlines+ [ ""+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , ""+ , "; Test"+ ]++targetStartCodeBlank :: Text+targetStartCodeBlank = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"2\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ , ""+ , "Test"+ ]++testStartCodeBlank :: TestTree+testStartCodeBlank = testCase "startCodeBlank" $+ targetStartCodeBlank @=? run sourceStartCodeBlank++------------------------------------------------------------------------------++sourceStartRuleDoc :: Text+sourceStartRuleDoc = TL.unlines+ [ ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"+ , "; Test"+ , ""+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ ]++targetStartRuleDoc :: Text+targetStartRuleDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.scheme .numberSource startFrom=\"4\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++testStartRuleDoc :: TestTree+testStartRuleDoc = testCase "startRuleDoc" $+ targetStartRuleDoc @=? run sourceStartRuleDoc++------------------------------------------------------------------------------++sourceStartRuleCode :: Text+sourceStartRuleCode = TL.unlines+ [ ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"+ , ""+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , ""+ , "; Test"+ ]++targetStartRuleCode :: Text+targetStartRuleCode = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"3\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ , ""+ , "Test"+ ]++testStartRuleCode :: TestTree+testStartRuleCode = testCase "startRuleCode" $+ targetStartRuleCode @=? run sourceStartRuleCode++------------------------------------------------------------------------------++sourceCodeDoc :: Text+sourceCodeDoc = TL.unlines+ [ "#lang racket/base"+ , ""+ , "print('one')"+ , "; Test"+ ]++targetCodeDoc :: Text+targetCodeDoc = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , ""+ , "print('one')"+ , "```"+ , ""+ , "Test"+ ]++testCodeDoc :: TestTree+testCodeDoc = testCase "codeDoc" $+ targetCodeDoc @=? run sourceCodeDoc++------------------------------------------------------------------------------++sourceCodeCodeBlanksCode :: Text+sourceCodeCodeBlanksCode = TL.unlines+ [ "#lang racket/base"+ , ""+ , ""+ , "print('one')"+ ]++targetCodeCodeBlanksCode :: Text+targetCodeCodeBlanksCode = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , ""+ , ""+ , "print('one')"+ , "```"+ ]++testCodeCodeBlanksCode :: TestTree+testCodeCodeBlanksCode = testCase "codeCodeBlanksCode" $+ targetCodeCodeBlanksCode @=? run sourceCodeCodeBlanksCode++------------------------------------------------------------------------------++sourceCodeCodeBlanksDoc :: Text+sourceCodeCodeBlanksDoc = TL.unlines+ [ "#lang racket/base"+ , ""+ , "print('one')"+ , ""+ , ""+ , "; Test"+ ]++targetCodeCodeBlanksDoc :: Text+targetCodeCodeBlanksDoc = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , ""+ , "print('one')"+ , "```"+ , ""+ , "Test"+ ]++testCodeCodeBlanksDoc :: TestTree+testCodeCodeBlanksDoc = testCase "codeCodeBlanksDoc" $+ targetCodeCodeBlanksDoc @=? run sourceCodeCodeBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksDoc :: Text+sourceCodeDocBlanksDoc = TL.unlines+ [ "#lang racket/base"+ , ""+ , "print('one')"+ , ";"+ , ";"+ , "; Test"+ ]++targetCodeDocBlanksDoc :: Text+targetCodeDocBlanksDoc = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , ""+ , "print('one')"+ , "```"+ , ""+ , "Test"+ ]++testCodeDocBlanksDoc :: TestTree+testCodeDocBlanksDoc = testCase "codeDocBlanksDoc" $+ targetCodeDocBlanksDoc @=? run sourceCodeDocBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksCode :: Text+sourceCodeDocBlanksCode = TL.unlines+ [ "#lang racket/base"+ , ";"+ , ";"+ , "print('one')"+ ]++targetCodeDocBlanksCode :: Text+targetCodeDocBlanksCode = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , "```"+ , ""+ , "``` {.scheme .numberSource startFrom=\"4\"}"+ , "print('one')"+ , "```"+ ]++testCodeDocBlanksCode :: TestTree+testCodeDocBlanksCode = testCase "codeDocBlanksCode" $+ targetCodeDocBlanksCode @=? run sourceCodeDocBlanksCode++------------------------------------------------------------------------------++sourceCodeRuleCode :: Text+sourceCodeRuleCode = TL.unlines+ [ "#lang racket/base"+ , ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"+ , "print('one')"+ ]++targetCodeRuleCode :: Text+targetCodeRuleCode = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , "```"+ , ""+ , "``` {.scheme .numberSource startFrom=\"3\"}"+ , "print('one')"+ , "```"+ ]++testCodeRuleCode :: TestTree+testCodeRuleCode = testCase "codeRuleCode" $+ targetCodeRuleCode @=? run sourceCodeRuleCode++------------------------------------------------------------------------------++sourceCodeRuleDoc :: Text+sourceCodeRuleDoc = TL.unlines+ [ "#lang racket/base"+ , ""+ , "print('one')"+ , ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"+ , "; Test"+ ]++targetCodeRuleDoc :: Text+targetCodeRuleDoc = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , ""+ , "print('one')"+ , "```"+ , ""+ , "Test"+ ]++testCodeRuleDoc :: TestTree+testCodeRuleDoc = testCase "codeRuleDoc" $+ targetCodeRuleDoc @=? run sourceCodeRuleDoc++------------------------------------------------------------------------------++sourceDocCode :: Text+sourceDocCode = TL.unlines+ [ "; Test"+ , "#lang racket/base"+ , ""+ , "print('one')"+ ]++targetDocCode :: Text+targetDocCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.scheme .numberSource startFrom=\"2\"}"+ , "#lang racket/base"+ , ""+ , "print('one')"+ , "```"+ ]++testDocCode :: TestTree+testDocCode = testCase "docCode" $+ targetDocCode @=? run sourceDocCode++------------------------------------------------------------------------------++sourceDocDocBlanksDoc :: Text+sourceDocDocBlanksDoc = TL.unlines+ [ "; one"+ , ";"+ , ";"+ , "; two"+ ]++targetDocDocBlanksDoc :: Text+targetDocDocBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocDocBlanksDoc :: TestTree+testDocDocBlanksDoc = testCase "docDocBlanksDoc" $+ targetDocDocBlanksDoc @=? run sourceDocDocBlanksDoc++------------------------------------------------------------------------------++sourceDocDocBlanksCode :: Text+sourceDocDocBlanksCode = TL.unlines+ [ "; Test"+ , ";"+ , ";"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ ]++targetDocDocBlanksCode :: Text+targetDocDocBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.scheme .numberSource startFrom=\"4\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++testDocDocBlanksCode :: TestTree+testDocDocBlanksCode = testCase "docDocBlanksCode" $+ targetDocDocBlanksCode @=? run sourceDocDocBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksCode :: Text+sourceDocCodeBlanksCode = TL.unlines+ [ "; Test"+ , ""+ , ""+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ ]++targetDocCodeBlanksCode :: Text+targetDocCodeBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.scheme .numberSource startFrom=\"4\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++testDocCodeBlanksCode :: TestTree+testDocCodeBlanksCode = testCase "docCodeBlanksCode" $+ targetDocCodeBlanksCode @=? run sourceDocCodeBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksDoc :: Text+sourceDocCodeBlanksDoc = TL.unlines+ [ "; one"+ , ""+ , ""+ , "; two"+ ]++targetDocCodeBlanksDoc :: Text+targetDocCodeBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocCodeBlanksDoc :: TestTree+testDocCodeBlanksDoc = testCase "docCodeBlanksDoc" $+ targetDocCodeBlanksDoc @=? run sourceDocCodeBlanksDoc++------------------------------------------------------------------------------++sourceDocRuleDoc :: Text+sourceDocRuleDoc = TL.unlines+ [ "; one"+ , ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"+ , "; two"+ ]++targetDocRuleDoc :: Text+targetDocRuleDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocRuleDoc :: TestTree+testDocRuleDoc = testCase "docRuleDoc" $+ targetDocRuleDoc @=? run sourceDocRuleDoc++------------------------------------------------------------------------------++sourceDocRuleCode :: Text+sourceDocRuleCode = TL.unlines+ [ "; Test"+ , ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ ]++targetDocRuleCode :: Text+targetDocRuleCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.scheme .numberSource startFrom=\"3\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++testDocRuleCode :: TestTree+testDocRuleCode = testCase "docRuleCode" $+ targetDocRuleCode @=? run sourceDocRuleCode++------------------------------------------------------------------------------++sourceEndDoc :: Text+sourceEndDoc = TL.unlines+ [ "; Test"+ ]++targetEndDoc :: Text+targetEndDoc = TL.unlines+ [ "Test"+ ]++testEndDoc :: TestTree+testEndDoc = testCase "endDoc" $+ targetEndDoc @=? run sourceEndDoc++------------------------------------------------------------------------------++sourceEndDocBlanks :: Text+sourceEndDocBlanks = TL.unlines+ [ ";"+ , ";"+ ]++targetEndDocBlanks :: Text+targetEndDocBlanks = ""++testEndDocBlanks :: TestTree+testEndDocBlanks = testCase "endDocBlanks" $+ targetEndDocBlanks @=? run sourceEndDocBlanks++------------------------------------------------------------------------------++sourceEndCode :: Text+sourceEndCode = TL.unlines+ [ "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ ]++targetEndCode :: Text+targetEndCode = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++testEndCode :: TestTree+testEndCode = testCase "endCode" $+ targetEndCode @=? run sourceEndCode++------------------------------------------------------------------------------++sourceEndCodeBlanks :: Text+sourceEndCodeBlanks = TL.unlines+ [ "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , ""+ , ""+ ]++targetEndCodeBlanks :: Text+targetEndCodeBlanks = TL.unlines+ [ "``` {.scheme .numberSource startFrom=\"1\"}"+ , "#lang racket/base"+ , ""+ , "(println \"Hello!\")"+ , "```"+ ]++testEndCodeBlanks :: TestTree+testEndCodeBlanks = testCase "endCodeBlanks" $+ targetEndCodeBlanks @=? run sourceEndCodeBlanks++------------------------------------------------------------------------------++sourceEmpty :: Text+sourceEmpty = ""++sourceOnlyRule :: Text+sourceOnlyRule = ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"++sourceOnlyDocBlanks :: Text+sourceOnlyDocBlanks = TL.unlines+ [ ";"+ , ";"+ ]++sourceOnlyCodeBlanks :: Text+sourceOnlyCodeBlanks = TL.unlines+ [ ""+ , ""+ ]++targetEmpty :: Text+targetEmpty = ""++testEmpty :: TestTree+testEmpty = testCase "empty" $+ targetEmpty @=? run sourceEmpty++testOnlyRule :: TestTree+testOnlyRule = testCase "onlyRule" $+ targetEmpty @=? run sourceOnlyRule++testOnlyDocBlanks :: TestTree+testOnlyDocBlanks = testCase "onlyDocBlanks" $+ targetEmpty @=? run sourceOnlyDocBlanks++testOnlyCodeBlanks :: TestTree+testOnlyCodeBlanks = testCase "onlyCodeBlanks" $+ targetEmpty @=? run sourceOnlyCodeBlanks++------------------------------------------------------------------------------++testLispSemicolons :: TestTree+testLispSemicolons = testGroup "lispSemicolons"+ [ testCase "oneSemicolonDoc" $+ target @=? run (sourceSemicolonDoc 1)+ , testCase "twoSemicolonDoc" $+ target @=? run (sourceSemicolonDoc 2)+ , testCase "threeSemicolonDoc" $+ target @=? run (sourceSemicolonDoc 3)+ , testCase "fourSemicolonDoc" $+ target @=? run (sourceSemicolonDoc 4)+ ]+ where+ sourceSemicolonDoc :: Int -> Text+ sourceSemicolonDoc count =+ TL.concat [TL.pack (replicate count ';'), " ", target]++ target :: Text+ target = TL.unlines ["Test"]++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "LispSemicolons"+ [ testStartShebangDoc+ , testStartShebangCode+ , testStartDoc+ , testStartCode+ , testStartDocBlank+ , testStartCodeBlank+ , testStartRuleDoc+ , testStartRuleCode+ , testCodeDoc+ , testCodeCodeBlanksCode+ , testCodeCodeBlanksDoc+ , testCodeDocBlanksDoc+ , testCodeDocBlanksCode+ , testCodeRuleCode+ , testCodeRuleDoc+ , testDocCode+ , testDocDocBlanksDoc+ , testDocDocBlanksCode+ , testDocCodeBlanksCode+ , testDocCodeBlanksDoc+ , testDocRuleDoc+ , testDocRuleCode+ , testEndDoc+ , testEndDocBlanks+ , testEndCode+ , testEndCodeBlanks+ , testEmpty+ , testOnlyRule+ , testOnlyDocBlanks+ , testOnlyCodeBlanks+ , testLispSemicolons+ ]
+ test/LiterateX/Test/SourceFormat/LiterateHaskell.hs view
@@ -0,0 +1,696 @@+{-# LANGUAGE OverloadedStrings #-}++module LiterateX.Test.SourceFormat.LiterateHaskell (tests) where++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy (Text)++-- (literatex)+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.TargetFormat as TargetFormat++------------------------------------------------------------------------------++rendererOpts :: Renderer.Options+rendererOpts = Renderer.Options+ { Renderer.targetFormat = TargetFormat.PandocMarkdown+ , Renderer.codeLanguage = Just "haskell"+ , Renderer.ignoreShebang = True+ , Renderer.renderCode = True+ , Renderer.numberCodeLines = True+ }++run' :: Text -> Renderer.Options -> Text+run' = flip $ LiterateX.transformTextToText SourceFormat.LiterateHaskell++run :: Text -> Text+run source = run' source rendererOpts++------------------------------------------------------------------------------++sourceStartShebangDoc :: Text+sourceStartShebangDoc = TL.unlines+ [ "#!/usr/bin/env stack"+ , ""+ , "This results in warnings!"+ , ""+ , "> {- stack script --resolver lts-17.11 -}"+ , ">"+ , "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ ]++targetStartShebangDocIgnore :: Text+targetStartShebangDocIgnore = TL.unlines+ [ "This results in warnings!"+ , ""+ , "``` {.haskell .numberSource startFrom=\"5\"}"+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++targetStartShebangDocNoIgnore :: Text+targetStartShebangDocNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env stack"+ , "```"+ , ""+ , "This results in warnings!"+ , ""+ , "``` {.haskell .numberSource startFrom=\"5\"}"+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++targetStartShebangDocNoCode :: Text+targetStartShebangDocNoCode = TL.unlines+ [ "This results in warnings!"+ ]++testStartShebangDoc :: TestTree+testStartShebangDoc = testGroup "startShebangDoc"+ [ testCase "Ignore" $+ targetStartShebangDocIgnore @=? run sourceStartShebangDoc+ , testCase "NoIgnore" $+ targetStartShebangDocNoIgnore @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangDocNoCode @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartShebangCode :: Text+sourceStartShebangCode = TL.unlines+ [ "#!/usr/bin/env stack"+ , "> {- stack script --resolver lts-17.11 -}"+ , ">"+ , "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ , ""+ , "Test"+ ]++targetStartShebangCodeIgnore :: Text+targetStartShebangCodeIgnore = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"2\"}"+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoIgnore :: Text+targetStartShebangCodeNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env stack"+ , "```"+ , ""+ , "``` {.haskell .numberSource startFrom=\"2\"}"+ , "{- stack script --resolver lts-17.11 -}"+ , ""+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoCode :: Text+targetStartShebangCodeNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangCode :: TestTree+testStartShebangCode = testGroup "startShebangCode"+ [ testCase "Ignore" $+ targetStartShebangCodeIgnore @=? run sourceStartShebangCode+ , testCase "NoIgnore" $+ targetStartShebangCodeNoIgnore @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangCodeNoCode @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartDoc :: Text+sourceStartDoc = TL.unlines+ [ "Test"+ , ""+ , "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ ]++targetStartDoc :: Text+targetStartDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"3\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testStartDoc :: TestTree+testStartDoc = testCase "startDoc" $+ targetStartDoc @=? run sourceStartDoc++------------------------------------------------------------------------------++sourceStartCode :: Text+sourceStartCode = TL.unlines+ [ "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ , ""+ , "Test"+ ]++targetStartCode :: Text+targetStartCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testStartCode :: TestTree+testStartCode = testCase "startCode" $+ targetStartCode @=? run sourceStartCode++------------------------------------------------------------------------------++sourceStartDocBlank :: Text+sourceStartDocBlank = TL.unlines+ [ ""+ , "Test"+ , ""+ , "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ ]++targetStartDocBlank :: Text+targetStartDocBlank = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"4\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testStartDocBlank :: TestTree+testStartDocBlank = testCase "startDocBlank" $+ targetStartDocBlank @=? run sourceStartDocBlank++------------------------------------------------------------------------------++sourceStartCodeBlank :: Text+sourceStartCodeBlank = TL.unlines+ [ ">"+ , "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ , ""+ , "Test"+ ]++targetStartCodeBlank :: Text+targetStartCodeBlank = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"2\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testStartCodeBlank :: TestTree+testStartCodeBlank = testCase "startCodeBlank" $+ targetStartCodeBlank @=? run sourceStartCodeBlank++------------------------------------------------------------------------------++sourceCodeDoc :: Text+sourceCodeDoc = TL.unlines+ [ "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ , "Test"+ ]++targetCodeDoc :: Text+targetCodeDoc = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testCodeDoc :: TestTree+testCodeDoc = testCase "codeDoc" $+ targetCodeDoc @=? run sourceCodeDoc++------------------------------------------------------------------------------++sourceCodeCodeBlanksCode :: Text+sourceCodeCodeBlanksCode = TL.unlines+ [ "> module Main (main) where"+ , ">"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ ]++targetCodeCodeBlanksCode :: Text+targetCodeCodeBlanksCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testCodeCodeBlanksCode :: TestTree+testCodeCodeBlanksCode = testCase "codeCodeBlanksCode" $+ targetCodeCodeBlanksCode @=? run sourceCodeCodeBlanksCode++------------------------------------------------------------------------------++sourceCodeCodeBlanksDoc :: Text+sourceCodeCodeBlanksDoc = TL.unlines+ [ "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ , ">"+ , ">"+ , "Test"+ ]++targetCodeCodeBlanksDoc :: Text+targetCodeCodeBlanksDoc = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testCodeCodeBlanksDoc :: TestTree+testCodeCodeBlanksDoc = testCase "codeCodeBlanksDoc" $+ targetCodeCodeBlanksDoc @=? run sourceCodeCodeBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksDoc :: Text+sourceCodeDocBlanksDoc = TL.unlines+ [ "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ , ""+ , ""+ , "Test"+ ]++targetCodeDocBlanksDoc :: Text+targetCodeDocBlanksDoc = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ , ""+ , "Test"+ ]++testCodeDocBlanksDoc :: TestTree+testCodeDocBlanksDoc = testCase "codeDocBlanksDoc" $+ targetCodeDocBlanksDoc @=? run sourceCodeDocBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksCode :: Text+sourceCodeDocBlanksCode = TL.unlines+ [ "> module Main (main) where"+ , ""+ , ""+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ ]++targetCodeDocBlanksCode :: Text+targetCodeDocBlanksCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , "```"+ , ""+ , "``` {.haskell .numberSource startFrom=\"4\"}"+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testCodeDocBlanksCode :: TestTree+testCodeDocBlanksCode = testCase "codeDocBlanksCode" $+ targetCodeDocBlanksCode @=? run sourceCodeDocBlanksCode++------------------------------------------------------------------------------++sourceDocCode :: Text+sourceDocCode = TL.unlines+ [ "Test"+ , "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ ]++targetDocCode :: Text+targetDocCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"2\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testDocCode :: TestTree+testDocCode = testCase "docCode" $+ targetDocCode @=? run sourceDocCode++------------------------------------------------------------------------------++sourceDocDocBlanksDoc :: Text+sourceDocDocBlanksDoc = TL.unlines+ [ "one"+ , ""+ , ""+ , "two"+ ]++targetDocDocBlanksDoc :: Text+targetDocDocBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocDocBlanksDoc :: TestTree+testDocDocBlanksDoc = testCase "docDocBlanksDoc" $+ targetDocDocBlanksDoc @=? run sourceDocDocBlanksDoc++------------------------------------------------------------------------------++sourceDocDocBlanksCode :: Text+sourceDocDocBlanksCode = TL.unlines+ [ "Test"+ , ""+ , ""+ , "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ ]++targetDocDocBlanksCode :: Text+targetDocDocBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"4\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testDocDocBlanksCode :: TestTree+testDocDocBlanksCode = testCase "docDocBlanksCode" $+ targetDocDocBlanksCode @=? run sourceDocDocBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksCode :: Text+sourceDocCodeBlanksCode = TL.unlines+ [ "Test"+ , ">"+ , ">"+ , "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ ]++targetDocCodeBlanksCode :: Text+targetDocCodeBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.haskell .numberSource startFrom=\"4\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testDocCodeBlanksCode :: TestTree+testDocCodeBlanksCode = testCase "docCodeBlanksCode" $+ targetDocCodeBlanksCode @=? run sourceDocCodeBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksDoc :: Text+sourceDocCodeBlanksDoc = TL.unlines+ [ "one"+ , ">"+ , ">"+ , "two"+ ]++targetDocCodeBlanksDoc :: Text+targetDocCodeBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocCodeBlanksDoc :: TestTree+testDocCodeBlanksDoc = testCase "docCodeBlanksDoc" $+ targetDocCodeBlanksDoc @=? run sourceDocCodeBlanksDoc++------------------------------------------------------------------------------++sourceEndDoc :: Text+sourceEndDoc = TL.unlines+ [ "Test"+ ]++targetEndDoc :: Text+targetEndDoc = TL.unlines+ [ "Test"+ ]++testEndDoc :: TestTree+testEndDoc = testCase "endDoc" $+ targetEndDoc @=? run sourceEndDoc++------------------------------------------------------------------------------++sourceEndDocBlanks :: Text+sourceEndDocBlanks = TL.unlines+ [ ""+ , ""+ ]++targetEndDocBlanks :: Text+targetEndDocBlanks = ""++testEndDocBlanks :: TestTree+testEndDocBlanks = testCase "endDocBlanks" $+ targetEndDocBlanks @=? run sourceEndDocBlanks++------------------------------------------------------------------------------++sourceEndCode :: Text+sourceEndCode = TL.unlines+ [ "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ ]++targetEndCode :: Text+targetEndCode = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testEndCode :: TestTree+testEndCode = testCase "endCode" $+ targetEndCode @=? run sourceEndCode++------------------------------------------------------------------------------++sourceEndCodeBlanks :: Text+sourceEndCodeBlanks = TL.unlines+ [ "> module Main (main) where"+ , ">"+ , "> main :: IO ()"+ , "> main = putStrLn \"Hello!\""+ , ">"+ , ">"+ ]++targetEndCodeBlanks :: Text+targetEndCodeBlanks = TL.unlines+ [ "``` {.haskell .numberSource startFrom=\"1\"}"+ , "module Main (main) where"+ , ""+ , "main :: IO ()"+ , "main = putStrLn \"Hello!\""+ , "```"+ ]++testEndCodeBlanks :: TestTree+testEndCodeBlanks = testCase "endCodeBlanks" $+ targetEndCodeBlanks @=? run sourceEndCodeBlanks++------------------------------------------------------------------------------++sourceEmpty :: Text+sourceEmpty = ""++sourceOnlyDocBlanks :: Text+sourceOnlyDocBlanks = TL.unlines+ [ ""+ , ""+ ]++sourceOnlyCodeBlanks :: Text+sourceOnlyCodeBlanks = TL.unlines+ [ ">"+ , ">"+ ]++targetEmpty :: Text+targetEmpty = ""++testEmpty :: TestTree+testEmpty = testCase "empty" $+ targetEmpty @=? run sourceEmpty++testOnlyDocBlanks :: TestTree+testOnlyDocBlanks = testCase "onlyDocBlanks" $+ targetEmpty @=? run sourceOnlyDocBlanks++testOnlyCodeBlanks :: TestTree+testOnlyCodeBlanks = testCase "onlyCodeBlanks" $+ targetEmpty @=? run sourceOnlyCodeBlanks++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "LiterateHaskell"+ [ testStartShebangDoc+ , testStartShebangCode+ , testStartDoc+ , testStartCode+ , testStartDocBlank+ , testStartCodeBlank+ , testCodeDoc+ , testCodeCodeBlanksCode+ , testCodeCodeBlanksDoc+ , testCodeDocBlanksDoc+ , testCodeDocBlanksCode+ , testDocCode+ , testDocDocBlanksDoc+ , testDocDocBlanksCode+ , testDocCodeBlanksCode+ , testDocCodeBlanksDoc+ , testEndDoc+ , testEndDocBlanks+ , testEndCode+ , testEndCodeBlanks+ , testEmpty+ , testOnlyDocBlanks+ , testOnlyCodeBlanks+ ]
+ test/LiterateX/Test/SourceFormat/Percent.hs view
@@ -0,0 +1,860 @@+{-# LANGUAGE OverloadedStrings #-}++module LiterateX.Test.SourceFormat.Percent (tests) where++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy (Text)++-- (literatex)+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.TargetFormat as TargetFormat++------------------------------------------------------------------------------++rendererOpts :: Renderer.Options+rendererOpts = Renderer.Options+ { Renderer.targetFormat = TargetFormat.PandocMarkdown+ , Renderer.codeLanguage = Just "erlang"+ , Renderer.ignoreShebang = True+ , Renderer.renderCode = True+ , Renderer.numberCodeLines = True+ }++run' :: Text -> Renderer.Options -> Text+run' = flip $ LiterateX.transformTextToText SourceFormat.Percent++run :: Text -> Text+run source = run' source rendererOpts++------------------------------------------------------------------------------++sourceStartShebangDoc :: Text+sourceStartShebangDoc = TL.unlines+ [ "#!/usr/bin/env escript"+ , ""+ , "% Test"+ , ""+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetStartShebangDocIgnore :: Text+targetStartShebangDocIgnore = TL.unlines+ [ "Test"+ , ""+ , "``` {.erlang .numberSource startFrom=\"5\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++targetStartShebangDocNoIgnore :: Text+targetStartShebangDocNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env escript"+ , "```"+ , ""+ , "Test"+ , ""+ , "``` {.erlang .numberSource startFrom=\"5\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++targetStartShebangDocNoCode :: Text+targetStartShebangDocNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangDoc :: TestTree+testStartShebangDoc = testGroup "startShebangDoc"+ [ testCase "Ignore" $+ targetStartShebangDocIgnore @=? run sourceStartShebangDoc+ , testCase "NoIgnore" $+ targetStartShebangDocNoIgnore @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangDocNoCode @=?+ run' sourceStartShebangDoc rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartShebangCode :: Text+sourceStartShebangCode = TL.unlines+ [ "#!/usr/bin/env escript"+ , ""+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , ""+ , "% Test"+ ]++targetStartShebangCodeIgnore :: Text+targetStartShebangCodeIgnore = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"3\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoIgnore :: Text+targetStartShebangCodeNoIgnore = TL.unlines+ [ "``` {.numberSource startFrom=\"1\"}"+ , "#!/usr/bin/env escript"+ , "```"+ , ""+ , "``` {.erlang .numberSource startFrom=\"3\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ , ""+ , "Test"+ ]++targetStartShebangCodeNoCode :: Text+targetStartShebangCodeNoCode = TL.unlines+ [ "Test"+ ]++testStartShebangCode :: TestTree+testStartShebangCode = testGroup "startShebangCode"+ [ testCase "Ignore" $+ targetStartShebangCodeIgnore @=? run sourceStartShebangCode+ , testCase "NoIgnore" $+ targetStartShebangCodeNoIgnore @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ }+ , testCase "NoCode" $+ targetStartShebangCodeNoCode @=?+ run' sourceStartShebangCode rendererOpts+ { Renderer.ignoreShebang = False+ , Renderer.renderCode = False+ }+ ]++------------------------------------------------------------------------------++sourceStartDoc :: Text+sourceStartDoc = TL.unlines+ [ "% Test"+ , ""+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetStartDoc :: Text+targetStartDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.erlang .numberSource startFrom=\"3\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testStartDoc :: TestTree+testStartDoc = testCase "startDoc" $+ targetStartDoc @=? run sourceStartDoc++------------------------------------------------------------------------------++sourceStartCode :: Text+sourceStartCode = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , ""+ , "% Test"+ ]++targetStartCode :: Text+targetStartCode = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ , ""+ , "Test"+ ]++testStartCode :: TestTree+testStartCode = testCase "startCode" $+ targetStartCode @=? run sourceStartCode++------------------------------------------------------------------------------++sourceStartDocBlank :: Text+sourceStartDocBlank = TL.unlines+ [ "%"+ , "% Test"+ , ""+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetStartDocBlank :: Text+targetStartDocBlank = TL.unlines+ [ "Test"+ , ""+ , "``` {.erlang .numberSource startFrom=\"4\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testStartDocBlank :: TestTree+testStartDocBlank = testCase "startDocBlank" $+ targetStartDocBlank @=? run sourceStartDocBlank++------------------------------------------------------------------------------++sourceStartCodeBlank :: Text+sourceStartCodeBlank = TL.unlines+ [ ""+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , ""+ , "% Test"+ ]++targetStartCodeBlank :: Text+targetStartCodeBlank = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"2\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ , ""+ , "Test"+ ]++testStartCodeBlank :: TestTree+testStartCodeBlank = testCase "startCodeBlank" $+ targetStartCodeBlank @=? run sourceStartCodeBlank++------------------------------------------------------------------------------++sourceStartRuleDoc :: Text+sourceStartRuleDoc = TL.unlines+ [ "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"+ , "% Test"+ , ""+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetStartRuleDoc :: Text+targetStartRuleDoc = TL.unlines+ [ "Test"+ , ""+ , "``` {.erlang .numberSource startFrom=\"4\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testStartRuleDoc :: TestTree+testStartRuleDoc = testCase "startRuleDoc" $+ targetStartRuleDoc @=? run sourceStartRuleDoc++------------------------------------------------------------------------------++sourceStartRuleCode :: Text+sourceStartRuleCode = TL.unlines+ [ "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"+ , ""+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , ""+ , "% Test"+ ]++targetStartRuleCode :: Text+targetStartRuleCode = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"3\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ , ""+ , "Test"+ ]++testStartRuleCode :: TestTree+testStartRuleCode = testCase "startRuleCode" $+ targetStartRuleCode @=? run sourceStartRuleCode++------------------------------------------------------------------------------++sourceCodeDoc :: Text+sourceCodeDoc = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "% Test"+ ]++targetCodeDoc :: Text+targetCodeDoc = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ , ""+ , "Test"+ ]++testCodeDoc :: TestTree+testCodeDoc = testCase "codeDoc" $+ targetCodeDoc @=? run sourceCodeDoc++------------------------------------------------------------------------------++sourceCodeCodeBlanksCode :: Text+sourceCodeCodeBlanksCode = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , ""+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetCodeCodeBlanksCode :: Text+targetCodeCodeBlanksCode = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testCodeCodeBlanksCode :: TestTree+testCodeCodeBlanksCode = testCase "codeCodeBlanksCode" $+ targetCodeCodeBlanksCode @=? run sourceCodeCodeBlanksCode++------------------------------------------------------------------------------++sourceCodeCodeBlanksDoc :: Text+sourceCodeCodeBlanksDoc = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , ""+ , ""+ , "% Test"+ ]++targetCodeCodeBlanksDoc :: Text+targetCodeCodeBlanksDoc = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ , ""+ , "Test"+ ]++testCodeCodeBlanksDoc :: TestTree+testCodeCodeBlanksDoc = testCase "codeCodeBlanksDoc" $+ targetCodeCodeBlanksDoc @=? run sourceCodeCodeBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksDoc :: Text+sourceCodeDocBlanksDoc = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "%"+ , "%"+ , "% Test"+ ]++targetCodeDocBlanksDoc :: Text+targetCodeDocBlanksDoc = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ , ""+ , "Test"+ ]++testCodeDocBlanksDoc :: TestTree+testCodeDocBlanksDoc = testCase "codeDocBlanksDoc" $+ targetCodeDocBlanksDoc @=? run sourceCodeDocBlanksDoc++------------------------------------------------------------------------------++sourceCodeDocBlanksCode :: Text+sourceCodeDocBlanksCode = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , "%"+ , "%"+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetCodeDocBlanksCode :: Text+targetCodeDocBlanksCode = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , "```"+ , ""+ , "``` {.erlang .numberSource startFrom=\"5\"}"+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testCodeDocBlanksCode :: TestTree+testCodeDocBlanksCode = testCase "codeDocBlanksCode" $+ targetCodeDocBlanksCode @=? run sourceCodeDocBlanksCode++------------------------------------------------------------------------------++sourceCodeRuleCode :: Text+sourceCodeRuleCode = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetCodeRuleCode :: Text+targetCodeRuleCode = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , "```"+ , ""+ , "``` {.erlang .numberSource startFrom=\"4\"}"+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testCodeRuleCode :: TestTree+testCodeRuleCode = testCase "codeRuleCode" $+ targetCodeRuleCode @=? run sourceCodeRuleCode++------------------------------------------------------------------------------++sourceCodeRuleDoc :: Text+sourceCodeRuleDoc = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"+ , "% Test"+ ]++targetCodeRuleDoc :: Text+targetCodeRuleDoc = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ , ""+ , "Test"+ ]++testCodeRuleDoc :: TestTree+testCodeRuleDoc = testCase "codeRuleDoc" $+ targetCodeRuleDoc @=? run sourceCodeRuleDoc++------------------------------------------------------------------------------++sourceDocCode :: Text+sourceDocCode = TL.unlines+ [ "% Test"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetDocCode :: Text+targetDocCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.erlang .numberSource startFrom=\"2\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testDocCode :: TestTree+testDocCode = testCase "docCode" $+ targetDocCode @=? run sourceDocCode++------------------------------------------------------------------------------++sourceDocDocBlanksDoc :: Text+sourceDocDocBlanksDoc = TL.unlines+ [ "% one"+ , "%"+ , "%"+ , "% two"+ ]++targetDocDocBlanksDoc :: Text+targetDocDocBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocDocBlanksDoc :: TestTree+testDocDocBlanksDoc = testCase "docDocBlanksDoc" $+ targetDocDocBlanksDoc @=? run sourceDocDocBlanksDoc++------------------------------------------------------------------------------++sourceDocDocBlanksCode :: Text+sourceDocDocBlanksCode = TL.unlines+ [ "% Test"+ , "%"+ , "%"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetDocDocBlanksCode :: Text+targetDocDocBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.erlang .numberSource startFrom=\"4\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testDocDocBlanksCode :: TestTree+testDocDocBlanksCode = testCase "docDocBlanksCode" $+ targetDocDocBlanksCode @=? run sourceDocDocBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksCode :: Text+sourceDocCodeBlanksCode = TL.unlines+ [ "% Test"+ , ""+ , ""+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetDocCodeBlanksCode :: Text+targetDocCodeBlanksCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.erlang .numberSource startFrom=\"4\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testDocCodeBlanksCode :: TestTree+testDocCodeBlanksCode = testCase "docCodeBlanksCode" $+ targetDocCodeBlanksCode @=? run sourceDocCodeBlanksCode++------------------------------------------------------------------------------++sourceDocCodeBlanksDoc :: Text+sourceDocCodeBlanksDoc = TL.unlines+ [ "% one"+ , ""+ , ""+ , "% two"+ ]++targetDocCodeBlanksDoc :: Text+targetDocCodeBlanksDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocCodeBlanksDoc :: TestTree+testDocCodeBlanksDoc = testCase "docCodeBlanksDoc" $+ targetDocCodeBlanksDoc @=? run sourceDocCodeBlanksDoc++------------------------------------------------------------------------------++sourceDocRuleDoc :: Text+sourceDocRuleDoc = TL.unlines+ [ "% one"+ , "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"+ , "% two"+ ]++targetDocRuleDoc :: Text+targetDocRuleDoc = TL.unlines+ [ "one"+ , ""+ , "two"+ ]++testDocRuleDoc :: TestTree+testDocRuleDoc = testCase "docRuleDoc" $+ targetDocRuleDoc @=? run sourceDocRuleDoc++------------------------------------------------------------------------------++sourceDocRuleCode :: Text+sourceDocRuleCode = TL.unlines+ [ "% Test"+ , "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetDocRuleCode :: Text+targetDocRuleCode = TL.unlines+ [ "Test"+ , ""+ , "``` {.erlang .numberSource startFrom=\"3\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testDocRuleCode :: TestTree+testDocRuleCode = testCase "docRuleCode" $+ targetDocRuleCode @=? run sourceDocRuleCode++------------------------------------------------------------------------------++sourceEndDoc :: Text+sourceEndDoc = TL.unlines+ [ "% Test"+ ]++targetEndDoc :: Text+targetEndDoc = TL.unlines+ [ "Test"+ ]++testEndDoc :: TestTree+testEndDoc = testCase "endDoc" $+ targetEndDoc @=? run sourceEndDoc++------------------------------------------------------------------------------++sourceEndDocBlanks :: Text+sourceEndDocBlanks = TL.unlines+ [ "%"+ , "%"+ ]++targetEndDocBlanks :: Text+targetEndDocBlanks = ""++testEndDocBlanks :: TestTree+testEndDocBlanks = testCase "endDocBlanks" $+ targetEndDocBlanks @=? run sourceEndDocBlanks++------------------------------------------------------------------------------++sourceEndCode :: Text+sourceEndCode = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ ]++targetEndCode :: Text+targetEndCode = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testEndCode :: TestTree+testEndCode = testCase "endCode" $+ targetEndCode @=? run sourceEndCode++------------------------------------------------------------------------------++sourceEndCodeBlanks :: Text+sourceEndCodeBlanks = TL.unlines+ [ "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , ""+ , ""+ ]++targetEndCodeBlanks :: Text+targetEndCodeBlanks = TL.unlines+ [ "``` {.erlang .numberSource startFrom=\"1\"}"+ , "-module(main)."+ , "-export([start/0])."+ , ""+ , "start() -> io:fwrite(\"Hello!\\n\")."+ , "```"+ ]++testEndCodeBlanks :: TestTree+testEndCodeBlanks = testCase "endCodeBlanks" $+ targetEndCodeBlanks @=? run sourceEndCodeBlanks++------------------------------------------------------------------------------++sourceEmpty :: Text+sourceEmpty = ""++sourceOnlyRule :: Text+sourceOnlyRule = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"++sourceOnlyDocBlanks :: Text+sourceOnlyDocBlanks = TL.unlines+ [ "%"+ , "%"+ ]++sourceOnlyCodeBlanks :: Text+sourceOnlyCodeBlanks = TL.unlines+ [ ""+ , ""+ ]++targetEmpty :: Text+targetEmpty = ""++testEmpty :: TestTree+testEmpty = testCase "empty" $+ targetEmpty @=? run sourceEmpty++testOnlyRule :: TestTree+testOnlyRule = testCase "onlyRule" $+ targetEmpty @=? run sourceOnlyRule++testOnlyDocBlanks :: TestTree+testOnlyDocBlanks = testCase "onlyDocBlanks" $+ targetEmpty @=? run sourceOnlyDocBlanks++testOnlyCodeBlanks :: TestTree+testOnlyCodeBlanks = testCase "onlyCodeBlanks" $+ targetEmpty @=? run sourceOnlyCodeBlanks++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "Percent"+ [ testStartShebangDoc+ , testStartShebangCode+ , testStartDoc+ , testStartCode+ , testStartDocBlank+ , testStartCodeBlank+ , testStartRuleDoc+ , testStartRuleCode+ , testCodeDoc+ , testCodeCodeBlanksCode+ , testCodeCodeBlanksDoc+ , testCodeDocBlanksDoc+ , testCodeDocBlanksCode+ , testCodeRuleCode+ , testCodeRuleDoc+ , testDocCode+ , testDocDocBlanksDoc+ , testDocDocBlanksCode+ , testDocCodeBlanksCode+ , testDocCodeBlanksDoc+ , testDocRuleDoc+ , testDocRuleCode+ , testEndDoc+ , testEndDocBlanks+ , testEndCode+ , testEndCodeBlanks+ , testEmpty+ , testOnlyRule+ , testOnlyDocBlanks+ , testOnlyCodeBlanks+ ]
+ test/LiterateX/Test/TargetFormat.hs view
@@ -0,0 +1,167 @@+{-# LANGUAGE OverloadedStrings #-}++module LiterateX.Test.TargetFormat (tests) where++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy (Text)++-- (literatex)+import qualified LiterateX+import qualified LiterateX.Renderer as Renderer+import qualified LiterateX.Types.SourceFormat as SourceFormat+import qualified LiterateX.Types.TargetFormat as TargetFormat++------------------------------------------------------------------------------++sourceTL :: Text+sourceTL = TL.unlines+ [ "#!/usr/bin/env python"+ , ""+ , "# Test"+ , ""+ , "print('Hello!')"+ ]++------------------------------------------------------------------------------++pandocLangNum :: Text+pandocLangNum = TL.unlines+ [ "Test"+ , ""+ , "``` {.python .numberSource startFrom=\"5\"}"+ , "print('Hello!')"+ , "```"+ ]++pandocLangNoNum :: Text+pandocLangNoNum = TL.unlines+ [ "Test"+ , ""+ , "```python"+ , "print('Hello!')"+ , "```"+ ]++pandocNoLangNum :: Text+pandocNoLangNum = TL.unlines+ [ "Test"+ , ""+ , "``` {.numberSource startFrom=\"5\"}"+ , "print('Hello!')"+ , "```"+ ]++pandocNoLangNoNum :: Text+pandocNoLangNoNum = TL.unlines+ [ "Test"+ , ""+ , "```"+ , "print('Hello!')"+ , "```"+ ]++------------------------------------------------------------------------------++githubLangNum :: Text+githubLangNum = TL.unlines+ [ "Test"+ , ""+ , "``` python startline=5"+ , "print('Hello!')"+ , "```"+ ]++githubLangNoNum :: Text+githubLangNoNum = TL.unlines+ [ "Test"+ , ""+ , "``` python"+ , "print('Hello!')"+ , "```"+ ]++githubNoLangNum :: Text+githubNoLangNum = TL.unlines+ [ "Test"+ , ""+ , "``` startline=5"+ , "print('Hello!')"+ , "```"+ ]++githubNoLangNoNum :: Text+githubNoLangNoNum = TL.unlines+ [ "Test"+ , ""+ , "```"+ , "print('Hello!')"+ , "```"+ ]++------------------------------------------------------------------------------++rendererOpts :: Renderer.Options+rendererOpts = Renderer.Options+ { Renderer.targetFormat = TargetFormat.PandocMarkdown+ , Renderer.codeLanguage = Just "python"+ , Renderer.ignoreShebang = True+ , Renderer.renderCode = True+ , Renderer.numberCodeLines = True+ }++rendererOptsGFM :: Renderer.Options+rendererOptsGFM = rendererOpts+ { Renderer.targetFormat = TargetFormat.GitHubFlavoredMarkdown+ }++run' :: Renderer.Options -> Text+run' opts = LiterateX.transformTextToText SourceFormat.Hash opts sourceTL++------------------------------------------------------------------------------++testPandocMarkdown :: TestTree+testPandocMarkdown = testGroup "PandocMarkdown"+ [ testCase "LangNum" $ pandocLangNum @=? run' rendererOpts+ , testCase "LangNoNum" $ pandocLangNoNum @=? run' rendererOpts+ { Renderer.numberCodeLines = False+ }+ , testCase "NoLangNum" $ pandocNoLangNum @=? run' rendererOpts+ { Renderer.codeLanguage = Nothing+ }+ , testCase "NoLangNoNum" $ pandocNoLangNoNum @=? run' rendererOpts+ { Renderer.codeLanguage = Nothing+ , Renderer.numberCodeLines = False+ }+ ]++------------------------------------------------------------------------------++testGitHubFlavoredMarkdown :: TestTree+testGitHubFlavoredMarkdown = testGroup "GitHubFlavoredMarkdown"+ [ testCase "LangNum" $ githubLangNum @=? run' rendererOptsGFM+ , testCase "LangNoNum" $ githubLangNoNum @=? run' rendererOptsGFM+ { Renderer.numberCodeLines = False+ }+ , testCase "NoLangNum" $ githubNoLangNum @=? run' rendererOptsGFM+ { Renderer.codeLanguage = Nothing+ }+ , testCase "NoLangNoNum" $ githubNoLangNoNum @=? run' rendererOptsGFM+ { Renderer.codeLanguage = Nothing+ , Renderer.numberCodeLines = False+ }+ ]++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "LiterateX.Test.TargetFormat"+ [ testPandocMarkdown+ , testGitHubFlavoredMarkdown+ ]
+ test/Spec.hs view
@@ -0,0 +1,18 @@+module Main (main) where++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (defaultMain, testGroup)++-- (literatex)+import qualified LiterateX.Test.API+import qualified LiterateX.Test.SourceFormat+import qualified LiterateX.Test.TargetFormat++------------------------------------------------------------------------------++main :: IO ()+main = defaultMain $ testGroup "test"+ [ LiterateX.Test.API.tests+ , LiterateX.Test.SourceFormat.tests+ , LiterateX.Test.TargetFormat.tests+ ]