Skip to content

Commit 57e445f

Browse files
authored
Merge pull request #73 from schnoddelbotz/master
RFE: Expose exit code from Terminal's shell #72
2 parents 5136d06 + ce253b5 commit 57e445f

File tree

5 files changed

+31
-8
lines changed

5 files changed

+31
-8
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,29 +45,29 @@ Already planned is:
4545
* Scroll-back
4646
* Background and font/size customisation
4747
* Split panels
48-
* Windows support
4948

5049
# Library
5150

5251
You can also use this project as a library to create your own
5352
terminal based applications, using the import path "github.com/fyne-io/terminal".
5453

55-
There are two modes, using the default shell (macOS and Linux) or connecting
56-
to a remote shell.
54+
There are two modes, using the default shell or connecting to a remote shell.
5755

5856
## Local Shell
5957

60-
To load a terminal widget and launch the current shell (works on macOS and Linux)
61-
use the `RunLocalShell` method after creating a `Terminal`, as follows:
58+
To load a terminal widget and launch the current shell (works on macOS and Linux;
59+
on Windows, it always uses PowerShell) use the `RunLocalShell` method after creating
60+
a `Terminal`, as follows:
6261

6362
```go
6463
// run new terminal and close app on terminal exit.
6564
t := terminal.New()
6665
go func() {
6766
_ = t.RunLocalShell()
67+
log.Printf("Terminal's shell exited with exit code: %d", t.ExitCode())
6868
a.Quit()
6969
}()
70-
70+
7171
// w is a fyne.Window created to hold the content
7272
w.SetContent(t)
7373
w.ShowAndRun()
@@ -82,7 +82,7 @@ For example to open a terminal to an SSH connection that you have created:
8282
in, _ := session.StdinPipe()
8383
out, _ := session.StdoutPipe()
8484
go session.Run("$SHELL || bash")
85-
85+
8686
// run new terminal and close app on terminal exit.
8787
t := terminal.New()
8888
go func() {

term.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"io"
66
"math"
77
"os"
8+
"os/exec"
89
"runtime"
910
"sync"
1011
"time"
@@ -82,6 +83,7 @@ type Terminal struct {
8283

8384
printData []byte
8485
printer Printer
86+
cmd *exec.Cmd
8587
}
8688

8789
// Printer is used for spooling print data when its received.
@@ -216,6 +218,16 @@ func (t *Terminal) Text() string {
216218
return t.content.Text()
217219
}
218220

221+
// ExitCode returns the exit code from the terminal's shell.
222+
// Returns -1 if called before shell was started or before shell exited.
223+
// Also returns -1 if shell was terminated by a signal.
224+
func (t *Terminal) ExitCode() int {
225+
if t.cmd == nil {
226+
return -1
227+
}
228+
return t.cmd.ProcessState.ExitCode()
229+
}
230+
219231
// TouchCancel handles the tap action for mobile apps that lose focus during tap.
220232
func (t *Terminal) TouchCancel(ev *mobile.TouchEvent) {
221233
if t.onMouseUp != nil {
@@ -294,6 +306,8 @@ func (t *Terminal) run() {
294306
for {
295307
num, err := t.out.Read(buf)
296308
if err != nil {
309+
// wait for cmd (shell) to exit, populates ProcessState.ExitCode
310+
t.cmd.Wait()
297311
// this is the pre-go 1.13 way to check for the read failing (terminal closed)
298312
if err.Error() == "EOF" {
299313
break // term exit on macOS

term_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ func TestNewTerminal(t *testing.T) {
1616
assert.NotNil(t, term.content)
1717
}
1818

19+
func TestExitCode(t *testing.T) {
20+
term := New()
21+
assert.Equal(t, term.ExitCode(), int(-1))
22+
}
23+
1924
func TestTerminal_Resize(t *testing.T) {
2025
term := New()
2126
term.Resize(fyne.NewSize(45, 45))

term_unix.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func (t *Terminal) startPTY() (io.WriteCloser, io.Reader, io.Closer, error) {
3737
env = append(env, "TERM=xterm-256color")
3838
c := exec.Command(shell)
3939
c.Env = env
40+
t.cmd = c
4041

4142
// Start the command with a pty.
4243
f, err := pty.Start(c)

term_windows.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"io"
55
"log"
66
"os"
7+
"os/exec"
78
"syscall"
89

910
"github.com/ActiveState/termtest/conpty"
@@ -33,15 +34,17 @@ func (t *Terminal) startPTY() (io.WriteCloser, io.Reader, io.Closer, error) {
3334
return nil, nil, nil, err
3435
}
3536

37+
t.cmd = &exec.Cmd{}
3638
process, err := os.FindProcess(pid)
3739
if err != nil {
3840
return nil, nil, nil, err
3941
}
4042
go func() {
41-
_, err := process.Wait()
43+
ps, err := process.Wait()
4244
if err != nil {
4345
log.Fatalf("Error waiting for process: %v", err)
4446
}
47+
t.cmd.ProcessState = ps
4548
if t.pty != nil {
4649
t.pty = nil
4750
_ = cpty.Close()

0 commit comments

Comments
 (0)