lentil 0.2.0.1 → 1.0.0.0
raw patch · 10 files changed
+222/−112 lines, 10 filesdep +pipesdep +terminal-progress-bardep +text
Dependencies added: pipes, terminal-progress-bar, text
Files
- changes.txt +8/−0
- issues.txt +34/−23
- lentil.cabal +5/−3
- src/Lentil/Args.hs +2/−2
- src/Lentil/File.hs +31/−12
- src/Lentil/Helpers.hs +6/−1
- src/Lentil/Parse/Run.hs +90/−33
- src/Lentil/Parse/Syntaxes.hs +36/−25
- src/Main.hs +3/−3
- test/Lentil/Parse/RunSpec.hs +7/−10
changes.txt view
@@ -1,3 +1,11 @@+1.0.0.0+-------++- Released Fri 02 Sep 2016 16:03:29 CEST+- Fixed command-line documentation+- Fixed "crash on wrong encoding" error+- Added progress bar for big (>100 source files) projects+ 0.2.0.1 -------
issues.txt view
@@ -8,36 +8,34 @@ 14 symlinks? [feature:intermediate] 15 check --output pretty, there are trailing white spaces [bug] [u:1] 16 test con 7.6.3 [feature:basic] [test]- 17 linux kernel e darcs, lentil si inceppa su dei caratteri [bug]- [2016]- 18 autoignore non-text files? (binary, images, bloom filter) [2016]- 19 da cabal a hpack [u:1] [feature:advanced]- 20 sm: issue numbers is valuable [design] [request]- 21 sm: have a way to link to discussion/history of issue [design]+ 17 autoignore non-text files? (binary, images, bloom filter) [2016]+ 18 da cabal a hpack [u:1] [feature:advanced]+ 19 sm: issue numbers is valuable [design] [request]+ 20 sm: have a way to link to discussion/history of issue [design] [request]- 22 sm: 1. lentil autogenerates numbers where missing adding tags, 2.+ 21 sm: 1. lentil autogenerates numbers where missing adding tags, 2. creates an associated numbered file in .issues/, displays associated notes written in those files is asked, 3. even update them when there is a source change. (4) these files could be webserved when they want something linkable. Vedi comments in doc/dev/issues.txt [design] [request]- 28 chickpea, lentil's brother. Two commands, add number to numberless+ 27 chickpea, lentil's brother. Two commands, add number to numberless tag (#1212 or something), create a mini db with those issues, which automatically updated and you can even write stuff in there. O maybe you can even add lentil, chickpea and quinoa. Vedi more in doc/dev/issues.txt [design]- 34 make it lazy in ouputting todos [refactor]- 35 way to 'group' (section) output by tag [feature:advanced]- 36 win (and mac?) builds [package] [u:3] [2016]- 37 Henning: don't output nothing on lentil xxx.cabal (maybe add 19+ 33 make it lazy in ouputting todos [refactor]+ 34 way to 'group' (section) output by tag [feature:advanced]+ 35 win (and mac?) builds [package] [u:3] [2016]+ 36 Henning: don't output nothing on lentil xxx.cabal (maybe add 19 skipped?) [request] [2016]- 38 code coverage [test]- 39 add .lentilignore (or even .lentilconf) Michał Antkiewicz+ 37 code coverage [test]+ 38 add .lentilignore (or even .lentilconf) Michał Antkiewicz [feature:intermediate] [request]- 41 + 40 https://blog.steve.org.uk/If_line_noise_is_a_program__all_fuzzers_are_developers.html in lentil? [debug] [u:2]- 42 parsing with http://awgn.github.io/cgrep/ [design]+ 41 parsing with http://awgn.github.io/cgrep/ [design] src/Lentil/Args.hs 26 disambiguation optparse-applicative [feature:intermediate]@@ -51,7 +49,9 @@ 41 not using canonised paths because it is extremely slow on big repositories (like darcs). Explore different possibilities (conduit, new Filepath, unix program). [u:2] [duct]- 61 combine funziona su windows? [feature:intermediate]+ 52 apparently toListM is not idiomatic [refactor] [duct]+ 66 use pipes-files when released [feature:intermediate]+ 77 combine funziona su windows? [feature:intermediate] src/Lentil/Parse/Issue.hs 30 "feature" flagword could (in theory) clash with a free-text comment@@ -60,16 +60,27 @@ .lentil dotfile [design] [u:2] [bug] src/Lentil/Parse/Run.hs- 27 hGetContents: invalid argument (invalid byte sequence) [fixme]- [u:3] [2016]- 33 a function String -> [Issue]- 70 change '\n' trick [refactor] [duct]+ 58 a function String -> [Issue]+ 80 personally i don't like when the leading character of the progress+ bar is different [feeback] [request]+ 97 sicuramente c'è un modo più elegante e breve [refactor] [duct] src/Lentil/Parse/Syntaxes.hs- 31 add langparsers che sia estensibile e leggibile a compilazione+ 33 add langparsers che sia estensibile e leggibile a compilazione [u:2] [feature:intermediate]- 56 multiline signature? [lint]+ 60 multiline signature? [lint] src/Main.hs 41 leave sort out as now? [design] 58 o ord? [fixme]+ +test/Lentil/ArgsSpec.hs+ 37 real parsing testing options [test]+ +test/Lentil/FileSpec.hs+ 38 excluding files fails on MS Windows! Check why! [u:3] [bug]+ +test/Tests.hs+ 4 + http://hackage.haskell.org/package/mockery-0.3.0/docs/Test-Mockery-Directory.html+ instead of folder use this? [refactor]
lentil.cabal view
@@ -1,5 +1,5 @@ name: lentil-version: 0.2.0.1+version: 1.0.0.0 synopsis: frugal issue tracker description: minumum effort, cohesive issue tracker based on ubiquitous @TODO@s and @FIXME@s conventions.@@ -48,7 +48,8 @@ build-depends: base==4.*, optparse-applicative==0.13.*, regex-tdfa==1.2.*, natural-sort==0.1.*, parsec==3.1.*, filepath==1.4.*, directory==1.2.*, filemanip==0.3.*,- ansi-wl-pprint==0.6.*, csv==0.1.*+ ansi-wl-pprint==0.6.*, csv==0.1.*, pipes==4.2.*,+ terminal-progress-bar==0.0.*, text==1.2.* other-modules: Lentil.Types, Lentil.Args, Lentil.File, Lentil.Print, Lentil.Query, Lentil.Export, Lentil.Parse.Source, Lentil.Parse.Issue Lentil.Parse.Syntaxes,@@ -64,7 +65,8 @@ build-depends: base==4.*, optparse-applicative==0.13.*, regex-tdfa==1.2.*, natural-sort==0.1.*, parsec==3.1.*, filepath==1.4.*, directory==1.2.*, filemanip==0.3.*,- ansi-wl-pprint==0.6.*, csv==0.1.*+ ansi-wl-pprint==0.6.*, csv==0.1.*, pipes==4.2.*,+ terminal-progress-bar==0.0.*, text==1.2.* -- same as above, plus hspec , hspec==2.2.* other-modules: Lentil.Types, Lentil.Args, Lentil.File, Lentil.Print,
src/Lentil/Args.hs view
@@ -80,8 +80,8 @@ alias = option (str >>= parseAlias) ( short 'a' <> metavar "ALIAS" <>- help ("extension alias (e.g.: -a cpp" ++ aliasSign ++- "d)") )+ help ("extension alias (e.g.: -a d" ++ aliasSign +++ "cpp)") ) where parseAlias :: String -> ReadM (Maybe Alias) parseAlias s = return (aliasp s)
src/Lentil/File.hs view
@@ -10,20 +10,19 @@ module Lentil.File where +import Lentil.Helpers import Lentil.Types import Lentil.Parse.Run+import Lentil.Parse.Syntaxes import System.FilePath import System.FilePath.Find import Data.Monoid import Control.Applicative+import Pipes import qualified Data.List as L---- import Data.Either--- import System.Directory--- import Control.Exception.Base-+import qualified Pipes.Prelude as PP --------------- -- INSTANCES --@@ -43,22 +42,42 @@ -- (conduit, new Filepath, unix program). [u:2] [duct] findIssues :: [Alias] -> [FilePath] -> [FilePath] -> IO [Issue]-findIssues as is xs = mapM fc is >>= (issueFinder as) . concat+findIssues as fps xs =+ (fmap concat $ PP.toListM+ (prodFilePaths fps xs as >-> issLoop)) >>= \r ->+ perrEph "\r" >> -- clean progress bar+ return r+ where issLoop = issueFinder as >> issLoop+ -- todo: [refactor] [duct] apparently toListM is not idiomatic++-- Filepaths to be parsed, as a Producer+prodFilePaths :: [FilePath] -> [FilePath] ->+ [Alias] -> Producer FilePathC IO ()+prodFilePaths fps xs as = liftIO (fmap concat (mapM fc fps)) >>= \is ->+ let is' = zip3 is [1..] (repeat $ length is) in+ each is' where- fc i = find recPred (findClause (xs' i)) i+ fc i = find recPred (findClause (xs' i) as) i -- search pattern xs' "." = map (combine ".") xs -- trick to exclude on '.' xs' _ = xs --- fp to exclude, clause-findClause :: [FilePath] -> FindClause Bool-findClause x = let xc = mconcat $ map fp2fc x- in fileType ==? RegularFile &&?- (not <$> fmap getAny xc)+ -- TODO: use pipes-files when released [feature:intermediate]++-- fp to exclude, clause (+ aliases, to include)+findClause :: [FilePath] -> [Alias] -> FindClause Bool+findClause xs as = let xc = mconcat $ map fp2fc xs+ in fileType ==? RegularFile &&?+ extCheck &&?+ (not <$> fmap getAny xc) where fp2fc :: FilePath -> FindClause Any fp2fc f = Any . L.isPrefixOf f <$> filePath -- TODO: combine funziona su windows? [feature:intermediate]++ extCheck = (fmap getAny . mconcat)+ (map (fmap Any . (extension ==?)) (extensionList as))+ -- recursion predicate: excludes dot ('.') or _ folders
src/Lentil/Helpers.hs view
@@ -18,9 +18,14 @@ import Control.Applicative hiding ( (<|>), optional, many ) import Prelude -- 7.8 hack --- output errors+-- output errors (to stderr) perr :: String -> IO () perr cs = I.hPutStrLn I.stderr cs++-- output errors (to stderr), but without newline *and* calling /r+-- (erase what's before) first+perrEph :: String -> IO ()+perrEph cs = I.hPutStr I.stderr ("\r" ++ cs) -------------
src/Lentil/Parse/Run.hs view
@@ -7,6 +7,7 @@ -- Parsing functions interface ----------------------------------------------------------------------------- +{-# LANGUAGE FlexibleContexts #-} module Lentil.Parse.Run where @@ -17,63 +18,119 @@ import Lentil.Parse.Syntaxes import Text.Parsec+import Pipes import Control.Applicative hiding (many, (<|>))+ import qualified System.Directory as D+import qualified Data.Functor.Identity as I+import qualified System.ProgressBar as PB+import qualified Control.Monad as CM+import qualified Data.Text as T+import qualified Data.Text.IO as TI+import qualified Control.Exception as E import Prelude -- 7.8 hack +-----------+-- TYPES --+----------- --- fixme: hGetContents: invalid argument (invalid byte sequence) [u:3] [2016]+type Cur = Int+type Tot = Int+type FilePathC = (FilePath, Cur, Tot) --- main function with wich to parse issues; errors on stderr-issueFinder :: [Alias] -> [FilePath] -> IO [Issue]-issueFinder as fps = fmap concat (mapM (fileParser as) fps) +++issueFinder :: [Alias] -> Pipe FilePathC [Issue] IO ()+issueFinder as = fpExist >->+ fp2par as >->+ fp2comm >->+ cms2iss+ where+ -- comm2Issues accepts Comment, we need [Comment]+ cms2iss = await >>= \(fp, cs) ->+ let tra = zip (repeat fp) cs in+ each tra >->+ comm2Issues+ -- todo a function String -> [Issue] (w/o IO) [debug] [refactor] --------------------- ANCILLARIES --------------------+-----------+-- PIPES --+----------- --- errors to stderr-fileParser :: [Alias] -> FilePath -> IO [Issue]-fileParser as fp = D.doesFileExist fp >>= \fb ->+-- file exist check+fpExist :: Pipe FilePathC FilePath IO ()+fpExist = await >>= \(fp, k, t) ->+ pbe k t >>+ liftIO (D.doesFileExist fp) >>= \fb ->+ if fb == False+ then liftIO (perr $ fp ++ " : no such file")+ else yield fp+ where+ fi i = fromIntegral i+ lbl t = show t ++ " source files"+ pb k t = PB.mkProgressBar (PB.msg $ lbl t)+ PB.percentage 40 (fi k) (fi t)+ pbe k t = CM.when (mod k 30 == 0 && t > 100)+ (liftIO (perrEph $ pb k t)) - -- file exists- if fb == False- then perr (fp ++ " : no such file") >> return []- else+ -- todo: <qptain> personally i don't like when the leading+ -- character of the progress bar is different [feeback]+ -- [request] - -- parser exists- case langParserAlias as fp of- Nothing -> return [] -- no error just empy list- Just p -> readFile fp >>=- runParIO p fp >>=- parIssues fp . comms2Tuple+-- pick appropriate parser (if exists)+fp2par :: [Alias] -> Pipe FilePath+ (FilePath, ParSource [Comment]) IO ()+fp2par as = await >>= \fp ->+ case langParserAlias as fp of+ Nothing -> return ()+ Just p -> yield (fp, fmap comms2Tuple p) +-- Parse raw comments+fp2comm :: Pipe (FilePath, ParSource [Comment]) (FilePath, [Comment]) IO ()+fp2comm = await >>= \(fp, p) ->+ liftIO (safeRead fp) >>= \t -> + (runParPipe p fp t >-> -- todo: sicuramente c'è un modo più elegante+ (await >>= \r -> -- e breve. Ah! quando mettono le+ -- tuples section! [refactor] [duct]+ yield (fp, r))) --- generic parsing --+comm2Issues :: Pipe (FilePath, Comment) [Issue] IO ()+comm2Issues = await >>= \(fp, (r, i)) ->+ runParPipe (setRow r >> issues)+ fp ('\n':i) >>+ comm2Issues -- needed or will pick just head issue -runParIO :: Parsec String () [a] -> FilePath -> String -> IO [a]-runParIO p fp t = case runParser p () fp t of- Left l -> perr (fp ++ " : parse error " ++- show l) >> return []- Right r -> return r --- issue parsing --+-----------------+-- ANCILLARIES --+----------------- -parIssues :: FilePath -> [Comment] -> IO [Issue]-parIssues fp cs = concat <$> mapM (parIssue fp) cs+-- generic parsing -- --- todo change '\n' trick [refactor] [duct]--- why '\n'? see setRow comment-parIssue :: FilePath -> Comment -> IO [Issue]-parIssue fp (r, t) = runParIO (setRow r >> issues) fp ('\n':t)+runParPipe :: (Stream i I.Identity t) => Parsec i () o ->+ FilePath -> i ->+ Pipe ip o IO ()+runParPipe p fp i = case runParser p () fp i of+ Left l -> liftIO (perr $ fp ++ " : parse error " +++ show l)+ Right r -> yield r +-- issue parsing --+ -- why (r-1)? Every TODO must start on a newline, so we have to add a top -- '\n' in case there immediately is one setRow :: Row -> ParIssue () setRow r = getPosition >>= setPosition . flip setSourceLine (r-1) +safeRead :: FilePath -> IO String+safeRead fp = E.try (TI.readFile fp) >>= \e ->+ case e of+ Right t -> return (T.unpack t)+ Left x -> perr (fp ++ " : " ++ show (x :: E.IOException) +++ " -- ignoring file") >>+ return ""
src/Lentil/Parse/Syntaxes.hs view
@@ -18,41 +18,45 @@ import Prelude import qualified System.FilePath as SF--import Data.Char (toLower)+import qualified Data.Char as C +type MaybePar = Maybe (ParSource [CommentString]) -- as langParser, with alias added-langParserAlias :: [Alias] -> String -> Maybe (ParSource [CommentString])+langParserAlias :: [Alias] -> String -> MaybePar langParserAlias as fp = maybe (langParser fp) langParser (lookup ext as)- where ext = map toLower (SF.takeExtension fp)+ where ext = map C.toLower (SF.takeExtension fp) +extensionList :: [Alias] -> [String]+extensionList as = concatMap fst languages ++ map fst as -- TODO: add langparsers che sia estensibile e leggibile -- a compilazione [u:2] [feature:intermediate] -langParser :: String -> Maybe (ParSource [CommentString])-langParser fp | ext `elem` [".hs", ".lhs",- ".hsc", ".chs" ] = Just haskell- | ext `elem` [".cabal"] = Just haskell -- cabal- | ext `elem` [".elm"] = Just haskell -- Elm- | ext `elem` [".c", ".h"] = Just c- | ext `elem` [".cpp", ".hpp"] = Just c -- C++- | ext `elem` [".java"] = Just c -- Java- | ext `elem` [".js"] = Just javascript- | ext `elem` [".ts"] = Just javascript -- TypeScript- | ext `elem` [".pas", ".pp", ".inc"] = Just pascal- | ext `elem` [".py"] = Just python- | ext `elem` [".coffee"] = Just python -- CoffeeScript- | ext `elem` [".rb"] = Just ruby- | ext `elem` [".pl", ".pm", ".t"] = Just perl- | ext `elem` [".sh"] = Just perl -- shell- | ext `elem` [".nix"] = Just nix- | ext `elem` [".xml", ".html"] = Just xml- | ext `elem` [".txt"] = Just text- | otherwise = Nothing- where ext = map toLower (SF.takeExtension fp)+langParser :: String -> MaybePar+langParser fp = lookupExt languages ext+ where ext = map C.toLower (SF.takeExtension fp) +languages :: [([String], MaybePar)]+languages = [ ([".hs", ".lhs",+ ".hsc", ".chs" ], Just haskell),+ ([".cabal"], Just haskell), -- cabal+ ([".elm"], Just haskell), -- Elm+ ([".c", ".h"], Just c),+ ([".cpp", ".hpp"], Just c), -- C+++ ([".java"], Just c), -- Java+ ([".js"], Just javascript),+ ([".ts"], Just javascript), -- TypeScript+ ([".pas", ".pp", ".inc"], Just pascal),+ ([".py"], Just python),+ ([".coffee"], Just python), -- CoffeeScript+ ([".rb"], Just ruby),+ ([".pl", ".pm", ".t"], Just perl),+ ([".sh"], Just perl), -- shell+ ([".nix"], Just nix),+ ([".xml", ".html"], Just xml),+ ([".txt"], Just text) ]+ -- todo multiline signature? [lint] haskell, c, javascript, pascal, python, ruby :: ParSource [CommentString] perl, nix :: ParSource [CommentString]@@ -77,4 +81,11 @@ xml = source $ ParSyntax [] [("<!--", "-->")] ClangLike ['"', '\''] [] text = (:[]) . MultiLine 1 <$> many anyChar++-- ANCILLARIES --++lookupExt :: [([String], MaybePar)] -> String -> MaybePar+lookupExt [] _ = Nothing+lookupExt ((ss,p):ds) e | elem e ss = p+ | otherwise = lookupExt ds e
src/Main.hs view
@@ -11,9 +11,9 @@ import Data.Monoid -- 7.8 import qualified System.IO as I - main :: IO ()-main = execParser opts >>= runLentil+main = I.hSetBuffering I.stderr I.NoBuffering >> -- b/c progress bar+ execParser opts >>= runLentil where opts = info (helpOvert <*> lOpts <* version) ( fullDesc <> header "lentil - frugal issue tracker" )@@ -28,7 +28,7 @@ short 'v' <> help "show version and copyright info" ) where- versionCopy = "\nlentil - frugal issue tracker, version 0.2.0.1\n\+ versionCopy = "\nlentil - frugal issue tracker, version 1.0.0.0\n\ \(C) 2015-2016 Francesco Ariis - http://www.ariis.it\n\ \released under the GNU General Public License v3\n"
test/Lentil/Parse/RunSpec.hs view
@@ -1,12 +1,15 @@ module Lentil.Parse.RunSpec where import Test.Hspec+import Pipes import Text.Parsec ( runParser ) import Lentil.Types import Lentil.Parse.Run import Lentil.Parse.Source +import qualified Pipes.Prelude as PP+ import Prelude -- 7.8 hack -- Parsing tests@@ -17,6 +20,9 @@ (runParser p () fp cs) where fp = "<f>" +fileParser :: [Alias] -> FilePath -> IO [Issue]+fileParser as fp = fmap concat (PP.toListM $ yield (fp, 0, 0) >-> issLoop)+ where issLoop = issueFinder as >> issLoop main :: IO () main = hspec spec@@ -31,7 +37,7 @@ Issue fp 8 (Just "block1") [], Issue fp 9 (Just "block2") [Tag "tog"]] - describe "commentParser - specific" $ do+ describe "issueFinder - specific" $ do it "doesn't parse contiguous line/block as a single issue" $ fileParser [] "test/test-files/specific/contiguous.c" `shouldReturn` [Issue "test/test-files/specific/contiguous.c" 1@@ -77,13 +83,4 @@ it "parses a .xyz file as if it were a .c file" $ fileParser [(".xyz", ".c")] "test/test-files/lang-comm/xyz.xyz" `shouldReturn` spt "test/test-files/lang-comm/xyz.xyz"-- describe "issueFinder" $ do- it "reads a file (code or txt) for issues" $- let fp = "test/test-files/lang-comm/test.txt" in- issueFinder [] [fp] >>= \i ->- i `shouldBe` [Issue fp 1 (Just "palla") [],- Issue fp 3 (Just "beta") [Tag "fixme"],- Issue fp 4 (Just "gamma") [Tag "xxx"],- Issue fp 6 (Just "qqq") [Tag "fixme", Tag "bug"]]