diff --git a/cmd/dynamo-browse/main.go b/cmd/dynamo-browse/main.go index c0efd12..8c77891 100644 --- a/cmd/dynamo-browse/main.go +++ b/cmd/dynamo-browse/main.go @@ -177,7 +177,6 @@ func main() { keyBindingController, pasteboardProvider, settingsController, - itemRendererService, ) commandController, err := commandctrl.NewCommandController(inputHistoryService, stdCommands) diff --git a/go.mod b/go.mod index 3f5b6d1..dd7d9d6 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 github.com/muesli/reflow v0.3.0 github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.11.1 + github.com/stretchr/testify v1.10.0 golang.design/x/clipboard v0.6.2 golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a ucl.lmika.dev v0.1.2 @@ -50,12 +50,9 @@ require ( github.com/aymanbagabas/go-osc52 v1.0.3 // indirect github.com/containerd/console v1.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-co-op/gocron/v2 v2.17.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/jonboulle/clockwork v0.5.0 // indirect github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc // indirect github.com/kr/pretty v0.3.1 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -66,7 +63,6 @@ require ( github.com/muesli/termenv v0.13.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.2 // indirect - github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/sahilm/fuzzy v0.1.0 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect diff --git a/go.sum b/go.sum index cf34a68..3adfbdd 100644 --- a/go.sum +++ b/go.sum @@ -75,8 +75,6 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-co-op/gocron/v2 v2.17.0 h1:e/oj6fcAM8vOOKZxv2Cgfmjo+s8AXC46po5ZPtaSea4= -github.com/go-co-op/gocron/v2 v2.17.0/go.mod h1:Zii6he+Zfgy5W9B+JKk/KwejFOW0kZTFvHtwIpR4aBI= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= @@ -86,16 +84,12 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= -github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc h1:ZQrgZFsLzkw7o3CoDzsfBhx0bf/1rVBXrLy8dXKRe8o= github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc/go.mod h1:PyXUpnI3olx3bsPcHt98FGPX/KCFZ1Fi+hw1XLI6384= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -152,8 +146,6 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= @@ -162,8 +154,6 @@ github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= diff --git a/internal/common/ui/commandctrl/cmdpacks/modasync.go b/internal/common/ui/commandctrl/cmdpacks/modasync.go deleted file mode 100644 index 9526e03..0000000 --- a/internal/common/ui/commandctrl/cmdpacks/modasync.go +++ /dev/null @@ -1,96 +0,0 @@ -package cmdpacks - -import ( - "context" - "time" - - "github.com/go-co-op/gocron/v2" - "lmika.dev/cmd/dynamo-browse/internal/common/ui/commandctrl" - "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/controllers" - "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/services/tables" - "ucl.lmika.dev/ucl" -) - -type asyncModule struct { - tableService *tables.Service - state *controllers.State -} - -func (m asyncModule) asyncDo(ctx context.Context, args ucl.CallArgs) (any, error) { - var block ucl.Invokable - if err := args.Bind(&block); err != nil { - return nil, err - } - - return nil, commandctrl.ScheduleTask(ctx, func(ctx context.Context) error { - _, err := block.Invoke(ctx) - return err - }) -} - -func (m asyncModule) asyncIn(ctx context.Context, args ucl.CallArgs) (any, error) { - var ( - duration int - block ucl.Invokable - ) - if err := args.Bind(&duration, &block); err != nil { - return nil, err - } - - _, err := commandctrl.CronScheduler(ctx).NewJob( - gocron.OneTimeJob( - gocron.OneTimeJobStartDateTime(time.Now().Add(time.Duration(duration)*time.Second)), - ), - gocron.NewTask(func(ctx context.Context) { - commandctrl.ScheduleTask(ctx, func(ctx context.Context) error { - _, err := block.Invoke(ctx) - return err - }) - }), - gocron.WithContext(ctx), - ) - return nil, err -} - -func (m asyncModule) asyncQuery(ctx context.Context, args ucl.CallArgs) (any, error) { - var ( - block ucl.Invokable - ) - - args, q, tableInfo, err := parseQuery(ctx, args, m.state.ResultSet(), m.tableService, 1) - if err != nil { - return nil, err - } - - if err := args.Bind(&block); err != nil { - return nil, err - } - - return nil, commandctrl.ScheduleAuxTask(ctx, "query: "+q.String(), func(ctx context.Context) error { - newResultSet, err := m.tableService.ScanOrQuery(context.Background(), tableInfo, q, nil) - if err != nil { - return err - } - - return commandctrl.ScheduleTask(ctx, func(ctx context.Context) error { - _, err := block.Invoke(ctx, newResultSetProxy(newResultSet)) - return err - }) - }) -} - -func moduleAsync(tableService *tables.Service, state *controllers.State) ucl.Module { - m := asyncModule{ - state: state, - tableService: tableService, - } - - return ucl.Module{ - Name: "async", - Builtins: map[string]ucl.BuiltinHandler{ - "do": m.asyncDo, - "in": m.asyncIn, - "query": m.asyncQuery, - }, - } -} diff --git a/internal/common/ui/commandctrl/cmdpacks/modav.go b/internal/common/ui/commandctrl/cmdpacks/modav.go index 6c850ac..977a7c1 100644 --- a/internal/common/ui/commandctrl/cmdpacks/modav.go +++ b/internal/common/ui/commandctrl/cmdpacks/modav.go @@ -2,7 +2,6 @@ package cmdpacks import ( "context" - "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" "ucl.lmika.dev/ucl" ) diff --git a/internal/common/ui/commandctrl/cmdpacks/modrs.go b/internal/common/ui/commandctrl/cmdpacks/modrs.go index 56c5548..addcaeb 100644 --- a/internal/common/ui/commandctrl/cmdpacks/modrs.go +++ b/internal/common/ui/commandctrl/cmdpacks/modrs.go @@ -2,8 +2,6 @@ package cmdpacks import ( "context" - "time" - "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" "github.com/pkg/errors" "lmika.dev/cmd/dynamo-browse/internal/common/ui/commandctrl" @@ -11,6 +9,7 @@ import ( "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/models" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/models/queryexpr" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/services/tables" + "time" "ucl.lmika.dev/repl" "ucl.lmika.dev/ucl" ) @@ -72,22 +71,21 @@ func parseQuery( args ucl.CallArgs, currentRS *models.ResultSet, tablesService *tables.Service, - extraArgs int, -) (ucl.CallArgs, *queryexpr.QueryExpr, *models.TableInfo, error) { +) (*queryexpr.QueryExpr, *models.TableInfo, error) { var expr string if err := args.Bind(&expr); err != nil { - return args, nil, nil, err + return nil, nil, err } q, err := queryexpr.Parse(expr) if err != nil { - return args, nil, nil, err + return nil, nil, err } - if args.NArgs() > extraArgs { + if args.NArgs() > 0 { var queryArgs ucl.Hashable if err := args.Bind(&queryArgs); err != nil { - return args, nil, nil, err + return nil, nil, err } queryNames := map[string]string{} @@ -99,15 +97,12 @@ func parseQuery( queryNames[k] = v.String() - switch t := v.(type) { + switch v.(type) { case ucl.StringObject: queryValues[k] = &types.AttributeValueMemberS{Value: v.String()} case ucl.IntObject: queryValues[k] = &types.AttributeValueMemberN{Value: v.String()} - case ucl.BoolObject: - queryValues[k] = &types.AttributeValueMemberBOOL{Value: t.Truthy()} - case attributeValueProxy: - queryValues[k] = t.value + // TODO: other types } return nil }) @@ -119,24 +114,24 @@ func parseQuery( if args.HasSwitch("table") { var tblName string if err := args.BindSwitch("table", &tblName); err != nil { - return args, nil, nil, err + return nil, nil, err } tableInfo, err = tablesService.Describe(ctx, tblName) if err != nil { - return args, nil, nil, err + return nil, nil, err } } else if currentRS != nil && currentRS.TableInfo != nil { tableInfo = currentRS.TableInfo } else { - return args, nil, nil, errors.New("no table specified") + return nil, nil, errors.New("no table specified") } - return args, q, tableInfo, nil + return q, tableInfo, nil } func (rs *rsModule) rsQuery(ctx context.Context, args ucl.CallArgs) (any, error) { - _, q, tableInfo, err := parseQuery(ctx, args, rs.state.ResultSet(), rs.tableService, 0) + q, tableInfo, err := parseQuery(ctx, args, rs.state.ResultSet(), rs.tableService) if err != nil { return nil, err } diff --git a/internal/common/ui/commandctrl/cmdpacks/modrs_test.go b/internal/common/ui/commandctrl/cmdpacks/modrs_test.go index 13a2dd7..b3f6f82 100644 --- a/internal/common/ui/commandctrl/cmdpacks/modrs_test.go +++ b/internal/common/ui/commandctrl/cmdpacks/modrs_test.go @@ -214,14 +214,6 @@ func TestModRS_First(t *testing.T) { rs = rs:query 'pk="zzz"' -table service-test-data assert (eq $rs.First ()) "expected First to be nil" `, - }, { - descr: "returns the first item using placeholders", - cmd: ` - rs = rs:query 'pk=$v and sk=$u' [v:"abc" u:"222"] -table service-test-data - assert (eq $rs.First.pk "abc") "expected First.pk == abc" - assert (eq $rs.First.sk "222") "expected First.sk == 222" - assert (eq $rs.First.beta 1231) "expected First.beta == 1231" - `, }, } for _, tt := range tests { diff --git a/internal/common/ui/commandctrl/cmdpacks/modui.go b/internal/common/ui/commandctrl/cmdpacks/modui.go index e27822a..8075639 100644 --- a/internal/common/ui/commandctrl/cmdpacks/modui.go +++ b/internal/common/ui/commandctrl/cmdpacks/modui.go @@ -2,14 +2,11 @@ package cmdpacks import ( "context" - "fmt" tea "github.com/charmbracelet/bubbletea" "lmika.dev/cmd/dynamo-browse/internal/common/ui/commandctrl" "lmika.dev/cmd/dynamo-browse/internal/common/ui/events" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/controllers" - "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/models" - "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/services/itemrenderer" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/services/tables" "ucl.lmika.dev/ucl" ) @@ -19,7 +16,6 @@ type uiModule struct { state *controllers.State ckb *customKeyBinding readController *controllers.TableReadController - itemRenderer *itemrenderer.Service } func (m *uiModule) uiCommand(ctx context.Context, args ucl.CallArgs) (any, error) { @@ -175,7 +171,7 @@ func (m *uiModule) uiBind(ctx context.Context, args ucl.CallArgs) (any, error) { } func (m *uiModule) uiQuery(ctx context.Context, args ucl.CallArgs) (any, error) { - _, q, tableInfo, err := parseQuery(ctx, args, m.state.ResultSet(), m.tableService, 0) + q, tableInfo, err := parseQuery(ctx, args, m.state.ResultSet(), m.tableService) if err != nil { return nil, err } @@ -195,36 +191,15 @@ func (m *uiModule) uiFilter(ctx context.Context, args ucl.CallArgs) (any, error) return nil, nil } -func (m *uiModule) uiSetItemAnnotator(ctx context.Context, args ucl.CallArgs) (any, error) { - var inv ucl.Invokable - if err := args.Bind(&inv); err != nil { - return nil, err - } - - m.itemRenderer.SetAnnotation(itemrenderer.AnnotationFunc(func(rs *models.ResultSet, item models.Item, path models.AttrPathNode) string { - v, err := inv.Invoke(ctx, newResultSetProxy(rs), itemProxy{rs, 0, item}, attrPathProxy{attrPath: &path}) - if err != nil { - return "" - } else if v == nil { - return "" - } - return fmt.Sprint(v) - })) - commandctrl.QueueRefresh(ctx) - return nil, nil -} - func moduleUI( tableService *tables.Service, state *controllers.State, readController *controllers.TableReadController, - itemRenderer *itemrenderer.Service, ) (ucl.Module, controllers.CustomKeyBindingSource) { m := &uiModule{ tableService: tableService, state: state, readController: readController, - itemRenderer: itemRenderer, ckb: &customKeyBinding{ bindings: map[string]tea.Cmd{}, keyBindings: map[string]string{}, @@ -234,15 +209,14 @@ func moduleUI( return ucl.Module{ Name: "ui", Builtins: map[string]ucl.BuiltinHandler{ - "command": m.uiCommand, - "prompt": m.uiPrompt, - "prompt-table": m.uiPromptTable, - "prompt-keypress": m.uiInKey, - "confirm": m.uiConfirm, - "query": m.uiQuery, - "filter": m.uiFilter, - "bind": m.uiBind, - "set-item-annotator": m.uiSetItemAnnotator, + "command": m.uiCommand, + "prompt": m.uiPrompt, + "prompt-table": m.uiPromptTable, + "prompt-keypress": m.uiInKey, + "confirm": m.uiConfirm, + "query": m.uiQuery, + "filter": m.uiFilter, + "bind": m.uiBind, }, }, m.ckb } diff --git a/internal/common/ui/commandctrl/cmdpacks/proxy.go b/internal/common/ui/commandctrl/cmdpacks/proxy.go index 02f2325..9aa9fb3 100644 --- a/internal/common/ui/commandctrl/cmdpacks/proxy.go +++ b/internal/common/ui/commandctrl/cmdpacks/proxy.go @@ -234,49 +234,6 @@ func (tp itemProxy) Each(fn func(k string, v ucl.Object) error) error { return nil } -type attrPathProxy struct { - attrPath *models.AttrPathNode -} - -func (ap attrPathProxy) String() string { - return "RSItem()" -} - -func (ap attrPathProxy) Truthy() bool { - return true -} - -func (ap attrPathProxy) Len() (l int) { - for p := ap.attrPath; p != nil; p = p.Parent { - l++ - } - return -} - -func (ap attrPathProxy) Index(k int) ucl.Object { - if k == -1 { - return ucl.StringObject(ap.attrPath.Key) - } - - if k >= 0 { - k = ap.Len() - k - 1 - } else { - k = -k - 1 - } - - if k < 0 { - return nil - } - for p := ap.attrPath; p != nil; p = p.Parent { - if k <= 0 { - return ucl.StringObject(p.Key) - } - k -= 1 - } - - return nil -} - type attributeValueProxy struct { value types.AttributeValue } diff --git a/internal/common/ui/commandctrl/cmdpacks/proxy_test.go b/internal/common/ui/commandctrl/cmdpacks/proxy_test.go deleted file mode 100644 index 372e211..0000000 --- a/internal/common/ui/commandctrl/cmdpacks/proxy_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package cmdpacks - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/models" -) - -func TestAttrPathProxy_Index(t *testing.T) { - tests := []struct { - descr string - attrPath models.AttrPathNode - index int - want string - wantNil bool - }{ - { - descr: "return leaf 1", - attrPath: models.AttrPathNode{Key: "leaf"}, - index: -1, - want: "leaf", - }, - { - descr: "return leaf 2", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent"}}, - index: -1, - want: "leaf", - }, - { - descr: "return parent 1", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent"}}, - index: -2, - want: "parent", - }, - { - descr: "return parent 1", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent", Parent: &models.AttrPathNode{Key: "grandparent"}}}, - index: -2, - want: "parent", - }, - { - descr: "return parent 3", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent", Parent: &models.AttrPathNode{Key: "grandparent"}}}, - index: -3, - want: "grandparent", - }, - { - descr: "return root 1", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent", Parent: &models.AttrPathNode{Key: "grandparent"}}}, - index: 0, - want: "grandparent", - }, - { - descr: "return root 2", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent"}}, - index: 0, - want: "parent", - }, - { - descr: "return root 3", - attrPath: models.AttrPathNode{Key: "leaf"}, - index: 0, - want: "leaf", - }, - { - descr: "return first child 1", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent", Parent: &models.AttrPathNode{Key: "grandparent"}}}, - index: 1, - want: "parent", - }, - { - descr: "return first child 2", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent"}}, - index: 1, - want: "leaf", - }, - { - descr: "return nil 1", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent", Parent: &models.AttrPathNode{Key: "grandparent"}}}, - index: -5, - wantNil: true, - }, - { - descr: "return nil 2", - attrPath: models.AttrPathNode{Key: "leaf", Parent: &models.AttrPathNode{Key: "parent"}}, - index: 56, - wantNil: true, - }, - } - for _, tt := range tests { - t.Run(tt.descr, func(t *testing.T) { - proxy := attrPathProxy{&tt.attrPath} - if tt.wantNil { - assert.Nil(t, proxy.Index(tt.index)) - } else { - assert.Equal(t, tt.want, proxy.Index(tt.index).String()) - } - }) - } -} diff --git a/internal/common/ui/commandctrl/cmdpacks/stdcmds.go b/internal/common/ui/commandctrl/cmdpacks/stdcmds.go index 0d5c494..326543b 100644 --- a/internal/common/ui/commandctrl/cmdpacks/stdcmds.go +++ b/internal/common/ui/commandctrl/cmdpacks/stdcmds.go @@ -9,7 +9,6 @@ import ( "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/controllers" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/models" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/services" - "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/services/itemrenderer" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/services/tables" "ucl.lmika.dev/repl" "ucl.lmika.dev/ucl" @@ -24,7 +23,6 @@ type StandardCommands struct { KeyBindingController *controllers.KeyBindingController PBProvider services.PasteboardProvider SettingsController *controllers.SettingsController - ItemRenderer *itemrenderer.Service modUI ucl.Module } @@ -38,9 +36,8 @@ func NewStandardCommands( keyBindingController *controllers.KeyBindingController, pbProvider services.PasteboardProvider, settingsController *controllers.SettingsController, - itemRenderer *itemrenderer.Service, ) StandardCommands { - modUI, ckbs := moduleUI(tableService, state, readController, itemRenderer) + modUI, ckbs := moduleUI(tableService, state, readController) keyBindingController.SetCustomKeyBindingSource(ckbs) return StandardCommands{ @@ -52,7 +49,6 @@ func NewStandardCommands( KeyBindingController: keyBindingController, PBProvider: pbProvider, SettingsController: settingsController, - ItemRenderer: itemRenderer, modUI: modUI, } } @@ -404,7 +400,6 @@ func (sc StandardCommands) InstOptions() []ucl.InstOption { ucl.WithModule(modulePB(sc.PBProvider)), ucl.WithModule(moduleOpt(sc.SettingsController)), ucl.WithModule(moduleAttrValue()), - ucl.WithModule(moduleAsync(sc.TableService, sc.State)), } } @@ -454,30 +449,4 @@ ui:bind "view.toggle-marked-items" "M" { mark all } } - -proc _prep_officeCount { - openedOffices = 0 - closedOffices = 0 - - async:query 'officeOpened=$v' [v:(av:true)] { |rs| - openedOffices = len $rs - async:query 'officeOpened=$u' [u:(av:false)] { |rs| - closedOffices = len $rs - - ui:set-item-annotator { |rs item path| - if (eq $path.(-1) "officeOpened") { - if $item.officeOpened { - "Count = ${openedOffices}" - } else { - "Count = ${closedOffices}" - } - } else { - "" - } - } - } -table business-addresses - } -table business-addresses -} - -_prep_officeCount ` diff --git a/internal/common/ui/commandctrl/cmdpacks/stdcmds_test.go b/internal/common/ui/commandctrl/cmdpacks/stdcmds_test.go index 8863ca4..2d65be8 100644 --- a/internal/common/ui/commandctrl/cmdpacks/stdcmds_test.go +++ b/internal/common/ui/commandctrl/cmdpacks/stdcmds_test.go @@ -2,8 +2,6 @@ package cmdpacks_test import ( "fmt" - "testing" - tea "github.com/charmbracelet/bubbletea" bus "github.com/lmika/events" "github.com/stretchr/testify/assert" @@ -23,6 +21,7 @@ import ( "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/ui/keybindings" "lmika.dev/cmd/dynamo-browse/test/testdynamo" "lmika.dev/cmd/dynamo-browse/test/testworkspace" + "testing" ) func TestStdCmds_Mark(t *testing.T) { @@ -163,7 +162,6 @@ func newService(t *testing.T, opts ...serviceOpt) *services { keyBindingController, testPB, settingsController, - itemRendererService, ), ) diff --git a/internal/common/ui/commandctrl/commandctrl.go b/internal/common/ui/commandctrl/commandctrl.go index 7dc6ba4..5e0c330 100644 --- a/internal/common/ui/commandctrl/commandctrl.go +++ b/internal/common/ui/commandctrl/commandctrl.go @@ -4,14 +4,12 @@ import ( "bytes" "context" "fmt" + tea "github.com/charmbracelet/bubbletea" + "github.com/pkg/errors" "log" "os" "path/filepath" "strings" - - tea "github.com/charmbracelet/bubbletea" - "github.com/go-co-op/gocron/v2" - "github.com/pkg/errors" "ucl.lmika.dev/ucl" "ucl.lmika.dev/ucl/builtins" @@ -19,22 +17,12 @@ import ( "lmika.dev/cmd/dynamo-browse/internal/common/ui/events" ) -const ( - commandsCategory = "commands" - pendingTaskBuffer = 50 - pendingAuxTaskBuffer = 50 - auxWorkers = 4 -) +const commandsCategory = "commands" type cmdMessage struct { cmd string } -type pendingTask struct { - descr string - task func(ctx context.Context) error -} - type CommandController struct { uclInst *ucl.Inst historyProvider IterProvider @@ -42,29 +30,19 @@ type CommandController struct { lookupExtensions []CommandLookupExtension completionProvider CommandCompletionProvider uiStateProvider UIStateProvider - cronScheduler gocron.Scheduler cmdChan chan cmdMessage - pendingTaskChan chan pendingTask - pendingAuxTaskChan chan pendingTask msgChan chan tea.Msg interactive bool } func NewCommandController(historyProvider IterProvider, pkgs ...CommandPack) (*CommandController, error) { - sched, err := gocron.NewScheduler() - if err != nil { - return nil, err - } cc := &CommandController{ - historyProvider: historyProvider, - commandList: nil, - lookupExtensions: nil, - cronScheduler: sched, - cmdChan: make(chan cmdMessage), - pendingTaskChan: make(chan pendingTask, pendingTaskBuffer), - pendingAuxTaskChan: make(chan pendingTask, pendingAuxTaskBuffer), - msgChan: make(chan tea.Msg), - interactive: true, + historyProvider: historyProvider, + commandList: nil, + lookupExtensions: nil, + cmdChan: make(chan cmdMessage), + msgChan: make(chan tea.Msg), + interactive: true, } options := []ucl.InstOption{ @@ -97,8 +75,6 @@ func NewCommandController(historyProvider IterProvider, pkgs ...CommandPack) (*C } go cc.cmdLooper() - go cc.auxCmdLooper() - sched.Start() return cc, nil } @@ -196,13 +172,12 @@ func (c *CommandController) Invoke(invokable ucl.Invokable, args []any) (msg tea } func (c *CommandController) cmdLooper() { - ctx := context.Background() + execCtx := execContext{ctrl: c} + ctx := context.WithValue(context.Background(), commandCtlKey, &execCtx) + for { select { case cmdChan := <-c.cmdChan: - execCtx := execContext{ctrl: c} - ctx := context.WithValue(ctx, commandCtlKey, &execCtx) - res, err := c.ExecuteAndWait(ctx, cmdChan.cmd) if err != nil { c.postMessage(events.Error(err)) @@ -212,16 +187,6 @@ func (c *CommandController) cmdLooper() { if execCtx.requestRefresh { c.postMessage(events.ResultSetUpdated{}) } - case task := <-c.pendingTaskChan: - execCtx := execContext{ctrl: c} - ctx := context.WithValue(ctx, commandCtlKey, &execCtx) - - if err := task.task(ctx); err != nil { - c.postMessage(events.Error(err)) - } - if execCtx.requestRefresh { - c.postMessage(events.ResultSetUpdated{}) - } } } } @@ -340,13 +305,15 @@ func (c *CommandController) cmdInvoker(ctx context.Context, name string, args uc } func (c *CommandController) printLine(s string) { - log.Println(s) if c.msgChan == nil || !c.interactive { + log.Println(s) return } select { case c.msgChan <- events.StatusMsg(s): + default: + log.Println(s) } } @@ -358,21 +325,6 @@ func (c *CommandController) postMessage(msg tea.Msg) { c.msgChan <- msg } -func (c *CommandController) auxCmdLooper() { - ctx := context.WithValue(context.Background(), commandCtlKey, &execContext{ctrl: c}) - - for i := 0; i < auxWorkers; i++ { - go func() { - for auxTask := range c.pendingAuxTaskChan { - log.Printf("running aux task: %v", auxTask.descr) - if err := auxTask.task(ctx); err != nil { - log.Printf("aux task error: %v", err) - } - } - }() - } -} - type teaMsgWrapper struct { msg tea.Msg } diff --git a/internal/common/ui/commandctrl/ctx.go b/internal/common/ui/commandctrl/ctx.go index 3f5c7db..dffff70 100644 --- a/internal/common/ui/commandctrl/ctx.go +++ b/internal/common/ui/commandctrl/ctx.go @@ -2,10 +2,7 @@ package commandctrl import ( "context" - tea "github.com/charmbracelet/bubbletea" - "github.com/go-co-op/gocron/v2" - "github.com/pkg/errors" "ucl.lmika.dev/ucl" ) @@ -60,40 +57,6 @@ func QueueRefresh(ctx context.Context) { cmdCtl.requestRefresh = true } -func CronScheduler(ctx context.Context) gocron.Scheduler { - cmdCtl, ok := ctx.Value(commandCtlKey).(*execContext) - if !ok { - return nil - } - return cmdCtl.ctrl.cronScheduler -} - -func ScheduleTask(ctx context.Context, task func(ctx context.Context) error) error { - cmdCtl, ok := ctx.Value(commandCtlKey).(*execContext) - if !ok { - return errors.New("no command controller") - } - select { - case cmdCtl.ctrl.pendingTaskChan <- pendingTask{task: task}: - return nil - default: - return errors.New("task queue is full") - } -} - -func ScheduleAuxTask(ctx context.Context, descr string, task func(ctx context.Context) error) error { - cmdCtl, ok := ctx.Value(commandCtlKey).(*execContext) - if !ok { - return errors.New("no command controller") - } - select { - case cmdCtl.ctrl.pendingAuxTaskChan <- pendingTask{descr: descr, task: task}: - return nil - default: - return errors.New("aux task queue is full") - } -} - type Invoker interface { Invoke(invokable ucl.Invokable, args []any) tea.Msg Inst() *ucl.Inst diff --git a/internal/dynamo-browse/models/attrpath.go b/internal/dynamo-browse/models/attrpath.go deleted file mode 100644 index 34c3a2c..0000000 --- a/internal/dynamo-browse/models/attrpath.go +++ /dev/null @@ -1,6 +0,0 @@ -package models - -type AttrPathNode struct { - Key string - Parent *AttrPathNode -} diff --git a/internal/dynamo-browse/services/itemrenderer/service.go b/internal/dynamo-browse/services/itemrenderer/service.go index f4cee9e..d3a4881 100644 --- a/internal/dynamo-browse/services/itemrenderer/service.go +++ b/internal/dynamo-browse/services/itemrenderer/service.go @@ -2,30 +2,18 @@ package itemrenderer import ( "fmt" - "io" - "text/tabwriter" - "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/models" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/models/itemrender" + "io" + "text/tabwriter" ) type Service struct { - annotation Annotation - styles styleRenderer + styles styleRenderer } -func NewService( - fileTypeStyle StyleRenderer, - metaInfoStyle StyleRenderer, -) *Service { - if fileTypeStyle == nil { - fileTypeStyle = plainTextStyleRenderer{} - } - if metaInfoStyle == nil { - metaInfoStyle = plainTextStyleRenderer{} - } +func NewService(fileTypeStyle StyleRenderer, metaInfoStyle StyleRenderer) *Service { return &Service{ - annotation: nil, styles: styleRenderer{ fileTypeRenderer: fileTypeStyle, metaInfoRenderer: metaInfoStyle, @@ -33,10 +21,6 @@ func NewService( } } -func (s *Service) SetAnnotation(a Annotation) { - s.annotation = a -} - func (s *Service) RenderItem(w io.Writer, item models.Item, resultSet *models.ResultSet, plainText bool) { styles := s.styles if plainText { @@ -49,47 +33,25 @@ func (s *Service) RenderItem(w io.Writer, item models.Item, resultSet *models.Re for _, colName := range resultSet.Columns() { seenColumns[colName] = struct{}{} if r := itemrender.ToRenderer(item[colName]); r != nil { - p := models.AttrPathNode{Key: colName} - s.renderItem(tabWriter, resultSet, item, p, "", r, styles) + s.renderItem(tabWriter, "", colName, r, styles) } } for k, _ := range item { if _, seen := seenColumns[k]; !seen { if r := itemrender.ToRenderer(item[k]); r != nil { - p := models.AttrPathNode{Key: k} - s.renderItem(tabWriter, resultSet, item, p, "", r, styles) + s.renderItem(tabWriter, "", k, r, styles) } } } tabWriter.Flush() } -func (m *Service) renderItem( - w io.Writer, - resultSet *models.ResultSet, - item models.Item, - path models.AttrPathNode, - prefix string, - r itemrender.Renderer, - sr styleRenderer, -) { - fmt.Fprint(w, prefix) - fmt.Fprint(w, path.Key) - fmt.Fprint(w, "\t") - fmt.Fprint(w, sr.fileTypeRenderer.Render(r.TypeName())) - fmt.Fprint(w, "\t") - fmt.Fprint(w, r.StringValue()) - fmt.Fprint(w, sr.metaInfoRenderer.Render(r.MetaInfo())) - if m.annotation != nil { - fmt.Fprint(w, " ") - fmt.Fprint(w, sr.metaInfoRenderer.Render(m.annotation.AnnotateAttribute(resultSet, item, path))) - } - fmt.Fprint(w, "\n") - +func (m *Service) renderItem(w io.Writer, prefix string, name string, r itemrender.Renderer, sr styleRenderer) { + fmt.Fprintf(w, "%s%v\t%s\t%s%s\n", + prefix, name, sr.fileTypeRenderer.Render(r.TypeName()), r.StringValue(), sr.metaInfoRenderer.Render(r.MetaInfo())) if subitems := r.SubItems(); len(subitems) > 0 { for _, si := range subitems { - p := models.AttrPathNode{Key: si.Key, Parent: &path} - m.renderItem(w, resultSet, item, p, prefix+" ", si.Value, sr) + m.renderItem(w, prefix+" ", si.Key, si.Value, sr) } } } @@ -98,13 +60,3 @@ type styleRenderer struct { fileTypeRenderer StyleRenderer metaInfoRenderer StyleRenderer } - -type Annotation interface { - AnnotateAttribute(rs *models.ResultSet, item models.Item, path models.AttrPathNode) string -} - -type AnnotationFunc func(rs *models.ResultSet, item models.Item, path models.AttrPathNode) string - -func (af AnnotationFunc) AnnotateAttribute(rs *models.ResultSet, item models.Item, path models.AttrPathNode) string { - return af(rs, item, path) -} diff --git a/internal/dynamo-browse/ui/teamodels/dynamoitemview/model.go b/internal/dynamo-browse/ui/teamodels/dynamoitemview/model.go index dc95276..9bd770c 100644 --- a/internal/dynamo-browse/ui/teamodels/dynamoitemview/model.go +++ b/internal/dynamo-browse/ui/teamodels/dynamoitemview/model.go @@ -1,8 +1,6 @@ package dynamoitemview import ( - "strings" - "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" @@ -11,6 +9,7 @@ import ( "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/ui/teamodels/frame" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/ui/teamodels/layout" "lmika.dev/cmd/dynamo-browse/internal/dynamo-browse/ui/teamodels/styles" + "strings" ) type Model struct { diff --git a/internal/dynamo-browse/ui/teamodels/styles/styles.go b/internal/dynamo-browse/ui/teamodels/styles/styles.go index 504bc41..c288077 100644 --- a/internal/dynamo-browse/ui/teamodels/styles/styles.go +++ b/internal/dynamo-browse/ui/teamodels/styles/styles.go @@ -20,7 +20,7 @@ type ItemViewStyle struct { var DefaultStyles = Styles{ ItemView: ItemViewStyle{ FieldType: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#2B800C", Dark: "#73C653"}), - MetaInfo: lipgloss.NewStyle().Foreground(lipgloss.Color("#707070")), + MetaInfo: lipgloss.NewStyle().Foreground(lipgloss.Color("#888888")), }, Frames: frame.Style{ ActiveTitle: lipgloss.NewStyle().