cmd-up cmd-down working, new line type, remotealias

This commit is contained in:
sawka
2022-08-16 15:59:28 -07:00
parent 7af1d5cee6
commit cc058490b2
8 changed files with 203 additions and 19 deletions
+9
View File
@@ -73,6 +73,15 @@ function createWindow() {
}
return;
}
if (input.meta && (input.code == "ArrowUp" || input.code == "ArrowDown")) {
if (input.code == "ArrowUp") {
win.webContents.send("meta-arrowup");
} else {
win.webContents.send("meta-arrowdown");
}
e.preventDefault();
return;
}
if (input.code.startsWith("Digit") && input.meta) {
let digitNum = parseInt(input.code.substr(5));
if (isNaN(digitNum) || digitNum < 1 || digitNum > 9) {
+18 -8
View File
@@ -120,7 +120,7 @@ class LineText extends React.Component<{sw : ScreenWindow, line : LineType}, {}>
let line = this.props.line;
let formattedTime = getLineDateStr(line.ts);
return (
<div className="line line-text">
<div className="line line-text" data-lineid={line.lineid} data-windowid={line.windowid}>
<div className="avatar">
S
</div>
@@ -139,7 +139,7 @@ class LineText extends React.Component<{sw : ScreenWindow, line : LineType}, {}>
}
@mobxReact.observer
class LineCmd extends React.Component<{sw : ScreenWindow, line : LineType, width : number, interObs : IntersectionObserver, initVis : boolean}, {}> {
class LineCmd extends React.Component<{sw : ScreenWindow, line : LineType, width : number, interObs : IntersectionObserver, initVis : boolean, cmdRefNum : number}, {}> {
termLoaded : mobx.IObservableValue<boolean> = mobx.observable.box(false);
lineRef : React.RefObject<any> = React.createRef();
iobsVal : InterObsValue = null;
@@ -249,7 +249,7 @@ class LineCmd extends React.Component<{sw : ScreenWindow, line : LineType, width
render() {
let {sw, line, width} = this.props;
let model = GlobalModel;
let lineid = line.lineid.toString();
let lineid = line.lineid;
let formattedTime = getLineDateStr(line.ts);
let cmd = model.getCmd(line);
if (cmd == null) {
@@ -271,11 +271,12 @@ class LineCmd extends React.Component<{sw : ScreenWindow, line : LineType, width
let detached = (status == "detached");
let termOpts = cmd.getTermOpts();
let isFocused = sw.getIsFocused(line.cmdid);
let cmdRefNumStr = (this.props.cmdRefNum == null ? "?" : this.props.cmdRefNum.toString());
return (
<div className={cn("line", "line-cmd", {"focus": isFocused})} id={"line-" + getLineId(line)} ref={this.lineRef} style={{position: "relative"}}>
<div className={cn("line", "line-cmd", {"focus": isFocused})} id={"line-" + getLineId(line)} ref={this.lineRef} style={{position: "relative"}} data-lineid={line.lineid} data-windowid={line.windowid} data-cmdid={line.cmdid}>
<div className="line-header">
<div className={cn("avatar",{"num4": lineid.length == 4}, {"num5": lineid.length >= 5}, {"running": running}, {"detached": detached})} onClick={this.doRefresh}>
{lineid}
<div className={cn("avatar",{"num4": cmdRefNumStr.length == 4}, {"num5": cmdRefNumStr.length >= 5}, {"running": running}, {"detached": detached})} onClick={this.doRefresh}>
{cmdRefNumStr}
</div>
<div className="meta-wrap">
<div className="meta">
@@ -301,7 +302,7 @@ class LineCmd extends React.Component<{sw : ScreenWindow, line : LineType, width
}
@mobxReact.observer
class Line extends React.Component<{sw : ScreenWindow, line : LineType, width : number, interObs : IntersectionObserver, initVis : boolean}, {}> {
class Line extends React.Component<{sw : ScreenWindow, line : LineType, width : number, interObs : IntersectionObserver, initVis : boolean, cmdRefNum : number}, {}> {
render() {
let line = this.props.line;
if (line.linetype == "text") {
@@ -702,6 +703,15 @@ class ScreenWindowView extends React.Component<{sw : ScreenWindow}, {}> {
if (win.lines.length == 0) {
linesStyle.display = "none";
}
let cmdRefMap : Record<string, number> = {};
let cmdNum = 1;
for (let i=0; i<win.lines.length; i++) {
let line = win.lines[i];
if (line.cmdid != null) {
cmdRefMap[line.lineid] = cmdNum;
cmdNum++;
}
}
return (
<div className="window-view" style={this.getWindowViewStyle()} id={this.getWindowViewDOMId()}>
<div key="window-tag" className="window-tag">
@@ -709,7 +719,7 @@ class ScreenWindowView extends React.Component<{sw : ScreenWindow}, {}> {
</div>
<div key="lines" className="lines" onScroll={this.scrollHandler} id={this.getLinesDOMId()} style={linesStyle}>
<For each="line" of={win.lines} index="idx">
<Line key={line.lineid} line={line} sw={sw} width={this.width.get()} interObs={this.interObs} initVis={idx > win.lines.length-1-7}/>
<Line key={line.lineid} line={line} sw={sw} width={this.width.get()} interObs={this.interObs} initVis={idx > win.lines.length-1-7} cmdRefNum={cmdRefMap[line.lineid] ?? 0}/>
</For>
</div>
<If condition={win.lines.length == 0}>
+162 -5
View File
@@ -28,6 +28,8 @@ type ElectronApi = {
getId : () => string,
onTCmd : (callback : (mods : KeyModsType) => void) => void,
onICmd : (callback : (mods : KeyModsType) => void) => void,
onMetaArrowUp : (callback : () => void) => void,
onMetaArrowDown : (callback : () => void) => void,
onBracketCmd : (callback : (event : any, arg : {relative : number}, mods : KeyModsType) => void) => void,
onDigitCmd : (callback : (event : any, arg : {digit : number}, mods : KeyModsType) => void) => void,
contextScreen : (screenOpts : {screenId : string}, position : {x : number, y : number}) => void,
@@ -285,7 +287,8 @@ class Window {
if (load) {
this.loaded.set(true);
}
genMergeSimpleData(this.lines, win.lines, (l : LineType) => String(l.lineid), (l : LineType) => l.lineid);
genMergeSimpleData(this.lines, win.lines, (l : LineType) => String(l.lineid), (l : LineType) => sprintf("%013d:%s", l.ts, l.lineid));
let cmds = win.cmds || [];
for (let i=0; i<cmds.length; i++) {
this.cmds[cmds[i].cmdid] = new Cmd(cmds[i]);
@@ -308,6 +311,25 @@ class Window {
return this.cmds[cmdId];
}
getRunningCmdLines() : LineType[] {
let rtn : LineType[] = [];
for (let i=0; i<this.lines.length; i++) {
let line = this.lines[i];
if (line.cmdid == null) {
continue;
}
let cmd = this.getCmd(line.cmdid);
if (cmd == null) {
continue;
}
let status = cmd.getStatus();
if (status == "running" || status == "detached") {
rtn.push(line);
}
}
return rtn;
}
getCurRemoteInstance() : RemoteInstanceType {
let rname = this.curRemote.get();
if (rname == null) {
@@ -353,11 +375,12 @@ class Window {
let lineIdx = 0;
for (lineIdx=0; lineIdx<lines.length; lineIdx++) {
let lineId = lines[lineIdx].lineid;
let curTs = lines[lineIdx].ts;
if (lineId == line.lineid) {
this.lines[lineIdx] = line;
return;
}
if (lineId > line.lineid) {
if (curTs > line.ts || (curTs == line.ts && lineId > line.lineid)) {
break;
}
}
@@ -637,6 +660,13 @@ class InputModel {
}
};
type LineFocusType = {
cmdInputFocus : boolean,
lineid? : string,
windowid? : string,
cmdid? : string,
};
class Model {
clientId : string;
activeSessionId : OV<string> = mobx.observable.box(null);
@@ -661,6 +691,8 @@ class Model {
this.inputModel = new InputModel();
getApi().onTCmd(this.onTCmd.bind(this));
getApi().onICmd(this.onICmd.bind(this));
getApi().onMetaArrowUp(this.onMetaArrowUp.bind(this));
getApi().onMetaArrowDown(this.onMetaArrowDown.bind(this));
getApi().onBracketCmd(this.onBracketCmd.bind(this));
getApi().onDigitCmd(this.onDigitCmd.bind(this));
}
@@ -726,13 +758,122 @@ class Model {
GlobalInput.createNewScreen();
}
onICmd(mods : KeyModsType) {
focusCmdInput() : void {
let elem = document.getElementById("main-cmd-input");
if (elem != null) {
elem.focus();
}
}
onICmd(mods : KeyModsType) {
this.focusCmdInput();
}
getFocusedLine() : LineFocusType {
let elem = document.getElementById("main-cmd-input");
if (document.activeElement == elem) {
return {cmdInputFocus: true};
}
let lineElem : any = document.activeElement.closest(".line[data-lineid]");
if (lineElem == null) {
return null;
}
return {
cmdInputFocus: false,
lineid: lineElem.dataset.lineid,
windowid: lineElem.dataset.windowid,
cmdid: lineElem.dataset.cmdid,
};
}
onMetaArrowUp() : void {
let focus = this.getFocusedLine();
if (focus == null) {
return;
}
let sw : ScreenWindow = null;
if (focus.cmdInputFocus) {
sw = this.getActiveSW();
}
else {
sw = this.getSWByWindowId(focus.windowid);
}
if (sw == null) {
return;
}
let win = sw.getWindow();
if (win == null) {
return;
}
let runningLines = win.getRunningCmdLines();
if (runningLines.length == 0) {
return;
}
let switchLine : LineType = null;
if (focus.cmdInputFocus) {
switchLine = runningLines[runningLines.length-1];
}
else {
let foundIdx = -1;
for (let i=0; i<runningLines.length; i++) {
if (runningLines[i].lineid == focus.lineid) {
foundIdx = i;
break;
}
}
if (foundIdx > 0) {
switchLine = runningLines[foundIdx-1];
}
}
if (switchLine == null || switchLine.cmdid == null) {
return;
}
let termWrap = sw.getTermWrap(switchLine.cmdid);
if (termWrap == null || termWrap.terminal == null) {
return;
}
termWrap.terminal.focus();
console.log("arrow-up", this.getFocusedLine(), "=>", switchLine);
}
onMetaArrowDown() : void {
let focus = this.getFocusedLine();
if (focus == null || focus.cmdInputFocus) {
return;
}
let sw = this.getSWByWindowId(focus.windowid);
if (sw == null) {
return;
}
let win = sw.getWindow();
if (win == null) {
return;
}
let runningLines = win.getRunningCmdLines();
if (runningLines.length == 0) {
this.focusCmdInput();
return;
}
let foundIdx = -1;
for (let i=0; i<runningLines.length; i++) {
if (runningLines[i].lineid == focus.lineid) {
foundIdx = i;
break;
}
}
if (foundIdx == -1 || foundIdx == runningLines.length - 1) {
this.focusCmdInput();
return;
}
let switchLine = runningLines[foundIdx+1];
let termWrap = sw.getTermWrap(switchLine.cmdid);
if (termWrap == null || termWrap.terminal == null) {
return;
}
termWrap.terminal.focus();
console.log("arrow-down", this.getFocusedLine());
}
onBracketCmd(e : any, arg : {relative: number}, mods : KeyModsType) {
console.log("switch screen (bracket)", arg, mods);
let activeSession = this.getActiveSession();
@@ -801,7 +942,7 @@ class Model {
let cmdline : CmdLineUpdateType = update.cmdline;
this.inputModel.updateCmdLine(cmdline);
}
console.log("run-update>", interactive, update);
// console.log("run-update>", interactive, update);
}
getActiveSession() : Session {
@@ -872,6 +1013,22 @@ class Model {
return this.windows.get(screen.sessionId + "/" + activeWindowId);
}
getActiveSW() : ScreenWindow {
let screen = this.getActiveScreen();
if (screen == null) {
return null;
}
return screen.getActiveSW();
}
getSWByWindowId(windowId : string) : ScreenWindow {
let screen = this.getActiveScreen();
if (screen == null) {
return null;
}
return screen.getSW(windowId);
}
getActiveScreen() : Screen {
let session = this.getActiveSession();
if (session == null) {
@@ -1049,7 +1206,7 @@ class Model {
getRemoteByName(name : string) : RemoteType {
for (let i=0; i<this.remotes.length; i++) {
if (this.remotes[i].remotename == name) {
if (this.remotes[i].remotecanonicalname == name || this.remotes[i].remotealias == name) {
return this.remotes[i];
}
}
+2
View File
@@ -4,6 +4,8 @@ contextBridge.exposeInMainWorld("api", {
getId: () => ipcRenderer.sendSync("get-id"),
onTCmd: (callback) => ipcRenderer.on("t-cmd", callback),
onICmd: (callback) => ipcRenderer.on("i-cmd", callback),
onMetaArrowUp: (callback) => ipcRenderer.on("meta-arrowup", callback),
onMetaArrowDown: (callback) => ipcRenderer.on("meta-arrowdown", callback),
onBracketCmd: (callback) => ipcRenderer.on("bracket-cmd", callback),
onDigitCmd: (callback) => ipcRenderer.on("digit-cmd", callback),
contextScreen: (screenOpts, position) => ipcRenderer.send("context-screen", screenOpts, position),
+1
View File
@@ -19,5 +19,6 @@ document.addEventListener("DOMContentLoaded", () => {
});
(window as any).mobx = mobx;
(window as any).sprintf = sprintf;
console.log("SCRIPTHAUS", VERSION)
+2 -1
View File
@@ -194,8 +194,9 @@ class TermWrap {
this.dataUpdates.push({data: data, pos: pos});
return;
}
console.log("pty-update", this.cmdId, this.ptyPos, data.length);
if (pos > this.ptyPos) {
throw new Error(sprintf("invalid pty-update, data-pos[%d] does not match term-pos[%d]", pos, this.ptyPos));
throw new Error(sprintf("invalid pty-update, data-pos[%d] does not match term-pos[%d] cmdid[%s]", pos, this.ptyPos, this.cmdId));
}
if (pos < this.ptyPos) {
let diff = this.ptyPos - pos;
+5 -3
View File
@@ -17,7 +17,7 @@ type SessionDataType = {
type LineType = {
sessionid : string,
windowid : string,
lineid : number,
lineid : string,
ts : number,
userid : string,
linetype : string,
@@ -71,7 +71,9 @@ type ScreenWindowType = {
type RemoteType = {
remotetype : string,
remoteid : string,
remotename : string,
physicalid : string,
remotealias : string,
remotecanonicalname : string,
remotevars : Record<string, string>,
status : string,
defaultstate : RemoteStateType,
@@ -112,7 +114,7 @@ type HistoryItem = {
sessionid : string,
screenid : string,
windowid : string,
lineid : number,
lineid : string,
haderror : boolean,
cmdid : string,
cmdstr : string,
+4 -2
View File
@@ -62,7 +62,7 @@ interface ISimpleDataType {
remove? : boolean;
}
function genMergeSimpleData<T extends ISimpleDataType>(objs : mobx.IObservableArray<T>, dataArr : T[], idFn : (obj : T) => string, sortIdxFn : (obj : T) => number) {
function genMergeSimpleData<T extends ISimpleDataType>(objs : mobx.IObservableArray<T>, dataArr : T[], idFn : (obj : T) => string, sortIdxFn : (obj : T) => string) {
if (dataArr == null || dataArr.length == 0) {
return;
}
@@ -86,7 +86,9 @@ function genMergeSimpleData<T extends ISimpleDataType>(objs : mobx.IObservableAr
let newObjs = Object.values(objMap);
if (sortIdxFn) {
newObjs.sort((a, b) => {
return sortIdxFn(a) - sortIdxFn(b);
let astr = sortIdxFn(a);
let bstr = sortIdxFn(b);
return astr.localeCompare(bstr);
});
}
objs.replace(newObjs);