From 9b3151d3eee1dd534f990e5fb0e3151d383fd393 Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Thu, 20 Nov 2025 13:59:39 -0500 Subject: task: prettier tree visualization and flag ordering fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Implement box-drawing characters (├──, └──, │) for task tree visualization - Fix 'task create' flag ordering by using [options] in docopt (same as 'task list') - Document TASK_TEST_MODE environment variable in AGENTS.md Testing section - Add test case for multi-flag ordering on 'task create' - Clean up test tasks polluted in production database All 29 tests passing. Amp-Thread-ID: https://ampcode.com/threads/T-4e6225cf-3e78-4538-963c-5377bbbccee8 Co-authored-by: Amp --- Omni/Task/Core.hs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'Omni/Task/Core.hs') diff --git a/Omni/Task/Core.hs b/Omni/Task/Core.hs index 1dc31a8..f463040 100644 --- a/Omni/Task/Core.hs +++ b/Omni/Task/Core.hs @@ -10,6 +10,7 @@ import qualified Data.Aeson as Aeson import qualified Data.Aeson.KeyMap as KM import Data.Aeson.Types (parseMaybe) import qualified Data.ByteString.Lazy.Char8 as BLC +import qualified Data.List as List import qualified Data.Text as T import qualified Data.Text.IO as TIO import Data.Time (UTCTime, diffTimeToPicoseconds, getCurrentTime, utctDayTime) @@ -324,9 +325,19 @@ showTaskTree maybeId = do printEpicTree allTasks task = printTreeNode allTasks task 0 printTreeNode :: [Task] -> Task -> Int -> IO () - printTreeNode allTasks task indent = do - let prefix = T.pack (replicate (indent * 2) ' ') - children = filter (\t -> taskParent t == Just (taskId task)) allTasks + printTreeNode allTasks task indent = printTreeNode' allTasks task indent [] + + printTreeNode' :: [Task] -> Task -> Int -> [Bool] -> IO () + printTreeNode' allTasks task indent ancestry = do + let children = filter (\t -> taskParent t == Just (taskId task)) allTasks + -- Build tree prefix using box-drawing characters + prefix = + if indent == 0 + then "" + else + let ancestorPrefixes = map (\hasMore -> if hasMore then "│ " else " ") (List.init ancestry) + myPrefix = if List.last ancestry then "├── " else "└── " + in T.pack <| concat ancestorPrefixes ++ myPrefix -- For epics, show progress count [completed/total]; for tasks, show status checkbox statusStr = case taskType task of Epic -> @@ -349,8 +360,15 @@ showTaskTree maybeId = do else taskTitle task putText <| prefix <> taskId task <> " " <> statusStr <> " " <> nsStr <> truncatedTitle - -- Print children - traverse_ (\child -> printTreeNode allTasks child (indent + 1)) children + -- Print children with updated ancestry + let indexedChildren = zip [1 ..] children + totalChildren = length children + traverse_ + ( \(idx, child) -> + let hasMoreSiblings = idx < totalChildren + in printTreeNode' allTasks child (indent + 1) (ancestry ++ [hasMoreSiblings]) + ) + indexedChildren -- Helper to print a task printTask :: Task -> IO () -- cgit v1.2.3