返回 DeepSeek-Reasonix
terminal_process_unix.go
根目录 / desktop / terminal_process_unix.go
1 //go:build !windows
2
3 package main
4
5 import (
6 "errors"
7 "os"
8 "os/exec"
9 "sync"
10 "syscall"
11
12 "github.com/creack/pty"
13 )
14
15 type unixTerminalProcess struct {
16 cmd *exec.Cmd
17 pty *os.File
18 closeOnce sync.Once
19 }
20
21 func terminalPlatformAvailable() (bool, string) {
22 return true, ""
23 }
24
25 func startTerminalProcess(spec terminalStartSpec) (terminalProcess, error) {
26 cmd := exec.Command(spec.command.path, spec.command.args...)
27 cmd.Dir = spec.dir
28 cmd.Env = spec.env
29 file, err := pty.StartWithSize(cmd, &pty.Winsize{Rows: uint16(spec.rows), Cols: uint16(spec.cols)})
30 if err != nil {
31 return nil, err
32 }
33 return &unixTerminalProcess{cmd: cmd, pty: file}, nil
34 }
35
36 func (p *unixTerminalProcess) Read(data []byte) (int, error) {
37 return p.pty.Read(data)
38 }
39
40 func (p *unixTerminalProcess) Write(data []byte) (int, error) {
41 return p.pty.Write(data)
42 }
43
44 func (p *unixTerminalProcess) Resize(cols, rows int) error {
45 return pty.Setsize(p.pty, &pty.Winsize{Rows: uint16(rows), Cols: uint16(cols)})
46 }
47
48 func (p *unixTerminalProcess) Wait() (int, error) {
49 err := p.cmd.Wait()
50 if p.cmd.ProcessState != nil {
51 return p.cmd.ProcessState.ExitCode(), err
52 }
53 var exitErr *exec.ExitError
54 if errors.As(err, &exitErr) {
55 return exitErr.ExitCode(), err
56 }
57 return -1, err
58 }
59
60 func (p *unixTerminalProcess) Close() error {
61 var closeErr error
62 p.closeOnce.Do(func() {
63 if p.cmd.Process != nil {
64 // creack/pty starts the command in a new session. Killing the process
65 // group prevents foreground children from surviving a closed tab.
66 _ = syscall.Kill(-p.cmd.Process.Pid, syscall.SIGKILL)
67 }
68 closeErr = p.pty.Close()
69 })
70 return closeErr
71 }
72
72 lines GO