mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
Windows Pty (#206)
Add Windows Pty support, so the terminal works properly on windows machines
This commit is contained in:
parent
4498ca8e9d
commit
c192fe2663
10
Taskfile.yml
10
Taskfile.yml
@ -8,6 +8,8 @@ vars:
|
||||
BIN_DIR: "bin"
|
||||
VERSION:
|
||||
sh: node version.cjs
|
||||
RM: '{{if eq OS "windows"}}powershell Remove-Item{{else}}rm{{end}}'
|
||||
DATE: '{{if eq OS "windows"}}powershell date -UFormat{{else}}date{{end}}'
|
||||
|
||||
tasks:
|
||||
electron:dev:
|
||||
@ -50,7 +52,7 @@ tasks:
|
||||
status:
|
||||
- exit {{if eq OS "darwin"}}1{{else}}0{{end}}
|
||||
cmds:
|
||||
- cmd: rm dist/bin/wavesrv*
|
||||
- cmd: '{{.RM}} "dist/bin/wavesrv*"'
|
||||
ignore_error: true
|
||||
- task: build:server:internal
|
||||
vars:
|
||||
@ -64,7 +66,7 @@ tasks:
|
||||
status:
|
||||
- exit {{if eq OS "darwin"}}0{{else}}1{{end}}
|
||||
cmds:
|
||||
- cmd: rm dist/bin/wavesrv*
|
||||
- cmd: '{{.RM}} "dist/bin/wavesrv*"'
|
||||
ignore_error: true
|
||||
- task: build:server:internal
|
||||
vars:
|
||||
@ -77,7 +79,7 @@ tasks:
|
||||
vars:
|
||||
- GOARCH
|
||||
cmds:
|
||||
- CGO_ENABLED=1 GOARCH={{.GOARCH}} go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "{{.GO_LDFLAGS}} -X main.BuildTime=$(date +'%Y%m%d%H%M') -X main.WaveVersion={{.VERSION}}" -o dist/bin/wavesrv.{{.GOARCH}}{{exeExt}} cmd/server/main-server.go
|
||||
- CGO_ENABLED=1 GOARCH={{.GOARCH}} go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "{{.GO_LDFLAGS}} -X main.BuildTime=$({{.DATE}} +'%Y%m%d%H%M') -X main.WaveVersion={{.VERSION}}" -o dist/bin/wavesrv.{{.GOARCH}}{{exeExt}} cmd/server/main-server.go
|
||||
sources:
|
||||
- "cmd/server/*.go"
|
||||
- "pkg/**/*.go"
|
||||
@ -133,7 +135,7 @@ tasks:
|
||||
generates:
|
||||
- dist/bin/wsh-{{.VERSION}}-{{.GOOS}}.{{.GOARCH}}{{.EXT}}
|
||||
cmds:
|
||||
- (CGO_ENABLED=0 GOOS={{.GOOS}} GOARCH={{.GOARCH}} go build -ldflags="-s -w -X main.BuildTime=$(date +'%Y%m%d%H%M')" -o dist/bin/wsh-{{.VERSION}}-{{.GOOS}}.{{.GOARCH}}{{.EXT}} cmd/wsh/main-wsh.go)
|
||||
- (CGO_ENABLED=0 GOOS={{.GOOS}} GOARCH={{.GOARCH}} go build -ldflags="-s -w -X main.BuildTime=$({{.DATE}} +'%Y%m%d%H%M')" -o dist/bin/wsh-{{.VERSION}}-{{.GOOS}}.{{.GOARCH}}{{.EXT}} cmd/wsh/main-wsh.go)
|
||||
deps:
|
||||
- generate
|
||||
- go:mod:tidy
|
||||
|
@ -226,6 +226,9 @@ func main() {
|
||||
if pidStr != "" {
|
||||
_, err := strconv.Atoi(pidStr)
|
||||
if err == nil {
|
||||
if BuildTime == "" {
|
||||
BuildTime = "0"
|
||||
}
|
||||
// use fmt instead of log here to make sure it goes directly to stderr
|
||||
fmt.Fprintf(os.Stderr, "WAVESRV-ESTART ws:%s web:%s version:%s buildtime:%s\n", wsListener.Addr(), webListener.Addr(), WaveVersion, BuildTime)
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ function getWaveSrvPath(): string {
|
||||
if (process.platform === "win32") {
|
||||
const winBinName = `${wavesrvBinName}.exe`;
|
||||
const appPath = path.join(getGoAppBasePath(), "bin", winBinName);
|
||||
return `& "${appPath}"`;
|
||||
return `${appPath}`;
|
||||
}
|
||||
return path.join(getGoAppBasePath(), "bin", wavesrvBinName);
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -44,3 +44,5 @@ require (
|
||||
)
|
||||
|
||||
replace github.com/kevinburke/ssh_config => github.com/wavetermdev/ssh_config v0.0.0-20240306041034-17e2087ebde2
|
||||
|
||||
replace github.com/creack/pty => github.com/photostorm/pty v1.1.19-0.20230903182454-31354506054b
|
||||
|
5
go.sum
5
go.sum
@ -3,8 +3,6 @@ filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4
|
||||
github.com/alexflint/go-filemutex v1.3.0 h1:LgE+nTUWnQCyRKbpoceKZsPQbs84LivvgwUymZXdOcM=
|
||||
github.com/alexflint/go-filemutex v1.3.0/go.mod h1:U0+VA/i30mGBlLCrFPGtTe9y6wGQfNAWPBTekHQ+c8A=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
||||
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -48,6 +46,8 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/photostorm/pty v1.1.19-0.20230903182454-31354506054b h1:cLGKfKb1uk0hxI0Q8L83UAJPpeJ+gSpn3cCU/tjd3eg=
|
||||
github.com/photostorm/pty v1.1.19-0.20230903182454-31354506054b/go.mod h1:KO+FcPtyLAiRC0hJwreJVvfwc7vnNz77UxBTIGHdPVk=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
@ -90,6 +90,7 @@ golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220721230656-c6bc011c0c49/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/creack/pty"
|
||||
"github.com/wavetermdev/thenextwave/pkg/eventbus"
|
||||
"github.com/wavetermdev/thenextwave/pkg/filestore"
|
||||
"github.com/wavetermdev/thenextwave/pkg/shellexec"
|
||||
@ -329,7 +328,7 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
|
||||
shellInputCh := make(chan *BlockInputUnion, 32)
|
||||
bc.ShellInputCh = shellInputCh
|
||||
messageCh := make(chan []byte, 32)
|
||||
ptyBuffer := wshutil.MakePtyBuffer(wshutil.WaveOSCPrefix, bc.ShellProc.Pty, messageCh)
|
||||
ptyBuffer := wshutil.MakePtyBuffer(wshutil.WaveOSCPrefix, bc.ShellProc.Cmd, messageCh)
|
||||
outputCh := make(chan []byte, 32)
|
||||
WshServerFactoryFn(messageCh, outputCh, wshrpc.RpcContext{BlockId: bc.BlockId, TabId: bc.TabId})
|
||||
go func() {
|
||||
@ -368,17 +367,13 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
|
||||
// handles input from the shellInputCh, sent to pty
|
||||
for ic := range shellInputCh {
|
||||
if len(ic.InputData) > 0 {
|
||||
bc.ShellProc.Pty.Write(ic.InputData)
|
||||
bc.ShellProc.Cmd.Write(ic.InputData)
|
||||
}
|
||||
if ic.TermSize != nil {
|
||||
log.Printf("SETTERMSIZE: %dx%d\n", ic.TermSize.Rows, ic.TermSize.Cols)
|
||||
err := pty.Setsize(bc.ShellProc.Pty, &pty.Winsize{Rows: uint16(ic.TermSize.Rows), Cols: uint16(ic.TermSize.Cols)})
|
||||
if err != nil {
|
||||
log.Printf("error setting term size: %v\n", err)
|
||||
}
|
||||
err = bc.ShellProc.Cmd.SetSize(ic.TermSize.Rows, ic.TermSize.Cols)
|
||||
if err != nil {
|
||||
log.Printf("error setting remote SIGWINCH: %v\n", err)
|
||||
log.Printf("error setting pty size: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ package shellexec
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/creack/pty"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
@ -16,10 +16,12 @@ type ConnInterface interface {
|
||||
StdoutPipe() (io.ReadCloser, error)
|
||||
StderrPipe() (io.ReadCloser, error)
|
||||
SetSize(w int, h int) error
|
||||
pty.Pty
|
||||
}
|
||||
|
||||
type CmdWrap struct {
|
||||
Cmd *exec.Cmd
|
||||
pty.Pty
|
||||
}
|
||||
|
||||
func (cw CmdWrap) Kill() {
|
||||
@ -54,13 +56,18 @@ func (cw CmdWrap) StderrPipe() (io.ReadCloser, error) {
|
||||
}
|
||||
|
||||
func (cw CmdWrap) SetSize(w int, h int) error {
|
||||
err := pty.Setsize(cw.Pty, &pty.Winsize{Rows: uint16(w), Cols: uint16(h)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SessionWrap struct {
|
||||
Session *ssh.Session
|
||||
StartCmd string
|
||||
Tty *os.File
|
||||
Tty pty.Tty
|
||||
pty.Pty
|
||||
}
|
||||
|
||||
func (sw SessionWrap) Kill() {
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -24,7 +25,6 @@ import (
|
||||
"github.com/wavetermdev/thenextwave/pkg/remote"
|
||||
"github.com/wavetermdev/thenextwave/pkg/util/shellutil"
|
||||
"github.com/wavetermdev/thenextwave/pkg/wavebase"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
type TermSize struct {
|
||||
@ -41,7 +41,6 @@ type CommandOptsType struct {
|
||||
|
||||
type ShellProc struct {
|
||||
Cmd ConnInterface
|
||||
Pty *os.File
|
||||
CloseOnce *sync.Once
|
||||
DoneCh chan any // closed after proc.Wait() returns
|
||||
WaitErr error // WaitErr is synchronized by DoneCh (written before DoneCh is closed) and CloseOnce
|
||||
@ -52,7 +51,13 @@ func (sp *ShellProc) Close() {
|
||||
go func() {
|
||||
waitErr := sp.Cmd.Wait()
|
||||
sp.SetWaitErrorAndSignalDone(waitErr)
|
||||
sp.Pty.Close()
|
||||
|
||||
// windows cannot handle the pty being
|
||||
// closed twice, so we let the pty
|
||||
// close itself instead
|
||||
if runtime.GOOS != "windows" {
|
||||
sp.Cmd.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@ -115,6 +120,41 @@ func checkCwd(cwd string) error {
|
||||
|
||||
var userHostRe = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9._@\\-]*@)?([a-z0-9][a-z0-9.-]*)(?::([0-9]+))?$`)
|
||||
|
||||
type PipePty struct {
|
||||
remoteStdinWrite *os.File
|
||||
remoteStdoutRead *os.File
|
||||
}
|
||||
|
||||
func (pp *PipePty) Fd() uintptr {
|
||||
return pp.remoteStdinWrite.Fd()
|
||||
}
|
||||
|
||||
func (pp *PipePty) Name() string {
|
||||
return "pipe-pty"
|
||||
}
|
||||
|
||||
func (pp *PipePty) Read(p []byte) (n int, err error) {
|
||||
return pp.remoteStdoutRead.Read(p)
|
||||
}
|
||||
|
||||
func (pp *PipePty) Write(p []byte) (n int, err error) {
|
||||
return pp.remoteStdinWrite.Write(p)
|
||||
}
|
||||
|
||||
func (pp *PipePty) Close() error {
|
||||
err1 := pp.remoteStdinWrite.Close()
|
||||
err2 := pp.remoteStdoutRead.Close()
|
||||
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
return err2
|
||||
}
|
||||
|
||||
func (pp *PipePty) WriteString(s string) (n int, err error) {
|
||||
return pp.Write([]byte(s))
|
||||
}
|
||||
|
||||
func StartRemoteShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsType, remoteName string) (*ShellProc, error) {
|
||||
ctx, cancelFunc := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancelFunc()
|
||||
@ -158,14 +198,21 @@ func StartRemoteShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsT
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// todo: connect pty output, etc
|
||||
// redirect to fake pty???
|
||||
|
||||
cmdPty, cmdTty, err := pty.Open()
|
||||
remoteStdinRead, remoteStdinWriteOurs, err := os.Pipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening new pty: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
remoteStdoutReadOurs, remoteStdoutWrite, err := os.Pipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipePty := &PipePty{
|
||||
remoteStdinWrite: remoteStdinWriteOurs,
|
||||
remoteStdoutRead: remoteStdoutReadOurs,
|
||||
}
|
||||
term.MakeRaw(int(cmdTty.Fd()))
|
||||
if termSize.Rows == 0 || termSize.Cols == 0 {
|
||||
termSize.Rows = shellutil.DefaultTermRows
|
||||
termSize.Cols = shellutil.DefaultTermCols
|
||||
@ -173,10 +220,9 @@ func StartRemoteShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsT
|
||||
if termSize.Rows <= 0 || termSize.Cols <= 0 {
|
||||
return nil, fmt.Errorf("invalid term size: %v", termSize)
|
||||
}
|
||||
pty.Setsize(cmdPty, &pty.Winsize{Rows: uint16(termSize.Rows), Cols: uint16(termSize.Cols)})
|
||||
session.Stdin = cmdTty
|
||||
session.Stdout = cmdTty
|
||||
session.Stderr = cmdTty
|
||||
session.Stdin = remoteStdinRead
|
||||
session.Stdout = remoteStdoutWrite
|
||||
session.Stderr = remoteStdoutWrite
|
||||
for envKey, envVal := range cmdOpts.Env {
|
||||
// note these might fail depending on server settings, but we still try
|
||||
session.Setenv(envKey, envVal)
|
||||
@ -184,13 +230,13 @@ func StartRemoteShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsT
|
||||
|
||||
session.RequestPty("xterm-256color", termSize.Rows, termSize.Cols, nil)
|
||||
|
||||
sessionWrap := SessionWrap{session, cmdCombined, cmdTty}
|
||||
sessionWrap := SessionWrap{session, cmdCombined, pipePty, pipePty}
|
||||
err = sessionWrap.Start()
|
||||
if err != nil {
|
||||
cmdPty.Close()
|
||||
pipePty.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &ShellProc{Cmd: sessionWrap, Pty: cmdPty, CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil
|
||||
return &ShellProc{Cmd: sessionWrap, CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil
|
||||
}
|
||||
|
||||
func isZshShell(shellPath string) bool {
|
||||
@ -216,7 +262,7 @@ func StartShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsType) (
|
||||
// add --rcfile
|
||||
// cant set -l or -i with --rcfile
|
||||
shellOpts = append(shellOpts, "--rcfile", shellutil.GetBashRcFileOverride())
|
||||
} else {
|
||||
} else if runtime.GOOS != "windows" {
|
||||
if cmdOpts.Login {
|
||||
shellOpts = append(shellOpts, "-l")
|
||||
}
|
||||
@ -252,10 +298,6 @@ func StartShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsType) (
|
||||
}
|
||||
shellutil.UpdateCmdEnv(ecmd, envToAdd)
|
||||
shellutil.UpdateCmdEnv(ecmd, cmdOpts.Env)
|
||||
cmdPty, cmdTty, err := pty.Open()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening new pty: %w", err)
|
||||
}
|
||||
if termSize.Rows == 0 || termSize.Cols == 0 {
|
||||
termSize.Rows = shellutil.DefaultTermRows
|
||||
termSize.Cols = shellutil.DefaultTermCols
|
||||
@ -263,28 +305,17 @@ func StartShellProc(termSize TermSize, cmdStr string, cmdOpts CommandOptsType) (
|
||||
if termSize.Rows <= 0 || termSize.Cols <= 0 {
|
||||
return nil, fmt.Errorf("invalid term size: %v", termSize)
|
||||
}
|
||||
pty.Setsize(cmdPty, &pty.Winsize{Rows: uint16(termSize.Rows), Cols: uint16(termSize.Cols)})
|
||||
ecmd.Stdin = cmdTty
|
||||
ecmd.Stdout = cmdTty
|
||||
ecmd.Stderr = cmdTty
|
||||
ecmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
setSysProcAttrs(ecmd)
|
||||
err = ecmd.Start()
|
||||
cmdTty.Close()
|
||||
cmdPty, err := pty.StartWithSize(ecmd, &pty.Winsize{Rows: uint16(termSize.Rows), Cols: uint16(termSize.Cols)})
|
||||
if err != nil {
|
||||
cmdPty.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &ShellProc{Cmd: CmdWrap{ecmd}, Pty: cmdPty, CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil
|
||||
return &ShellProc{Cmd: CmdWrap{ecmd, cmdPty}, CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil
|
||||
}
|
||||
|
||||
func RunSimpleCmdInPty(ecmd *exec.Cmd, termSize TermSize) ([]byte, error) {
|
||||
ecmd.Env = os.Environ()
|
||||
shellutil.UpdateCmdEnv(ecmd, shellutil.WaveshellLocalEnvVars(shellutil.DefaultTermType))
|
||||
cmdPty, cmdTty, err := pty.Open()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening new pty: %w", err)
|
||||
}
|
||||
if termSize.Rows == 0 || termSize.Cols == 0 {
|
||||
termSize.Rows = shellutil.DefaultTermRows
|
||||
termSize.Cols = shellutil.DefaultTermCols
|
||||
@ -292,19 +323,14 @@ func RunSimpleCmdInPty(ecmd *exec.Cmd, termSize TermSize) ([]byte, error) {
|
||||
if termSize.Rows <= 0 || termSize.Cols <= 0 {
|
||||
return nil, fmt.Errorf("invalid term size: %v", termSize)
|
||||
}
|
||||
pty.Setsize(cmdPty, &pty.Winsize{Rows: uint16(termSize.Rows), Cols: uint16(termSize.Cols)})
|
||||
ecmd.Stdin = cmdTty
|
||||
ecmd.Stdout = cmdTty
|
||||
ecmd.Stderr = cmdTty
|
||||
ecmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
setSysProcAttrs(ecmd)
|
||||
err = ecmd.Start()
|
||||
cmdTty.Close()
|
||||
cmdPty, err := pty.StartWithSize(ecmd, &pty.Winsize{Rows: uint16(termSize.Rows), Cols: uint16(termSize.Cols)})
|
||||
if err != nil {
|
||||
cmdPty.Close()
|
||||
return nil, err
|
||||
}
|
||||
defer cmdPty.Close()
|
||||
if runtime.GOOS != "windows" {
|
||||
defer cmdPty.Close()
|
||||
}
|
||||
ioDone := make(chan bool)
|
||||
var outputBuf bytes.Buffer
|
||||
go func() {
|
||||
|
@ -81,6 +81,9 @@ export PATH=$WAVETERM_WSHBINDIR:$PATH
|
||||
)
|
||||
|
||||
func DetectLocalShellPath() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return "powershell.exe"
|
||||
}
|
||||
shellPath := GetMacUserShell()
|
||||
if shellPath == "" {
|
||||
shellPath = os.Getenv("SHELL")
|
||||
|
Loading…
Reference in New Issue
Block a user