packages feed

toodles 0.1.0.16 → 0.1.1

raw patch · 10 files changed

+167/−61 lines, 10 files

Files

+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2018 Avi Press++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
@@ -51,6 +51,7 @@ Currently via config you can:  - Set files to ignore via a list of regular expressions+- Specify your own flags to scan for other than the built-ins (TODO, FIXME, XXX)  ### Scanned Languages 
app/Config.hs view
@@ -1,23 +1,34 @@-{-# LANGUAGE DeriveDataTypeable,-             DataKinds,-             OverloadedStrings,-             ScopedTypeVariables,-             TypeOperators #-}+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE DeriveDataTypeable  #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators       #-} -module Config where+module Config+  ( toodlesArgs+  , ToodlesArgs(..)+  , SearchFilter(..)+  , AssigneeFilterRegex(..)+  )+  where  import           Paths_toodles+import           Types  import           Data.Text              (Text) import           Data.Version           (showVersion) import           System.Console.CmdArgs +toodlesArgs :: IO ToodlesArgs+toodlesArgs = cmdArgs argParser+ data ToodlesArgs = ToodlesArgs   { directory       :: FilePath   , assignee_search :: Maybe SearchFilter   , limit_results   :: Int   , port            :: Maybe Int   , no_server       :: Bool+  , userFlag        :: [UserFlag]   } deriving (Show, Data, Typeable, Eq)  newtype SearchFilter =@@ -34,6 +45,7 @@           , limit_results = def &= help "Limit number of search results"           , port = def &= help "Run server on port"           , no_server = def &= help "Output matching todos to the command line and exit"+          , userFlag = def &= help "Additional flagword (e.g.: MAYBE)"           } &= summary ("toodles " ++ showVersion version)             &= program "toodles"             &= verbosity
app/Main.hs view
@@ -11,15 +11,14 @@ import           Data.Maybe               (fromMaybe) import qualified Data.Text                as T (unpack) import           Network.Wai.Handler.Warp (run)-import           System.Console.CmdArgs   (cmdArgs) import           Text.Printf              (printf)  main :: IO () main = do-  userArgs <- cmdArgs argParser >>= setAbsolutePath+  userArgs <- toodlesArgs >>= setAbsolutePath   sResults <- runFullSearch userArgs   case userArgs of-    (ToodlesArgs _ _ _ _ True) -> mapM_ (putStrLn . prettyFormat) $ todos sResults+    (ToodlesArgs _ _ _ _ True _) -> mapM_ (putStrLn . prettyFormat) $ todos sResults     _ -> do           let webPort = fromMaybe 9001 $ port userArgs           ref <- newIORef sResults@@ -28,12 +27,13 @@           run webPort $ app $ ToodlesState ref dataDir  prettyFormat :: TodoEntry -> String-prettyFormat (TodoEntryHead _ l a p n entryPriority _ _ _) =+prettyFormat (TodoEntryHead _ l a p n entryPriority f _ _ _) =   printf-    "Assignee: %s\n%s%s:%d\n%s"+    "Assignee: %s\n%s%s:%d\n%s - %s"     (fromMaybe "None" a)     (maybe "" (\x -> "Priority: " ++ show x ++ "\n") entryPriority)     p     n+    (show f)     (unlines $ map T.unpack l) prettyFormat (TodoBodyLine _) = error "Invalid type for prettyFormat"
app/Parse.hs view
@@ -63,6 +63,21 @@       entryTags = filter (T.isPrefixOf "#") dataTokens   in (assigneeTo, priorityVal, filteredDetails, entryTags) +-- | parse "hard-coded" flags, and user-defined flags if any+parseFlag :: [UserFlag] -> Parser Flag+parseFlag us = foldr (\a b -> b <|> foo a) (try parseFlagHardcoded) us+  where+    foo :: UserFlag -> Parser Flag+    foo (UserFlag x) = try (symbol x *> pure (UF $ UserFlag x))++-- | parse flags TODO, FIXME, XXX+parseFlagHardcoded :: Parser Flag+parseFlagHardcoded =+      try (symbol "TODO"  *> pure TODO )+  <|> try (symbol "FIXME" *> pure FIXME)+  <|>     (symbol "XXX"   *> pure XXX  )++ fileTypeToComment :: [(Text, Text)] fileTypeToComment =   [ (".c", "//")@@ -102,16 +117,16 @@   , (".yaml", "#")   ] -runTodoParser :: SourceFile -> [TodoEntry]-runTodoParser (SourceFile path ls) =+runTodoParser :: [UserFlag] -> SourceFile -> [TodoEntry]+runTodoParser us (SourceFile path ls) =   let parsedTodoLines =         map-          (\(lineNum, lineText) -> parseMaybe (parseTodo path lineNum) lineText)+          (\(lineNum, lineText) -> parseMaybe (parseTodo us path lineNum) lineText)           (zip [1 ..] ls)       groupedTodos = foldl foldTodoHelper ([], False) parsedTodoLines   in fst groupedTodos -    where+  where     -- fold fn to concatenate todos that a multiple, single line comments     foldTodoHelper :: ([TodoEntry], Bool) -> Maybe TodoEntry -> ([TodoEntry], Bool)     foldTodoHelper (todoEntries, currentlyBuildingTodoLines) maybeTodo@@ -124,7 +139,7 @@             (init todoEntries ++ [combineTodo (last todoEntries) (fromJust maybeTodo)], True)         | otherwise = (todoEntries, False) -            where+          where             isEntryHead :: TodoEntry -> Bool             isEntryHead TodoEntryHead {} = True             isEntryHead _                = False@@ -134,8 +149,8 @@             isBodyLine _                = False              combineTodo :: TodoEntry -> TodoEntry -> TodoEntry-            combineTodo (TodoEntryHead i b a p n entryPriority attrs entryTags entryLeadingText) (TodoBodyLine l) =-                TodoEntryHead i (b ++ [l]) a p n entryPriority  attrs entryTags entryLeadingText+            combineTodo (TodoEntryHead i b a p n entryPriority f attrs entryTags entryLeadingText) (TodoBodyLine l) =+                TodoEntryHead i (b ++ [l]) a p n entryPriority f attrs entryTags entryLeadingText             combineTodo _ _ = error "Can't combine todoEntry of these types"  getExtension :: FilePath -> Text@@ -162,15 +177,14 @@ unkownMarker :: Text unkownMarker = "UNKNOWN-DELIMETER-UNKNOWN-DELIMETER-UNKNOWN-DELIMETER" -parseTodo :: FilePath -> LineNumber -> Parser TodoEntry-parseTodo path lineNum = try parseTodoEntryHead-                     <|> parseComment (getExtension path)--    where-    parseTodoEntryHead :: Parser TodoEntry-    parseTodoEntryHead = do+parseTodo :: [UserFlag] -> FilePath -> LineNumber -> Parser TodoEntry+parseTodo us path lineNum = try (parseTodoEntryHead us)+                            <|> parseComment (getExtension path)+  where+    parseTodoEntryHead :: [UserFlag] -> Parser TodoEntry+    parseTodoEntryHead uf = do         entryLeadingText <- manyTill anyChar (prefixParserForFileType $ getExtension path)-        _ <- symbol "TODO"+        f <- parseFlag uf         entryDetails <- optional $ try (inParens $ many (noneOf [')', '(']))         let parsedDetails = parseDetails . T.pack <$> entryDetails             entryPriority = (readMaybe . T.unpack) =<< (snd4 =<< parsedDetails)@@ -187,6 +201,7 @@             path             lineNum             entryPriority+            f             otherDetails             entryTags             (T.pack entryLeadingText)
app/Server.hs view
@@ -26,7 +26,6 @@ import qualified Data.Yaml              as Y import           GHC.Generics           (Generic) import           Servant-import           System.Console.CmdArgs import           System.Directory import           System.IO.HVFS import qualified System.IO.Strict       as SIO@@ -37,8 +36,9 @@ import           Text.Printf import           Text.Regex.Posix -newtype ToodlesConfig = ToodlesConfig+data ToodlesConfig = ToodlesConfig   { ignore :: [FilePath]+  , flags  :: [UserFlag]   } deriving (Show, Generic, FromJSON)  app :: ToodlesState -> Application@@ -115,7 +115,7 @@   let comment =         fromJust $ lookup ("." <> getExtension (sourceFile t)) fileTypeToComment       detail =-        "TODO (" <>+        renderFlag (flag t) <> " (" <>         (T.pack $          Data.String.Utils.join            "|"@@ -129,7 +129,7 @@       mapHead (\l -> leadingText t <> l) $         mapInit (\l -> foldl (<>) "" [" " | _ <- [1..(T.length $ leadingText t)]] <> l) commented -    where+  where     mapHead :: (a -> a) -> [a] -> [a]     mapHead f (x:xs) = f x : xs     mapHead _ xs     = xs@@ -142,6 +142,12 @@     listIfNotNull "" = []     listIfNotNull s  = [s] +    renderFlag :: Flag -> Text+    renderFlag TODO                = "TODO"+    renderFlag FIXME               = "FIXME"+    renderFlag XXX                 = "XXX"+    renderFlag (UF (UserFlag x))   = x+ -- | Given a function to emit new lines for a given todo, write that update in -- place of the current todo lines updateTodoLinesInFile :: MonadIO m => (TodoEntry -> [Text]) -> TodoEntry -> m ()@@ -201,19 +207,19 @@         removeTodoFromCode = updateTodoLinesInFile (const [])  setAbsolutePath :: ToodlesArgs -> IO ToodlesArgs-setAbsolutePath toodlesArgs = do-    let pathOrDefault = if T.null . T.pack $ directory toodlesArgs+setAbsolutePath args = do+    let pathOrDefault = if T.null . T.pack $ directory args                             then "."-                            else directory toodlesArgs+                            else directory args     absolute <- normalise_path <$> absolute_path pathOrDefault-    return $ toodlesArgs {directory = absolute}+    return $ args {directory = absolute}  getFullSearchResults :: ToodlesState -> Bool -> IO TodoListResult getFullSearchResults (ToodlesState ref _) recompute =   if recompute     then do       putStrLn "refreshing todo's"-      userArgs <- cmdArgs argParser >>= setAbsolutePath+      userArgs <- toodlesArgs >>= setAbsolutePath       sResults <- runFullSearch userArgs       atomicModifyIORef' ref (const (sResults, sResults))     else putStrLn "cached read" >> readIORef ref@@ -224,11 +230,12 @@     configExists <- doesFileExist $ projectRoot ++ "/.toodles.yaml"     config <- if configExists         then Y.decodeFileEither (projectRoot ++ "/.toodles.yaml")-        else return . Right $ ToodlesConfig []+        else return . Right $ ToodlesConfig [] []     when (isLeft config)         $ putStrLn $ "[WARNING] Invalid .toodles.yaml: " ++ show config-    allFiles <- getAllFiles (fromRight (ToodlesConfig []) config) projectRoot-    let parsedTodos = concatMap runTodoParser allFiles+    let config' = fromRight (ToodlesConfig [] []) config+    allFiles <- getAllFiles config' projectRoot+    let parsedTodos = concatMap (runTodoParser $ userFlag userArgs ++ flags config') allFiles         filteredTodos = filter (filterSearch (assignee_search userArgs)) parsedTodos         resultList = limitSearch filteredTodos $ limit_results userArgs         indexedResults = map (\(i, r) -> r {entryId = i}) $ zip [1 ..] resultList@@ -244,7 +251,7 @@     limitSearch todoList n = take n todoList  getAllFiles :: ToodlesConfig -> FilePath -> IO [SourceFile]-getAllFiles (ToodlesConfig ignoredPaths) basePath =+getAllFiles (ToodlesConfig ignoredPaths _) basePath =   E.catch     (do putStrLn $ printf "Running toodles for path: %s" basePath         files <- recurseDir SystemFS basePath
app/Types.hs view
@@ -1,12 +1,19 @@-{-# LANGUAGE DeriveAnyClass,-             DeriveGeneric #-}+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE DeriveGeneric              #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}  module Types where -import Data.Aeson             (ToJSON, FromJSON)-import Data.IORef             (IORef)-import Data.Text              (Text)-import GHC.Generics           (Generic)+import           Data.Aeson       (FromJSON, ToJSON, Value (String), parseJSON,+                                   toJSON)+import           Data.Aeson.Types (typeMismatch)+import           Data.Data+import           Data.IORef       (IORef)+import           Data.String      (IsString)+import           Data.Text        (Text)+import qualified Data.Text        as T (unpack)+import           GHC.Generics     (Generic)  data SourceFile = SourceFile   { fullPath    :: FilePath@@ -27,20 +34,24 @@                   , sourceFile       :: FilePath                   , lineNumber       :: LineNumber                   , priority         :: Maybe Integer+                  , flag             :: Flag                   , customAttributes :: [(Text, Text)]                   , tags             :: [Text]                   , leadingText      :: Text }   | TodoBodyLine Text-  deriving (Show, Generic, ToJSON)+  deriving (Show, Generic)+instance ToJSON TodoEntry  data TodoListResult = TodoListResult   { todos   :: [TodoEntry]   , message :: Text-  } deriving (Show, Generic, ToJSON)+  } deriving (Show, Generic)+instance ToJSON TodoListResult  newtype DeleteTodoRequest = DeleteTodoRequest   { ids :: [Integer]-  } deriving (Show, Generic, FromJSON)+  } deriving (Show, Generic)+instance FromJSON DeleteTodoRequest  data EditTodoRequest = EditTodoRequest   { editIds     :: [Integer]@@ -48,4 +59,39 @@   , addTags     :: [Text]   , addKeyVals  :: [(Text, Text)]   , setPriority :: Maybe Integer-  } deriving (Show, Generic, FromJSON)+  } deriving (Show, Generic)+instance FromJSON EditTodoRequest++data Flag = TODO | FIXME | XXX | UF UserFlag+  deriving (Generic)++newtype UserFlag = UserFlag Text+  deriving (Show, Eq, IsString, Data, Generic)++instance Show Flag where+  show TODO              = "TODO"+  show FIXME             = "FIXME"+  show XXX               = "XXX"+  show (UF (UserFlag x)) = T.unpack x++instance ToJSON Flag where+  toJSON TODO              = Data.Aeson.String "TODO"+  toJSON FIXME             = Data.Aeson.String "FIXME"+  toJSON XXX               = Data.Aeson.String "XXX"+  toJSON (UF (UserFlag x)) = Data.Aeson.String x++instance FromJSON Flag where+  parseJSON (Data.Aeson.String x) =+    case x of+      "TODO"  -> pure TODO+      "FIXME" -> pure FIXME+      "XXX"   -> pure XXX+      _       -> pure $ UF $ UserFlag x+  parseJSON invalid               = typeMismatch "UserFlag" invalid++instance ToJSON UserFlag where+  toJSON (UserFlag x) = Data.Aeson.String x++instance FromJSON UserFlag where+  parseJSON (Data.Aeson.String x) = pure $ UserFlag x+  parseJSON invalid               = typeMismatch "UserFlag" invalid
toodles.cabal view
@@ -1,7 +1,8 @@-cabal-version: >=1.10+cabal-version: 1.12 name: toodles-version: 0.1.0.16+version: 0.1.1 license: MIT+license-file: LICENSE copyright: 2018 Avi Press maintainer: mail@avi.press author: Avi Press@@ -13,16 +14,16 @@ category: Project Management build-type: Simple data-files:+    web/js/app.js+    web/js/jquery-3.3.1.min.js+    web/js/vue.js+    web/html/index.html     web/css/bulma.min.css     web/css/font-awesome.min.css     web/css/toodles.css     web/fonts/fontawesome-webfont.woff     web/fonts/fontawesome-webfont.woff2-    web/html/index.html     web/img/favicon.png-    web/js/app.js-    web/js/jquery-3.3.1.min.js-    web/js/vue.js extra-source-files:     README.md @@ -41,7 +42,8 @@         Types         Paths_toodles     default-language: Haskell2010-    ghc-options: -threaded -rtsopts -O3 -Wall -with-rtsopts=-N+    ghc-options: -Wall -Wcompat -threaded -rtsopts -O3 -Wall+                 -with-rtsopts=-N     build-depends:         MissingH >=1.4.0.1 && <1.5,         aeson ==1.3.1.1,
web/html/index.html view
@@ -124,16 +124,18 @@                                     <i class="fa fa-sort"></i>                                 </span>                             </th>+                            <th>Flag</th>                             <th class="todo-item-body">Body</th>                             <th>Assignee</th>                             <th>Tags</th>                         </tr>                     </thead>-                    <tr class="todo-item" v-for="todo in todos" v-if="todo.body.indexOf(todoSearch) !== -1 || (todo.assignee || '').indexOf(todoSearch) !== -1 || (todo.tags || []).toString().indexOf(todoSearch) !== -1" @change="updateTodo('top level')">+                    <tr class="todo-item" v-for="todo in todos" v-if="todo.body.indexOf(todoSearch) !== -1 || (todo.assignee || '').indexOf(todoSearch) !== -1 || (todo.tags || []).toString().indexOf(todoSearch) !== -1 || (todo.flag || '').indexOf(todoSearch) !== -1" @change="updateTodo('top level')">                         <td><input type="checkbox" v-model="todo.selected"></td>                         <td class="todo-item-priority" >                             <div v-show="todo.priority !== undefined">{{ todo.priority }}</div>                         </td>+                        <td class="todo-item-flag" >{{ todo.flag }}</td>                         <td class='todo-item-body'>                             <div class="todo-source-link"><a :href="'/source_file/' + todo.id + '#line-' + todo.lineNumber" target="_blank">{{ todo.sourceFile }}:{{ todo.lineNumber}}</a></div>                             <div>{{ todo.body }}</div>
web/js/app.js view
@@ -33,18 +33,19 @@               this.todos = data.todos.map(t => {                 return {                   id: t.entryId,-                  assignee: t.assignee,                   body: t.body.join("\n"),-                  lineNumber: t.lineNumber,+                  assignee: t.assignee,                   sourceFile: t.sourceFile,+                  lineNumber: t.lineNumber,                   priority: t.priority,-                  tags: t.tags,+                  flag: t.flag,                   customAttributes: t.customAttributes.reduce((acc, curr) => {                     console.log(acc, curr)                     acc[curr[0]] = curr[1]                     console.log(acc, curr)                     return acc                   }, {}),+                  tags: t.tags,                   selected: false                 }               })@@ -236,4 +237,3 @@     }   }) })-