From d1fc43ff6a4bd6ad6b5e058360f78539040dd754 Mon Sep 17 00:00:00 2001 From: Caleb Foust Date: Thu, 9 Nov 2023 05:36:28 -0500 Subject: [PATCH] feat: can open borg files! --- pkg/cy/api/path.go | 4 +++ pkg/cy/api/replay.go | 41 +++++++++++++++++++++++++---- pkg/cy/cy-boot.janet | 9 +++++++ pkg/cy/janet.go | 17 +++++++----- pkg/cy/module.go | 2 +- pkg/mux/screen/replay/copy.go | 7 ++--- pkg/mux/screen/replay/module.go | 30 +++++++++++++-------- pkg/mux/screen/replay/update.go | 4 +++ pkg/mux/screen/replayable/module.go | 3 +-- pkg/taro/program.go | 9 +++++++ 10 files changed, 98 insertions(+), 28 deletions(-) diff --git a/pkg/cy/api/path.go b/pkg/cy/api/path.go index 26c6f975..029393d9 100644 --- a/pkg/cy/api/path.go +++ b/pkg/cy/api/path.go @@ -17,3 +17,7 @@ func (p *PathModule) Base(path string) string { func (p *PathModule) Join(elem []string) string { return filepath.Join(elem...) } + +func (p *PathModule) Glob(pattern string) ([]string, error) { + return filepath.Glob(pattern) +} diff --git a/pkg/cy/api/replay.go b/pkg/cy/api/replay.go index d5e502a9..85433cc4 100644 --- a/pkg/cy/api/replay.go +++ b/pkg/cy/api/replay.go @@ -2,15 +2,20 @@ package api import ( "fmt" + "io" + "github.com/cfoust/cy/pkg/bind" "github.com/cfoust/cy/pkg/mux/screen/replay" "github.com/cfoust/cy/pkg/mux/screen/tree" "github.com/cfoust/cy/pkg/sessions" "github.com/cfoust/cy/pkg/taro" + "github.com/cfoust/cy/pkg/util" ) type ReplayModule struct { - Tree *tree.Tree + Lifetime util.Lifetime + Tree *tree.Tree + Binds *bind.BindScope } func (m *ReplayModule) send(context interface{}, msg taro.Msg) error { @@ -128,11 +133,37 @@ func (m *ReplayModule) Select(context interface{}) error { func (m *ReplayModule) Open( groupId tree.NodeID, path string, -) error { - _, err := sessions.Open(path) +) (tree.NodeID, error) { + group, ok := m.Tree.GroupById(groupId) + if !ok { + return 0, fmt.Errorf("node not found: %d", groupId) + } + + reader, err := sessions.Open(path) if err != nil { - return err + return 0, err } - return nil + events := make([]sessions.Event, 0) + for { + event, err := reader.Read() + if err == io.EOF || err == io.ErrUnexpectedEOF { + break + } + if err != nil { + return 0, err + } + events = append(events, event) + } + + ctx := m.Lifetime.Ctx() + replay := replay.New( + ctx, + events, + m.Binds, + replay.WithNoQuit, + ) + + pane := group.NewPane(ctx, replay) + return pane.Id(), nil } diff --git a/pkg/cy/cy-boot.janet b/pkg/cy/cy-boot.janet index 43560d00..4983cf78 100644 --- a/pkg/cy/cy-boot.janet +++ b/pkg/cy/cy-boot.janet @@ -128,6 +128,15 @@ (def [lines cols] (frame/size)) (frame/set-size [lines (- cols 10)])) +(key/def + cy/open-log + "open an existing log file" + (-?>> + (path/glob "/Users/cfoust/.local/share/cy/*.borg") + (fzf/find) + (replay/open (tree/root)) + (pane/attach))) + (key/bind :root [prefix "j"] ot/new-shell) (key/bind :root [prefix "n"] ot/new-project) (key/bind :root [prefix "k"] ot/jump-project) diff --git a/pkg/cy/janet.go b/pkg/cy/janet.go index 9f4395b9..fcb4e8a3 100644 --- a/pkg/cy/janet.go +++ b/pkg/cy/janet.go @@ -78,7 +78,7 @@ func (c *Cy) resolveGroup(target *janet.Value) (*tree.Group, error) { return group, nil } -func (c *Cy) initJanet(ctx context.Context) (*janet.VM, error) { +func (c *Cy) initJanet(ctx context.Context, dataDir string) (*janet.VM, error) { vm, err := janet.New(ctx) if err != nil { return nil, err @@ -87,13 +87,18 @@ func (c *Cy) initJanet(ctx context.Context) (*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}, - "pane": &api.PaneModule{Tree: c.tree}, - "path": &api.PathModule{}, - "replay": &api.ReplayModule{}, - "tree": &api.TreeModule{Tree: c.tree}, + "group": &api.GroupModule{Tree: c.tree}, + "pane": &api.PaneModule{Tree: c.tree}, + "path": &api.PathModule{}, + "replay": &api.ReplayModule{ + Lifetime: util.NewLifetime(c.Ctx()), + Tree: c.tree, + Binds: c.replayBinds, + }, + "tree": &api.TreeModule{Tree: c.tree}, } for name, module := range modules { diff --git a/pkg/cy/module.go b/pkg/cy/module.go index 56d1516b..4c1d1b5a 100644 --- a/pkg/cy/module.go +++ b/pkg/cy/module.go @@ -132,7 +132,7 @@ func Start(ctx context.Context, options Options) (*Cy, error) { consoleWriter := zerolog.ConsoleWriter{Out: logs.Writer(), TimeFormat: time.RFC3339} cy.log = log.Output(zerolog.MultiLevelWriter(consoleWriter, os.Stdout)) - vm, err := cy.initJanet(ctx) + vm, err := cy.initJanet(ctx, options.DataDir) if err != nil { return nil, err } diff --git a/pkg/mux/screen/replay/copy.go b/pkg/mux/screen/replay/copy.go index 2160afc0..9ee96120 100644 --- a/pkg/mux/screen/replay/copy.go +++ b/pkg/mux/screen/replay/copy.go @@ -66,9 +66,10 @@ func (r *Replay) handleCopy() (taro.Model, tea.Cmd) { r.viewportToTerm(r.cursor), ) return r, func() tea.Msg { - r.emit <- CopyEvent{ - Text: text, + return taro.PublishMsg{ + Message: CopyEvent{ + Text: text, + }, } - return nil } } diff --git a/pkg/mux/screen/replay/module.go b/pkg/mux/screen/replay/module.go index 78bfc581..189b2d16 100644 --- a/pkg/mux/screen/replay/module.go +++ b/pkg/mux/screen/replay/module.go @@ -6,7 +6,6 @@ import ( "github.com/cfoust/cy/pkg/bind" "github.com/cfoust/cy/pkg/emu" - "github.com/cfoust/cy/pkg/events" "github.com/cfoust/cy/pkg/geom" "github.com/cfoust/cy/pkg/sessions" "github.com/cfoust/cy/pkg/sessions/search" @@ -20,6 +19,9 @@ type Replay struct { render *taro.Renderer binds *bind.Engine[bind.Action] + // whether Replay will actually quit itself + preventExit bool + // the size of the terminal terminal emu.Terminal @@ -71,8 +73,6 @@ type Replay struct { isWaiting bool searchInput textinput.Model matches []search.SearchResult - - emit chan<- events.Msg } var _ taro.Model = (*Replay)(nil) @@ -134,7 +134,6 @@ func (r *Replay) Init() tea.Cmd { func newReplay( events []sessions.Event, binds *bind.Engine[bind.Action], - emit chan<- events.Msg, ) *Replay { ti := textinput.New() ti.Focus() @@ -148,24 +147,33 @@ func newReplay( searchInput: ti, playbackRate: 1, binds: binds, - emit: emit, skipInactivity: true, } m.gotoIndex(-1, -1) return m } +type ReplayOption func(r *Replay) + +func WithNoQuit(r *Replay) { + r.preventExit = true +} + func New( ctx context.Context, - recorder *sessions.Recorder, + events []sessions.Event, replayBinds *bind.BindScope, - replayEvents chan<- events.Msg, + options ...ReplayOption, ) *taro.Program { - events := recorder.Events() - engine := bind.NewEngine[bind.Action]() engine.SetScopes(replayBinds) go engine.Poll(ctx) + r := newReplay(events, engine) + for _, option := range options { + option(r) + } + program := taro.New(ctx, r) + go func() { for { select { @@ -173,11 +181,11 @@ func New( return case event := <-engine.Recv(): if bindEvent, ok := event.(bind.BindEvent); ok { - replayEvents <- bindEvent + program.Publish(bindEvent) } } } }() - return taro.New(ctx, newReplay(events, engine, replayEvents)) + return program } diff --git a/pkg/mux/screen/replay/update.go b/pkg/mux/screen/replay/update.go index 347215f5..d2c2dfd6 100644 --- a/pkg/mux/screen/replay/update.go +++ b/pkg/mux/screen/replay/update.go @@ -10,6 +10,10 @@ import ( ) func (r *Replay) quit() (taro.Model, tea.Cmd) { + if r.preventExit { + return r, nil + } + return r, tea.Quit } diff --git a/pkg/mux/screen/replayable/module.go b/pkg/mux/screen/replayable/module.go index 995529fc..908e9563 100644 --- a/pkg/mux/screen/replayable/module.go +++ b/pkg/mux/screen/replayable/module.go @@ -47,9 +47,8 @@ func (r *Replayable) EnterReplay() { events := make(chan mux.Msg) replay := replay.New( r.Ctx(), - r.recorder, + r.recorder.Events(), r.binds, - events, ) r.NewLayer( diff --git a/pkg/taro/program.go b/pkg/taro/program.go index 067502d9..b501c58d 100644 --- a/pkg/taro/program.go +++ b/pkg/taro/program.go @@ -110,6 +110,11 @@ func Sequence(cmds ...tea.Cmd) tea.Cmd { // sequenceMsg is used internally to run the given commands in order. type sequenceMsg []tea.Cmd +// Indicates that this message should be emitted upwards. +type PublishMsg struct { + Message Msg +} + // NewProgram creates a new Program. func NewProgram(model Model) *Program { p := &Program{ @@ -185,6 +190,10 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) { case tea.QuitMsg: return model, nil + case PublishMsg: + p.Publish(msg.Message) + continue + case tea.BatchMsg: for _, cmd := range msg { cmds <- cmd