packages feed

toodles 1.0.0 → 1.0.1

raw patch · 7 files changed

+132/−92 lines, 7 files

Files

README.md view
@@ -53,6 +53,14 @@ - 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) +#### Ignoring Files++Ignore as many files as you can! Large autogenerated files will slow Toodles+down quite a bit. Check the output of the server to see any files/folders that+may be causing slowness for your repo and add them to the `ignore` section your+`.toodles.yaml` If the performance of Toodles is not good enough for your use+case, please open an issue.+ ### Scanned Languages  These languages will be scanned for any TODO's:
app/Main.hs view
@@ -16,15 +16,16 @@ main :: IO () main = do   userArgs <- toodlesArgs >>= setAbsolutePath-  sResults <- runFullSearch userArgs   case userArgs of-    (ToodlesArgs _ _ _ _ True _) -> mapM_ (putStrLn . prettyFormat) $ todos sResults+    (ToodlesArgs _ _ _ _ True _) -> do+      sResults <- runFullSearch userArgs+      mapM_ (putStrLn . prettyFormat) $ todos sResults     _ -> do-          let webPort = fromMaybe 9001 $ port userArgs-          ref <- newIORef sResults-          dataDir <- (++ "/web") <$> getDataDir-          putStrLn $ "serving on " ++ show webPort-          run webPort $ app $ ToodlesState ref dataDir+      let webPort = fromMaybe 9001 $ port userArgs+      ref <- newIORef Nothing+      dataDir <- (++ "/web") <$> getDataDir+      putStrLn $ "serving on " ++ show webPort+      run webPort $ app $ ToodlesState ref dataDir  prettyFormat :: TodoEntry -> String prettyFormat (TodoEntryHead _ l a p n entryPriority f _ _ _ _ _ _) =
src/Server.hs view
@@ -1,7 +1,7 @@+{-# LANGUAGE BangPatterns        #-} {-# LANGUAGE DataKinds           #-} {-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE ScopedTypeVariables #-}- {-# LANGUAGE TypeOperators       #-}  module Server where@@ -67,13 +67,16 @@  showRawFile :: ToodlesState -> Integer -> Handler Html showRawFile (ToodlesState ref _) eId = do-    (TodoListResult r _) <- liftIO $ readIORef ref-    let entry = find (\t -> entryId t == eId) r-    liftIO $-        maybe-        (return "Not found")-        (\e -> addAnchors <$> readFile (sourceFile e))-        entry+    storedResults <- liftIO $ readIORef ref+    case storedResults of+      (Just (TodoListResult r _)) -> do+        let entry = find (\t -> entryId t == eId) r+        liftIO $+            maybe+            (return "Not found")+            (\e -> addAnchors <$> readFile (sourceFile e))+            entry+      Nothing -> error "no files to show"      where     addAnchors :: String -> Html@@ -87,17 +90,20 @@  editTodos :: ToodlesState -> EditTodoRequest -> Handler Text editTodos (ToodlesState ref _) req = do-  (TodoListResult r _) <- liftIO $ readIORef ref-  let editedList =-        map-          (\t ->-             if willEditTodo req t-               then editTodo req t-               else t)-          r-      editedFilteredList = filter (willEditTodo req) editedList-  _ <- mapM_ recordUpdates editedFilteredList-  return "{}"+  storedResults <- liftIO $ readIORef ref+  case storedResults of+    (Just (TodoListResult r _)) -> do+      let editedList =+            map+              (\t ->+                if willEditTodo req t+                  then editTodo req t+                  else t)+              r+          editedFilteredList = filter (willEditTodo req) editedList+      _ <- mapM_ recordUpdates editedFilteredList+      return "{}"+    Nothing -> error "no stored todos to edit"   where     willEditTodo :: EditTodoRequest -> TodoEntry -> Bool     willEditTodo editRequest entry = entryId entry `elem` editIds editRequest@@ -189,14 +195,17 @@  deleteTodos :: ToodlesState -> DeleteTodoRequest -> Handler Text deleteTodos (ToodlesState ref _) req = do-    refVal@(TodoListResult r _) <- liftIO $ readIORef ref-    let toDelete = filter (\t -> entryId t `elem` ids req) r-    liftIO $ doUntilNull removeAndAdjust toDelete-    let remainingResults = filter (\t -> entryId t `notElem` map entryId toDelete) r-    let updatedResults = foldl (flip adjustLinesAfterDeletionOf) remainingResults toDelete-    let remainingResultsRef = refVal { todos = updatedResults }-    _ <- liftIO $ atomicModifyIORef' ref (const (remainingResultsRef, remainingResultsRef))-    return "{}"+    storedResults <- liftIO $ readIORef ref+    case storedResults of+      (Just refVal@(TodoListResult r _)) -> do+        let toDelete = filter (\t -> entryId t `elem` ids req) r+        liftIO $ doUntilNull removeAndAdjust toDelete+        let remainingResults = filter (\t -> entryId t `notElem` map entryId toDelete) r+        let updatedResults = foldl (flip adjustLinesAfterDeletionOf) remainingResults toDelete+        let remainingResultsRef = refVal { todos = updatedResults }+        _ <- liftIO $ atomicModifyIORef' ref (const (Just remainingResultsRef, Just remainingResultsRef))+        return "{}"+      Nothing -> error "no stored todos"      where @@ -239,14 +248,17 @@     return $ args {directory = absolute}  getFullSearchResults :: ToodlesState -> Bool -> IO TodoListResult-getFullSearchResults (ToodlesState ref _) recompute =-  if recompute+getFullSearchResults (ToodlesState ref _) recompute = do+  result <- readIORef ref+  if recompute || isNothing result     then do       putStrLn "refreshing todo's"       userArgs <- toodlesArgs >>= setAbsolutePath       sResults <- runFullSearch userArgs-      atomicModifyIORef' ref (const (sResults, sResults))-    else putStrLn "cached read" >> readIORef ref+      atomicModifyIORef' ref (const (Just sResults, sResults))+    else do+      putStrLn "cached read"+      return $ fromMaybe (error "tried to read from the cache when there wasn't anything there") result  runFullSearch :: ToodlesArgs -> IO TodoListResult runFullSearch userArgs = do@@ -259,8 +271,8 @@         $ putStrLn $ "[WARNING] Invalid .toodles.yaml: " ++ show config     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+    parsedTodos <- concat <$> mapM (parseFileAndLog userArgs config') allFiles+    let filteredTodos = filter (filterSearch (assignee_search userArgs)) parsedTodos         resultList = limitSearch filteredTodos $ limit_results userArgs         indexedResults = map (\(i, r) -> r {entryId = i}) $ zip [1 ..] resultList     return $ TodoListResult indexedResults ""@@ -273,6 +285,14 @@     limitSearch :: [TodoEntry] -> Int -> [TodoEntry]     limitSearch todoList 0 = todoList     limitSearch todoList n = take n todoList++parseFileAndLog :: ToodlesArgs -> ToodlesConfig -> SourceFile -> IO [TodoEntry]+parseFileAndLog  userArgs config f = do+  -- the strictness is so we can print "done" when we're actually done+  !_ <- putStrLn $ fullPath f+  !result <- return (runTodoParser (userFlag userArgs ++ flags config) f)+  !_ <- putStrLn "done"+  return result  getAllFiles :: ToodlesConfig -> FilePath -> IO [SourceFile] getAllFiles (ToodlesConfig ignoredPaths _) basePath =
src/Types.hs view
@@ -23,7 +23,7 @@ type LineNumber = Integer  data ToodlesState = ToodlesState-  { results  :: IORef TodoListResult,+  { results  :: IORef (Maybe TodoListResult),     dataPath :: FilePath   } 
toodles.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: toodles-version: 1.0.0+version: 1.0.1 license: MIT license-file: LICENSE copyright: 2018 Avi Press
web/css/toodles.css view
@@ -67,15 +67,21 @@  .tag-block{     margin-top: .3em;+}++.tag-column {     max-width: 200px; } +.todo-item-customAttributes {+    max-width: 200px;+}+ .tag-item {-    /* background-color: #E9F1F7; */     background-color: #4F6D7A;     line-height: 2;     color: white;-    font-size: .75em;+    font-size: .66em;     margin-right: .2em;     padding: .3em;     text-align: center;@@ -101,7 +107,7 @@     margin-right: .2em;     padding: .3em;     line-height: 2;-    font-size: .75em;+    font-size: .66em; }  .priority-column {@@ -131,10 +137,6 @@  .is-active .navbar-item:hover {     background-color: #dbdbdb;-}--.top-div {-    overflow-x: scroll; }  .toodles-nav-title-text {
web/html/index.html view
@@ -39,7 +39,7 @@                     </div>                     <div class="navbar-item deselect-all" v-on:click="deselectAll" v-show="todos.length && todos.every(t => t.selected)">                         <span class="icon">-                           <i class="fa fa-square"></i>+                            <i class="fa fa-square"></i>                         </span>                         <span>Deselect All</span>                     </div>@@ -119,48 +119,57 @@                 </span>             </div>             <div class="main-container container content column is-three-quarters">-                <div class="loading-spinner" v-show="loading"><a class="button is-loading">Loading</a> Loading TODO's. If your project is large, this can take a few moments...</div>-                <table class="table todo-list is-striped is-hoverable">-                    <thead>-                        <tr>-                            <td></td>-                            <th v-on:click="sortTodos('priority')" class="sortable priority-column">-                                Priority-                                <span class="icon">-                                    <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 || (todo.flag || '').indexOf(todoSearch) !== -1" @change="updateTodo('top level')" @click="toggleTodo(todo)">-                        <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" @click="stopPropagation"><a :href="'/source_file/' + todo.id + '#line-' + todo.lineNumber" target="_blank">{{ todo.sourceFile }}:{{ todo.lineNumber}}</a></div>-                            <div>{{ todo.body }}</div>-                        </td>-                        <td class="todo-item-assignee" >{{ todo.assignee }}</td>-                        <td class="todo-item-customAttributes">-                            <div v-show="Object.keys(todo.customAttributes).length" class="attribute-block">-                                <span v-for="entry in Object.entries(todo.customAttributes)" class="attribute-item" @change="updateTodo('here')">-                                    <span >{{entry[0]}}</span>=<span >{{entry[1]}}</span>-                                </span>-                            </div>-                            <div class="tag-block" v-show="Object.keys(todo.tags).length">-                                <span v-for="tag in todo.tags" class="tag-item">-                                    <span >{{tag}}</span>-                                </span>-                            </div>-                        </td>-                    </tr>-                </table>+                <div class="loading-spinner" v-show="loading"><a class="button is-loading">Loading</a> Loading+                    TODO's. If your project is large, this can take a few moments.+                    Try configuring toodles to ignore large, autogenerated, or+                    third-party files.+                    <a target="_blank" href="https://github.com/aviaviavi/toodles/blob/master/.toodles.yaml">More info on configuring toodles</a>+                </div>+                <div class="box">+                    <div class="table-container">+                        <table class="table is-striped is-narrow is-hoverable is-fullwidth table-container todo-list">+                            <thead>+                                <tr>+                                    <td></td>+                                    <th v-on:click="sortTodos('priority')" class="sortable priority-column">+                                        Priority+                                        <span class="icon">+                                            <i class="fa fa-sort"></i>+                                        </span>+                                    </th>+                                    <th>Flag</th>+                                    <th class="todo-item-body">Body</th>+                                    <th>Assignee</th>+                                    <th class="todo-item-tags">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 || (todo.flag || '').indexOf(todoSearch) !== -1" @change="updateTodo('top level')" @click="toggleTodo(todo)">+                                <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" @click="stopPropagation"><a :href="'/source_file/' + todo.id + '#line-' + todo.lineNumber" target="_blank">{{ todo.sourceFile }}:{{ todo.lineNumber}}</a></div>+                                    <div>{{ todo.body }}</div>+                                </td>+                                <td class="todo-item-assignee" >{{ todo.assignee }}</td>+                                <td class="todo-item-customAttributes">+                                    <div v-show="Object.keys(todo.customAttributes).length" class="attribute-block">+                                        <span v-for="entry in Object.entries(todo.customAttributes)" class="attribute-item" @change="updateTodo('here')">+                                            <span >{{entry[0]}}</span>=<span >{{entry[1]}}</span>+                                        </span>+                                    </div>+                                    <div class="tag-block" v-show="Object.keys(todo.tags).length">+                                        <span v-for="tag in todo.tags" class="tag-item">+                                            <span >{{tag}}</span>+                                        </span>+                                    </div>+                                </td>+                            </tr>+                        </table>+                    </div>+                </div>             </div>         </div>     </div>