package main import ( "fmt" "os" "strings" todotxt "git.bullercodeworks.com/brian/go-todotxt" termboxScreen "git.bullercodeworks.com/brian/termbox-screen" userConfig "git.bullercodeworks.com/brian/user-config" termbox "github.com/nsf/termbox-go" ) const ( ScreenIdMain = iota ScreenIdTodo ScreenIdAbout ScreenIdExit ) type AppState struct { Name string Version int config *userConfig.Config directory string fileTodo string fileDone string fileReport string ValidOperations map[string][]string OpFuncs map[string]func([]string) int mode ResourceId TodoList *todotxt.TodoList DoneList *todotxt.TodoList taskListLoaded bool doneListLoaded bool uiManager *termboxScreen.Manager lang *Translator } const ( DefaultFg = termbox.ColorWhite DefaultBg = termbox.ColorBlack TitleFg = termbox.ColorWhite TitleBg = termbox.ColorBlue CursorFg = termbox.ColorBlack CursorBg = termbox.ColorGreen ) func NewApp() *AppState { app := &AppState{Name: AppName, Version: AppVersion} app.initialize() app.doVersionCheck() if err := app.LoadTodoList(); err != nil { if len(os.Args) > 1 && os.Args[1] != "--reinit" { panic(err) } } return app } func (a *AppState) run(parms []string) int { if len(parms) == 0 || parms[0] == "ui" { // UI Mode a.mode = ResModeUI a.uiManager = termboxScreen.NewManager() a.uiManager.AddScreen(&MainScreen{}) a.uiManager.AddScreen(&TodoScreen{}) a.uiManager.AddScreen(&AboutScreen{}) mainBundle := termboxScreen.Bundle{} mainBundle.SetValue(MainBundleListKey, MainBundleListTodo) if err := a.uiManager.InitializeScreen(ScreenIdMain, mainBundle); err != nil { return 1 } if err := a.uiManager.Loop(); err != nil { return 1 } return 0 } a.mode = ResModeCLI if fn, ok := a.OpFuncs[parms[0]]; ok { return fn(parms[1:]) } fmt.Println("Unknown Command") return 1 } func (a *AppState) filterList(list *todotxt.TodoList, filter string) *todotxt.TodoList { return list //TODO: Fix //return list.Filter(a.getFilterPredicate(filter)) } func (a *AppState) getFilteredList(filter string) *todotxt.TodoList { return a.TodoList // TODO: Fix // return a.TodoList.Filter(a.getFilterPredicate(filter)) } func (a *AppState) getFilteredDoneList(filter string) *todotxt.TodoList { return a.DoneList // TODO: Fix // return a.DoneList.Filter(a.getFilterPredicate(filter)) } func (a *AppState) getTodoFile() string { return a.directory + a.fileTodo } func (a *AppState) getDoneFile() string { return a.directory + a.fileDone } func (a *AppState) getReportFile() string { return a.directory + a.fileReport } func (a *AppState) addOperation(name string, desc []string, fn func([]string) int) { a.ValidOperations[name] = desc a.OpFuncs[name] = fn } func (a *AppState) getTodoString(task todotxt.Todo) string { var completed string completed = " " if task.Completed { completed = "X" } return fmt.Sprintf("%d. [%s] %s", task.Id, completed, strings.TrimPrefix(task.String(), "x ")) } func (a *AppState) getDoneTodoString(task todotxt.Todo) string { var completed string completed = " " if task.Completed { completed = "X" } return fmt.Sprintf("0. [%s] %s", completed, strings.TrimPrefix(task.String(), "x ")) } func (a *AppState) doVersionCheck() { confVer, _ := a.config.GetInt("version") for confVer < a.Version { confVer = a.migrate(confVer, a.Version) } a.config.SetInt("version", confVer) } func (a *AppState) migrate(from, to int) int { if from == to { return to } switch from { case 0: a.initializeConfig() return 1 } // If we get all the way down here, we _must_ be done. return to } func (a *AppState) initialize() { a.initLanguage() var err error a.config, err = userConfig.NewConfig(a.Name) if err != nil { panic(err) } a.ValidOperations = make(map[string][]string) a.OpFuncs = make(map[string]func([]string) int) a.addOperation("i3status", []string{"i3status - Output json appropriate for an i3status-rust block"}, a.opI3Status, ) a.addOperation("ls", []string{"ls - List Todos"}, a.opListTodos, ) a.addOperation("lsa", []string{"lsa - The same as 'ls -a'"}, func(args []string) int { return a.opListTodos(append([]string{"-a"}, args...)) }, ) a.addOperation("add", []string{"add - Add a task"}, a.opAddTodo, ) a.addOperation("new", []string{"new - Same as 'add'"}, a.opAddTodo, ) a.addOperation("x", []string{"x - Toggle a task's complete flag on/off"}, a.opToggleTodoComplete, ) a.addOperation("done", []string{"done - The same as 'x'"}, a.opToggleTodoComplete, ) a.addOperation("archive", []string{"archive [id1 id2 ...] - Archive completed tasks"}, a.opArchiveTodos, ) a.addOperation("--reinit", []string{"--reinit - Reset all Configuration Settings"}, func(args []string) int { a.initializeConfig() return 0 }, ) a.addOperation("-h", []string{"-h - Print this message"}, a.opPrintUsage, ) a.addOperation("help", []string{"help - Print this message"}, a.opPrintUsage, ) a.addOperation("--h", []string{"--h - Print this message"}, a.opPrintUsage, ) a.addOperation("editor", []string{"editor - Open todo.txt file in your editor"}, a.opEditor, ) a.directory = a.config.Get("directory") a.fileTodo = a.config.Get("todofile") a.fileDone = a.config.Get("donefile") a.fileReport = a.config.Get("reportfile") } func (a *AppState) initializeConfig() { fmt.Println("Initializing " + a.Name) for { var add string if a.directory != "" { add = " (" + a.directory + ")" } fmt.Println("Path to todo.txt" + add + ":") var resp string fmt.Scanln(&resp) if resp == "" && a.directory != "" { resp = a.directory } if resp != "" { if !strings.HasSuffix(resp, "/") { resp = resp + "/" } fmt.Println("Setting todo.txt directory to: " + resp) a.config.Set("directory", resp) break } } a.config.Set("todofile", "todo.txt") a.config.Set("donefile", "done.txt") a.config.Set("reportfile", "report.txt") }