From 422338c04be18f367fb0f26dda8c976ff548a6f3 Mon Sep 17 00:00:00 2001 From: Mike Sawka Date: Tue, 16 Jan 2024 16:11:04 -0800 Subject: [PATCH] zsh support (#227) adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature. Commits: * refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions * checkpoint * work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec) * more refactoring * create shellapi interface to abstract bash specific functionality * more refactoring, move bash shell state parsing to shellapi * move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell * get shellType passed through to server/single paths for waveshell * add a local shelltype detector * mock out a zshapi * move shelltype through more of the code * get a command to run via zsh * zsh can now switch directories. poc, needs cleanup * working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv) * switch to use []byte for vardecl serialization + diffs * progress on zsh environment. still have issues reconciling init environment with trap environment * fix typeset argument parsing * parse promptvars, more zsh specific ignores * fix bug with promptvar not getting set (wrong check in FeState func) * add sdk (issue #188) to list of rtnstate commands * more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base. * must return a value * zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1. * force zmodload of zsh/parameter * starting work on zsh functions * need a v1 of mapdiff as well (to handle null chars) * pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt * reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values) * fixes, working on functions, issue with line endings * zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output. * write uuid tempdir, cleanup with tmprcfilename code * hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh * make sure key order is constant so shell hashes are consistent * fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash * add log packet and new shellstate packets * switch to shellstate map that's also keyed by shelltype * add shelltype to remoteinstance * remove shell argument from waveshell * added new shelltype statemap to remote.go (msh), deal with fallout * move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states * change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells * add shellpref field to remote table. use to drive the default shell choice for new tabs * show shelltag on cmdinput, pass through ri and remote (defaultshellstate) * bump mshell version to v0.4 * better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match) * better error handling, check shellstate compatibility during run (on waveshell server) * add extra separator for bash shellstate processing to deal with spurious output from rc files * special migration for v30 -- flag invalid bash shell states and show special button in UI to fix * format * remove zsh-decls (unused) * remove test code * remove debug print * fix typo --- buildres/osx-sign.js | 8 +- scripthaus.md | 24 +- src/app/common/modals/createremoteconn.tsx | 24 + src/app/common/modals/editremoteconn.tsx | 266 +++--- .../common/modals/viewremoteconndetail.tsx | 5 +- src/app/workspace/cmdinput/cmdinput.less | 16 + src/app/workspace/cmdinput/cmdinput.tsx | 18 + src/app/workspace/cmdinput/textareainput.tsx | 20 +- src/model/model.ts | 5 + src/types/types.ts | 3 + waveshell/main-waveshell.go | 462 +--------- waveshell/pkg/base/base.go | 15 +- waveshell/pkg/binpack/binpack.go | 22 +- waveshell/pkg/packet/packet.go | 90 +- waveshell/pkg/packet/parser.go | 8 +- waveshell/pkg/packet/shellstate.go | 72 +- waveshell/pkg/packet/shellstate_test.go | 58 ++ waveshell/pkg/server/server.go | 164 +++- waveshell/pkg/shellapi/bashapi.go | 260 ++++++ waveshell/pkg/shellapi/bashparser.go | 328 +++++++ waveshell/pkg/shellapi/shellapi.go | 254 ++++++ waveshell/pkg/shellapi/zshapi.go | 826 ++++++++++++++++++ waveshell/pkg/shellapi/zshapi_test.go | 29 + waveshell/pkg/shellenv/shellenv.go | 362 ++++++++ waveshell/pkg/shellutil/shellutil.go | 62 ++ waveshell/pkg/shexec/parser.go | 641 -------------- waveshell/pkg/shexec/shexec.go | 591 +++---------- waveshell/pkg/statediff/linediff.go | 170 +++- waveshell/pkg/statediff/mapdiff.go | 103 ++- waveshell/pkg/statediff/statediff_test.go | 135 ++- {wavesrv => waveshell}/pkg/utilfn/linediff.go | 0 waveshell/pkg/utilfn/utilfn.go | 522 +++++++++++ waveshell/pkg/utilfn/utilfn_test.go | 175 ++++ wavesrv/cmd/main-server.go | 2 + .../db/migrations/000030_zsh_support.down.sql | 2 + .../db/migrations/000030_zsh_support.up.sql | 2 + wavesrv/pkg/cmdrunner/cmdrunner.go | 63 +- wavesrv/pkg/cmdrunner/resolver.go | 8 +- wavesrv/pkg/cmdrunner/shparse.go | 50 +- wavesrv/pkg/cmdrunner/termopts.go | 9 +- wavesrv/pkg/comp/comp.go | 6 +- wavesrv/pkg/comp/comp_test.go | 2 +- wavesrv/pkg/comp/simplecomp.go | 2 +- wavesrv/pkg/promptenc/promptenc.go | 2 +- wavesrv/pkg/remote/remote.go | 275 ++++-- wavesrv/pkg/rtnstate/rtnstate.go | 148 +++- wavesrv/pkg/scbase/scbase.go | 2 +- wavesrv/pkg/scpacket/scpacket.go | 2 +- wavesrv/pkg/shparse/comp.go | 2 +- wavesrv/pkg/shparse/extend.go | 2 +- wavesrv/pkg/shparse/shparse.go | 2 +- wavesrv/pkg/shparse/shparse_test.go | 2 +- wavesrv/pkg/sstore/dbops.go | 47 +- wavesrv/pkg/sstore/memops.go | 2 +- wavesrv/pkg/sstore/migrate.go | 9 +- wavesrv/pkg/sstore/sstore.go | 27 +- wavesrv/pkg/sstore/sstore_migrate.go | 31 + wavesrv/pkg/sstore/updatebus.go | 2 +- wavesrv/pkg/utilfn/utilfn.go | 249 ------ wavesrv/pkg/utilfn/utilfn_test.go | 103 --- 60 files changed, 4417 insertions(+), 2374 deletions(-) create mode 100644 waveshell/pkg/packet/shellstate_test.go create mode 100644 waveshell/pkg/shellapi/bashapi.go create mode 100644 waveshell/pkg/shellapi/bashparser.go create mode 100644 waveshell/pkg/shellapi/shellapi.go create mode 100644 waveshell/pkg/shellapi/zshapi.go create mode 100644 waveshell/pkg/shellapi/zshapi_test.go create mode 100644 waveshell/pkg/shellenv/shellenv.go create mode 100644 waveshell/pkg/shellutil/shellutil.go delete mode 100644 waveshell/pkg/shexec/parser.go rename {wavesrv => waveshell}/pkg/utilfn/linediff.go (100%) create mode 100644 waveshell/pkg/utilfn/utilfn.go create mode 100644 waveshell/pkg/utilfn/utilfn_test.go create mode 100644 wavesrv/db/migrations/000030_zsh_support.down.sql create mode 100644 wavesrv/db/migrations/000030_zsh_support.up.sql delete mode 100644 wavesrv/pkg/utilfn/utilfn.go delete mode 100644 wavesrv/pkg/utilfn/utilfn_test.go diff --git a/buildres/osx-sign.js b/buildres/osx-sign.js index a7e0347c..3d29277e 100644 --- a/buildres/osx-sign.js +++ b/buildres/osx-sign.js @@ -7,10 +7,10 @@ signAsync({ app: "temp/Wave.app", binaries: [ waveAppPath + "/Contents/Resources/app/bin/wavesrv", - waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.3-linux.amd64", - waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.3-linux.arm64", - waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.3-darwin.amd64", - waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.3-darwin.arm64", + waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.4-linux.amd64", + waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.4-linux.arm64", + waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.4-darwin.amd64", + waveAppPath + "/Contents/Resources/app/bin/mshell/mshell-v0.4-darwin.arm64", ], }).then(() => { console.log("signing success"); diff --git a/scripthaus.md b/scripthaus.md index 2296c243..f3020142 100644 --- a/scripthaus.md +++ b/scripthaus.md @@ -44,10 +44,10 @@ rm -rf bin/ rm -rf build/ node_modules/.bin/webpack --env prod GO_LDFLAGS="-s -w -X main.BuildTime=$(date +'%Y%m%d%H%M')" -(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-darwin.amd64 main-waveshell.go) -(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-darwin.arm64 main-waveshell.go) -(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-linux.amd64 main-waveshell.go) -(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-linux.arm64 main-waveshell.go) +(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.amd64 main-waveshell.go) +(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.arm64 main-waveshell.go) +(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.amd64 main-waveshell.go) +(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.arm64 main-waveshell.go) (cd wavesrv; CGO_ENABLED=1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "-X main.BuildTime=$(date +'%Y%m%d%H%M')" -o ../bin/wavesrv ./cmd) node_modules/.bin/electron-forge make ``` @@ -60,10 +60,10 @@ rm -rf bin/ rm -rf build/ node_modules/.bin/webpack --env prod GO_LDFLAGS="-s -w -X main.BuildTime=$(date +'%Y%m%d%H%M')" -(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-darwin.amd64 main-waveshell.go) -(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-darwin.arm64 main-waveshell.go) -(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-linux.amd64 main-waveshell.go) -(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-linux.arm64 main-waveshell.go) +(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.amd64 main-waveshell.go) +(cd waveshell; CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.arm64 main-waveshell.go) +(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.amd64 main-waveshell.go) +(cd waveshell; CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.arm64 main-waveshell.go) # adds -extldflags=-static, *only* on linux (macos does not support fully static binaries) to avoid a glibc dependency (cd wavesrv; CGO_ENABLED=1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflags "-linkmode 'external' -extldflags=-static $GO_LDFLAGS" -o ../bin/wavesrv ./cmd) node_modules/.bin/electron-forge make @@ -86,10 +86,10 @@ CGO_ENABLED=1 go build -tags "osusergo,netgo,sqlite_omit_load_extension" -ldflag set -e cd waveshell GO_LDFLAGS="-s -w -X main.BuildTime=$(date +'%Y%m%d%H%M')" -CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-linux.amd64 main-waveshell.go -CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-linux.arm64 main-waveshell.go -CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-darwin.amd64 main-waveshell.go -CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.3-darwin.arm64 main-waveshell.go +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.amd64 main-waveshell.go +CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-linux.arm64 main-waveshell.go +CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.amd64 main-waveshell.go +CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="$GO_LDFLAGS" -o ../bin/mshell/mshell-v0.4-darwin.arm64 main-waveshell.go ``` ```bash diff --git a/src/app/common/modals/createremoteconn.tsx b/src/app/common/modals/createremoteconn.tsx index 78ddd498..90e197d5 100644 --- a/src/app/common/modals/createremoteconn.tsx +++ b/src/app/common/modals/createremoteconn.tsx @@ -25,6 +25,7 @@ class CreateRemoteConnModal extends React.Component<{}, {}> { tempConnectMode: OV; tempPassword: OV; tempKeyFile: OV; + tempShellPref: OV; errorStr: OV; remoteEdit: T.RemoteEditType; model: RemotesModel; @@ -40,6 +41,7 @@ class CreateRemoteConnModal extends React.Component<{}, {}> { this.tempConnectMode = mobx.observable.box("auto", { name: "CreateRemote-connectMode" }); this.tempKeyFile = mobx.observable.box("", { name: "CreateRemote-keystr" }); this.tempPassword = mobx.observable.box("", { name: "CreateRemote-password" }); + this.tempShellPref = mobx.observable.box("detect", { name: "CreateRemote-shellPref" }); this.errorStr = mobx.observable.box(this.remoteEdit?.errorstr ?? null, { name: "CreateRemote-errorStr" }); } @@ -121,6 +123,7 @@ class CreateRemoteConnModal extends React.Component<{}, {}> { kwargs["password"] = ""; } kwargs["connectmode"] = this.tempConnectMode.get(); + kwargs["shellpref"] = this.tempShellPref.get(); kwargs["visual"] = "1"; kwargs["submit"] = "1"; let prtn = GlobalCommandRunner.createRemote(cname, kwargs, false); @@ -174,6 +177,13 @@ class CreateRemoteConnModal extends React.Component<{}, {}> { })(); } + @boundMethod + handleChangeShellPref(value: string): void { + mobx.action(() => { + this.tempShellPref.set(value); + })(); + } + @boundMethod handleChangePort(value: string): void { mobx.action(() => { @@ -357,6 +367,20 @@ class CreateRemoteConnModal extends React.Component<{}, {}> { }} /> +
+ { + this.tempShellPref.set(val); + }} + /> +
Error: {this.getErrorStr()}
diff --git a/src/app/common/modals/editremoteconn.tsx b/src/app/common/modals/editremoteconn.tsx index f08efc80..6502aa19 100644 --- a/src/app/common/modals/editremoteconn.tsx +++ b/src/app/common/modals/editremoteconn.tsx @@ -24,6 +24,7 @@ class EditRemoteConnModal extends React.Component<{}, {}> { tempPassword: OV; tempConnectMode: OV; tempAuthMode: OV; + tempShellPref: OV; model: RemotesModel; constructor(props: { remotesModel?: RemotesModel }) { @@ -34,6 +35,7 @@ class EditRemoteConnModal extends React.Component<{}, {}> { this.tempKeyFile = mobx.observable.box(null, { name: "EditRemoteSettings-tempKeyFile" }); this.tempPassword = mobx.observable.box(null, { name: "EditRemoteSettings-tempPassword" }); this.tempConnectMode = mobx.observable.box(null, { name: "EditRemoteSettings-tempConnectMode" }); + this.tempShellPref = mobx.observable.box(null, { name: "EditRemoteSettings-tempShellPref" }); } get selectedRemoteId() { @@ -52,6 +54,10 @@ class EditRemoteConnModal extends React.Component<{}, {}> { return this.model.isAuthEditMode(); } + isLocalRemote(): boolean { + return this.selectedRemote?.local; + } + componentDidMount(): void { mobx.action(() => { this.tempAlias.set(this.selectedRemote?.remotealias); @@ -59,6 +65,7 @@ class EditRemoteConnModal extends React.Component<{}, {}> { this.tempPassword.set(this.remoteEdit?.haspassword ? PasswordUnchangedSentinel : ""); this.tempConnectMode.set(this.selectedRemote?.connectmode); this.tempAuthMode.set(this.selectedRemote?.authtype); + this.tempShellPref.set(this.selectedRemote?.shellpref); })(); } @@ -103,6 +110,13 @@ class EditRemoteConnModal extends React.Component<{}, {}> { })(); } + @boundMethod + handleChangeShellPref(value: string): void { + mobx.action(() => { + this.tempShellPref.set(value); + })(); + } + @boundMethod canResetPw(): boolean { if (this.remoteEdit == null) { @@ -154,6 +168,9 @@ class EditRemoteConnModal extends React.Component<{}, {}> { if (!util.isStrEq(this.tempConnectMode.get(), this.selectedRemote?.connectmode)) { kwargs["connectmode"] = this.tempConnectMode.get(); } + if (!util.isStrEq(this.tempShellPref.get(), this.selectedRemote?.shellpref)) { + kwargs["shellpref"] = this.tempShellPref.get(); + } kwargs["visual"] = "1"; kwargs["submit"] = "1"; GlobalCommandRunner.editRemote(this.selectedRemote?.remoteid, kwargs); @@ -183,11 +200,150 @@ class EditRemoteConnModal extends React.Component<{}, {}> { return null; } - render() { + renderAlias() { + return ( +
+ + } + > + + + + ), + }} + /> +
+ ); + } + + renderConnectMode() { + return ( +
+ +
+ ); + } + + renderShellPref() { + return ( +
+ +
+ ); + } + + renderAuthMode() { let authMode = this.tempAuthMode.get(); + return ( + <> +
+ + +
  • + none - no authentication, or authentication is already + configured in your ssh config. +
  • +
  • + key - use a private key. +
  • +
  • + password - use a password. +
  • +
  • + key+password - use a key with a passphrase. +
  • + + } + icon={} + > + +
    + + ), + }} + /> +
    + + + } + > + + + + ), + }} + /> + + + + + + ); + } + + render() { if (this.remoteEdit === null || !this.isAuthEditMode) { return null; } + let isLocal = this.isLocalRemote(); return ( @@ -195,110 +351,10 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
    {util.getRemoteName(this.selectedRemote)}
    -
    - - } - > - - - - ), - }} - /> -
    -
    - - -
  • - none - no authentication, or authentication is already - configured in your ssh config. -
  • -
  • - key - use a private key. -
  • -
  • - password - use a password. -
  • -
  • - key+password - use a key with a passphrase. -
  • - - } - icon={} - > - -
    - - ), - }} - /> -
    - - - } - > - - - - ), - }} - /> - - - - -
    - -
    + {this.renderAlias()} + {this.renderAuthMode()} + {this.renderConnectMode()} + {this.renderShellPref()}
    Error: {this.remoteEdit?.errorstr}
    diff --git a/src/app/common/modals/viewremoteconndetail.tsx b/src/app/common/modals/viewremoteconndetail.tsx index c0518d07..5fa461fb 100644 --- a/src/app/common/modals/viewremoteconndetail.tsx +++ b/src/app/common/modals/viewremoteconndetail.tsx @@ -206,7 +206,6 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> { ); if (remote.local) { installNowButton = <>; - updateAuthButton = <>; cancelInstallButton = <>; } if (remote.sshconfigsrc == "sshconfig-import") { @@ -352,6 +351,10 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
    Connect Mode
    {remote.connectmode}
    +
    +
    Shell Pref
    +
    {remote.shellpref}
    +
    {this.renderInstallStatus(remote)}
    diff --git a/src/app/workspace/cmdinput/cmdinput.less b/src/app/workspace/cmdinput/cmdinput.less index 69efc852..21a34236 100644 --- a/src/app/workspace/cmdinput/cmdinput.less +++ b/src/app/workspace/cmdinput/cmdinput.less @@ -128,6 +128,22 @@ padding: 1em 2px; } + .textareainput-div { + position: relative; + + .shelltag { + position: absolute; + bottom: 4px; + right: 3px; + font-size: 10px; + color: @text-secondary; + line-height: 1; + padding: 0px 8px 3px 8px; + background-color: @textarea-background; + border-radius: 0 0 5px 5px; + } + } + textarea { color: @term-bright-white; background-color: @textarea-background; diff --git a/src/app/workspace/cmdinput/cmdinput.tsx b/src/app/workspace/cmdinput/cmdinput.tsx index a13e961d..f6b0693b 100644 --- a/src/app/workspace/cmdinput/cmdinput.tsx +++ b/src/app/workspace/cmdinput/cmdinput.tsx @@ -99,6 +99,11 @@ class CmdInput extends React.Component<{}, {}> { })(); } + @boundMethod + clickResetState(): void { + GlobalCommandRunner.resetShellState(); + } + render() { let model = GlobalModel; let inputModel = model.inputModel; @@ -115,6 +120,7 @@ class CmdInput extends React.Component<{}, {}> { remote = GlobalModel.getRemote(ri.remoteid); feState = ri.festate; } + feState = feState || {}; let infoShow = inputModel.infoShow.get(); let historyShow = !infoShow && inputModel.historyShow.get(); let aiChatShow = inputModel.aIChatShow.get(); @@ -162,6 +168,18 @@ class CmdInput extends React.Component<{}, {}> {
    + +
    + WARNING:  The shell state for this tab is invalid ( + + see FAQ + + ). Must reset to continue. +
    + reset shell state +
    +
    +
    diff --git a/src/app/workspace/cmdinput/textareainput.tsx b/src/app/workspace/cmdinput/textareainput.tsx index 8cca3b89..eb1a550b 100644 --- a/src/app/workspace/cmdinput/textareainput.tsx +++ b/src/app/workspace/cmdinput/textareainput.tsx @@ -5,6 +5,8 @@ import * as React from "react"; import * as mobxReact from "mobx-react"; import * as mobx from "mobx"; import type * as T from "../../../types/types"; +import * as util from "../../../util/util"; +import { If } from "tsx-control-statements/components"; import { boundMethod } from "autobind-decorator"; import cn from "classnames"; import { GlobalModel, GlobalCommandRunner, Screen } from "../../../model/model"; @@ -585,8 +587,24 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: () let computedInnerHeight = displayLines * (termFontSize * 1.5) + 2 * 0.5 * termFontSize; // inner height + 2*1em padding let computedOuterHeight = computedInnerHeight + 2 * 1.0 * termFontSize; + let shellType: string = ""; + let screen = GlobalModel.getActiveScreen(); + if (screen != null) { + let ri = screen.getCurRemoteInstance(); + console.log("got ri", ri); + if (ri != null && ri.shelltype != null) { + shellType = ri.shelltype; + } + } return ( -
    +
    + +
    {shellType}
    +