Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 64 additions & 30 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,44 @@ func (m *home) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case instanceChangedMsg:
// Handle instance changed after confirmation action
return m, m.instanceChanged()
case instanceStartedMsg:
if msg.err != nil {
// Find and select the failed instance, then kill it
for i, inst := range m.list.GetInstances() {
if inst == msg.instance {
m.list.SetSelectedInstance(i)
break
}
}
m.list.Kill()
return m, tea.Batch(m.handleError(msg.err), m.instanceChanged())
}

// Save after successful start
if err := m.storage.SaveInstances(m.list.GetInstances()); err != nil {
return m, m.handleError(err)
}
if m.autoYes {
msg.instance.AutoYes = true
}

if msg.promptAfterName {
// Select the started instance
for i, inst := range m.list.GetInstances() {
if inst == msg.instance {
m.list.SetSelectedInstance(i)
break
}
}
m.state = statePrompt
m.menu.SetState(ui.StatePrompt)
m.textInputOverlay = overlay.NewTextInputOverlay("Enter prompt", "")
} else {
m.menu.SetState(ui.StateDefault)
m.showHelpScreen(helpStart(msg.instance), nil)
}

return m, tea.Batch(tea.WindowSize(), m.instanceChanged())
case spinner.TickMsg:
var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
Expand Down Expand Up @@ -331,35 +369,25 @@ func (m *home) handleKeyPress(msg tea.KeyMsg) (mod tea.Model, cmd tea.Cmd) {
return m, m.handleError(fmt.Errorf("title cannot be empty"))
}

if err := instance.Start(true); err != nil {
m.list.Kill()
m.state = stateDefault
return m, m.handleError(err)
}
// Save after adding new instance
if err := m.storage.SaveInstances(m.list.GetInstances()); err != nil {
return m, m.handleError(err)
}
// Instance added successfully, call the finalizer.
m.newInstanceFinalizer()
if m.autoYes {
instance.AutoYes = true
}

// Set Loading status and finalize into the list immediately
instance.SetStatus(session.Loading)
m.newInstanceFinalizer()
promptAfterName := m.promptAfterName
m.promptAfterName = false
m.state = stateDefault
if m.promptAfterName {
m.state = statePrompt
m.menu.SetState(ui.StatePrompt)
// Initialize the text input overlay
m.textInputOverlay = overlay.NewTextInputOverlay("Enter prompt", "")
m.promptAfterName = false
} else {
m.menu.SetState(ui.StateDefault)
m.showHelpScreen(helpStart(instance), nil)
m.menu.SetState(ui.StateDefault)

// Return a tea.Cmd that runs instance.Start in the background
startCmd := func() tea.Msg {
err := instance.Start(true)
return instanceStartedMsg{
instance: instance,
err: err,
promptAfterName: promptAfterName,
}
}

return m, tea.Batch(tea.WindowSize(), m.instanceChanged())
return m, tea.Batch(tea.WindowSize(), m.instanceChanged(), startCmd)
case tea.KeyRunes:
if runewidth.StringWidth(instance.Title) >= 32 {
return m, m.handleError(fmt.Errorf("title cannot be longer than 32 characters"))
Expand Down Expand Up @@ -527,7 +555,7 @@ func (m *home) handleKeyPress(msg tea.KeyMsg) (mod tea.Model, cmd tea.Cmd) {
return m, m.instanceChanged()
case keys.KeyKill:
selected := m.list.GetSelectedInstance()
if selected == nil {
if selected == nil || selected.Status == session.Loading {
return m, nil
}

Expand Down Expand Up @@ -563,7 +591,7 @@ func (m *home) handleKeyPress(msg tea.KeyMsg) (mod tea.Model, cmd tea.Cmd) {
return m, m.confirmAction(message, killAction)
case keys.KeySubmit:
selected := m.list.GetSelectedInstance()
if selected == nil {
if selected == nil || selected.Status == session.Loading {
return m, nil
}

Expand All @@ -586,7 +614,7 @@ func (m *home) handleKeyPress(msg tea.KeyMsg) (mod tea.Model, cmd tea.Cmd) {
return m, m.confirmAction(message, pushAction)
case keys.KeyCheckout:
selected := m.list.GetSelectedInstance()
if selected == nil {
if selected == nil || selected.Status == session.Loading {
return m, nil
}

Expand All @@ -600,7 +628,7 @@ func (m *home) handleKeyPress(msg tea.KeyMsg) (mod tea.Model, cmd tea.Cmd) {
return m, nil
case keys.KeyResume:
selected := m.list.GetSelectedInstance()
if selected == nil {
if selected == nil || selected.Status == session.Loading {
return m, nil
}
if err := selected.Resume(); err != nil {
Expand All @@ -612,7 +640,7 @@ func (m *home) handleKeyPress(msg tea.KeyMsg) (mod tea.Model, cmd tea.Cmd) {
return m, nil
}
selected := m.list.GetSelectedInstance()
if selected == nil || selected.Paused() || !selected.TmuxAlive() {
if selected == nil || selected.Paused() || selected.Status == session.Loading || !selected.TmuxAlive() {
return m, nil
}
// Show help screen before attaching
Expand Down Expand Up @@ -674,6 +702,12 @@ type tickUpdateMetadataMessage struct{}

type instanceChangedMsg struct{}

type instanceStartedMsg struct {
instance *session.Instance
err error
promptAfterName bool
}

// tickUpdateMetadataCmd is the callback to update the metadata of the instances every 500ms. Note that we iterate
// overall the instances and capture their output. It's a pretty expensive operation. Let's do it 2x a second only.
var tickUpdateMetadataCmd = func() tea.Msg {
Expand Down
2 changes: 2 additions & 0 deletions ui/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ func (r *InstanceRenderer) Render(i *session.Instance, idx int, selected bool, h
switch i.Status {
case session.Running:
join = fmt.Sprintf("%s ", r.spinner.View())
case session.Loading:
join = fmt.Sprintf("%s ", r.spinner.View())
case session.Ready:
join = readyStyle.Render(readyIcon)
case session.Paused:
Expand Down
6 changes: 6 additions & 0 deletions ui/menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ func (m *Menu) updateOptions() {
}

func (m *Menu) addInstanceOptions() {
// Loading instances only get minimal options
if m.instance != nil && m.instance.Status == session.Loading {
m.options = []keys.KeyName{keys.KeyNew, keys.KeyHelp, keys.KeyQuit}
return
}

// Instance management group
options := []keys.KeyName{keys.KeyNew, keys.KeyKill}

Expand Down
3 changes: 3 additions & 0 deletions ui/preview.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ func (p *PreviewPane) UpdateContent(instance *session.Instance) error {
)),
))
return nil
case instance.Status == session.Loading:
p.setFallbackState("Setting up workspace...")
return nil
}

var content string
Expand Down
Loading