diff --git a/.gitignore b/.gitignore index 6ecc4ba..f94dc98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ .gitignore data +d else.go +parse.go tomorrow + +funcs diff --git a/tdm.go b/tdm.go index 40d4318..cd06b71 100644 --- a/tdm.go +++ b/tdm.go @@ -1,7 +1,7 @@ // ============================================================================= // Auth: Alex Celani // File: tdm.go -// Revn: 03-11-2022 1.0 +// Revn: 03-27-2022 2.0 // // Func: display and manage progress of a litany of items to be done, // with an organization scheme similar to Trello. It's CLI @@ -9,15 +9,14 @@ // // TODO: add debug statements // -// literally how do I handle parsing multi-word input to the -// program??? -// +// fix issue where fileIn() breaks on empty board // add second object to hold command information // make subsubtasks for greater depth // M or rooms to contain boards // handle command line args +// auto-update task fill based on subtask fills and (settable) +// weighting // M remember last args -// research git branches // handle ^C gracefully // move most (read: all) helper functions to external files // M add priority to tasks @@ -31,6 +30,11 @@ // keep track of finished items // periodic tasks? something to do with the time package // convert file delimiters to (customizable?) variables +// do some more legit testing +// ============================================================================= +// JUMP TAGS +// for the lucky few who use vim, press * on a tag to jump to that function +// INPUT JOIN FILEIN FILEOUT HELP DELETE FIND СДЕЛАЙ MARK PARSE SHOW MAIN // ============================================================================= // CHANGE LOG // ----------------------------------------------------------------------------- @@ -93,14 +97,27 @@ //*03-11-2022: updated help() // commented /move/ and /mark/ of parse() // super fixed subtask propogation bug in fileIn() +// 03-12-2022: rewrote /delete/, /show/, and /mark/ +// 03-13-2022: added missing call to lower() in input() +// rewrote /make/ +// began testing /delete/ +// 03-14-2022: finished testing /delete/ +// tested /show/, /mark/, and /make/ +// 03-15-2022: integrated parse.go as parse() +// added jump tags :) +// commented parse() +// 03-20-2022: first draft rewrite of find() +//*03-27-2022: fixed bug where tasks can't be made under boards with +// name of length 1 // // ============================================================================= + package main import ( "fmt" // used for Println - "strings" // used for Split + "strings" // used for Split, ToLower, Join "strconv" // used for Atoi "os" // used for Exit, Stdin "io/ioutil" // used for ReadFile, WriteFile @@ -121,16 +138,36 @@ var read = ioutil.ReadFile var write = ioutil.WriteFile +// INPUT // wrapper function to print input prompt, take user input func input( ps1 string ) string { p( ps1 ) // print prompt // create scanner on stdin scanner := bufio.NewScanner( os.Stdin ) scanner.Scan() // read input - return scanner.Text() // return text + return lower( scanner.Text() ) // return text } +// JOIN +// quick function to join an array of strings, with delimiting spaces +func join( subcommands []string ) string { + + var ret string // declare returnable string + + // iterate over contained strings inside array + for _, word := range subcommands { + // add word and delimiting space to returnable + ret = ret + word + " " + } + + // return everything but last character, a trailing space + return ret[:len( ret ) - 1] + +} + + +// FILEOUT // wrapper function to contain all the file writing func fileOut() { @@ -232,8 +269,9 @@ func fileOut() { } + +// FILEIN // warpper function to contain all the file reading -// literally yanked from main() and pasted here func fileIn() { // test string to use in lieu of a file @@ -361,7 +399,7 @@ func fileIn() { // ----------------------------------------------------------------------------- -// help( commands []string ) +// HELP( commands []string ) // // Revn: 03-10-2022 // Args: commands - array of strings @@ -464,9 +502,9 @@ func help( commands []string ) { // ----------------------------------------------------------------------------- -// delete( search query ) +// DELETE( search query ) // -// Revn: 03-08-2022 +// Revn: 03-15-2022 // Args: search - query // object that summarizes what needs deleting // Func: delete entries @@ -482,6 +520,7 @@ func help( commands []string ) { // wrote bones, not working // 03-03-2022: commented // 03-08-2022: changed arguments from commands []string to search query +// 03-15-2022: added quick check for search.comm = fail // // ----------------------------------------------------------------------------- func del( search query ) { @@ -494,6 +533,11 @@ func del( search query ) { return } + // if fail is set, quit + if search.command == "fail" { + return + } + // determine "coordinates" of object that needs finding // x -> ( string ) name of board, shouldn't ever be blank // y -> ( int ) index of task array for a given board @@ -549,15 +593,15 @@ func del( search query ) { } } } else { // should be unreachable - print( "Error in delete(): board does not exist or not specified" ) + print( "Error in delete(): object does not exist or not specified" ) } } // ----------------------------------------------------------------------------- -// find( search query ) ( string, int, int ) +// FIND( search query ) ( string, int, int ) // -// Revn: 03-03-2022 +// Revn: 03-27-2022 // Args: search - query // object that outlines what needs finding // Retn: x, y, z - string, int, int @@ -565,13 +609,15 @@ func del( search query ) { // objects are // Func: iterate over all everything until exact positions of // sought-after object is found -// TODO: incorporate with sanitize? -// error messages +// TODO: error messages +// make returnables into struct ( "coords"? ) // ----------------------------------------------------------------------------- // CHANGE LOG // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 03-01-2022: essentially stole from show() // 03-03-2022: commented +// 03-20-2022: rewrote for updated query definition +// 03-27-2022: commented // // ----------------------------------------------------------------------------- func find( search query ) ( string, int, int ) { @@ -580,55 +626,63 @@ func find( search query ) ( string, int, int ) { var rtask int = -1 // init ints as -1, the forbidden index var rsubt int = -1 - //subcom := search.subcom - brd := search.board - tsk := search.task - sbt := search.subtask - // if user is looking for a board - if brd != "" { - _, prs := boards[brd] // quick check to see if board exists - if prs == true { // if exists... - rboard = brd // set returnable board name - //} else { // requested board doesn't exist - // print error about it - // print( "Board /" + brd + "/ does not exist" ) - } - } else if tsk != "" { // if user is looking for task - // iterate over all boards - for bd, contents := range boards { - // iterate over tasks in given board - for tindex, ts := range contents { - // if found task matches sought task - if ts.name == tsk { - // keep track of board and task index - rboard = bd - rtask = tindex - } + // look at subcommand A specifically + switch search.subA { + case "board": + // prs is true if search.board is in boards + _, prs := boards[search.board] + if prs { // if prs _is_ true, keep track of that board + rboard = search.board } - } - } else if sbt != "" { // if user is looking for subtask - // iterate over all boards - for bd, contents := range boards { - // iterate over tasks in given board - for tindex, ts := range contents { - // iterate over subtask in given board - for sindex, st := range ts.subt { - // if found subtask matches sought subtask - if st.name == sbt { - // keep track of board, task index, and - // subtask index - rboard = bd - rtask = tindex - rsubt = sindex + case "task": + // iterate over boards in boards + // board -> names of boards ( key in map ) + // contents -> []task ( value in map ) + for board, contents := range boards { + // iterate through task array + // ind -> index + // task -> actual task object + for ind, task := range contents { + // if name of found task is requested task name + if task.name == search.task { + // keep track of board and index + rboard = board + rtask = ind } } } - } - } else { // should be unreachable - // implies that user wasnt looking for board, task, or - // subtask - //print( "what is happen" ) + case "subtask": + // iterate over boards in boards + // board -> names of boards ( key in map ) + // contents -> []task ( value in map ) + for board, contents := range boards { + // iterate through task array + // tind -> task index + // task -> actual task object + for tind, task := range contents { + // iterate through subtask array + // sind -> subtask index + // subtask -> actual subtask object + for sind, subtask := range task.subt { + // if name of found subtask is requested + // subtask name + if subtask.name == search.subtask { + // keep track of board, task index, and + // subtask index + rboard = board + rtask = tind + rsubt = sind + } + } + } + } + default: + // if the subcommand A is not a known object, error out + // I'm like 90% sure that this is unreachable, but + // whatever + print( "Error in find()" ) + print( "Object /", search.subA, "/ not recognized" ) } // return returnable 3-tuple @@ -638,20 +692,21 @@ func find( search query ) ( string, int, int ) { // ----------------------------------------------------------------------------- -// сделай( search query ) +// СДЕЛАЙ( search query ) // -// Revn: 03-09-2022 +// Revn: 03-27-2022 // Args: search - query // object that summarizes what needs making // Func: create new boards, tasks, and subtasks // Meth: find parent object, create new child object, attach -// TODO: write second draft -// add debug +// TODO: add debug // ----------------------------------------------------------------------------- // CHANGE LOG // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 03-07-2022: wrote first draft // 03-10-2022: commented +// 03-16-2022: rewrote to work with updated query{} definition +// 03-27-2022: added check for command == "fail" // // ----------------------------------------------------------------------------- func сделай( search query ) { @@ -660,6 +715,11 @@ func сделай( search query ) { print( search ) } + // if fail is set, quit + if search.command == "fail" { + return + } + // init variable to mark if parent object exists var exists bool = false // declare variable to determine what caused error @@ -775,10 +835,11 @@ func сделай( search query ) { } + // ----------------------------------------------------------------------------- -// mark( search query ) +// MARK( search query ) // -// Revn: 03-11-2022 +// Revn: 03-17-2022 // Args: search - query // object that summarizes what needs showing // Func: allow user to complete tasks @@ -796,6 +857,7 @@ func сделай( search query ) { // what kind of object user and printed hanging slash // 03-11-2022: added reference to variable 'change', so fileOut() // will run +// 03-17-2022: added references to updated definition of a query // // ----------------------------------------------------------------------------- func mark( search query ) { @@ -806,6 +868,12 @@ func mark( search query ) { return } + // if parse() failed, simply return + // probably print failure too? + if search.command == "fail" { + return + } + // determine "coordinates" of object that needs finding // x -> ( string ) name of board, shouldn't ever be blank // y -> ( int ) index of task array for a given board @@ -819,11 +887,11 @@ func mark( search query ) { // markFill -> converted value // err -> contains value of atoi() error // would happen if passed value isn't ascii - markFill, err := atoi( search.subcom ) + markFill, err := atoi( search.subB ) // on error, print failure, call help about it, return if err != nil { - print( "Fill value /" + search.subcom + "/ is not a number" ) + print( "Fill value /" + search.subB + "/ is not a number" ) markFailure := []string{ "help", "mark" } help( markFailure ) return @@ -860,14 +928,16 @@ func mark( search query ) { } else { // reachable if the user gives input that DNE // notify user requested object did not exist p( "Error in mark(): " ) - if search.board != "" { - p( "board /", search.board ) - } else if search.task != "" { - p( "task /", search.task ) - } else if search.subtask != "" { - p( "subtask /", search.subtask ) - } else { - p( "object /", search.board ) + p( search.subA + " /" ) + switch search.subA { + case "board": + p( search.board ) + case "task": + p( search.task ) + case "subtask": + p( search.subtask ) + default: + p( "object" ) } print( "/ does not exist" ) } @@ -875,9 +945,9 @@ func mark( search query ) { // ----------------------------------------------------------------------------- -// parse( commands []string ) +// PARSE( commands []string ) // -// Revn: 03-10-2022 +// Revn: 03-27-2022 // Args: commands - []string // list of commands of what board, task, or subtask // to make @@ -889,11 +959,7 @@ func mark( search query ) { // switch over first command // switch over length of subcommand // switch over contents of subcommand -// TODO: comments for -// /make/ -// /mark/ -// -// contemplate help case +// TODO: contemplate help case // move to external file? // ----------------------------------------------------------------------------- // CHANGE LOG @@ -903,6 +969,17 @@ func mark( search query ) { // tested pass cases // 03-10-2022: commented /delete/ portion // commented /show/ portion +// 03-12-2022: rewrote /delete/, /show/, and /mark/ +// 03-13-2022: rewrote /make/ +// began testing /delete/ +// 03-14-2022: finished testing /delete/ +// tested /show/, /mark/, and /make/ +// 03-15-2022: commented +// fixed small bugs related to valid keyword positions +// 03-17-2022: added small reference to /save/ in the bugout case +// 03-27-2022: fixed bug in /make/ where tasks under boards with +// names of length 1 failed ( literally changed "> 1" +// to "> 0" ) // // ----------------------------------------------------------------------------- func parse( commands []string ) query { @@ -918,12 +995,12 @@ func parse( commands []string ) query { // set pre-emptively, clear if it's bad // unused as of right now - //search.command = comm + search.command = comm // big switch statement over command switch comm { // these don't really need processing, break out immediately - case "set", "quit", "exit": + case "save", "set", "quit", "exit": return search case "delete": // there are only so many types of commands that work here @@ -932,36 +1009,37 @@ func parse( commands []string ) query { // -> delete task // -> delete subtask // i.e. subcommand can have either length 1 or 2 - switch subcomlen { - case 1: - // -> delete - // requested item is subcommands[0], so set - search.board = subcommands[0] - case 2: - // -> delete board|task|subtask - // can be any of three, so switch over subcom[0] - // kind of wish I could do like a reverse set - // like subcommands[1] = board or task or subtask - switch subcommands[0] { - case "board": - search.board = subcommands[1] - case "task": - search.task = subcommands[1] - case "subtask": - search.subtask = subcommands[1] - default: // user didn't input valid object - // print error, call help about it - print( "Incorrect object specified" ) - p( "Object /", subcommands[0] ) - print( "/ is not valid" ) - delFailure := []string{ "help", "delete" } - help( delFailure ) + + // if user enters JUST delete, set fail and return + if subcomlen == 0 { + search.command = "fail" + return search + } + + switch subcommands[0] { + case "task": + // delete task xyz + // set subcommand ( focus ) of search + search.subA = subcommands[0] + // join array into string and set as task + search.task = join( subcommands[1:] ) + case "subtask": + // delete subtask xyz + // set subcommand ( focus ) of search + search.subA = subcommands[0] + // join array into string and set as subtask + search.subtask = join( subcommands[1:] ) + default: + // delete board xyz + // delete xyz + // set subcommand ( focus ) of search + search.subA = "board" + // if keyword board is given, join without keyword + if subcommands[0] == "board" && subcomlen > 1 { + search.board = join( subcommands[1:] ) + } else { // otherwise, join everything + search.board = join( subcommands[:] ) } - default: // user had the wrong number of args - // print error, call help about it - print( "Incorrect number of arguments" ) - delFailure := []string{ "help", "delete" } - help( delFailure ) } case "help": // help( subcommands ) @@ -973,116 +1051,141 @@ func parse( commands []string ) query { // -> make task subtask // if subcommand length is 1 or 2, make a board // if subcommand length is 3 or 4, make a task/subtask - switch subcomlen { - case 1: - // -> make - // only subcommand is argument, so set - search.board = subcommands[0] - case 2: - // -> make board - // double triple check that user asked for board, - // then set second subcommand - if subcommands[0] == "board" { - search.board = subcommands[1] - } else { // user didn't seem to want to make a - // board - // print error, call help about it - print( "Incorrect argument type:" ) - print( "Object /", subcommands[0], "/ does not match the following types:" ) - print( "/board/" ) - makeFailure := []string{ "help", "make" } - help( makeFailure ) + + // if user enters JUST make, set fail and return + if subcomlen == 0 { + search.command = "fail" + return search + } + + var x int = -1 // keep track of position of subcom + + if subcommands[0] == "task" { + // make task xyz subtask ijk + // iterate over subcommands ( not counting task ) + // looking for the subtask keyword + for ind, _ := range subcommands[1:] { + // set x equal to index when subtask is found + if subcommands[ind] == "subtask" { + x = ind } - case 3: - // -> make task - // if task is actually task, set to board - // and to task - if subcommands[1] == "task" { - search.board = subcommands[0] - search.task = subcommands[2] - } else { // user didn't want to make a task - // print error, call help about it - print( "Incorrect argument type:" ) - print( "Object /", subcommands[1], "/ does not match the following types:" ) - makeFailure := []string{ "help", "make" } - help( makeFailure ) + } + // the absolute minimum index for subtask keyword is 2 + // if its found before 2, thats a problem + // set fail and return + if x < 2 { + search.command = "fail" + return search + } else { // valid keyword position + // set secondary focus to subtask + search.subB = "subtask" + // set main focus to parent task + search.subA = "task" + // join everything between keywords, set to task + search.task = join( subcommands[1:x] ) + // join everything after subtask, set to subtask + search.subtask = join( subcommands[x+1:] ) + } + } else { + // make xyz + // make board xyz + // make xyz task ijk + // make board xyz task ijk + + // declare string to hold subsubcommand + var subsubcom []string + + // determine what subsubcommand should include + if subcommands[0] == "board" { + subsubcom = subcommands[1:] + } else { + subsubcom = subcommands[:] + } + // iterate over subsubcommand looking for task keyword + for ind, _ := range subsubcom { + // set x equal to index when task is found + if subsubcom[ind] == "task" { + x = ind } - case 4: - // -> make board task - // -> make task subtask - // look for a signature that matches the two above - // set appropriate fields - if subcommands[0] == "board" && subcommands[2] == "task" { - search.board = subcommands[1] - search.task = subcommands[3] - } else if subcommands[0] == "task" && subcommands[2] == "subtask" { - search.task = subcommands[1] - search.subtask = subcommands[3] - } else { // user input didn't conform to scope - // print error, call help about it - print( "Unknown call signature" ) - makeFailure := []string{ "help", "make" } - help( makeFailure ) - } - default: // subcommand length > 4 - // print error, call help about it - print( "Incorrect number of arguments" ) - makeFailure := []string{ "help", "make" } - help( makeFailure ) + } + + // if task was never found, making a board + if x == -1 { + // set focus to board + search.subA = "board" + // join everything and set to board + search.board = join( subsubcom ) + // task was found in a valid position + } else if x > 0 { + // set secondary focus to task + search.subB = "task" + // set main focus to parent board + search.subA = "board" + // join everything between keywords, set to board + search.board = join( subsubcom[:x] ) + // join everything after task, set to task + search.task = join( subsubcom[x+1:] ) + // task was not in valid position + } else { + // set fail and return + return search + } } case "mark": - // NYI -> mark [100] - // NYI -> mark board [100] + // NYI -> mark + // NYI -> mark board // -> mark task fill // -> mark subtask fill - switch subcomlen { - case 1, 2: - // -> mark - // -> mark board - // -> mark 100 - // marking boards isn't support yet -// if subcomlen == 2 { -// if subcommands[0] == "board" { -// search.board = subcommands[1] -// } else { -// // fail -// // unrecognized argument object -// // /[subcommands[0]]/ -// // help mark -// print( "fail h" ) -// } -// } else { -// search.board = subcommands[0] -// } -// search.subcom = "100" - print( "Incorrect number of arguments" ) - markFailure := []string{ "help", "mark" } - help( markFailure ) - case 3: - // -> mark task fill - // -> mark subtask fill - // -> mark board 100 NYI - // pretty simple, double check first subcommand to - // see what object is being marked, set name as - // needed, set fill to subcommand - switch subcommands[0] { - case "task": - search.task = subcommands[1] - case "subtask": - search.subtask = subcommands[1] - default: // user didnt want task or subtask - // print error, call help about it - p( "Object /", subcommands[0] ) - print( "/ not recognized" ) - markFailure := []string{ "help", "mark" } - help( markFailure ) + + // if user enters JUST mark, set fail and return + if subcomlen == 0 { + search.command = "fail" + return search + } + + switch subcommands[0] { + case "task": + // mark task xyz # + if subcomlen < 3 { + // absolute minimum length possible is 3 + // task, name, and fill + search.command = "fail" + return search + } + // set focus to task + // set fill to absolute last word in list + search.subA = subcommands[0] + search.subB = subcommands[subcomlen - 1] + // join all the other words, set to task + search.task = join( subcommands[1:subcomlen - 1] ) + case "subtask": + // mark subtask xyz # + if subcomlen < 3 { + // absolute minimum length possible is 3 + // subtask, name, and fill + search.command = "fail" + return search + } + // set focus to subtask + // set fill to absolute last word in list + search.subA = subcommands[0] + search.subB = subcommands[subcomlen - 1] + // join all the other words, set to subtask + search.subtask = join( subcommands[1:subcomlen - 1] ) + default: + // delete board xyz + // delete xyz + // set focus to board + // set fill to 100 + search.subA = "board" + search.subB = "100" + + // if keyword board is given, join without keyword + if subcommands[0] == "board" && subcomlen > 1 { + search.board = join( subcommands[1:] ) + } else { // otherwise, join everything + search.board = join( subcommands[:] ) } - search.subcom = subcommands[2] - default: // subcommand length != 3 - // print error, call help about it - print( "Incorrect number of arguments" ) - markFailure := []string{ "help", "mark" } - help( markFailure ) } case "show": // similar call signature to delete() @@ -1093,47 +1196,54 @@ func parse( commands []string ) query { // -> show task // -> show subtask // subcom lengths of 1, 2, and 3 are all possible - switch subcomlen { - case 0: - // show - // equivalent to show all, so set to all - search.subcom = "all" - case 1: - // show all - // show - // if user asks for all, give all - if subcommands[0] == "all" { - search.subcom = "all" - } else { // otherwise, user is asking for board - search.board = subcommands[0] - } - case 2: - // show [board|task|subtask] - // switch to see what was specified, set the - // appropriate field in search, easy peasy - switch subcommands[0] { - case "board": - search.board = subcommands[1] - case "task": - search.task = subcommands[1] - case "subtask": - search.subtask = subcommands[1] - default: // user didn't input valid object - // print error, call help about it - print( "Incorrect object specified" ) - p( "Object /", subcommands[0] ) - print( "/ is not valid" ) - showFailure := []string{ "help", "show" } - help( showFailure ) - } - default: // user had the wrong number of args - // print error, call help about it - print( "Incorrect number of arguments" ) - showFailure := []string{ "help", "show" } - help( showFailure ) + if subcomlen == 0 { + // show + // set subcommand to all + search.subA = "all" + } else { + switch subcommands[0] { + case "task": + // show task xyz + // set focus to task + // join all the other words, set to task + search.subA = subcommands[0] + search.task = join( subcommands[1:] ) + case "subtask": + // show subtask xyz + // set focus to subtask + // join all the other words, set to subtask + search.subA = subcommands[0] + search.subtask = join( subcommands[1:] ) + case "all": + // show all + // show + if subcomlen == 1 { + // if there's only one subcommand, it's + // show all... + // set subcommand to all + search.subA = subcommands[0] + } else { // otherwise, it must be a board + // set focus to board + // join all the other words, set to board + search.subA = "board" + search.board = join( subcommands[:] ) + } + default: + // show board xyz + // show xyz + // set focus to board + search.subA = "board" + // if keyword board is given, join without keyword + if subcommands[0] == "board" && subcomlen > 1 { + search.board = join( subcommands[1:] ) + } else { // otherwise, join everything + search.board = join( subcommands[:] ) + } + } } default: // command not recognized // print error, call help about it + //print( "Command /", comm, "/ not recognized" ) print( "Command /", comm, "/ not recognized" ) commFailure := []string{ "help" } help( commFailure ) @@ -1145,16 +1255,15 @@ func parse( commands []string ) query { // ----------------------------------------------------------------------------- -// show( search query ) +// SHOW( search query ) // -// Revn: 03-09-2022 +// Revn: 03-27-2022 // Args: search - query // object that summarizes what needs showing // Func: display stored information to the user -// Meth: iterate through everything, look for mathcing info, print +// Meth: iterate through everything, look for matching info, print // TODO: stylize print in some way // add debug flag -// add call to find() // ----------------------------------------------------------------------------- // CHANGE LOG // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1166,6 +1275,9 @@ func parse( commands []string ) query { // []string, so it can call sanitize() // 02-27-2022: commented /all/ portion // 03-02-2022: commented /board/, /task/, and /subtask/ portions +// 03-16-2022: updated to switch/case system to work with the new +// version of parse() +// 03-27-2022: removed 1.x version // // ----------------------------------------------------------------------------- func show( search query ) { @@ -1177,20 +1289,19 @@ func show( search query ) { } // ease of use variables from search struct - subcom := search.subcom + subcom := search.subA sbd := search.board stk := search.task sstk := search.subtask - if subcom != "" { // show all - // might not actually contain "all", double check - if subcom == "all" { + switch search.subA { + case "all": // iterate over boards' contents - for showBoard, contents := range boards { + for boardName, boardContents := range boards { // show all -> print board name - print( showBoard ) + print( boardName ) // iterate over board's tasks - for _, showTask := range contents { + for _, showTask := range boardContents { // print indent with no trailing newline // indent has len 4 p( " " ) @@ -1214,152 +1325,137 @@ func show( search query ) { } } } - } else { // if command isn't "all" - // print error, call help about it + case "board": + // grab user requested board from boards + // prs is set true if board exists + contents, prs := boards[sbd] + if prs { // if user specified board exists + print( sbd ) // print board name + // iterate over tasks in board + for _, showTask := range contents { + // print indent with no trailing newline + // indent has len 4 + p( " " ) + // print task name, right justified (with respect + // to the indent) + printf( "%-16s", showTask.name ) + // print task fill, left justified + // indent len 4 + 16 = 20 + printf( "%16d\n", showTask.fill ) + for _, showSubtask := range showTask.subt { + // double indent + // double indent has len 8 + p( " " ) + // print subtask name, right justified (with + // respect to indent again) + printf( "%-12s", showSubtask.name ) + // print subtask fill, left justified + // indent len 8 + 12 = 20 + printf( "%16d\n", showSubtask.fill ) + } + } + } else { // if board DNE + // print error, call help about it + print( "Board /" + sbd + "/ does not exist" ) + showFailure := []string{ "help", "show" } + help( showFailure ) + return + } + case "task": + // can check if a board is present with _, prs := + // but this is a flag to be set if a task exists + var exists bool + + // iterate over all boards looking for named task + for showBoard, contents := range boards { + // iterate through all tasks in boards + for _, showTask := range contents { + // look for matching task name + if showTask.name == stk { + exists = true // set exists true + // print containing board name + print( showBoard ) + // print task name with same justification + printf( "%-16s", showTask.name ) + // print task fill with right justification + printf( "%20d\n", showTask.fill ) + // iterate over contained subtasks + for _, showSubtask := range showTask.subt { + // print indent + p( " " ) + // print subtask name left justified + printf( "%-16s", showSubtask.name ) + // print subtask fill right justified + printf( "%16d\n", showSubtask.fill ) + } + } + } + } + if !exists { // if task not found + // print error + // call help about it + print( "Task /" + stk + "/ does not exist" ) + showFailure := []string{ "help", "show" } + help( showFailure ) + return + } + case "subtask": + // can check if a board is present with _, prs := + // but this is a flag to be set if a task exists + var exists bool + + // iterate over all boards looking for named task + for showBoard, contents := range boards { + // iterate through all tasks in boards + for _, showTask := range contents { + // iterate over contained subtasks + for _, showSubtask := range showTask.subt { + // look for matching subtask name + if showSubtask.name == sstk { + exists = true // set exists true + // print containing board name + print( showBoard ) + // print containing task name + print( showTask.name ) + // print subtask name left justified + printf( "%-16s", showSubtask.name ) + // print subtask fill right justified + printf( "%20d\n", showSubtask.fill ) + } + } + } + } + + if !exists { // if subtask not found + // print error + // call help about it + print( "Subtask /" + sstk + "/ does not exist" ) + showFailure := []string{ "help", "show" } + help( showFailure ) + return + } + default: // unrecognized subcommand + // print error, call help about it print( "Error in show()" ) print( "Subcommand /" + subcom + "/ does not exist" ) showFailure := []string{ "help", "show" } help( showFailure ) return - } - } else if sbd != "" { // show board <> - // grab user requested board from boards - // prs is set true if board exists - contents, prs := boards[sbd] - if prs { // if user specified board exists - print( sbd ) // print board name - // iterate over tasks in board - for _, showTask := range contents { - // print indent with no trailing newline - // indent has len 4 - p( " " ) - // print task name, right justified (with respect - // to the indent) - printf( "%-16s", showTask.name ) - // print task fill, left justified - // indent len 4 + 16 = 20 - printf( "%16d\n", showTask.fill ) - for _, showSubtask := range showTask.subt { - // double indent - // double indent has len 8 - p( " " ) - // print subtask name, right justified (with - // respect to indent again) - printf( "%-12s", showSubtask.name ) - // print subtask fill, left justified - // indent len 8 + 12 = 20 - printf( "%16d\n", showSubtask.fill ) - } - } - } else { // if board DNE - // print error, call help about it - print( "Board /" + sbd + "/ does not exist" ) - showFailure := []string{ "help", "show" } - help( showFailure ) - return - } - } else if stk != "" { // show task <> - // can check if a board is present with _, prs := - // but this is a flag to be set if a task exists - var exists bool - - // iterate over all boards looking for named task - for showBoard, contents := range boards { - // iterate through all tasks in boards - for _, showTask := range contents { - // look for matching task name - if showTask.name == stk { - exists = true // set exists true - // print containing board name - print( showBoard ) - // print task name with same justification - printf( "%-16s", showTask.name ) - // print task fill with right justification - printf( "%20d\n", showTask.fill ) - // iterate over contained subtasks - for _, showSubtask := range showTask.subt { - // print indent - p( " " ) - // print subtask name left justified - printf( "%-16s", showSubtask.name ) - // print subtask fill right justified - printf( "%16d\n", showSubtask.fill ) - } - } - } - } - if !exists { // if task not found - // print error - // call help about it - print( "Task /" + stk + "/ does not exist" ) - showFailure := []string{ "help", "show" } - help( showFailure ) - return - } - } else if sstk != "" { // show subtask <> - // can check if a board is present with _, prs := - // but this is a flag to be set if a task exists - var exists bool - - // iterate over all boards looking for named task - for showBoard, contents := range boards { - // iterate through all tasks in boards - for _, showTask := range contents { - // iterate over contained subtasks - for _, showSubtask := range showTask.subt { - // look for matching subtask name - if showSubtask.name == sstk { - exists = true // set exists true - // print containing board name - print( showBoard ) - // print containing task name - print( showTask.name ) - // print subtask name left justified - printf( "%-16s", showSubtask.name ) - // print subtask fill right justified - printf( "%20d\n", showSubtask.fill ) - } - } - } - } - - if !exists { // if subtask not found - // print error - // call help about it - print( "Subtask /" + sstk + "/ does not exist" ) - showFailure := []string{ "help", "show" } - help( showFailure ) - return - } - - } else { // should be undefined behavior - // print contents of the query (human-readable) - print( "Error with input query!" ) - print( " query.board -> " + sbd ) - print( " query.task -> " + stk ) - print( " query.subtask -> " + sstk ) - print( " query.subcommand -> " + subcom ) - - // call help about it - showFailure := []string{ "help", "show" } - help( showFailure ) - return } } - - var flag bool = false // debug flag var changed bool = false // struct used for defining search parameters -type query struct { // relatively clean way to specify... - board string // a board - task string // a task - subtask string // a subtask - subcom string // and\or a subcommand - command string // and finally the command +type query struct { + command string // command passed, or fail + board string // requested board + task string // requested task + subtask string // requested subtaks + subA string // subcom A, usually object being acted upon + subB string // sometimes, two are needed } @@ -1375,7 +1471,7 @@ type subsubtask struct { type subtask struct { name string // subtasks are named fill int // subtasks contain progress - //ssbt subsubtask // subtasks can contain subsubtasks + //ssbt []subsubtask // subtasks can contain subsubtasks //note string // subtasks can contain files } @@ -1396,7 +1492,7 @@ var boards = make( map[string][]task ) var tasks []task // array of tasks referenced above var subtasks []subtask // array of subtasks belonging to tasks - +// MAIN func main() { fileIn() @@ -1427,6 +1523,10 @@ func main() { сделай( search ) case "mark": mark( search ) + case "save": + fileOut() + changed = false + print( "Updates saved" ) case "show": show( search ) case "exit", "quit": @@ -1451,7 +1551,6 @@ func main() { default: // if the input is unrecognized continue // try again } - } }