init: working task add parser for go #5
33
README
Normal file
33
README
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# Mast
|
||||||
|
|
||||||
|
This project is born out of frustration with Taskwarrior's upgrade to version 3.0.0
|
||||||
|
|
||||||
|
I'm looking to build my own task management software, after nearly a decade of using taskwarrior. It tries very hard to emulate the good of taskwarrior, while also being more modern. Opinionated defaults, meets malleable software. I loved Taskwarrior, it grew with me so much, but I believe I can do better.
|
||||||
|
|
||||||
|
## Goal Map
|
||||||
|
|
||||||
|
I want a syncing cross platform, fast and effective tasks program. A web client for phone usage, and a CLI client at a computer. They sync through cr-sqlite, using a fairly simple websocket server (at this stage)
|
||||||
|
|
||||||
|
I plan to keep the `filter` and `add` commands from Taskwarrior. Probably lots of the properties too. I'm using PEGs for parsing these grammars.
|
||||||
|
I'd like real calendar integration (iCS) for `due:`
|
||||||
|
|
||||||
|
I'm not yet sure what I'd like to do for priority. I like the configurability of taskwarrior, but it's very heavy handed. Some kind of slider would be nice
|
||||||
|
|
||||||
|
I also need to find out a solution to virtual tags, and especially ID
|
||||||
|
|
||||||
|
I need it to keep integration with Kitaab. That largely means a _json interface, which is fine. Some compatibility layer with Taskwarrior for taskwarrior-tui would be cool too, but isn't yet on the goal list.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
A vaguely unordered list of the next tasks to be accomplished, and those recently completed
|
||||||
|
|
||||||
|
Next:
|
||||||
|
- Parsing `task add` grammar (For JS)
|
||||||
|
- Make SQL files common, instead of embedded in each
|
||||||
|
- Parsing `task filter` grammar
|
||||||
|
- Defining all attributes
|
||||||
|
- Defining virtual attributes
|
||||||
|
|
||||||
|
Completed:
|
||||||
|
- Syncing between JS & Go clients
|
||||||
|
- Parsing `task add` grammar (For Go)
|
BIN
architecture.png
Normal file
BIN
architecture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
24
cli/main.go
24
cli/main.go
|
@ -8,6 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
mast "mast/db"
|
mast "mast/db"
|
||||||
|
parser "mast/parser"
|
||||||
|
|
||||||
"github.com/charmbracelet/bubbles/textinput"
|
"github.com/charmbracelet/bubbles/textinput"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
@ -221,10 +222,25 @@ func (m model) View() string {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// Remove the parser test and call it when adding a todo
|
||||||
func main() {
|
func main() {
|
||||||
p := tea.NewProgram(initialModel())
|
if len(os.Args) < 2 {
|
||||||
if _, err := p.Run(); err != nil {
|
fmt.Println("Please provide a Taskwarrior add command to parse")
|
||||||
fmt.Printf("Alas, there's been an error: %v", err)
|
return
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input := os.Args[1]
|
||||||
|
result, err := parser.Parse("", []byte(input))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error parsing input: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Parsed result: %+v\n", result)
|
||||||
|
// p := tea.NewProgram(initialModel())
|
||||||
|
// if _, err := p.Run(); err != nil {
|
||||||
|
// fmt.Printf("Alas, there's been an error: %v", err)
|
||||||
|
// os.Exit(1)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
15
flake.nix
15
flake.nix
|
@ -3,16 +3,9 @@
|
||||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
|
||||||
outputs = { nixpkgs, ... }:
|
outputs = { nixpkgs, ... }:
|
||||||
let
|
let pkgs = nixpkgs.legacyPackages."x86_64-linux";
|
||||||
pkgs = nixpkgs.legacyPackages."x86_64-linux";
|
in {
|
||||||
in
|
devShells."x86_64-linux".default =
|
||||||
{
|
pkgs.mkShell { packages = with pkgs; [ go sqlite nodejs pigeon ]; };
|
||||||
devShells."x86_64-linux".default = pkgs.mkShell {
|
|
||||||
packages = with pkgs; [
|
|
||||||
go
|
|
||||||
sqlite
|
|
||||||
nodejs
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
7
go.mod
7
go.mod
|
@ -23,13 +23,16 @@ require (
|
||||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
|
github.com/mna/pigeon v1.2.1 // indirect
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
github.com/muesli/reflow v0.3.0 // indirect
|
github.com/muesli/reflow v0.3.0 // indirect
|
||||||
github.com/muesli/termenv v0.15.2 // indirect
|
github.com/muesli/termenv v0.15.2 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/mod v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.21.0 // indirect
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
|
golang.org/x/sys v0.24.0 // indirect
|
||||||
golang.org/x/text v0.3.8 // indirect
|
golang.org/x/text v0.3.8 // indirect
|
||||||
|
golang.org/x/tools v0.24.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
10
go.sum
10
go.sum
|
@ -33,6 +33,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/mna/pigeon v1.2.1 h1:m5FxEbGdQxLaiHF+QurbWUAjmRqd5cstjIPN89svYgg=
|
||||||
|
github.com/mna/pigeon v1.2.1/go.mod h1:BUZAoRldTdU7Ac3WYkXy8hzIHfCgj1doJxGjlB+AbLI=
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||||
|
@ -49,11 +51,19 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
||||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||||
|
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||||
|
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||||
|
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
|
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||||
|
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||||
|
|
65
parser/add.peg
Normal file
65
parser/add.peg
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
{
|
||||||
|
package parser
|
||||||
|
|
||||||
|
type Attribute struct{
|
||||||
|
Type string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddCommand struct {
|
||||||
|
Description string
|
||||||
|
Attributes []Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeAdd(description interface{}, attributes interface{}) (*AddCommand, error) {
|
||||||
|
attribs, _ := attributes.([]Attribute)
|
||||||
|
return &AddCommand{Description: description.(string), Attributes: attribs}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeAttributes(attributes interface{}) ([]Attribute, error) {
|
||||||
|
ats := attributes.([]interface{})
|
||||||
|
|
||||||
|
attribs := make([]Attribute, 0)
|
||||||
|
for _, p := range ats {
|
||||||
|
pa := p.([]interface{})
|
||||||
|
px := pa[1:]
|
||||||
|
for _, pi := range px {
|
||||||
|
ps := pi.(*Attribute)
|
||||||
|
attribs = append(attribs, *ps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return attribs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Add <- desc:Description attributes:Attributes? {
|
||||||
|
return MakeAdd(desc, attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
Description <- (!Attribute .)+ {
|
||||||
|
return string(c.text), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
Attributes <- attributes:(_ Attribute)* {
|
||||||
|
return MakeAttributes(attributes)
|
||||||
|
}
|
||||||
|
Attribute <- Project / Priority / Tag
|
||||||
|
|
||||||
|
Project <- ("pro:" / "project:") value:Word {
|
||||||
|
return &Attribute{Type:"project", Value:value.(string)}, nil
|
||||||
|
}
|
||||||
|
Priority <- "priority:" value:[HML] {
|
||||||
|
return &Attribute{Type:"priority", Value:value.(string)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
Tag <- "+" value:Word {
|
||||||
|
return &Attribute{Type:"tag", Value:value.(string)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
Word <- [a-zA-Z0-9_-]+ {
|
||||||
|
return string(c.text), nil
|
||||||
|
}
|
||||||
|
_ <- [ \t]*
|
||||||
|
|
||||||
|
EOF = !.
|
1651
parser/add_parser.go
Normal file
1651
parser/add_parser.go
Normal file
File diff suppressed because it is too large
Load diff
22
parser/main.go
Normal file
22
parser/main.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package parser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
fmt.Println("Please provide a Taskwarrior add command to parse")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
input := os.Args[1]
|
||||||
|
result, err := Parse("", []byte(input))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error parsing input: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Parsed result: %+v\n", result)
|
||||||
|
}
|
Loading…
Reference in a new issue