Compare commits
7 commits
Author | SHA1 | Date | |
---|---|---|---|
a8babd5e99 | |||
d2ce0cc991 | |||
457dd298bd | |||
30f6f2b7b4 | |||
98482784bc | |||
bb9f171579 | |||
ffb5389f6b |
17
README
17
README
|
@ -19,15 +19,24 @@ Designed to help you overcome being overwhelmed
|
||||||
= Roadmap / Issues =
|
= Roadmap / Issues =
|
||||||
|
|
||||||
- Implement state machine to manage state (See design docs)
|
- Implement state machine to manage state (See design docs)
|
||||||
- Implement timer
|
- Timer spinner
|
||||||
- It should have big full screen countdown MM:SS
|
- Timer counts down
|
||||||
- Ideally the individual digits are ascii art made from the digit itself
|
- Task marked as `start`ed once timer begins
|
||||||
|
- Ask if task completed on end of timer
|
||||||
|
- Set break timer
|
||||||
|
- Loop continues once break is completed
|
||||||
- TaskList Active tasks should _always_ display, and then let the cursor indexing kick in
|
- TaskList Active tasks should _always_ display, and then let the cursor indexing kick in
|
||||||
|
- Full screen application
|
||||||
- Dynamic column spacing based on WindowResizeMsg
|
- Dynamic column spacing based on WindowResizeMsg
|
||||||
- When going from TaskList to nvim, don't overwrite! Ask!
|
- When going from TaskList to nvim, don't overwrite! Ask!
|
||||||
- Show hints about actions / shortcuts on screen
|
- Show hints about actions / shortcuts on screen (help information)
|
||||||
- Refactor extra functions out of `main.go` and into `task.go`
|
- Refactor extra functions out of `main.go` and into `task.go`
|
||||||
- Make sure task loading happens through `tea.Cmd`
|
- Make sure task loading happens through `tea.Cmd`
|
||||||
|
- Set up debugging environment?
|
||||||
|
|
||||||
|
= Associated Tooling =
|
||||||
|
When developing this I also realized I need associated tooling to help manage my backlog more generally.
|
||||||
|
Similar to how I have a task selection section here, for which tasks will be active, I think I also want a backlogger and de-backlogger, for putting things into and out of my backlog easily. I was thinking that things that get backlogged in this way should also get a `recently backlogged` tag or something so that I can sort them easily, but then I thought there should also be a script which removes the recently tag after some time, and then I wondered if I'm just over engineering this for no fucking reason, I don't need cascading backlogs???
|
||||||
|
|
||||||
= Design Docs =
|
= Design Docs =
|
||||||
- [Excalidraw drawings](https://excalidraw.com/#json=Tucrdp__TOwmtOEvNnbVv,ep_J-9-vB3BRVjnd0Y2H0w)
|
- [Excalidraw drawings](https://excalidraw.com/#json=Tucrdp__TOwmtOEvNnbVv,ep_J-9-vB3BRVjnd0Y2H0w)
|
||||||
|
|
73
main.go
73
main.go
|
@ -4,14 +4,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
table "git.sealight.xyz/aynish/poms/table"
|
table "git.sealight.xyz/aynish/poms/table"
|
||||||
task "git.sealight.xyz/aynish/poms/task"
|
task "git.sealight.xyz/aynish/poms/task"
|
||||||
timer "git.sealight.xyz/aynish/poms/timer"
|
// timer "git.sealight.xyz/aynish/poms/timer"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/looplab/fsm"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,22 +30,18 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type model struct {
|
type model struct {
|
||||||
|
FSM *fsm.FSM
|
||||||
state string
|
state string
|
||||||
taskList table.Model
|
taskList table.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
func TasksToRows(tasks []task.Task) []table.Row {
|
type LoadedTasksMsg struct {
|
||||||
rows := make([]table.Row, len(tasks))
|
TaskList table.Model
|
||||||
for i := 0; i < len(tasks); i++ {
|
|
||||||
t := tasks[i]
|
|
||||||
rows[i] = []string{strconv.Itoa(t.Id), t.Project, strings.Join(t.Tags[:], " "), t.Description} // fmt.Sprintf("%f", t.Urgency)
|
|
||||||
}
|
|
||||||
return rows
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateTable() table.Model {
|
func loadTasks() tea.Msg {
|
||||||
var t table.Model
|
var t table.Model
|
||||||
rows := TasksToRows(tasks)
|
rows := task.TasksToRows(tasks)
|
||||||
t = table.New(
|
t = table.New(
|
||||||
table.WithColumns(columns),
|
table.WithColumns(columns),
|
||||||
table.WithRows(rows),
|
table.WithRows(rows),
|
||||||
|
@ -68,50 +63,11 @@ func CreateTable() table.Model {
|
||||||
Foreground(lipgloss.Color("0")).
|
Foreground(lipgloss.Color("0")).
|
||||||
Background(lipgloss.Color("120"))
|
Background(lipgloss.Color("120"))
|
||||||
t.SetStyles(s)
|
t.SetStyles(s)
|
||||||
return t
|
return LoadedTasksMsg{t}
|
||||||
}
|
}
|
||||||
|
|
||||||
type editorFinishedMsg struct{ err error }
|
type editorFinishedMsg struct{ err error }
|
||||||
|
|
||||||
func (m model) rowsToFile() []string {
|
|
||||||
var rows []string
|
|
||||||
for index, row := range m.taskList.Rows() {
|
|
||||||
if index < m.taskList.ActiveIndex() {
|
|
||||||
// get uuid
|
|
||||||
id := row[0]
|
|
||||||
uuid_byte, err := exec.Command("task", "_get", id+".uuid").Output()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
uuid := string(uuid_byte[:len(uuid_byte)-1])
|
|
||||||
|
|
||||||
// create task-note if it doesn't exist
|
|
||||||
note_path := "/home/anish/kitaab/vimwiki/task-notes/" + uuid + ".wiki"
|
|
||||||
if _, err := os.Stat(note_path); os.IsNotExist(err) {
|
|
||||||
f, err := os.Create(note_path)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
path := time.Now().Format(time.DateOnly)
|
|
||||||
tags := strings.Replace(row[2], " ", ":", -1)
|
|
||||||
tags = ":" + row[1] + ":" + tags + ":"
|
|
||||||
fmt.Fprintln(f, "%title "+row[3])
|
|
||||||
fmt.Fprintln(f, tags)
|
|
||||||
fmt.Fprintln(f, "%date "+path)
|
|
||||||
fmt.Fprintln(f, "")
|
|
||||||
f.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// link to task-note from pom-note
|
|
||||||
rowClone := make(table.Row, len(row))
|
|
||||||
_ = copy(rowClone, row)
|
|
||||||
rowClone[3] = "[[../task-notes/" + uuid + ".wiki|" + row[3] + "]]"
|
|
||||||
rows = append(rows, strings.Join(row[1:], " - "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m model) writeFile() string {
|
func (m model) writeFile() string {
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
var path, full_path string
|
var path, full_path string
|
||||||
|
@ -126,10 +82,10 @@ func (m model) writeFile() string {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
fmt.Fprintln(f, "%title ")
|
fmt.Fprintln(f, "%title ")
|
||||||
fmt.Fprintln(f, ":pom:priv:plan:")
|
fmt.Fprintln(f, ":pom:priv:plan:")
|
||||||
fmt.Fprintln(f, "%date "+path)
|
fmt.Fprintln(f, "%date "+t.Format("2006-01-02 15:06"))
|
||||||
fmt.Fprintln(f, "")
|
fmt.Fprintln(f, "")
|
||||||
|
|
||||||
rows := m.rowsToFile()
|
rows := task.RowsToFile(m.taskList.Rows(), m.taskList.ActiveIndex())
|
||||||
for _, value := range rows {
|
for _, value := range rows {
|
||||||
fmt.Fprintln(f, value) // print values to f, one per line
|
fmt.Fprintln(f, value) // print values to f, one per line
|
||||||
}
|
}
|
||||||
|
@ -148,9 +104,9 @@ func (m model) openEditor() tea.Cmd {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
func (m model) Init() tea.Cmd {
|
||||||
// This is where the data should be loaded...
|
return loadTasks
|
||||||
func (m model) Init() tea.Cmd { return nil }
|
}
|
||||||
|
|
||||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
|
@ -166,6 +122,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
//top, right, bottom, left := baseStyle.GetMargin()
|
//top, right, bottom, left := baseStyle.GetMargin()
|
||||||
m.taskList.SetWidth(msg.Width - 5)
|
m.taskList.SetWidth(msg.Width - 5)
|
||||||
m.taskList.SetHeight(msg.Height - 5)
|
m.taskList.SetHeight(msg.Height - 5)
|
||||||
|
case LoadedTasksMsg:
|
||||||
|
m.taskList = msg.TaskList
|
||||||
}
|
}
|
||||||
m.taskList, cmd = m.taskList.Update(msg)
|
m.taskList, cmd = m.taskList.Update(msg)
|
||||||
return m, cmd
|
return m, cmd
|
||||||
|
@ -177,7 +135,6 @@ func (m model) View() string {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var m model
|
var m model
|
||||||
m.taskList = CreateTable()
|
|
||||||
if _, err := tea.NewProgram(m).Run(); err != nil {
|
if _, err := tea.NewProgram(m).Run(); err != nil {
|
||||||
fmt.Println("Error running program:", err)
|
fmt.Println("Error running program:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
63
task/task.go
63
task/task.go
|
@ -3,8 +3,14 @@ package task
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"sort"
|
"sort"
|
||||||
|
"time"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
table "git.sealight.xyz/aynish/poms/table"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Task representation.
|
// Task representation.
|
||||||
|
@ -38,3 +44,60 @@ func GetTasks() []Task {
|
||||||
})
|
})
|
||||||
return tasks
|
return tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TasksToRows(tasks []Task) []table.Row {
|
||||||
|
rows := make([]table.Row, len(tasks))
|
||||||
|
for i := 0; i < len(tasks); i++ {
|
||||||
|
t := tasks[i]
|
||||||
|
rows[i] = []string{strconv.Itoa(t.Id), t.Project, strings.Join(t.Tags[:], " "), t.Description} // fmt.Sprintf("%f", t.Urgency)
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
func RowsToFile(taskList []table.Row, activeIndex int) []string {
|
||||||
|
var rows []string
|
||||||
|
for index, row := range taskList {
|
||||||
|
if index < activeIndex {
|
||||||
|
// get uuid
|
||||||
|
id := row[0]
|
||||||
|
uuid_byte, err := exec.Command("task", "_get", id+".uuid").Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
uuid := string(uuid_byte[:len(uuid_byte)-1])
|
||||||
|
|
||||||
|
// create task-note if it doesn't exist
|
||||||
|
note_path := "/home/anish/kitaab/vimwiki/task-notes/" + uuid + ".wiki"
|
||||||
|
if _, err := os.Stat(note_path); os.IsNotExist(err) {
|
||||||
|
CreateTaskNote(note_path, row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// link to task-note from pom-note
|
||||||
|
rowClone := make(table.Row, len(row))
|
||||||
|
_ = copy(rowClone, row)
|
||||||
|
// TODO add links to indexs of EACH tag
|
||||||
|
rowClone[2] = ""
|
||||||
|
for _, tag := range strings.Split(row[2], " ") {
|
||||||
|
rowClone[2] += "[[../indexs/" + tag + ".wiki|" + tag + "]]"
|
||||||
|
}
|
||||||
|
rowClone[3] = "[[../task-notes/" + uuid + ".wiki|" + row[3] + "]]"
|
||||||
|
rows = append(rows, strings.Join(rowClone[1:], " - "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateTaskNote(note_path string, row table.Row) {
|
||||||
|
t := time.Now()
|
||||||
|
f, err := os.Create(note_path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
tags := strings.Replace(row[2], " ", ":", -1)
|
||||||
|
tags = ":" + row[1] + ":" + tags + ":"
|
||||||
|
fmt.Fprintln(f, "%title "+row[3])
|
||||||
|
fmt.Fprintln(f, tags)
|
||||||
|
fmt.Fprintln(f, "%date "+t.Format("2006-01-02 15:06"))
|
||||||
|
fmt.Fprintln(f, "")
|
||||||
|
defer f.Close()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue