Skip to content

Commit

Permalink
feat: add support for parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
cfoust committed Nov 10, 2023
1 parent 3692ec0 commit 462b229
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 12 deletions.
14 changes: 10 additions & 4 deletions pkg/cy/api/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/cfoust/cy/pkg/bind"
"github.com/cfoust/cy/pkg/cy/cmd"
"github.com/cfoust/cy/pkg/cy/params"
"github.com/cfoust/cy/pkg/janet"
"github.com/cfoust/cy/pkg/mux/screen/replayable"
"github.com/cfoust/cy/pkg/mux/screen/tree"
Expand All @@ -21,16 +22,15 @@ type CmdParams struct {
type Cmd struct {
Lifetime util.Lifetime
Tree *tree.Tree
DataDir string
replayBinds *bind.BindScope
}

func (c *Cmd) New(
groupId tree.NodeID,
path string,
params *janet.Named[CmdParams],
cmdParams *janet.Named[CmdParams],
) (tree.NodeID, error) {
values := params.WithDefault(CmdParams{
values := cmdParams.WithDefault(CmdParams{
Command: "/bin/bash",
})

Expand All @@ -39,14 +39,20 @@ func (c *Cmd) New(
return 0, fmt.Errorf("node not found: %d", groupId)
}

param, _ := group.Params().Get(params.ParamDataDirectory)
dataDir, ok := param.(string)
if !ok {
return 0, fmt.Errorf("param %s was not a string", params.ParamDataDirectory)
}

replayable, err := cmd.New(
c.Lifetime.Ctx(),
stream.CmdOptions{
Command: values.Command,
Args: values.Args,
Directory: path,
},
c.DataDir,
dataDir,
c.replayBinds,
)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cy/cy-boot.janet
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
cy/open-log
"open an existing log file"
(-?>>
(path/glob "/Users/cfoust/.local/share/cy/*.borg")
(path/glob (path/join [(cy/get :data-dir) "*.borg"]))
(map |(tuple $ [:replay [$]] $))
(fzf/find)
(replay/open (tree/root))
Expand Down
19 changes: 19 additions & 0 deletions pkg/cy/defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cy

import (
"github.com/cfoust/cy/pkg/cy/params"
)

func (c *Cy) setDefaults(options Options) error {
defaults := map[string]interface{}{
params.ParamDataDirectory: options.DataDir,
}

for key, value := range defaults {
err := c.defaults.Set(key, value)
if err != nil {
return err
}
}
return nil
}
58 changes: 57 additions & 1 deletion pkg/cy/janet.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ func (c *Cy) initJanet(ctx context.Context, dataDir string) (*janet.VM, error) {
modules := map[string]interface{}{
"cmd": &api.Cmd{
Lifetime: util.NewLifetime(c.Ctx()),
DataDir: dataDir,
Tree: c.tree,
},
"group": &api.GroupModule{Tree: c.tree},
Expand Down Expand Up @@ -120,6 +119,63 @@ func (c *Cy) initJanet(ctx context.Context, dataDir string) (*janet.VM, error) {

client.Detach("detached")
},
"cy/get": func(user interface{}, key *janet.Value) (interface{}, error) {
defer key.Free()

client, ok := user.(*Client)
if !ok {
return nil, fmt.Errorf("missing client context")
}

node := client.Node()
if node == nil {
return nil, fmt.Errorf("client was not attached")
}

var keyword janet.Keyword
err := key.Unmarshal(&keyword)
if err != nil {
return nil, err
}

value, ok := node.Params().Get(string(keyword))
return value, nil
},
"cy/set": func(user interface{}, key *janet.Value, value *janet.Value) error {
defer key.Free()

client, ok := user.(*Client)
if !ok {
return fmt.Errorf("missing client context")
}

node := client.Node()
if node == nil {
return fmt.Errorf("client was not attached")
}

var keyword janet.Keyword
err := key.Unmarshal(&keyword)
if err != nil {
return err
}

var str string
err = value.Unmarshal(&str)
if err == nil {
node.Params().Set(string(keyword), str)
return nil
}

var _int int
err = value.Unmarshal(&_int)
if err == nil {
node.Params().Set(string(keyword), _int)
return nil
}

return fmt.Errorf("parameter type not supported")
},
"cy/replay": func(user interface{}) {
client, ok := user.(*Client)
if !ok {
Expand Down
15 changes: 14 additions & 1 deletion pkg/cy/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/cfoust/cy/pkg/mux/screen/toasts"
"github.com/cfoust/cy/pkg/mux/screen/tree"
"github.com/cfoust/cy/pkg/mux/stream"
"github.com/cfoust/cy/pkg/params"
"github.com/cfoust/cy/pkg/util"

"github.com/rs/zerolog"
Expand All @@ -32,10 +33,16 @@ type Options struct {
type Cy struct {
util.Lifetime
deadlock.RWMutex

janet *janet.VM

muxServer *server.Server

// The top-level fallback for all parameter queries. This is distinct
// from the *Parameters at the root node of the tree, which the user
// can actually change.
defaults *params.Parameters

// The tree of groups and panes
tree *tree.Tree

Expand Down Expand Up @@ -101,14 +108,20 @@ func (c *Cy) Shutdown() error {
func Start(ctx context.Context, options Options) (*Cy, error) {
replayBinds := bind.NewBindScope()

t := tree.NewTree()
defaults := params.New()
t := tree.NewTree(tree.WithParams(defaults.NewChild()))
cy := Cy{
Lifetime: util.NewLifetime(ctx),
tree: t,
muxServer: server.New(),
replayBinds: replayBinds,
defaults: defaults,
}
cy.toast = NewToastLogger(cy.sendToast)
err := cy.setDefaults(options)
if err != nil {
return nil, err
}

subscriber := t.Subscribe(cy.Ctx())
go cy.pollNodeEvents(cy.Ctx(), subscriber.Recv())
Expand Down
6 changes: 6 additions & 0 deletions pkg/cy/params/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package params

const (
// The directory in which .borg files will be saved.
ParamDataDirectory = "data-dir"
)
14 changes: 13 additions & 1 deletion pkg/janet/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ func isValidType(type_ reflect.Type) bool {
}
}

// IsValidType returns true if the given value can be translated to a Janet value.
func IsValidType(value interface{}) bool {
return isValidType(reflect.TypeOf(value))
}

// Marshal a Go value into a Janet value.
func (v *VM) marshal(item interface{}) (result C.Janet, err error) {
result = C.janet_wrap_nil()
Expand Down Expand Up @@ -293,9 +298,16 @@ func (v *VM) unmarshal(source C.Janet, dest interface{}) error {
}

strPtr := strings.Clone(C.GoString(C.cast_janet_string(C.janet_unwrap_keyword(source))))
if strPtr != string(keyword) {

// if the keyword already contains a value, act as if
// we're comparing against a constant
keywordValue := string(keyword)
if len(keywordValue) == 0 {
value.SetString(strings.Clone(strPtr))
} else if strPtr != keywordValue {
return fmt.Errorf("keyword :%s does not match :%s", strPtr, keyword)
}

return nil
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/mux/screen/tree/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func (g *Group) NewPane(ctx context.Context, screen mux.Screen) *Pane {
metadata := g.tree.newMetadata()
pane := newPane(ctx, metadata.Id(), screen)
pane.metaData = metadata
metadata.params = g.params.NewChild()
g.addNode(pane)

go func() {
Expand All @@ -78,6 +79,7 @@ func (g *Group) NewGroup() *Group {
metaData: g.tree.newMetadata(),
tree: g.tree,
}
g.params = g.params.NewChild()
g.addNode(group)
return group
}
13 changes: 10 additions & 3 deletions pkg/mux/screen/tree/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"unicode"

"github.com/cfoust/cy/pkg/bind"
"github.com/cfoust/cy/pkg/params"

"github.com/sasha-s/go-deadlock"
)
Expand All @@ -13,9 +14,10 @@ type NodeID = int32

type metaData struct {
deadlock.RWMutex
id NodeID
name string
binds *bind.BindScope
id NodeID
name string
binds *bind.BindScope
params *params.Parameters
}

func (m *metaData) Id() int32 {
Expand All @@ -28,6 +30,10 @@ func (m *metaData) Name() string {
return m.name
}

func (m *metaData) Params() *params.Parameters {
return m.params
}

func (m *metaData) SetName(name string) {
m.Lock()
defer m.Unlock()
Expand All @@ -47,6 +53,7 @@ func (m *metaData) Binds() *bind.BindScope {
type Node interface {
Id() NodeID
Name() string
Params() *params.Parameters
SetName(string)
Binds() *bind.BindScope
}
15 changes: 14 additions & 1 deletion pkg/mux/screen/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/cfoust/cy/pkg/bind"
"github.com/cfoust/cy/pkg/mux"
"github.com/cfoust/cy/pkg/params"

"github.com/sasha-s/go-deadlock"
)
Expand Down Expand Up @@ -140,7 +141,15 @@ func (t *Tree) GroupById(id NodeID) (*Group, bool) {
return group, true
}

func NewTree() *Tree {
type TreeOption func(*Tree)

func WithParams(p *params.Parameters) TreeOption {
return func(t *Tree) {
t.root.params = p
}
}

func NewTree(options ...TreeOption) *Tree {
tree := &Tree{
UpdatePublisher: mux.NewPublisher(),
nodes: make(map[NodeID]Node),
Expand All @@ -153,5 +162,9 @@ func NewTree() *Tree {

tree.storeNode(tree.root)

for _, option := range options {
option(tree)
}

return tree
}
53 changes: 53 additions & 0 deletions pkg/params/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package params

import (
"fmt"

"github.com/cfoust/cy/pkg/janet"

"github.com/sasha-s/go-deadlock"
)

type Parameters struct {
deadlock.RWMutex
parent *Parameters
table map[string]interface{}
}

func (p *Parameters) Set(key string, value interface{}) error {
if !janet.IsValidType(value) {
return fmt.Errorf("all parameters must be representable in Janet")
}

p.Lock()
p.table[key] = value
p.Unlock()
return nil
}

func (p *Parameters) Get(key string) (value interface{}, ok bool) {
var current *Parameters = p
for current != nil {
current.RLock()
value, ok = current.table[key]
current.RUnlock()
if ok {
return value, ok
}
current = current.parent
}

return nil, false
}

func (p *Parameters) NewChild() *Parameters {
child := New()
child.parent = p
return child
}

func New() *Parameters {
return &Parameters{
table: make(map[string]interface{}),
}
}

0 comments on commit 462b229

Please sign in to comment.