use screenmap instead of screenlist, some tweaks to hints

This commit is contained in:
sawka 2023-03-14 21:15:26 -07:00
parent b9f10fb9b6
commit 6fe54f5fde
6 changed files with 121 additions and 29 deletions

View File

@ -6,6 +6,10 @@ import {boundMethod} from "autobind-decorator";
import cn from "classnames";
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
function renderCmdText(text : string) : any {
return <span>&#x2318;{text}</span>;
}
class CmdStrCode extends React.Component<{cmdstr : string, onUse : () => void, onCopy : () => void, isCopied : boolean, fontSize : "normal" | "large", limitHeight : boolean}, {}> {
@boundMethod
handleUse(e : any) {
@ -65,4 +69,4 @@ class Toggle extends React.Component<{checked : boolean, onChange : (value : boo
}
}
export {CmdStrCode, Toggle};
export {CmdStrCode, Toggle, renderCmdText};

View File

@ -12,6 +12,7 @@ import type {LineType, CmdDataType, FeStateType, RemoteType, RemotePtrType, Rend
import cn from "classnames";
import {TermWrap} from "./term";
import type {LineContainerModel} from "./model";
import {renderCmdText} from "./elements";
dayjs.extend(localizedFormat)
@ -125,7 +126,7 @@ class LineAvatar extends React.Component<{line : LineType, cmd : Cmd}, {}> {
@mobxReact.observer
class LineCmd extends React.Component<{screen : LineContainerModel, line : LineType, width : number, staticRender : boolean, visible : OV<boolean>, onHeightChange : HeightChangeCallbackType, topBorder : boolean, renderMode : RenderModeType, overrideCollapsed : OV<boolean>, noSelect? : boolean}, {}> {
class LineCmd extends React.Component<{screen : LineContainerModel, line : LineType, width : number, staticRender : boolean, visible : OV<boolean>, onHeightChange : HeightChangeCallbackType, topBorder : boolean, renderMode : RenderModeType, overrideCollapsed : OV<boolean>, noSelect? : boolean, showHints? : boolean}, {}> {
lineRef : React.RefObject<any> = React.createRef();
cmdTextRef : React.RefObject<any> = React.createRef();
rtnStateDiff : mobx.IObservableValue<string> = mobx.observable.box(null, {name: "linecmd-rtn-state-diff"});
@ -514,6 +515,11 @@ class LineCmd extends React.Component<{screen : LineContainerModel, line : LineT
</If>
</div>
</If>
<If condition={isSelected && !isFocused}>
<div className="cmd-hints">
<div className="hint-item color-nohover-white">focus line ({renderCmdText("L")})</div>
</div>
</If>
</div>
);
}

View File

@ -19,6 +19,7 @@ import {BookmarksView} from "./bookmarks";
import {HistoryView} from "./history";
import {Line, Prompt} from "./linecomps";
import {ScreenSettingsModal, SessionSettingsModal} from "./settings";
import {renderCmdText} from "./elements";
dayjs.extend(localizedFormat)
@ -41,10 +42,6 @@ type InterObsValue = {
timeoutid? : any,
};
function renderCmdText(text : string) : any {
return <span>&#x2318;{text}</span>;
}
function isBlank(s : string) : boolean {
return (s == null || s == "");
}
@ -1444,8 +1441,12 @@ class CmdInput extends React.Component<{}, {}> {
}
@boundMethod
clickHistoryHint() : void {
clickHistoryHint(e : any) : void {
e.preventDefault();
e.stopPropagation();
let inputModel = GlobalModel.inputModel;
console.log("hitory hint", inputModel.historyShow.get());
if (inputModel.historyShow.get()) {
inputModel.resetHistory();
}
@ -1514,7 +1515,7 @@ class CmdInput extends React.Component<{}, {}> {
</div>
<div className="cmd-hints">
<If condition={!focusVal}><div onClick={this.clickFocusInputHint} className="hint-item color-white">focus input ({renderCmdText("I")})</div></If>
<If condition={focusVal}><div onClick={this.clickHistoryHint} className="hint-item color-green"><i className={cn("fa-sharp fa-solid", (historyShow ? "fa-angle-down" : "fa-angle-up"))}/> {historyShow ? "close history (esc)" : "show history (ctrl-r)"}</div></If>
<If condition={focusVal}><div onMouseDown={this.clickHistoryHint} className="hint-item color-green"><i className={cn("fa-sharp fa-solid", (historyShow ? "fa-angle-down" : "fa-angle-up"))}/> {historyShow ? "close history (esc)" : "show history (ctrl-r)"}</div></If>
</div>
</div>
</div>
@ -2173,6 +2174,17 @@ class ScreenTabs extends React.Component<{session : Session}, {}> {
showingScreens.push(screen);
}
}
showingScreens.sort((a, b) => {
let aidx = a.screenIdx.get();
let bidx = b.screenIdx.get();
if (aidx < bidx) {
return -1;
}
if (aidx > bidx) {
return 1;
}
return 0;
});
return (
<div className="screen-tabs-container">
<div className={cn("screen-tabs", {"scrolling": this.scrolling.get()})} ref={this.tabsRef} onScroll={this.handleScroll}>

View File

@ -2,7 +2,7 @@ import * as mobx from "mobx";
import {sprintf} from "sprintf-js";
import {boundMethod} from "autobind-decorator";
import {debounce} from "throttle-debounce";
import {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, boundInt, isModKeyPress} from "./util";
import {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeDataMap, genMergeSimpleData, boundInt, isModKeyPress} from "./util";
import {TermWrap} from "./term";
import {v4 as uuidv4} from "uuid";
import type {SessionDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, RemotePtrType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenOptsType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, UIContextType, HistoryInfoType, HistoryQueryOpts, FeInputPacketType, TermWinSize, RemoteInputPacketType, FeStateType, ContextMenuOpts, RendererContext, RendererModel, PtyDataType, BookmarkType, ClientDataType, HistoryViewDataType, AlertMessageType, HistorySearchParams, FocusTypeStrs, ScreenLinesType, HistoryTypeStrs} from "./types";
@ -2228,7 +2228,7 @@ class Model {
activeSessionId : OV<string> = mobx.observable.box(null, {name: "activeSessionId"});
sessionListLoaded : OV<boolean> = mobx.observable.box(false, {name: "sessionListLoaded"});
sessionList : OArr<Session> = mobx.observable.array([], {name: "SessionList", deep: false});
screenList : OArr<Screen> = mobx.observable.array([], {name: "ScreenList", deep: false});
screenMap : OMap<string, Screen> = mobx.observable.map({}, {name: "ScreenMap", deep: false});
ws : WSControl;
remotes : OArr<RemoteType> = mobx.observable.array([], {name: "remotes", deep: false});
remotesLoaded : OV<boolean> = mobx.observable.box(false, {name: "remotesLoaded"});
@ -2580,14 +2580,11 @@ class Model {
let update : ModelUpdateType = genUpdate;
if ("screens" in update) {
if (update.connect) {
this.screenList.clear();
this.screenMap.clear();
}
genMergeData(this.screenList, update.screens, (s : Screen) => s.screenId, (sdata : ScreenDataType) => sdata.screenid, (sdata : ScreenDataType) => new Screen(sdata), null);
for (let i=0; i<update.screens.length; i++) {
let screen = update.screens[i];
if (screen.remove) {
this.removeScreenLinesByScreenId(screen.screenid);
}
let mods = genMergeDataMap(this.screenMap, update.screens, (s : Screen) => s.screenId, (sdata : ScreenDataType) => sdata.screenid, (sdata : ScreenDataType) => new Screen(sdata));
for (let i=0; i<mods.removed.length; i++) {
this.removeScreenLinesByScreenId(mods.removed[i]);
}
}
if ("sessions" in update) {
@ -2689,8 +2686,7 @@ class Model {
getScreenNames() : Record<string, string> {
let rtn : Record<string, string> = {};
for (let i=0; i<this.screenList.length; i++) {
let screen = this.screenList[i];
for (let screen of this.screenMap.values()) {
rtn[screen.screenId] = screen.name.get();
}
return rtn;
@ -2752,19 +2748,12 @@ class Model {
}
getScreenById(sessionId : string, screenId : string) : Screen {
for (let i=0; i<this.screenList.length; i++) {
let screen = this.screenList[i];
if (screen.screenId == screenId) {
return screen;
}
}
return null;
return this.screenMap.get(screenId);
}
getSessionScreens(sessionId : string) : Screen[] {
let rtn : Screen[] = [];
for (let i=0; i<this.screenList.length; i++) {
let screen = this.screenList[i];
for (let screen of this.screenMap.values()) {
if (screen.sessionId == sessionId) {
rtn.push(screen);
}

View File

@ -1671,6 +1671,21 @@ body::-webkit-scrollbar {
padding-bottom: 5px;
}
}
.cmd-hints {
position: absolute;
bottom: 0px;
right: 0px;
display: none;
.hint-item {
border-radius: 3px;
}
}
&:hover .cmd-hints {
display: flex;
}
}
body .xterm .xterm-viewport {
@ -2782,6 +2797,12 @@ input[type=checkbox] {
color: white;
}
}
.hint-item.color-nohover-green {
color: black;
background-color: @tab-green;
cursor: default;
}
.hint-item.color-white {
color: black;
@ -2791,6 +2812,27 @@ input[type=checkbox] {
background-color: @term-bright-white;
}
}
.hint-item.color-nohover-white {
color: black;
background-color: @term-white;
cursor: default;
}
.hint-item.color-blue {
color: black;
background-color: @tab-blue;
&:hover {
color: white;
}
}
.hint-item.color-nohover-blue {
color: black;
background-color: @tab-blue;
cursor: default;
}
}
.settings-field {

View File

@ -142,6 +142,45 @@ function genMergeData<ObjType extends IObjType<DataType>, DataType extends IData
objs.replace(newObjs);
}
function genMergeDataMap<ObjType extends IObjType<DataType>, DataType extends IDataType>(
objMap : mobx.ObservableMap<string, ObjType>,
dataArr : DataType[],
objIdFn : (obj : ObjType) => string,
dataIdFn : (data : DataType) => string,
ctorFn : (data : DataType) => ObjType,
) : {added : string[], removed : string[]}
{
let rtn : {added : string[], removed : string[]} = {added: [], removed: []};
if (dataArr == null || dataArr.length == 0) {
return rtn;
}
for (let i=0; i<dataArr.length; i++) {
let dataItem = dataArr[i];
let id = dataIdFn(dataItem);
let obj = objMap.get(id);
if (dataItem.remove) {
if (obj != null) {
obj.dispose();
objMap.delete(id);
rtn.removed.push(id);
}
continue;
}
if (obj == null) {
if (!dataItem.full) {
console.log("cannot create object, dataitem is not full", dataItem);
continue
}
obj = ctorFn(dataItem);
objMap.set(id, obj);
rtn.added.push(id);
continue;
}
obj.mergeData(dataItem);
}
return rtn;
}
function parseEnv0(envStr64 : string) : Map<string, string> {
let envStr = atob(envStr64);
let parts = envStr.split("\x00");
@ -182,4 +221,4 @@ function incObs(inum : mobx.IObservableValue<number>) {
})();
}
export {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, parseEnv0, boundInt, isModKeyPress, incObs};
export {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeDataMap, genMergeSimpleData, parseEnv0, boundInt, isModKeyPress, incObs};