about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--commands/term-close.go29
-rw-r--r--commands/term.go13
-rw-r--r--lib/ui/tab.go4
-rw-r--r--lib/ui/text.go6
-rw-r--r--widgets/aerc.go8
-rw-r--r--widgets/terminal.go42
6 files changed, 85 insertions, 17 deletions
diff --git a/commands/term-close.go b/commands/term-close.go
new file mode 100644
index 0000000..38fcc27
--- /dev/null
+++ b/commands/term-close.go
@@ -0,0 +1,29 @@
+package commands
+
+import (
+	"errors"
+
+	"git.sr.ht/~sircmpwn/aerc2/lib/ui"
+	"git.sr.ht/~sircmpwn/aerc2/widgets"
+)
+
+func init() {
+	Register("term-close", TermClose)
+}
+
+func TermClose(aerc *widgets.Aerc, args []string) error {
+	if len(args) != 1 {
+		return errors.New("Usage: term-close")
+	}
+	grid, ok := aerc.SelectedTab().(*ui.Grid)
+	if !ok {
+		return errors.New("Error: not a terminal")
+	}
+	for _, child := range grid.Children() {
+		if term, ok := child.(*widgets.Terminal); ok {
+			term.Close(nil)
+			return nil
+		}
+	}
+	return errors.New("Error: not a terminal")
+}
diff --git a/commands/term.go b/commands/term.go
index 7ce1947..976ce29 100644
--- a/commands/term.go
+++ b/commands/term.go
@@ -2,10 +2,12 @@ package commands
 
 import (
 	"os/exec"
+	"time"
 
 	"git.sr.ht/~sircmpwn/aerc2/lib/ui"
 	"git.sr.ht/~sircmpwn/aerc2/widgets"
 
+	"github.com/gdamore/tcell"
 	"github.com/riywo/loginshell"
 )
 
@@ -32,13 +34,20 @@ func Term(aerc *widgets.Aerc, args []string) error {
 		{ui.SIZE_WEIGHT, 1},
 	})
 	grid.AddChild(term).At(0, 1)
-	tab := aerc.NewTab(grid, "Terminal")
+	tab := aerc.NewTab(grid, args[1])
 	term.OnTitle = func(title string) {
 		if title == "" {
-			title = "Terminal"
+			title = args[1]
 		}
 		tab.Name = title
 		tab.Content.Invalidate()
 	}
+	term.OnClose = func(err error) {
+		aerc.RemoveTab(grid)
+		if err != nil {
+			aerc.PushStatus(" "+err.Error(), 10*time.Second).
+				Color(tcell.ColorRed, tcell.ColorWhite)
+		}
+	}
 	return nil
 }
diff --git a/lib/ui/tab.go b/lib/ui/tab.go
index e41e906..32b195c 100644
--- a/lib/ui/tab.go
+++ b/lib/ui/tab.go
@@ -62,13 +62,13 @@ func (tabs *Tabs) Remove(content Drawable) {
 	}
 	/* Force the selected index into the existing range */
 	if tabs.Selected >= len(tabs.Tabs) {
-		tabs.Select(len(tabs.Tabs) - 1)
+		tabs.Select(tabs.Selected - 1)
 	}
 	tabs.TabStrip.Invalidate()
 }
 
 func (tabs *Tabs) Select(index int) {
-	if tabs.Selected >= len(tabs.Tabs) {
+	if index >= len(tabs.Tabs) {
 		panic("Tried to set tab index to a non-existing element")
 	}
 
diff --git a/lib/ui/text.go b/lib/ui/text.go
index d3f6c6b..b962166 100644
--- a/lib/ui/text.go
+++ b/lib/ui/text.go
@@ -20,7 +20,11 @@ type Text struct {
 }
 
 func NewText(text string) *Text {
-	return &Text{text: text}
+	return &Text{
+		bg:   tcell.ColorDefault,
+		fg:   tcell.ColorDefault,
+		text: text,
+	}
 }
 
 func (t *Text) Text(text string) *Text {
diff --git a/widgets/aerc.go b/widgets/aerc.go
index a968ab1..49a61bd 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -139,12 +139,20 @@ func (aerc *Aerc) SelectedAccount() *AccountView {
 	return acct
 }
 
+func (aerc *Aerc) SelectedTab() ui.Drawable {
+	return aerc.tabs.Tabs[aerc.tabs.Selected].Content
+}
+
 func (aerc *Aerc) NewTab(drawable ui.Drawable, name string) *ui.Tab {
 	tab := aerc.tabs.Add(drawable, name)
 	aerc.tabs.Select(len(aerc.tabs.Tabs) - 1)
 	return tab
 }
 
+func (aerc *Aerc) RemoveTab(tab ui.Drawable) {
+	aerc.tabs.Remove(tab)
+}
+
 func (aerc *Aerc) NextTab() {
 	next := aerc.tabs.Selected + 1
 	if next >= len(aerc.tabs.Tabs) {
diff --git a/widgets/terminal.go b/widgets/terminal.go
index bd84ab4..7726273 100644
--- a/widgets/terminal.go
+++ b/widgets/terminal.go
@@ -20,12 +20,14 @@ type Terminal struct {
 	cursorPos    vterm.Pos
 	cursorShown  bool
 	damage       []vterm.Rect
+	err          error
 	focus        bool
 	onInvalidate func(d ui.Drawable)
 	pty          *os.File
 	start        chan interface{}
 	vterm        *vterm.VTerm
 
+	OnClose func(err error)
 	OnTitle func(title string)
 }
 
@@ -41,11 +43,11 @@ func NewTerminal(cmd *exec.Cmd) (*Terminal, error) {
 		for {
 			n, err := term.pty.Read(buf)
 			if err != nil {
-				term.Close()
+				term.Close(err)
 			}
 			n, err = term.vterm.Write(buf[:n])
 			if err != nil {
-				term.Close()
+				term.Close(err)
 			}
 			term.Invalidate()
 		}
@@ -79,14 +81,24 @@ func NewTerminal(cmd *exec.Cmd) (*Terminal, error) {
 	return term, nil
 }
 
-func (term *Terminal) Close() {
-	if term.closed {
-		return
+func (term *Terminal) Close(err error) {
+	term.err = err
+	if term.vterm != nil {
+		term.vterm.Close()
+		term.vterm = nil
+	}
+	if term.pty != nil {
+		term.pty.Close()
+		term.pty = nil
+	}
+	if term.cmd != nil && term.cmd.Process != nil {
+		term.cmd.Process.Kill()
+		term.cmd = nil
+	}
+	if !term.closed && term.OnClose != nil {
+		term.OnClose(err)
 	}
 	term.closed = true
-	term.vterm.Close()
-	term.pty.Close()
-	term.cmd.Process.Kill()
 }
 
 func (term *Terminal) OnInvalidate(cb func(d ui.Drawable)) {
@@ -100,6 +112,15 @@ func (term *Terminal) Invalidate() {
 }
 
 func (term *Terminal) Draw(ctx *ui.Context) {
+	if term.closed {
+		if term.err != nil {
+			ui.NewText(term.err.Error()).Strategy(ui.TEXT_CENTER).Draw(ctx)
+		} else {
+			ui.NewText("Terminal closed").Strategy(ui.TEXT_CENTER).Draw(ctx)
+		}
+		return
+	}
+
 	winsize := pty.Winsize{
 		Cols: uint16(ctx.Width()),
 		Rows: uint16(ctx.Height()),
@@ -110,16 +131,13 @@ func (term *Terminal) Draw(ctx *ui.Context) {
 		tty, err := pty.StartWithSize(term.cmd, &winsize)
 		term.pty = tty
 		if err != nil {
-			term.Close()
+			term.Close(err)
 			return
 		}
 		term.start <- nil
 	}
 
 	term.ctx = ctx // gross
-	if term.closed {
-		return
-	}
 
 	rows, cols, err := pty.Getsize(term.pty)
 	if err != nil {