submark 0.1.0 → 0.2.0
raw patch · 6 files changed
+163/−59 lines, 6 files
Files
- CHANGELOG.md +21/−0
- README.md +40/−1
- app/Main.hs +12/−2
- src/Text/CommonMark/Sub.hs +8/−8
- submark.cabal +44/−36
- test/Text/CommonMark/SubSpec.hs +38/−12
CHANGELOG.md view
@@ -1,6 +1,27 @@ `subtoml` changelog =================== +Version 0.2.0+-------------++Released on November 6, 2017.++ - Added `-i`/`--ignore-case` option for case insensitive match.++ - Wordwrap became turned off by default unless `-c`/`--columns` option is+ present.++ - The signature of `Text.CommonMark.Sub.extractSection` function was changed+ from `Level -> Text -> Node -> Node` to+ `Level -> (Text -> Text -> Bool) -> Text -> Node -> Node`; the second+ parameter, a predicate for text equality, was added.++ - The signature of `Text.CommonMark.Sub.matchesHeading` function was changed+ from `Level -> Text -> Node -> Bool` to+ `Level -> (Text -> Text -> Bool) -> Text -> Node -> Bool`; the second+ parameter, a predicate for text equality, was added.++ Version 0.1.0 --------------
README.md view
@@ -2,17 +2,43 @@ ======================================================= [![CircleCI][circleci-badge]][circleci]+[![Hackage][hackage-badge]][hackage] `submark` is a CLI program to extract some particular section from-a givne CommonMark/Markdown document. I use it for myself to extract+a given CommonMark/Markdown document. I use it for myself to extract the latest version section from the CHANGELOG.md file, and then reuse the text for the corresponding release note on GitHub releases, during automated release process which is run on CI. [circleci-badge]: https://circleci.com/gh/dahlia/submark.svg?style=shield [circleci]: https://circleci.com/gh/dahlia/submark+[hackage-badge]: https://img.shields.io/hackage/v/submark.svg+[hackage]: https://hackage.haskell.org/package/submark +Download & installation+-----------------------++For Linux x86_64, executable binaries are available on [GitHub releases][].+Each file is a single executable, and statically linked so that it's executable+as a standalone without dependencies.++For other platforms, you need to build it by yourself. It's written in Haskell,+so you need to install [Haskell Stack][] first. It can be built in the same+way other Haskell programs are:++~~~~~~~~ bash+$ stack setup && stack install+~~~~~~~~++I'm going to officially support executable binaries for other platforms+if anyone asks. (I thought `submark` wouldn't be useful on other than Linux+since the most of CI machines are Linux, but it might be wrong.)++[GitHub releases]: https://github.com/dahlia/submark/releases+[Haskell Stack]: https://haskellstack.org/++ Usage examples -------------- @@ -56,6 +82,19 @@ ~~~~~~~~ bash $ submark --h2 "Download" --omit-heading index.text+[Markdown 1.0.1](http://daringfireball.net/projects/downloads/Markdown_1.0.1.zip)+(18 KB) -- 17 Dec 2004+~~~~~~~~++Matching is case sensitive by default, but case can be ignored using the option+`-i`/`--ignore-case`:++~~~~~~~~ bash+$ submark --h2 "DOWNload" index.text++$ submark --h2 "DOWNload" --ignore-case index.text+## Download+ [Markdown 1.0.1](http://daringfireball.net/projects/downloads/Markdown_1.0.1.zip) (18 KB) -- 17 Dec 2004 ~~~~~~~~
app/Main.hs view
@@ -1,3 +1,4 @@+import Data.Maybe import Data.Semigroup ((<>)) import System.IO @@ -13,6 +14,7 @@ data Extraction = Extraction { outputFilePath :: FilePath , headingPattern :: HeadingPattern+ , ignoreCase :: Bool , omitHeading :: Bool , columnWidth :: Maybe Int , inputFilePath :: FilePath@@ -46,6 +48,10 @@ <> help "Write output to FILE" ) <*> headingLevel+ <*> switch ( long "ignore-case"+ <> short 'i'+ <> help "Ignore case distinctions"+ ) <*> switch ( long "omit-heading" <> short 'O' <> help "Omit a leading heading"@@ -88,16 +94,20 @@ extract :: Extraction -> IO () extract e@Extraction { headingPattern = (HeadingPattern level title)+ , ignoreCase = ignoreCase' , omitHeading = omitHeading' , columnWidth = width } = do text <- withInputFile e TIO.hGetContents let doc = commonmarkToNode [] text- node = case (omitHeading', extractSection level title doc) of+ node = case (omitHeading', extractSection level equals title doc) of (True, Node p DOCUMENT (_ : xs)) -> Node p DOCUMENT xs (_, other) -> other- result = nodeToCommonmark [] width node+ result = nodeToCommonmark [] (Just $ fromMaybe (-1) width) node withOutputFile e (`TIO.hPutStrLn` result)+ where+ equals :: Text -> Text -> Bool+ equals = if ignoreCase' then (\ a b -> toLower a == toLower b) else (==) main :: IO () main = execParser parserInfo >>= extract
src/Text/CommonMark/Sub.hs view
@@ -10,8 +10,8 @@ import CMark import Data.Text (Text, concat, pack, strip) -extractSection :: Level -> Text -> Node -> Node-extractSection headingLevel headingTitle (Node pos DOCUMENT nodes) =+extractSection :: Level -> (Text -> Text -> Bool) -> Text -> Node -> Node+extractSection headingLevel equals headingTitle (Node pos DOCUMENT nodes) = Node pos DOCUMENT $ case headlessNodes of (x : xs) -> x : takeWhile (isInSection headingLevel) xs [] -> []@@ -21,13 +21,13 @@ isInSection _ _ = True headlessNodes :: [Node] headlessNodes =- dropWhile (not . matchesHeading headingLevel headingTitle) nodes-extractSection _ _ (Node pos _ _) = Node pos DOCUMENT []+ dropWhile (not . matchesHeading headingLevel equals headingTitle) nodes+extractSection _ _ _ (Node pos _ _) = Node pos DOCUMENT [] -matchesHeading :: Level -> Text -> Node -> Bool-matchesHeading level text (Node _ (HEADING lv) nodes) =- lv == level && flattenInlineNodes nodes == text-matchesHeading _ _ _ = False+matchesHeading :: Level -> (Text -> Text -> Bool) -> Text -> Node -> Bool+matchesHeading level equals text (Node _ (HEADING lv) nodes) =+ lv == level && flattenInlineNodes nodes `equals` text+matchesHeading _ _ _ _ = False flattenInlineNodes :: [Node] -> Text flattenInlineNodes =
submark.cabal view
@@ -1,9 +1,13 @@--- This file has been generated from package.yaml by hpack version 0.17.1.+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.2. -- -- see: https://github.com/sol/hpack+--+-- hash: 44a3cc6b647f89b49ca4596f50d12a252fc1f579338fb309629f51bb503696f7 name: submark-version: 0.1.0+version: 0.2.0 synopsis: Extract a part from CommonMark/Markdown docs category: Text stability: alpha@@ -15,11 +19,9 @@ license: GPL-3 license-file: LICENSE build-type: Simple-cabal-version: >= 1.10- extra-source-files:- CHANGELOG.md README.md+ CHANGELOG.md source-repository head type: git@@ -31,66 +33,72 @@ default: False library+ exposed-modules:+ Text.CommonMark.Sub+ other-modules:+ Paths_submark hs-source-dirs: src- ghc-options: -Wall -fwarn-incomplete-uni-patterns+ ghc-options: -fwarn-incomplete-uni-patterns build-depends:- base >= 4.7 && < 5- , cmark >= 0.5.6 && < 0.6.0- , text == 1.*- exposed-modules:- Text.CommonMark.Sub+ base >=4.7 && <5+ , cmark >=0.5.6 && <0.6.0+ , text ==1.* default-language: Haskell2010 executable submark main-is: Main.hs+ other-modules:+ Paths_submark hs-source-dirs: app- ghc-options: -Wall -fwarn-incomplete-uni-patterns+ ghc-options: -fwarn-incomplete-uni-patterns build-depends:- base >= 4.7 && < 5- , cmark >= 0.5.6 && < 0.6.0- , text == 1.*+ base >=4.7 && <5+ , cmark >=0.5.6 && <0.6.0+ , optparse-applicative >=0.13.2.0 && <0.15.0.0 , submark- , optparse-applicative >= 0.13.2.0 && < 0.15.0.0+ , text ==1.* if flag(static)- ghc-options: -Wall -fwarn-incomplete-uni-patterns -static -optl-static -optl-pthread -optc-Os -fPIC+ ghc-options: -fwarn-incomplete-uni-patterns -static -optl-static -optl-pthread -optc-Os -fPIC else- ghc-options: -Wall -fwarn-incomplete-uni-patterns+ ghc-options: -fwarn-incomplete-uni-patterns default-language: Haskell2010 test-suite hlint type: exitcode-stdio-1.0 main-is: HLint.hs- hs-source-dirs:- test- ghc-options: -Wall -fwarn-incomplete-uni-patterns- build-depends:- base >= 4.7 && < 5- , cmark >= 0.5.6 && < 0.6.0- , text == 1.*- , hlint >= 2.0.9 && < 3 other-modules: Spec Text.CommonMark.QQ Text.CommonMark.SubSpec+ Paths_submark+ hs-source-dirs:+ test+ ghc-options: -fwarn-incomplete-uni-patterns+ build-depends:+ base >=4.7 && <5+ , cmark >=0.5.6 && <0.6.0+ , hlint >=2.0.9 && <3+ , text ==1.* default-language: Haskell2010 test-suite spec type: exitcode-stdio-1.0 main-is: Spec.hs- hs-source-dirs:- test- ghc-options: -Wall -fwarn-incomplete-uni-patterns- build-depends:- base >= 4.7 && < 5- , cmark >= 0.5.6 && < 0.6.0- , text == 1.*- , hspec >= 2.4.4 && < 3.0.0- , submark- , template-haskell >= 2.5 other-modules: HLint Text.CommonMark.QQ Text.CommonMark.SubSpec+ Paths_submark+ hs-source-dirs:+ test+ ghc-options: -fwarn-incomplete-uni-patterns+ build-depends:+ base >=4.7 && <5+ , cmark >=0.5.6 && <0.6.0+ , hspec >=2.4.4 && <3.0.0+ , submark+ , template-haskell >=2.5+ , text ==1.* default-language: Haskell2010
test/Text/CommonMark/SubSpec.hs view
@@ -2,17 +2,20 @@ {-# LANGUAGE QuasiQuotes #-} module Text.CommonMark.SubSpec (spec) where +import Data.Text import Test.Hspec +import CMark (Node) import Text.CommonMark.QQ import Text.CommonMark.Sub -spec :: Spec-spec = do- specify "extractSection" $- extractSection 2 "Section to extract" [doc|Doc title-=====================================+ciEq :: Text -> Text -> Bool+ciEq t t' = toLower t == toLower t' +source :: Node+source = [doc|Doc title+=======================+ Lorem ipsum dolor sit amet, ne omnes vitae mel, alterum invenire duo ut, ad deterruisset comprehensam qui. At ius ludus iracundia vituperatoribus. @@ -38,7 +41,10 @@ Pro fuisset deserunt consulatu at, no epicuri quaestio vix, case scripserit at vis. No eam alia facilisis. At quo oratio omnium, nibh malis dolores an eam.-|] `shouldBe` [doc|+|]++expected :: Node+expected = [doc| Section to *extract* -------------------- @@ -56,14 +62,34 @@ ea agam putant consectetuer sed. |]++spec :: Spec+spec = do+ specify "extractSection" $ do+ extractSection 2 (==) "Section to extract" source `shouldBe` expected+ extractSection 3 (==) "Section to extract" source `shouldNotBe` expected+ extractSection 2 (==) "section to extract" source `shouldNotBe` expected+ extractSection 3 (==) "section to extract" source `shouldNotBe` expected+ -- Case insensitivity+ extractSection 2 ciEq "Section to extract" source `shouldBe` expected+ extractSection 3 ciEq "Section to extract" source `shouldNotBe` expected+ extractSection 2 ciEq "section to extract" source `shouldBe` expected+ extractSection 3 ciEq "section to extract" source `shouldNotBe` expected specify "matchesHeading" $ do- [node|# Title|] `shouldSatisfy` matchesHeading 1 "Title"- [node|### Title|] `shouldSatisfy` matchesHeading 3 "Title"- [node|# Other title|] `shouldSatisfy` matchesHeading 1 "Other title"+ [node|# Title|] `shouldSatisfy` matchesHeading 1 (==) "Title"+ [node|### Title|] `shouldSatisfy` matchesHeading 3 (==) "Title"+ [node|# Other title|] `shouldSatisfy`+ matchesHeading 1 (==) "Other title" [node|# Complex *title*|] `shouldSatisfy`- matchesHeading 1 "Complex title"- [node|# Title|] `shouldNotSatisfy` matchesHeading 2 "Title"- [node|# Title|] `shouldNotSatisfy` matchesHeading 1 "Wrong title"+ matchesHeading 1 (==) "Complex title"+ [node|# Title|] `shouldNotSatisfy` matchesHeading 2 (==) "Title"+ [node|# Title|] `shouldNotSatisfy` matchesHeading 1 (==) "Wrong title"+ [node|# Title|] `shouldNotSatisfy` matchesHeading 1 (==) "title"+ -- Case insensitivity+ [node|# Title|] `shouldNotSatisfy` matchesHeading 1 (==) "title"+ [node|# Title|] `shouldSatisfy` matchesHeading 1 ciEq "title"+ [node|# Title|] `shouldNotSatisfy` matchesHeading 2 (==) "title"+ [node|# Title|] `shouldNotSatisfy` matchesHeading 2 ciEq "title" specify "flattenInlineNodes" $ do flattenInlineNodes [nodes|*Test* nodes.|] `shouldBe` "Test nodes." flattenInlineNodes [nodes|Testing multiple paragraphs.