diff --git a/README.md b/README.md index 4175c58..3129a20 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,10 @@ See the [About page](http://about.regex.uk) for details. The library and tutorial, tests and examples have been split across two packages: - * the `regex` package contains the regex library and + * the `regex` package contains the regex library with the Posix TDFA + back end + * the `regex-with-pcre` library package contains the extra modules + needed for the PCRE back end * the `regex-examples` package contains the tutorial, tests and example programs. @@ -44,7 +47,8 @@ two packages: - [X] 2017-03-13 v0.6.0.0 [Split out PCRE](https://github.com/iconnect/regex/milestone/7) - [X] 2017-03-13 v0.6.0.1 [Fix .travis.yml release-stack script](https://github.com/iconnect/regex/issues/67) - [X] 2017-03-15 v0.7.0.0 [Better organization of API](https://github.com/iconnect/regex/milestone/8) -- [ ] 2017-03-17 v0.8.0.0 [Add type-safe replacement templates and use TemplateHaskellQuotes](https://github.com/iconnect/regex/milestone/9) +- [X] 2017-03-16 v0.8.0.0 [Tidy up the API](https://github.com/iconnect/regex/milestone/10) +- [ ] 2017-03-18 v0.9.0.0 [Add type-safe replacement templates and use TemplateHaskellQuotes](https://github.com/iconnect/regex/milestone/9) - [ ] 2017-03-31 v1.0.0.0 [First stable release](https://github.com/iconnect/regex/milestone/3) - [ ] 2017-08-31 v2.0.0.0 [Fast text replacement with benchmarks](https://github.com/iconnect/regex/milestone/4) diff --git a/Text/RE.hs b/Text/RE.hs index 7fef1c6..e3a4610 100644 --- a/Text/RE.hs +++ b/Text/RE.hs @@ -9,7 +9,7 @@ module Text.RE ( - -- * Tutorial + -- * The Tutorial -- $tutorial -- * How to use this library @@ -98,14 +98,8 @@ import Text.RE.Types.Replace -- or indeed a good old-fashioned polymorphic operators? -- -- While we aim to provide all combinations of these choices, some of them --- are currently not available. We have: +-- are currently not available. In the regex package we have: -- --- * "Text.RE.PCRE" --- * "Text.RE.PCRE.ByteString" --- * "Text.RE.PCRE.ByteString.Lazy" --- * "Text.RE.PCRE.RE" --- * "Text.RE.PCRE.Sequence" --- * "Text.RE.PCRE.String" -- * "Text.RE.TDFA" -- * "Text.RE.TDFA.ByteString" -- * "Text.RE.TDFA.ByteString.Lazy" @@ -114,6 +108,16 @@ import Text.RE.Types.Replace -- * "Text.RE.TDFA.String" -- * "Text.RE.TDFA.Text" -- * "Text.RE.TDFA.Text.Lazy" +-- +-- The PCRE modules are contained in the separate @regex-with-pcre@ +-- package: +-- +-- * "Text.RE.PCRE" +-- * "Text.RE.PCRE.ByteString" +-- * "Text.RE.PCRE.ByteString.Lazy" +-- * "Text.RE.PCRE.RE" +-- * "Text.RE.PCRE.Sequence" +-- * "Text.RE.PCRE.String" -- $operators -- diff --git a/Text/RE/PCRE/ByteString.hs b/Text/RE/PCRE/ByteString.hs index a21ab93..9b85b0c 100644 --- a/Text/RE/PCRE/ByteString.hs +++ b/Text/RE/PCRE/ByteString.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.PCRE.ByteString -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.PCRE.RE ) where diff --git a/Text/RE/PCRE/ByteString/Lazy.hs b/Text/RE/PCRE/ByteString/Lazy.hs index b1c785d..54c8e7f 100644 --- a/Text/RE/PCRE/ByteString/Lazy.hs +++ b/Text/RE/PCRE/ByteString/Lazy.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.PCRE.ByteString.Lazy -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.PCRE.RE ) where diff --git a/Text/RE/PCRE/Sequence.hs b/Text/RE/PCRE/Sequence.hs index 7bef0f6..e88631f 100644 --- a/Text/RE/PCRE/Sequence.hs +++ b/Text/RE/PCRE/Sequence.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.PCRE.Sequence -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.PCRE.RE ) where diff --git a/Text/RE/PCRE/String.hs b/Text/RE/PCRE/String.hs index dcf6c48..f74bd6b 100644 --- a/Text/RE/PCRE/String.hs +++ b/Text/RE/PCRE/String.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.PCRE.String -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.PCRE.RE ) where diff --git a/Text/RE/TDFA/ByteString.hs b/Text/RE/TDFA/ByteString.hs index d5e7f88..1ca5cd3 100644 --- a/Text/RE/TDFA/ByteString.hs +++ b/Text/RE/TDFA/ByteString.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.TDFA.ByteString -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.TDFA.RE ) where diff --git a/Text/RE/TDFA/ByteString/Lazy.hs b/Text/RE/TDFA/ByteString/Lazy.hs index 049bd71..d231b28 100644 --- a/Text/RE/TDFA/ByteString/Lazy.hs +++ b/Text/RE/TDFA/ByteString/Lazy.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.TDFA.ByteString.Lazy -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.TDFA.RE ) where diff --git a/Text/RE/TDFA/Sequence.hs b/Text/RE/TDFA/Sequence.hs index e83f305..7d35afb 100644 --- a/Text/RE/TDFA/Sequence.hs +++ b/Text/RE/TDFA/Sequence.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.TDFA.Sequence -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.TDFA.RE ) where diff --git a/Text/RE/TDFA/String.hs b/Text/RE/TDFA/String.hs index 96a095c..f43b3ae 100644 --- a/Text/RE/TDFA/String.hs +++ b/Text/RE/TDFA/String.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.TDFA.String -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.TDFA.RE ) where diff --git a/Text/RE/TDFA/Text.hs b/Text/RE/TDFA/Text.hs index 5bf5ba8..425a2ee 100644 --- a/Text/RE/TDFA/Text.hs +++ b/Text/RE/TDFA/Text.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.TDFA.Text -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.TDFA.RE ) where diff --git a/Text/RE/TDFA/Text/Lazy.hs b/Text/RE/TDFA/Text/Lazy.hs index 04e01ba..7812b64 100644 --- a/Text/RE/TDFA/Text/Lazy.hs +++ b/Text/RE/TDFA/Text/Lazy.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE CPP #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# OPTIONS_GHC -fno-warn-duplicate-exports #-} +{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #endif @@ -21,8 +22,13 @@ module Text.RE.TDFA.Text.Lazy -- * The Toolkit -- $toolkit , module Text.RE - -- * The 'RE' Type + -- * The 'RE' Type and functions -- $re + , RE + , reSource + , compileRegex + , compileRegexWith + , escape , module Text.RE.TDFA.RE ) where diff --git a/Text/RE/TestBench.lhs b/Text/RE/TestBench.lhs index 83d1ed7..acbd265 100644 --- a/Text/RE/TestBench.lhs +++ b/Text/RE/TestBench.lhs @@ -34,6 +34,10 @@ module Text.RE.TestBench , formatMacroSource , testMacroDescriptors , mdRegexSource + -- * Parsers + , module Text.RE.TestBench.Parsers + -- * Text.RE + , module Text.RE ) where import Data.Array @@ -45,11 +49,9 @@ import Data.Ord import Data.String import Text.Printf import Prelude.Compat -import Text.RE.Types.Capture +import Text.RE +import Text.RE.TestBench.Parsers import Text.RE.Types.Options -import Text.RE.Types.Match -import Text.RE.Types.Matches -import Text.RE.Types.Replace \end{code} Types diff --git a/Text/RE/Tools.hs b/Text/RE/Tools.hs new file mode 100644 index 0000000..b304259 --- /dev/null +++ b/Text/RE/Tools.hs @@ -0,0 +1,40 @@ +module Text.RE.Tools + ( + -- * The Tools + -- $tools + + -- * Sed + sed + , sed' + -- * Grep + , grep + , grepLines + , GrepScript + , grepScript + , linesMatched + -- * Lex + , alex + , alex' + -- * IsRegex + , IsRegex(..) + -- * Edit + , Edits(..) + , Edit(..) + , LineEdit(..) + , applyEdits + , applyEdit + , applyLineEdit + -- * LineNo + , LineNo(..) + , firstLine + , getLineNo + , lineNo + -- * Text.RE + , module Text.RE + ) where + +import Text.RE +import Text.RE.Tools.Edit +import Text.RE.Tools.Grep +import Text.RE.Tools.Lex +import Text.RE.Tools.Sed diff --git a/Text/RE/Tools/Edit.lhs b/Text/RE/Tools/Edit.lhs index b37d943..86dccce 100644 --- a/Text/RE/Tools/Edit.lhs +++ b/Text/RE/Tools/Edit.lhs @@ -7,40 +7,50 @@ #endif module Text.RE.Tools.Edit - ( LineNo - , Edits(..) + ( Edits(..) , Edit(..) , LineEdit(..) , applyEdits , applyEdit , applyLineEdit + -- * LineNo + , LineNo(..) + , firstLine + , getLineNo + , lineNo + -- * Text.RE + , module Text.RE ) where import Data.Maybe import Prelude.Compat -import Text.RE.Types.Capture -import Text.RE.Types.Match -import Text.RE.Types.Matches +import Text.RE import Text.RE.Types.IsRegex import Text.RE.Types.LineNo -import Text.RE.Types.Replace +-- | an 'Edits' script will, for each line in the file, either perform +-- the action selected by the first RE in the list, or perform all of the +-- actions on line, arranged as a pipeline data Edits m re s = Select [(re,Edit m s)] | Pipe [(re,Edit m s)] +-- | each Edit action specifies how the match should be processed data Edit m s = Template s | Function Context (LineNo->Match s->Location->Capture s->m (Maybe s)) | LineEdit (LineNo->Matches s->m (LineEdit s)) +-- | a LineEdit is the most general action thar can be performed on a line +-- and is the only means of deleting a line data LineEdit s = NoEdit | ReplaceWith s | Delete deriving (Show) +-- | apply an 'Edit' script to a single line applyEdits :: (IsRegex re s,Monad m,Functor m) => LineNo -> Edits m re s @@ -50,6 +60,10 @@ applyEdits lno ez0 s0 = case ez0 of Select ez -> select_edit_scripts lno ez s0 Pipe ez -> pipe_edit_scripts lno ez s0 +-- | apply a single edit action to a line, the function in the first argument +-- being used to add a new line onto the end of the line where appropriate; +-- the function returns @Nothing@ if no edit is to be performed on the line, +-- @Just mempty@ to delete the line applyEdit :: (IsRegex re s,Monad m,Functor m) => (s->s) -> LineNo @@ -68,10 +82,14 @@ applyEdit anl lno re edit s = s' = anl s acs = matchMany re s +-- | apply a 'LineEdit' to a line, using the function in the first +-- argument to append a new line to the result; Nothing should be +-- returned if no edit is to be performed, @Just mempty@ to +-- delete the line applyLineEdit :: Monoid s => (s->s) -> LineEdit s -> Maybe s applyLineEdit _ NoEdit = Nothing applyLineEdit anl (ReplaceWith s) = Just $ anl s -applyLineEdit _ Delete = Just $ mempty +applyLineEdit _ Delete = Just mempty select_edit_scripts :: (IsRegex re s,Monad m,Functor m) => LineNo diff --git a/Text/RE/Tools/Grep.lhs b/Text/RE/Tools/Grep.lhs index dc2e859..bc759e0 100644 --- a/Text/RE/Tools/Grep.lhs +++ b/Text/RE/Tools/Grep.lhs @@ -5,15 +5,23 @@ {-# LANGUAGE CPP #-} module Text.RE.Tools.Grep - ( Line(..) - , grep + ( grep + , Line(..) , grepLines , GrepScript , grepScript + , report + , Verbosity(..) , linesMatched + -- * IsRegex + , IsRegex(..) + -- * LineNo + , LineNo(..) + , firstLine + , getLineNo + , lineNo + -- * Text.RE , module Text.RE - , module Text.RE.Types.IsRegex - , module Text.RE.Types.LineNo ) where import qualified Data.ByteString.Lazy.Char8 as LBS @@ -24,24 +32,32 @@ import Text.RE.Types.IsRegex import Text.RE.Types.LineNo +-- | operates a bit like classic @grep@ printing out the lines matched +grep :: IsRegex re LBS.ByteString => Verbosity -> re -> FilePath -> IO () +grep v rex fp = grepLines rex fp >>= putStr . report v + +-- | 'grepLines' returns a 'Line' for each line in the file, listing all +-- of the 'Matches' for that line data Line = Line - { getLineNumber :: LineNo - , getLineMatches :: Matches LBS.ByteString + { getLineNumber :: LineNo -- ^ the 'LineNo' for this line + , getLineMatches :: Matches LBS.ByteString -- ^ all the 'Matches' of the RE on this line } deriving (Show) -grep :: IsRegex re LBS.ByteString => re -> FilePath -> IO () -grep rex fp = grepLines rex fp >>= putStr . report - +-- | returns a 'Line' for each line in the file enumerating all of the +-- matches for that line. grepLines :: IsRegex re LBS.ByteString => re -> FilePath -> IO [Line] grepLines rex fp = grepScript [(rex,mk)] . LBS.lines <$> LBS.readFile fp where mk i mtchs = Just $ Line i mtchs +-- | a GrepScript lists RE-action associations, with the first RE to match +-- a line selecting the action to be executed on each line in the file type GrepScript re s t = [(re,LineNo -> Matches s -> Maybe t)] +-- | given a list of lines, apply the 'GrepScript' to each line of the file grepScript :: IsRegex re s => GrepScript re s t -> [s] -> [t] grepScript scr = loop firstLine where @@ -53,13 +69,26 @@ grepScript scr = loop firstLine Nothing -> choose i ln lns scr' Just t -> t : loop (succ i) lns -report :: [Line] -> String -report = unlines . map fmt . linesMatched +-- | generate a grep report from a list of 'Line' +report :: Verbosity -> [Line] -> String +report v = unlines . map fmt . linesMatched v where fmt Line{..} = printf "%05d %s" (getLineNo getLineNumber) $ LBS.unpack $ matchesSource getLineMatches -linesMatched :: [Line] -> [Line] -linesMatched = filter $ anyMatches . getLineMatches +-- | specifies whether to return the linss matched or missed +data Verbosity + = LinesMatched + | LinesNotMatched + deriving (Show,Eq,Ord) + +-- | given a 'velocity' flag filter out either the lines matched or not +-- matched +linesMatched :: Verbosity -> [Line] -> [Line] +linesMatched v = filter $ f . anyMatches . getLineMatches + where + f = case v of + LinesMatched -> id + LinesNotMatched -> not \end{code} diff --git a/Text/RE/Tools/Lex.lhs b/Text/RE/Tools/Lex.lhs index 0dc4f1f..01cfa85 100644 --- a/Text/RE/Tools/Lex.lhs +++ b/Text/RE/Tools/Lex.lhs @@ -4,8 +4,10 @@ module Text.RE.Tools.Lex ( alex , alex' + -- * IsRegex + , IsRegex(..) + -- * Text.RE , module Text.RE - , module Text.RE.Types.IsRegex ) where import Prelude.Compat @@ -13,9 +15,13 @@ import Text.RE import Text.RE.Types.IsRegex +-- | a simple regex-based scanner interpretter for prototyping +-- scanners alex :: IsRegex re s => [(re,Match s->Maybe t)] -> t -> s -> [t] alex = alex' matchOnce +-- | a higher order version of 'alex' parameterised over the @matchOnce@ +-- function alex' :: Replace s => (re->s->Match s) -> [(re,Match s->Maybe t)] diff --git a/Text/RE/Tools/Sed.lhs b/Text/RE/Tools/Sed.lhs index 0c59fc5..a7f87db 100644 --- a/Text/RE/Tools/Sed.lhs +++ b/Text/RE/Tools/Sed.lhs @@ -8,27 +8,38 @@ #endif module Text.RE.Tools.Sed - ( SedScript - , sed + ( sed , sed' + -- * IsRegex + , IsRegex(..) + -- * Edit + , Edits(..) + , Edit(..) + , LineEdit(..) + , applyEdits + , applyEdit + , applyLineEdit + -- * LineNo + , LineNo(..) + , firstLine + , getLineNo + , lineNo + -- * Text.RE , module Text.RE - , module Text.RE.Types.IsRegex - , module Text.RE.Tools.Edit - , module Text.RE.Types.LineNo ) where import qualified Data.ByteString.Lazy.Char8 as LBS import Prelude.Compat import Text.RE import Text.RE.Tools.Edit -import Text.RE.Types.LineNo import Text.RE.Types.IsRegex -type SedScript re = Edits IO re LBS.ByteString - +-- | read a file, apply an 'Edits' script to each line it and +-- write the file out again; "-" is used to indicate standard input +-- standard output as appropriate sed :: IsRegex re LBS.ByteString - => SedScript re + => Edits IO re LBS.ByteString -> FilePath -> FilePath -> IO () @@ -40,6 +51,7 @@ sed as i_fp o_fp = do ] write_file o_fp $ LBS.concat lns' +-- | apply an 'Edits' script to each line of the argument text sed' :: (IsRegex re a,Monad m,Functor m) => Edits m re a -> a diff --git a/changelog b/changelog index d3bd4cb..214e854 100644 --- a/changelog +++ b/changelog @@ -1,5 +1,8 @@ -*-change-log-*- +0.8.0.0 Chris Dornan 2017-03-16 + * Tidy up the API after recent reorganization (#76) + 0.7.0.0 Chris Dornan 2017-03-15 * Fix and extend Replace class (#74) * Better package organisation (#73) diff --git a/docs/Edit.html b/docs/Edit.html index ee67ea8..402b8ad 100644 --- a/docs/Edit.html +++ b/docs/Edit.html @@ -74,40 +74,50 @@

Text.RE.Tools.Edit

#endif module Text.RE.Tools.Edit - ( LineNo - , Edits(..) + ( Edits(..) , Edit(..) , LineEdit(..) , applyEdits , applyEdit , applyLineEdit + -- * LineNo + , LineNo(..) + , firstLine + , getLineNo + , lineNo + -- * Text.RE + , module Text.RE ) where import Data.Maybe import Prelude.Compat -import Text.RE.Types.Capture -import Text.RE.Types.Match -import Text.RE.Types.Matches +import Text.RE import Text.RE.Types.IsRegex import Text.RE.Types.LineNo -import Text.RE.Types.Replace +-- | an 'Edits' script will, for each line in the file, either perform +-- the action selected by the first RE in the list, or perform all of the +-- actions on line, arranged as a pipeline data Edits m re s = Select [(re,Edit m s)] | Pipe [(re,Edit m s)] +-- | each Edit action specifies how the match should be processed data Edit m s = Template s | Function Context (LineNo->Match s->Location->Capture s->m (Maybe s)) | LineEdit (LineNo->Matches s->m (LineEdit s)) +-- | a LineEdit is the most general action thar can be performed on a line +-- and is the only means of deleting a line data LineEdit s = NoEdit | ReplaceWith s | Delete deriving (Show) +-- | apply an 'Edit' script to a single line applyEdits :: (IsRegex re s,Monad m,Functor m) => LineNo -> Edits m re s @@ -117,6 +127,10 @@

Text.RE.Tools.Edit

Select ez -> select_edit_scripts lno ez s0 Pipe ez -> pipe_edit_scripts lno ez s0 +-- | apply a single edit action to a line, the function in the first argument +-- being used to add a new line onto the end of the line where appropriate; +-- the function returns @Nothing@ if no edit is to be performed on the line, +-- @Just mempty@ to delete the line applyEdit :: (IsRegex re s,Monad m,Functor m) => (s->s) -> LineNo @@ -135,10 +149,14 @@

Text.RE.Tools.Edit

s' = anl s acs = matchMany re s +-- | apply a 'LineEdit' to a line, using the function in the first +-- argument to append a new line to the result; Nothing should be +-- returned if no edit is to be performed, @Just mempty@ to +-- delete the line applyLineEdit :: Monoid s => (s->s) -> LineEdit s -> Maybe s applyLineEdit _ NoEdit = Nothing applyLineEdit anl (ReplaceWith s) = Just $ anl s -applyLineEdit _ Delete = Just $ mempty +applyLineEdit _ Delete = Just mempty select_edit_scripts :: (IsRegex re s,Monad m,Functor m) => LineNo diff --git a/docs/Grep.html b/docs/Grep.html index c731ab2..2e22b7d 100644 --- a/docs/Grep.html +++ b/docs/Grep.html @@ -72,15 +72,23 @@

Text.RE.Tools.Grep

{-# LANGUAGE CPP #-} module Text.RE.Tools.Grep - ( Line(..) - , grep + ( grep + , Line(..) , grepLines , GrepScript , grepScript + , report + , Verbosity(..) , linesMatched + -- * IsRegex + , IsRegex(..) + -- * LineNo + , LineNo(..) + , firstLine + , getLineNo + , lineNo + -- * Text.RE , module Text.RE - , module Text.RE.Types.IsRegex - , module Text.RE.Types.LineNo ) where import qualified Data.ByteString.Lazy.Char8 as LBS @@ -91,24 +99,32 @@

Text.RE.Tools.Grep

import Text.RE.Types.LineNo +-- | operates a bit like classic @grep@ printing out the lines matched +grep :: IsRegex re LBS.ByteString => Verbosity -> re -> FilePath -> IO () +grep v rex fp = grepLines rex fp >>= putStr . report v + +-- | 'grepLines' returns a 'Line' for each line in the file, listing all +-- of the 'Matches' for that line data Line = Line - { getLineNumber :: LineNo - , getLineMatches :: Matches LBS.ByteString + { getLineNumber :: LineNo -- ^ the 'LineNo' for this line + , getLineMatches :: Matches LBS.ByteString -- ^ all the 'Matches' of the RE on this line } deriving (Show) -grep :: IsRegex re LBS.ByteString => re -> FilePath -> IO () -grep rex fp = grepLines rex fp >>= putStr . report - +-- | returns a 'Line' for each line in the file enumerating all of the +-- matches for that line. grepLines :: IsRegex re LBS.ByteString => re -> FilePath -> IO [Line] grepLines rex fp = grepScript [(rex,mk)] . LBS.lines <$> LBS.readFile fp where mk i mtchs = Just $ Line i mtchs +-- | a GrepScript lists RE-action associations, with the first RE to match +-- a line selecting the action to be executed on each line in the file type GrepScript re s t = [(re,LineNo -> Matches s -> Maybe t)] +-- | given a list of lines, apply the 'GrepScript' to each line of the file grepScript :: IsRegex re s => GrepScript re s t -> [s] -> [t] grepScript scr = loop firstLine where @@ -120,15 +136,28 @@

Text.RE.Tools.Grep

Nothing -> choose i ln lns scr' Just t -> t : loop (succ i) lns -report :: [Line] -> String -report = unlines . map fmt . linesMatched +-- | generate a grep report from a list of 'Line' +report :: Verbosity -> [Line] -> String +report v = unlines . map fmt . linesMatched v where fmt Line{..} = printf "%05d %s" (getLineNo getLineNumber) $ LBS.unpack $ matchesSource getLineMatches -linesMatched :: [Line] -> [Line] -linesMatched = filter $ anyMatches . getLineMatches +-- | specifies whether to return the linss matched or missed +data Verbosity + = LinesMatched + | LinesNotMatched + deriving (Show,Eq,Ord) + +-- | given a 'velocity' flag filter out either the lines matched or not +-- matched +linesMatched :: Verbosity -> [Line] -> [Line] +linesMatched v = filter $ f . anyMatches . getLineMatches + where + f = case v of + LinesMatched -> id + LinesNotMatched -> not