Skip to content

Commit

Permalink
fix: bug with pane deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
cfoust committed Dec 15, 2023
1 parent 38249a9 commit 64250f6
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 70 deletions.
14 changes: 6 additions & 8 deletions pkg/cy/api/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,13 @@ func (c *Cmd) New(
path string,
cmdParams *janet.Named[CmdParams],
) (tree.NodeID, error) {
client, ok := user.(Client)
if !ok {
return 0, fmt.Errorf("missing client context")
}

shell := "/bin/bash"
defaultShell, ok := client.Params().Get(cyParams.ParamDefaultShell)
if value, ok := defaultShell.(string); ok {
shell = value

if client, ok := user.(Client); ok {
defaultShell, _ := client.Params().Get(cyParams.ParamDefaultShell)
if value, ok := defaultShell.(string); ok {
shell = value
}
}

values := cmdParams.WithDefault(CmdParams{
Expand Down
60 changes: 40 additions & 20 deletions pkg/cy/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/cfoust/cy/pkg/geom"
P "github.com/cfoust/cy/pkg/io/protocol"
"github.com/cfoust/cy/pkg/io/ws"
"github.com/cfoust/cy/pkg/janet"
"github.com/cfoust/cy/pkg/mux/screen"
"github.com/cfoust/cy/pkg/mux/screen/server"
"github.com/cfoust/cy/pkg/mux/screen/splash"
Expand Down Expand Up @@ -212,14 +213,12 @@ func (c *Cy) pollClient(ctx context.Context, client *Client) {
go client.pollEvents()
go client.binds.Poll(client.Ctx())

node := c.findInitialPane()
if node == nil {
// TODO(cfoust): 06/08/23 handle this
err := client.findNewPane()
if err != nil {
client.closeError(err)
return
}

client.Attach(node)

c.sendQueuedToasts()

c.broadcastToast(client, toasts.Toast{
Expand Down Expand Up @@ -387,6 +386,32 @@ func (c *Client) initialize(handshake *P.HandshakeMessage) error {
return nil
}

// findNewPane looks for a pane that the client can attach to or creates a new
// one if none are suitable.
func (c *Client) findNewPane() error {
c.RLock()
history := c.history
c.RUnlock()

// First look back in history
for i := len(history) - 2; i >= 0; i-- {
node, ok := c.cy.tree.NodeById(history[i])
if !ok {
continue
}
return c.Attach(node)
}

// Then see if there are any other client panes
clientNode := c.cy.getFirstClientPane(c)
if clientNode != nil {
return c.Attach(clientNode)
}

// Otherwise just create a new shell and attach to it
return c.execute(`(shell/attach)`)
}

func (c *Client) Attach(node tree.Node) error {
pane, ok := node.(*tree.Pane)
if !ok {
Expand All @@ -407,21 +432,8 @@ func (c *Client) Attach(node tree.Node) error {
case <-c.muxClient.Attachment().Ctx().Done():
return
case <-pane.Ctx().Done():
// if the pane dies, just re-attach to the last node the user visited
c.RLock()
history := c.history
c.RUnlock()

if len(history) < 2 {
// TODO(cfoust): 09/20/23
return
}

node, ok := c.cy.tree.NodeById(history[len(history)-2])
if !ok {
return
}
c.Attach(node)
// TODO(cfoust): 12/15/23 handle error
c.findNewPane()
return
}
}()
Expand Down Expand Up @@ -473,4 +485,12 @@ func (c *Cy) HandleWSClient(conn ws.Client[P.Message]) {
<-conn.Ctx().Done()
}

// execute runs some Janet code on behalf of the client.
func (c *Client) execute(code string) error {
return c.cy.ExecuteCall(c.Ctx(), c, janet.Call{
Code: []byte(code),
Options: janet.DEFAULT_CALL_OPTIONS,
})
}

var _ ws.Server[P.Message] = (*Cy)(nil)
14 changes: 14 additions & 0 deletions pkg/cy/cy-boot.janet
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@
(input/find _ :prompt "search: actions")
(apply _)))

(defn
shell/new
```Create a new shell initialized in the working directory `path`.```
[&opt path]
(default path "")
(cmd/new shells path))

(defn
shell/attach
```Create a new shell initialized in the working directory `path` and attach to it.```
[&opt path]
(default path "")
(pane/attach (cmd/new shells path)))

(key/def
action/new-shell
"create a new shell"
Expand Down
17 changes: 9 additions & 8 deletions pkg/cy/cy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func TestEmpty(t *testing.T) {
time.Sleep(100 * time.Millisecond)

leaves := cy.tree.Leaves()
require.Equal(t, client.Node(), leaves[0])
require.Equal(t, client.Node(), leaves[1])
}

func TestSize(t *testing.T) {
Expand All @@ -175,7 +175,7 @@ func TestScopes(t *testing.T) {

_, client, err := server.Standard()
require.NoError(t, err)
require.Equal(t, 2, len(client.binds.Scopes()))
require.Equal(t, 3, len(client.binds.Scopes()))

cy := server.cy

Expand Down Expand Up @@ -205,14 +205,15 @@ func TestPaneKill(t *testing.T) {

_, client, err := server.Standard()
require.NoError(t, err)
leaves := server.cy.tree.Leaves()
id := client.Node().Id()
require.Equal(t, leaves[1].Id(), id)

require.NoError(t, client.execute(`
(def shell (cmd/new (tree/root) "/tmp"))
(pp shell)
(pane/attach shell)
(tree/kill shell)
(tree/kill (pane/current))
`))
time.Sleep(2 * time.Second) // lol
leaves := server.cy.tree.Leaves()
require.Equal(t, leaves[0].Id(), client.Node().Id())
require.NotEqual(t, id, client.Node().Id())
leaves = server.cy.tree.Leaves()
require.Equal(t, leaves[1].Id(), client.Node().Id())
}
8 changes: 0 additions & 8 deletions pkg/cy/janet.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,6 @@ var CY_BOOT_FILE []byte
//go:embed docs-cy.md
var DOCS_CY string

// execute runs some Janet code on behalf of the Client. This is only used in testing.
func (c *Client) execute(code string) error {
return c.cy.ExecuteCall(c.Ctx(), c, janet.Call{
Code: []byte(code),
Options: janet.DEFAULT_CALL_OPTIONS,
})
}

var (
KEYWORD_INFO = janet.Keyword("info")
KEYWORD_WARN = janet.Keyword("warn")
Expand Down
42 changes: 16 additions & 26 deletions pkg/cy/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"time"

"github.com/cfoust/cy/pkg/bind"
"github.com/cfoust/cy/pkg/cy/cmd"
"github.com/cfoust/cy/pkg/events"
"github.com/cfoust/cy/pkg/geom"
"github.com/cfoust/cy/pkg/janet"
Expand Down Expand Up @@ -86,26 +85,30 @@ func (c *Cy) loadUserConfig(ctx context.Context) {
}
}

// Get the pane that new clients attach to. If there are other clients, we
// attach to the pane of the first other client. Otherwise we attach to the
// first pane we find, depth-first.
func (c *Cy) findInitialPane() tree.Node {
// Get the first pane that another client is attached to or return nil if there
// are no other clients.
func (c *Cy) getFirstClientPane(except *Client) tree.Node {
c.RLock()
defer c.RUnlock()

if len(c.clients) > 0 {
node := c.clients[0].Node()
clients := c.clients

if len(clients) == 0 {
return nil
}

for _, client := range clients {
if client == except {
continue
}

node := client.Node()
if node != nil {
return node
}
}

leaves := c.tree.Leaves()
if len(leaves) == 0 {
return nil
}

return leaves[0]
return nil
}

func (c *Cy) Shutdown() error {
Expand Down Expand Up @@ -222,19 +225,6 @@ func Start(ctx context.Context, options Options) (*Cy, error) {
go cy.pollInteractions(cy.Ctx(), cy.lastWrite, cy.writes)
go cy.pollInteractions(cy.Ctx(), cy.lastVisit, cy.visits)

if len(options.Shell) > 0 {
replayable, _ := cmd.New(
cy.Ctx(),
stream.CmdOptions{
Command: "/bin/bash",
},
options.DataDir,
replayBinds,
)

t.Root().NewPane(cy.Ctx(), replayable)
}

logs := stream.NewReader()
terminal := screen.NewTerminal(cy.Ctx(), logs, geom.DEFAULT_SIZE)
logPane := t.Root().NewPane(cy.Ctx(), terminal)
Expand Down

0 comments on commit 64250f6

Please sign in to comment.