Skip to content

Commit

Permalink
Output in JSON format (projects, labels, tasks)
Browse files Browse the repository at this point in the history
  • Loading branch information
andreoliwa committed Mar 29, 2021
1 parent 2a9f649 commit aab6c3c
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 50 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ y.output

_vendor-*
vendor

.vscode/
42 changes: 34 additions & 8 deletions completed.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@ package main

import (
"context"
"encoding/json"

"github.com/sachaos/todoist/lib"
todoist "github.com/sachaos/todoist/lib"

"github.com/urfave/cli"
)

type CompletedJSON struct {
ID string `json:"id"`
CompletedDate string `json:"completed_date"`
Project string `json:"project"`
Content string `json:"content"`
}

func CompletedList(c *cli.Context) error {
client := GetClient(c)

Expand All @@ -25,12 +33,15 @@ func CompletedList(c *cli.Context) error {
return err
}

isJson := c.GlobalBool("json")

defer writer.Flush()

if c.GlobalBool("header") {
if !isJson && c.GlobalBool("header") {
writer.Write([]string{"ID", "CompletedDate", "Project", "Content"})
}

var jsonObjects []CompletedJSON
for _, item := range completed.Items {
result, err := Eval(ex, item, client.Store.Projects, client.Store.Labels)
if err != nil {
Expand All @@ -39,12 +50,27 @@ func CompletedList(c *cli.Context) error {
if !result {
continue
}
writer.Write([]string{
IdFormat(item),
CompletedDateFormat(item.DateTime()),
ProjectFormat(item.ProjectID, client.Store, projectColorHash, c),
ContentFormat(item),
})

obj := CompletedJSON{
ID: IdFormat(item),
CompletedDate: CompletedDateFormat(item.DateTime()),
Project: ProjectFormat(item.ProjectID, client.Store, projectColorHash, c),
Content: ContentFormat(item),
}
if isJson {
jsonObjects = append(jsonObjects, obj)
} else {
writer.Write([]string{obj.ID, obj.CompletedDate, obj.Project, obj.Content})
}

}

if isJson {
jsonData, err := json.Marshal(jsonObjects)
if err != nil {
return CommandFailed
}
writer.Write([]string{string(jsonData)})
}

return nil
Expand Down
30 changes: 27 additions & 3 deletions labels.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,50 @@
package main

import (
"encoding/json"
"os"
"text/tabwriter"

"github.com/urfave/cli"
)

type LabelJSON struct {
ID string `json:"id"`
Name string `json:"name"`
}

func Labels(c *cli.Context) error {
client := GetClient(c)

w := new(tabwriter.Writer)
w.Init(os.Stdout, 0, 4, 1, ' ', 0)

defer writer.Flush()
isJson := c.GlobalBool("json")

if c.GlobalBool("header") {
defer writer.Flush()
if !isJson && c.GlobalBool("header") {
writer.Write([]string{"ID", "Name"})
}

var jsonObjects []LabelJSON
for _, label := range client.Store.Labels {
writer.Write([]string{IdFormat(label), "@" + label.Name})
obj := LabelJSON{
ID: IdFormat(label),
Name: "@" + label.Name,
}
if isJson {
jsonObjects = append(jsonObjects, obj)
} else {
writer.Write([]string{obj.ID, obj.Name})
}
}

if isJson {
jsonData, err := json.Marshal(jsonObjects)
if err != nil {
return CommandFailed
}
writer.Write([]string{string(jsonData)})
}

return nil
Expand Down
66 changes: 38 additions & 28 deletions list.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package main

import (
"encoding/json"
"fmt"
"os"
"sort"

"github.com/acarl005/stripansi"
todoist "github.com/sachaos/todoist/lib"
Expand All @@ -21,18 +23,13 @@ func traverseItems(item *todoist.Item, f func(item *todoist.Item, depth int), de
}
}

func sortItems(itemListPtr *[][]string, byIndex int) {
itemList := *itemListPtr
length := len(itemList)
for i := 0; i < length-1; i++ {
for j := 0; j < length-1-i; j++ {
if stripansi.Strip(itemList[j][byIndex]) > stripansi.Strip(itemList[j+1][byIndex]) {
tmp := itemList[j]
itemList[j] = itemList[j+1]
itemList[j+1] = tmp
}
}
}
type TaskJSON struct {
ID string `json:"id"`
Priority string `json:"priority"`
DueDate string `json:"due_date"`
Project string `json:"project"`
Labels string `json:"labels"`
Content string `json:"content"`
}

func List(c *cli.Context) error {
Expand All @@ -47,14 +44,16 @@ func List(c *cli.Context) error {
projectColorHash := GenerateColorHash(projectIds, colorList)
ex := Filter(c.String("filter"))

itemList := [][]string{}
rootItem := client.Store.RootItem

if rootItem == nil {
fmt.Fprintln(os.Stderr, "There is no task. You can fetch latest tasks by `todoist sync`.")
return nil
}

isJson := c.GlobalBool("json")

var jsonObjects []TaskJSON
traverseItems(rootItem, func(item *todoist.Item, depth int) {
r, err := Eval(ex, item, client.Store.Projects, client.Store.Labels)
if err != nil {
Expand All @@ -63,31 +62,42 @@ func List(c *cli.Context) error {
if !r || item.Checked == 1 {
return
}
itemList = append(itemList, []string{
IdFormat(item),
PriorityFormat(item.Priority),
DueDateFormat(item.DateTime(), item.AllDay),
ProjectFormat(item.ProjectID, client.Store, projectColorHash, c) +
obj := TaskJSON{
ID: IdFormat(item),
Priority: PriorityFormat(item.Priority),
DueDate: DueDateFormat(item.DateTime(), item.AllDay),
Project: ProjectFormat(item.ProjectID, client.Store, projectColorHash, c) +
SectionFormat(item.SectionID, client.Store, c),
item.LabelsString(client.Store),
ContentPrefix(client.Store, item, depth, c) + ContentFormat(item),
})
Labels: item.LabelsString(client.Store),
Content: ContentPrefix(client.Store, item, depth, c) + ContentFormat(item),
}
jsonObjects = append(jsonObjects, obj)
}, 0)

if c.Bool("priority") == true {
if c.Bool("priority") {
// sort output by priority
// and no need to use "else block" as items returned by API are already sorted by task id
sortItems(&itemList, 1)
sort.Slice(jsonObjects, func(i, j int) bool {
return stripansi.Strip(jsonObjects[i].Priority) < stripansi.Strip(jsonObjects[j].Priority)
})
}

defer writer.Flush()

if c.GlobalBool("header") {
writer.Write([]string{"ID", "Priority", "DueDate", "Project", "Labels", "Content"})
}
if isJson {
jsonData, err := json.Marshal(jsonObjects)
if err != nil {
return CommandFailed
}
writer.Write([]string{string(jsonData)})
} else {
if c.GlobalBool("header") {
writer.Write([]string{"ID", "Priority", "DueDate", "Project", "Labels", "Content"})
}

for _, strings := range itemList {
writer.Write(strings)
for _, obj := range jsonObjects {
writer.Write([]string{obj.ID, obj.Priority, obj.DueDate, obj.Project, obj.Labels, obj.Content})
}
}

return nil
Expand Down
6 changes: 5 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

"github.com/fatih/color"
"github.com/rkoesters/xdg/basedir"
"github.com/sachaos/todoist/lib"
todoist "github.com/sachaos/todoist/lib"
"github.com/spf13/viper"
"github.com/urfave/cli"
)
Expand Down Expand Up @@ -101,6 +101,10 @@ func main() {
Name: "csv",
Usage: "output in CSV format",
},
cli.BoolFlag{
Name: "json, j",
Usage: "output in JSON format",
},
cli.BoolFlag{
Name: "debug",
Usage: "output logs",
Expand Down
36 changes: 27 additions & 9 deletions projects.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
package main

import (
"github.com/sachaos/todoist/lib"
"encoding/json"

todoist "github.com/sachaos/todoist/lib"
"github.com/urfave/cli"
)

type ProjectJSON struct {
ID string `json:"id"`
Name string `json:"name"`
}

func traverseProjects(pjt *todoist.Project, f func(pjt *todoist.Project, depth int), depth int) {
f(pjt, depth)

if pjt.ChildProject != nil {
traverseProjects(pjt.ChildProject, f, depth + 1)
traverseProjects(pjt.ChildProject, f, depth+1)
}

if pjt.BrotherProject != nil {
Expand All @@ -27,21 +34,32 @@ func Projects(c *cli.Context) error {
}
projectColorHash := GenerateColorHash(projectIds, colorList)

itemList := [][]string{}
project := client.Store.RootProject

var jsonObjects []ProjectJSON
traverseProjects(project, func(pjt *todoist.Project, depth int) {
itemList = append(itemList, []string{IdFormat(pjt), ProjectFormat(pjt.ID, client.Store, projectColorHash, c)})
jsonObjects = append(jsonObjects, ProjectJSON{
ID: IdFormat(pjt),
Name: ProjectFormat(pjt.ID, client.Store, projectColorHash, c),
})
}, 0)

defer writer.Flush()

if c.GlobalBool("header") {
writer.Write([]string{"ID", "Name"})
}
if c.GlobalBool("json") {
jsonData, err := json.Marshal(jsonObjects)
if err != nil {
return CommandFailed
}
writer.Write([]string{string(jsonData)})
} else {
if c.GlobalBool("header") {
writer.Write([]string{"ID", "Name"})
}

for _, strings := range itemList {
writer.Write(strings)
for _, obj := range jsonObjects {
writer.Write([]string{obj.ID, obj.Name})
}
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion todoist_functions_fzf_bash.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ _todoist() {
__todoist_debug "${FUNCNAME[0]}(): cmd=$cmd"

# Global options present in all commands
opts='--header --color --csv --debug --namespace --indent'\
opts='--header --color --csv --debug --namespace --indent --json -j'\
' --project-namespace --help -h --version -v '

case "$cmd" in
Expand Down

0 comments on commit aab6c3c

Please sign in to comment.