implement command history

This commit is contained in:
sawka 2022-08-11 23:46:52 -07:00
parent 034995ef2a
commit b70d42bca4
3 changed files with 118 additions and 34 deletions

View File

@ -249,12 +249,12 @@ class CmdInput extends React.Component<{}, {}> {
e.preventDefault(); e.preventDefault();
let lastTab = (ltCurLine != null && curLine == ltCurLine); let lastTab = (ltCurLine != null && curLine == ltCurLine);
if (lastTab) { if (lastTab) {
GlobalModel.submitCommand("compgen", null, [curLine], {"comppos": String(curLine.length), "compshow": "1"}); GlobalModel.submitCommand("compgen", null, [curLine], {"comppos": String(curLine.length), "compshow": "1", "nohist": "1"});
return; return;
} }
else { else {
this.lastTabCurLine.set(curLine); this.lastTabCurLine.set(curLine);
GlobalModel.submitCommand("compgen", null, [curLine], {"comppos": String(curLine.length)}); GlobalModel.submitCommand("compgen", null, [curLine], {"comppos": String(curLine.length), "nohist": "1"});
GlobalModel.clearInfoMsg(true); GlobalModel.clearInfoMsg(true);
return; return;
} }
@ -306,7 +306,7 @@ class CmdInput extends React.Component<{}, {}> {
let hitem = {cmdtext: commandStr}; let hitem = {cmdtext: commandStr};
inputModel.clearCurLine(); inputModel.clearCurLine();
GlobalModel.clearInfoMsg(true); GlobalModel.clearInfoMsg(true);
model.submitRawCommand(commandStr); model.submitRawCommand(commandStr, true);
} }
getAfterSlash(s : string) : string { getAfterSlash(s : string) : string {

View File

@ -263,7 +263,6 @@ class Window {
loaded : OV<boolean> = mobx.observable.box(false); loaded : OV<boolean> = mobx.observable.box(false);
loadError : OV<string> = mobx.observable.box(null); loadError : OV<string> = mobx.observable.box(null);
lines : OArr<LineType> = mobx.observable.array([], {deep: false}); lines : OArr<LineType> = mobx.observable.array([], {deep: false});
history : any[] = [];
cmds : Record<string, Cmd> = {}; cmds : Record<string, Cmd> = {};
remoteInstances : OArr<RemoteInstanceType> = mobx.observable.array([]); remoteInstances : OArr<RemoteInstanceType> = mobx.observable.array([]);
@ -272,14 +271,6 @@ class Window {
this.windowId = windowId; this.windowId = windowId;
} }
getNumHistoryItems() : number {
return 0;
}
getHistoryItem(hnum : number) : any {
return null
}
updatePtyData(ptyMsg : PtyDataUpdateType) { updatePtyData(ptyMsg : PtyDataUpdateType) {
let cmd = this.cmds[ptyMsg.cmdid]; let cmd = this.cmds[ptyMsg.cmdid];
if (cmd == null) { if (cmd == null) {
@ -297,7 +288,6 @@ class Window {
this.loaded.set(true); 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) => l.lineid);
this.history = win.history || [];
let cmds = win.cmds || []; let cmds = win.cmds || [];
for (let i=0; i<cmds.length; i++) { for (let i=0; i<cmds.length; i++) {
this.cmds[cmds[i].cmdid] = new Cmd(cmds[i]); this.cmds[cmds[i].cmdid] = new Cmd(cmds[i]);
@ -499,8 +489,12 @@ class Session {
} }
class InputModel { class InputModel {
historyIndex : mobx.IObservableValue<number> = mobx.observable.box(0, {name: "history-index"}); historyLoading : mobx.IObservableValue<boolean> = mobx.observable.box(false);
historySessionId : string = null;
historyItems : mobx.IObservableValue<HistoryItem[]> = mobx.observable.box(null, {name: "history-items", deep: false});
historyIndex : mobx.IObservableValue<number> = mobx.observable.box(0, {name: "history-index"}); // 1-indexed (because 0 is current)
modHistory : mobx.IObservableArray<string> = mobx.observable.array([""], {name: "mod-history"}); modHistory : mobx.IObservableArray<string> = mobx.observable.array([""], {name: "mod-history"});
setHIdx : number = 0;
updateCmdLine(cmdLine : CmdLineUpdateType) { updateCmdLine(cmdLine : CmdLineUpdateType) {
mobx.action(() => { mobx.action(() => {
@ -516,14 +510,66 @@ class InputModel {
setCurLine(val : string) { setCurLine(val : string) {
let hidx = this.historyIndex.get(); let hidx = this.historyIndex.get();
this.modHistory[hidx] = val; mobx.action(() => {
if (this.modHistory.length <= hidx) {
this.modHistory.length = hidx + 1;
}
this.modHistory[hidx] = val;
})();
}
loadHistory() {
if (this.historyLoading.get()) {
return;
}
let sessionId = GlobalModel.activeSessionId.get();
if (sessionId == null) {
this.setHIdx = 0;
return;
}
mobx.action(() => {
this.historySessionId = sessionId;
this.historyItems.set(null);
this.historyLoading.set(true);
})();
let usp = new URLSearchParams({sessionid: sessionId});
let url = new URL("http://localhost:8080/api/get-history?" + usp.toString());
fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
mobx.action(() => {
if (!this.historyLoading.get()) {
return;
}
if (sessionId != GlobalModel.activeSessionId.get()) {
this.resetHistory();
return;
}
if (data.data && data.data.history) {
let hitems : HistoryItem[] = data.data.history || [];
this.historySessionId = sessionId;
this.historyItems.set(hitems);
this.historyLoading.set(false);
let hlen = hitems.length;
let setHIdx = this.setHIdx;
if (setHIdx > hlen) {
setHIdx = hlen;
}
this.historyIndex.set(setHIdx);
this.setHIdx = 0;
}
})();
}).catch((err) => {
GlobalModel.errorHandler("getting history items", err, false);
mobx.action(() => {
this.historyLoading.set(false);
this.historyIndex.set(0);
})();
});
} }
clearCurLine() { clearCurLine() {
mobx.action(() => { mobx.action(() => {
this.historyIndex.set(0); this.resetHistory();
this.modHistory.clear(); this.modHistory.replace([""]);
this.modHistory[0] = "";
})(); })();
} }
@ -533,24 +579,43 @@ class InputModel {
if (hidx < this.modHistory.length && this.modHistory[hidx] != null) { if (hidx < this.modHistory.length && this.modHistory[hidx] != null) {
return this.modHistory[hidx]; return this.modHistory[hidx];
} }
let win = model.getActiveWindow(); let hitems = this.historyItems.get();
if (win == null) { if (hidx == 0 || hitems == null || hidx > hitems.length) {
return ""; return "";
} }
let hitem = win.getHistoryItem(-hidx); let hitem = hitems[hidx-1];
if (hitem == null) { if (hitem == null) {
return ""; return "";
} }
return hitem.cmdtext; return hitem.cmdstr;
}
resetHistory() : void {
mobx.action(() => {
this.historyLoading.set(false);
this.historyItems.set(null);
this.historyIndex.set(0);
if (this.modHistory.length > 1) {
this.modHistory.splice(1, this.modHistory.length-1);
}
this.setHIdx = 0;
})();
} }
prevHistoryItem() : void { prevHistoryItem() : void {
let model = GlobalModel; let loading = this.historyLoading.get();
let win = model.getActiveWindow(); let hitems = this.historyItems.get();
if (loading || hitems == null) {
this.setHIdx += 1;
if (!loading) {
this.loadHistory();
}
return;
}
let hidx = this.historyIndex.get(); let hidx = this.historyIndex.get();
hidx += 1; hidx += 1;
if (hidx > win.getNumHistoryItems()) { if (hidx > hitems.length) {
hidx = win.getNumHistoryItems(); hidx = hitems.length;
} }
mobx.action(() => { mobx.action(() => {
this.historyIndex.set(hidx); this.historyIndex.set(hidx);
@ -560,6 +625,9 @@ class InputModel {
nextHistoryItem() : void { nextHistoryItem() : void {
let hidx = this.historyIndex.get(); let hidx = this.historyIndex.get();
if (hidx == 0) {
return;
}
hidx -= 1; hidx -= 1;
if (hidx < 0) { if (hidx < 0) {
hidx = 0; hidx = 0;
@ -854,13 +922,16 @@ class Model {
this.submitCommandPacket(pk); this.submitCommandPacket(pk);
} }
submitRawCommand(cmdStr : string) { submitRawCommand(cmdStr : string, addToHistory : boolean) {
let pk : FeCmdPacketType = { let pk : FeCmdPacketType = {
type: "fecmd", type: "fecmd",
metacmd: "eval", metacmd: "eval",
args: [cmdStr], args: [cmdStr],
kwargs: this.getClientKwargs(), kwargs: this.getClientKwargs(),
}; };
if (!addToHistory) {
pk.kwargs["nohist"] = "1";
}
this.submitCommandPacket(pk) this.submitCommandPacket(pk)
} }
@ -913,7 +984,11 @@ class Model {
} }
mobx.action(() => { mobx.action(() => {
this.deactivateWindows(); this.deactivateWindows();
this.activeSessionId.set(sessionId); let curSessionId = this.activeSessionId.get();
if (curSessionId != sessionId) {
this.activeSessionId.set(sessionId);
this.inputModel.resetHistory();
}
this.getActiveSession().activeScreenId.set(screenId); this.getActiveSession().activeScreenId.set(screenId);
})(); })();
let curScreen = this.getActiveScreen(); let curScreen = this.getActiveScreen();
@ -1005,23 +1080,23 @@ class InputClass {
} }
switchSession(session : string) { switchSession(session : string) {
GlobalModel.submitCommand("session", null, [session], null); GlobalModel.submitCommand("session", null, [session], {"nohist": "1"});
} }
switchScreen(screen : string) { switchScreen(screen : string) {
GlobalModel.submitCommand("screen", null, [screen], null); GlobalModel.submitCommand("screen", null, [screen], {"nohist": "1"});
} }
createNewSession() { createNewSession() {
GlobalModel.submitCommand("session", "open", null, null); GlobalModel.submitCommand("session", "open", null, {"nohist": "1"});
} }
createNewScreen() { createNewScreen() {
GlobalModel.submitCommand("screen", "open", null, null); GlobalModel.submitCommand("screen", "open", null, {"nohist": "1"});
} }
closeScreen(screen : string) { closeScreen(screen : string) {
GlobalModel.submitCommand("screen", "close", [screen], null); GlobalModel.submitCommand("screen", "close", [screen], {"nohist": "1"});
} }
}; };

View File

@ -98,7 +98,6 @@ type WindowDataType = {
windowid : string, windowid : string,
curremote : string, curremote : string,
lines : LineType[], lines : LineType[],
history : HistoryItem[],
cmds : CmdDataType[], cmds : CmdDataType[],
remotes : RemoteInstanceType[], remotes : RemoteInstanceType[],
@ -107,7 +106,17 @@ type WindowDataType = {
}; };
type HistoryItem = { type HistoryItem = {
historyid : string,
ts : number,
userid : string,
sessionid : string,
screenid : string,
windowid : string,
lineid : number,
haderror : boolean,
cmdid : string,
cmdstr : string, cmdstr : string,
remove : boolean,
}; };
type CmdRemoteStateType = { type CmdRemoteStateType = {