diff --git a/src/linecomps.tsx b/src/linecomps.tsx index 513b1543..29fdb938 100644 --- a/src/linecomps.tsx +++ b/src/linecomps.tsx @@ -6,9 +6,9 @@ import {boundMethod} from "autobind-decorator"; import dayjs from "dayjs"; import localizedFormat from 'dayjs/plugin/localizedFormat'; import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components"; -import {GlobalModel, GlobalCommandRunner, Session, Cmd, ScreenLines, Screen} from "./model"; +import {GlobalModel, GlobalCommandRunner, Session, Cmd, ScreenLines, Screen, getTermPtyData} from "./model"; import {windowWidthToCols, windowHeightToRows, termHeightFromRows, termWidthFromCols} from "./textmeasure"; -import type {LineType, CmdDataType, FeStateType, RemoteType, RemotePtrType, RenderModeType, RendererContext, RendererOpts, SimpleBlobRendererComponent, RendererPluginType, LineHeightChangeCallbackType} from "./types"; +import type {LineType, CmdDataType, FeStateType, RemoteType, RemotePtrType, RenderModeType, RendererContext, RendererOpts, SimpleBlobRendererComponent, RendererPluginType, LineHeightChangeCallbackType, RendererModelInitializeParams, RendererModel} from "./types"; import cn from "classnames"; import {TermWrap} from "./term"; import type {LineContainerModel} from "./model"; @@ -441,6 +441,40 @@ class LineCmd extends React.Component<{screen : LineContainerModel, line : LineT termFontSize: GlobalModel.termFontSize.get(), }; } + + makeRendererModelInitializeParams() : RendererModelInitializeParams { + let {screen, line} = this.props; + let context = lineutil.getRendererContext(line); + let cmd = screen.getCmd(line); // won't be null + let savedHeight = screen.getContentHeight(context); + if (savedHeight == null) { + if (line.contentheight != null && line.contentheight != -1) { + savedHeight = line.contentheight; + } + else { + savedHeight = 0; + } + } + let api = { + saveHeight: (height : number) => { + screen.setContentHeight(lineutil.getRendererContext(line), height); + }, + onFocusChanged: (focus : boolean) => { + screen.setTermFocus(line.linenum, focus); + }, + dataHandler: (data : string, model : RendererModel) => { + cmd.handleDataFromRenderer(data, model); + }, + }; + return { + context: context, + isDone: !cmd.isRunning(), + savedHeight: savedHeight, + opts: this.getRendererOpts(cmd), + ptyDataSource: getTermPtyData, + api: api, + }; + } render() { let {screen, line, width, staticRender, visible, topBorder, renderMode} = this.props; @@ -517,7 +551,7 @@ class LineCmd extends React.Component<{screen : LineContainerModel, line : LineT - +
diff --git a/src/settings.tsx b/src/settings.tsx index 7c583094..60e04efe 100644 --- a/src/settings.tsx +++ b/src/settings.tsx @@ -322,11 +322,11 @@ class LineSettingsModal extends React.Component<{line : LineType}, {}> {
-
this.clickSetRenderer("none") } key="none" className="dropdown-item">none
this.clickSetRenderer(null) } key="terminal" className="dropdown-item">terminal
this.clickSetRenderer(plugin.name) } key={plugin.name} className="dropdown-item">{plugin.name}
+
this.clickSetRenderer("none") } key="none" className="dropdown-item">none
diff --git a/src/simplerenderer.tsx b/src/simplerenderer.tsx index 1c008db9..864012d6 100644 --- a/src/simplerenderer.tsx +++ b/src/simplerenderer.tsx @@ -4,8 +4,7 @@ import * as mobx from "mobx"; import {sprintf} from "sprintf-js"; import {boundMethod} from "autobind-decorator"; import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components"; -import type {RendererModelInitializeParams, TermOptsType, RendererContext, RendererOpts, SimpleBlobRendererComponent, RendererModelContainerApi, RendererPluginType, PtyDataType, RendererModel, RendererOptsUpdate, LineType} from "./types"; -import {LineContainerModel, getTermPtyData, Cmd} from "./model"; +import type {RendererModelInitializeParams, TermOptsType, RendererContext, RendererOpts, SimpleBlobRendererComponent, RendererModelContainerApi, RendererPluginType, PtyDataType, RendererModel, RendererOptsUpdate, LineType, TermContextUnion, RendererContainerType} from "./types"; import {PtyDataBuffer} from "./ptydata"; import {debounce, throttle} from "throttle-debounce"; @@ -21,7 +20,8 @@ class SimpleBlobRendererModel { loading : OV; loadError : OV = mobx.observable.box(null, {name: "renderer-loadError"}); ptyData : PtyDataType; - updateHeight_debounced : (newHeight : number) => void + updateHeight_debounced : (newHeight : number) => void; + ptyDataSource : (termContext : TermContextUnion) => Promise; constructor() { this.updateHeight_debounced = debounce(1000, this.updateHeight.bind(this)); @@ -34,6 +34,7 @@ class SimpleBlobRendererModel { this.opts = params.opts; this.api = params.api; this.savedHeight = params.savedHeight; + this.ptyDataSource = params.ptyDataSource; if (this.isDone.get()) { this.reload(0); } @@ -72,7 +73,7 @@ class SimpleBlobRendererModel { mobx.action(() => { this.loading.set(true); })(); - let rtnp = getTermPtyData(this.context); + let rtnp = this.ptyDataSource(this.context); rtnp.then((ptydata) => { setTimeout(() => { this.ptyData = ptydata; @@ -94,60 +95,18 @@ class SimpleBlobRendererModel { } } -function contextFromLine(line : LineType) : RendererContext { - return { - screenId: line.screenid, - cmdId: line.cmdid, - lineId: line.lineid, - lineNum: line.linenum, - }; -} - -function apiAdapter(lcm : LineContainerModel, line : LineType, cmd : Cmd) : RendererModelContainerApi { - return { - saveHeight: (height : number) => { - lcm.setContentHeight(contextFromLine(line), height); - }, - - onFocusChanged: (focus : boolean) => { - lcm.setTermFocus(line.linenum, focus); - }, - - dataHandler: (data : string, model : RendererModel) => { - cmd.handleDataFromRenderer(data, model); - }, - }; -} - @mobxReact.observer -class SimpleBlobRenderer extends React.Component<{lcm : LineContainerModel, line : LineType, cmd : Cmd, rendererOpts : RendererOpts, plugin : RendererPluginType, onHeightChange : () => void}, {}> { +class SimpleBlobRenderer extends React.Component<{rendererContainer : RendererContainerType, cmdId : string, plugin : RendererPluginType, onHeightChange : () => void, initParams : RendererModelInitializeParams}, {}> { model : SimpleBlobRendererModel; wrapperDivRef : React.RefObject = React.createRef(); rszObs : ResizeObserver; constructor(props : any) { super(props); - let {lcm, line, cmd, rendererOpts} = this.props; - let context = contextFromLine(line); - let savedHeight = lcm.getContentHeight(context); - if (savedHeight == null) { - if (line.contentheight != null && line.contentheight != -1) { - savedHeight = line.contentheight; - } - else { - savedHeight = 0; - } - } - let initOpts = { - context: context, - isDone: !cmd.isRunning(), - savedHeight: savedHeight, - opts: rendererOpts, - api: apiAdapter(lcm, line, cmd), - }; + let {rendererContainer, cmdId, initParams} = this.props; this.model = new SimpleBlobRendererModel(); - this.model.initialize(initOpts); - lcm.registerRenderer(line.cmdid, this.model); + this.model.initialize(initParams); + rendererContainer.registerRenderer(cmdId, this.model); } handleResize(entries : ResizeObserverEntry[]) : void { @@ -179,8 +138,8 @@ class SimpleBlobRenderer extends React.Component<{lcm : LineContainerModel, line } componentWillUnmount() { - let {lcm, line} = this.props; - lcm.unloadRenderer(line.cmdid); + let {rendererContainer, cmdId} = this.props; + rendererContainer.unloadRenderer(cmdId); if (this.rszObs != null) { this.rszObs.disconnect(); this.rszObs = null; diff --git a/src/types.ts b/src/types.ts index 83a4fba6..fd65c3bd 100644 --- a/src/types.ts +++ b/src/types.ts @@ -399,6 +399,7 @@ type RendererModelInitializeParams = { savedHeight : number, opts : RendererOpts, api : RendererModelContainerApi, + ptyDataSource: (termContext : TermContextUnion) => Promise, }; type RendererModel = { @@ -581,6 +582,11 @@ type LineFactoryProps = { noSelect? : boolean, } +type RendererContainerType = { + registerRenderer : (cmdId : string, model : RendererModel) => void, + unloadRenderer : (cmdId : string) => void, +}; + type LineHeightChangeCallbackType = (lineNum : number, newHeight : number, oldHeight : number) => void; -export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDataType, ScreenDataType, ScreenOptsType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, RemotePtrType, UIContextType, HistoryInfoType, HistoryQueryOpts, WatchScreenPacketType, TermWinSize, FeInputPacketType, RemoteInputPacketType, RemoteEditType, FeStateType, ContextMenuOpts, RendererContext, WindowSize, RendererModel, PtyDataType, BookmarkType, ClientDataType, PlaybookType, PlaybookEntryType, HistoryViewDataType, RenderModeType, AlertMessageType, HistorySearchParams, ScreenLinesType, FocusTypeStrs, HistoryTypeStrs, RendererOpts, RendererPluginType, SimpleBlobRendererComponent, RendererModelContainerApi, RendererModelInitializeParams, RendererOptsUpdate, ClientMigrationInfo, WebShareOpts, RemoteStatusTypeStrs, WebFullScreen, WebScreen, WebLine, WebCmd, RemoteTermContext, TermContextUnion, WebRemote, WebScreenUpdate, PtyDataUpdate, WebShareWSMessage, LineHeightChangeCallbackType, LineFactoryProps, LineInterface}; +export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDataType, ScreenDataType, ScreenOptsType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, RemotePtrType, UIContextType, HistoryInfoType, HistoryQueryOpts, WatchScreenPacketType, TermWinSize, FeInputPacketType, RemoteInputPacketType, RemoteEditType, FeStateType, ContextMenuOpts, RendererContext, WindowSize, RendererModel, PtyDataType, BookmarkType, ClientDataType, PlaybookType, PlaybookEntryType, HistoryViewDataType, RenderModeType, AlertMessageType, HistorySearchParams, ScreenLinesType, FocusTypeStrs, HistoryTypeStrs, RendererOpts, RendererPluginType, SimpleBlobRendererComponent, RendererModelContainerApi, RendererModelInitializeParams, RendererOptsUpdate, ClientMigrationInfo, WebShareOpts, RemoteStatusTypeStrs, WebFullScreen, WebScreen, WebLine, WebCmd, RemoteTermContext, TermContextUnion, WebRemote, WebScreenUpdate, PtyDataUpdate, WebShareWSMessage, LineHeightChangeCallbackType, LineFactoryProps, LineInterface, RendererContainerType}; diff --git a/src/webshare-elems.tsx b/src/webshare-elems.tsx index 6fd4d768..f5432bd7 100644 --- a/src/webshare-elems.tsx +++ b/src/webshare-elems.tsx @@ -5,7 +5,7 @@ import {sprintf} from "sprintf-js"; import {boundMethod} from "autobind-decorator"; import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components"; import cn from "classnames"; -import {WebShareModel} from "./webshare-model"; +import {WebShareModel, getTermPtyData} from "./webshare-model"; import * as T from "./types"; import {isBlank} from "./util"; import {PluginModel} from "./plugins"; @@ -15,6 +15,7 @@ import {windowWidthToCols, windowHeightToRows, termHeightFromRows, termWidthFrom import {debounce, throttle} from "throttle-debounce"; import {LinesView} from "./linesview"; import {Toggle} from "./elements"; +import {SimpleBlobRendererModel, SimpleBlobRenderer} from "./simplerenderer"; type OV = mobx.IObservableValue; type OArr = mobx.IObservableArray; @@ -122,6 +123,7 @@ class WebLineCmdView extends React.Component<{line : T.WebLine, cmd : T.WebCmd, cmdTextRef : React.RefObject = React.createRef(); copiedIndicator : OV = mobx.observable.box(false, {name: "copiedIndicator"}); lastHeight : number; + lastScreenSize : T.WindowSize; componentDidMount() : void { this.checkCmdText(); @@ -234,9 +236,14 @@ class WebLineCmdView extends React.Component<{line : T.WebLine, cmd : T.WebCmd, handleHeightChange() : void { let {line} = this.props; let curHeight = 0; + let curWidth = 0; let elem = this.lineRef.current; if (elem != null) { curHeight = elem.offsetHeight; + curWidth = elem.offsetWidth; + if (curHeight != 0 && curWidth != 0) { + this.lastScreenSize = {height: curHeight, width: curWidth}; + } } if (this.lastHeight == curHeight) { return; @@ -294,6 +301,72 @@ class WebLineCmdView extends React.Component<{line : T.WebLine, cmd : T.WebCmd, })(); }, 600); } + + getMaxContentSize() : T.WindowSize { + if (this.lastScreenSize == null) { + let width = termWidthFromCols(80, WebShareModel.getTermFontSize()); + let height = termHeightFromRows(25, WebShareModel.getTermFontSize()); + return {width, height}; + } + let winSize = this.lastScreenSize; + let width = util.boundInt(winSize.width-50, 100, 5000); + let height = util.boundInt(winSize.height-100, 100, 5000); + return {width, height}; + } + + getIdealContentSize() : T.WindowSize { + if (this.lastScreenSize == null) { + let width = termWidthFromCols(80, WebShareModel.getTermFontSize()); + let height = termHeightFromRows(25, WebShareModel.getTermFontSize()); + return {width, height}; + } + let winSize = this.lastScreenSize; + let width = util.boundInt(Math.ceil((winSize.width-50)*0.7), 100, 5000); + let height = util.boundInt(Math.ceil((winSize.height-100)*0.5), 100, 5000); + return {width, height}; + } + + getRendererOpts(cmd : T.WebCmd) : T.RendererOpts { + return { + maxSize: this.getMaxContentSize(), + idealSize: this.getIdealContentSize(), + termOpts: cmd.termopts, + termFontSize: WebShareModel.getTermFontSize(), + }; + } + + makeRendererModelInitializeParams() : T.RendererModelInitializeParams { + let {line, cmd} = this.props; + let context = lineutil.getWebRendererContext(line); + let savedHeight = WebShareModel.getContentHeight(context); + if (savedHeight == null) { + if (line.contentheight != null && line.contentheight != -1) { + savedHeight = line.contentheight; + } + else { + savedHeight = 0; + } + } + let api = { + saveHeight: (height : number) => { + WebShareModel.setContentHeight(lineutil.getWebRendererContext(line), height); + }, + onFocusChanged: (focus : boolean) => { + // nothing + }, + dataHandler: (data : string, model : T.RendererModel) => { + // nothing + }, + }; + return { + context: context, + isDone: !lineutil.cmdStatusIsRunning(cmd.status), + savedHeight: savedHeight, + opts: this.getRendererOpts(cmd), + ptyDataSource: getTermPtyData, + api: api, + }; + } render() { let {line, cmd, topBorder, staticRender, visible} = this.props; @@ -334,7 +407,12 @@ class WebLineCmdView extends React.Component<{line : T.WebLine, cmd : T.WebCmd,
- + + + + + + ); } diff --git a/src/webshare-model.ts b/src/webshare-model.ts index bec8cbe8..3e5ebb03 100644 --- a/src/webshare-model.ts +++ b/src/webshare-model.ts @@ -358,6 +358,10 @@ class WebShareModelClass { return this.renderers[lineId]; } + registerRenderer(cmdId : string, renderer : T.RendererModel) { + this.renderers[cmdId] = renderer; + } + loadFullScreenData() : void { if (isBlank(this.screenId)) { this.setErrMessage("No ScreenId Specified, Cannot Load."); @@ -455,4 +459,4 @@ if ((window as any).WebShareModel == null) { (window as any).WebShareModel = WebShareModel; } -export {WebShareModel}; +export {WebShareModel, getTermPtyData};