big update to get base history info panel working

This commit is contained in:
sawka 2022-08-30 23:12:37 -07:00
parent 087c0c4f1f
commit 9ed993078d
4 changed files with 365 additions and 255 deletions

View File

@ -441,10 +441,6 @@ class TextAreaInput extends React.Component<{}, {}> {
} }
if (e.code == "Enter") { if (e.code == "Enter") {
e.preventDefault(); e.preventDefault();
if (inputModel.historyShow.get()) {
inputModel.grabSelectedHistoryItem();
return;
}
if (!ctrlMod) { if (!ctrlMod) {
setTimeout(() => GlobalModel.inputModel.uiSubmitCommand(), 0); setTimeout(() => GlobalModel.inputModel.uiSubmitCommand(), 0);
return; return;
@ -460,19 +456,22 @@ class TextAreaInput extends React.Component<{}, {}> {
} }
if (e.code == "KeyC" && e.getModifierState("Control")) { if (e.code == "KeyC" && e.getModifierState("Control")) {
e.preventDefault(); e.preventDefault();
inputModel.clearCurLine(); inputModel.resetInput();
return; return;
} }
if (e.code == "KeyR" && e.getModifierState("Control")) { if (e.code == "KeyR" && e.getModifierState("Control")) {
e.preventDefault(); e.preventDefault();
GlobalCommandRunner.openHistory(); inputModel.openHistory();
return; return;
} }
if (e.code == "ArrowUp" || e.code == "ArrowDown") { if (e.code == "ArrowUp" || e.code == "ArrowDown") {
if (inputModel.historyShow.get()) { if (!inputModel.isHistoryLoaded()) {
inputModel.moveHistorySelection(e.code == "ArrowUp" ? -1 : 1); if (e.code == "ArrowUp") {
inputModel.loadHistory(false, 1);
}
return; return;
} }
// invisible history movement
let linePos = this.getLinePos(e.target); let linePos = this.getLinePos(e.target);
if (e.code == "ArrowUp") { if (e.code == "ArrowUp") {
if (!lastHist && linePos.linePos > 1) { if (!lastHist && linePos.linePos > 1) {
@ -480,7 +479,7 @@ class TextAreaInput extends React.Component<{}, {}> {
return; return;
} }
e.preventDefault(); e.preventDefault();
inputModel.prevHistoryItem(); inputModel.moveHistorySelection(1);
this.lastHistoryUpDown = true; this.lastHistoryUpDown = true;
return; return;
} }
@ -490,17 +489,13 @@ class TextAreaInput extends React.Component<{}, {}> {
return; return;
} }
e.preventDefault(); e.preventDefault();
inputModel.nextHistoryItem(); inputModel.moveHistorySelection(-1);
this.lastHistoryUpDown = true; this.lastHistoryUpDown = true;
return; return;
} }
} }
if (e.code == "PageUp" || e.code == "PageDown") { if (e.code == "PageUp" || e.code == "PageDown") {
e.preventDefault(); e.preventDefault();
if (inputModel.historyShow.get()) {
inputModel.moveHistorySelection(e.code == "PageUp" ? -10 : 10);
return;
}
let infoScroll = inputModel.hasScrollingInfoMsg(); let infoScroll = inputModel.hasScrollingInfoMsg();
if (infoScroll) { if (infoScroll) {
let div = document.querySelector(".cmd-input-info"); let div = document.querySelector(".cmd-input-info");
@ -529,6 +524,66 @@ class TextAreaInput extends React.Component<{}, {}> {
})(); })();
} }
@boundMethod
onHistoryKeyDown(e : any) {
let inputModel = GlobalModel.inputModel;
if (e.code == "Escape") {
e.preventDefault();
inputModel.resetHistory();
return;
}
if (e.code == "Enter") {
e.preventDefault();
inputModel.grabSelectedHistoryItem();
return;
}
if (e.code == "KeyC" && e.getModifierState("Control")) {
e.preventDefault();
inputModel.resetInput();
return;
}
if (e.code == "Tab") {
e.preventDefault();
return;
}
if (e.code == "ArrowUp" || e.code == "ArrowDown") {
e.preventDefault();
inputModel.moveHistorySelection(e.code == "ArrowUp" ? 1 : -1);
return;
}
if (e.code == "PageUp" || e.code == "PageDown") {
e.preventDefault();
inputModel.moveHistorySelection(e.code == "PageUp" ? 10 : -10);
return;
}
}
@boundMethod
handleHistoryInput(e : any) {
let inputModel = GlobalModel.inputModel;
mobx.action(() => {
inputModel.historyQueryOpts.get().queryStr = e.target.value;
})();
}
@boundMethod
handleMainFocus(e : any) {
let inputModel = GlobalModel.inputModel;
if (inputModel.historyShow.get()) {
e.preventDefault();
inputModel.giveFocus();
}
}
@boundMethod
handleHistoryFocus(e : any) {
let inputModel = GlobalModel.inputModel;
if (!inputModel.historyShow.get()) {
e.preventDefault();
inputModel.giveFocus();
}
}
render() { render() {
let model = GlobalModel; let model = GlobalModel;
let inputModel = model.inputModel; let inputModel = model.inputModel;
@ -538,8 +593,12 @@ class TextAreaInput extends React.Component<{}, {}> {
if (displayLines > 5) { if (displayLines > 5) {
displayLines = 5; displayLines = 5;
} }
let disabled = inputModel.historyShow.get();
return ( return (
<textarea id="main-cmd-input" rows={displayLines} value={curLine} onKeyDown={this.onKeyDown} onChange={this.onChange} className="textarea"></textarea> <div className="control cmd-input-control is-expanded">
<textarea spellCheck="false" id="main-cmd-input" onFocus={this.handleMainFocus} rows={displayLines} value={curLine} onKeyDown={this.onKeyDown} onChange={this.onChange} className={cn("textarea", {"display-disabled": disabled})}></textarea>
<input spellCheck="false" className="history-input" type="text" onFocus={this.handleHistoryFocus} onKeyDown={this.onHistoryKeyDown} onChange={this.handleHistoryInput} value={inputModel.historyQueryOpts.get().queryStr}/>
</div>
); );
} }
} }
@ -548,24 +607,28 @@ class TextAreaInput extends React.Component<{}, {}> {
class HistoryInfo extends React.Component<{}, {}> { class HistoryInfo extends React.Component<{}, {}> {
lastClickHNum : string = null; lastClickHNum : string = null;
lastClickTs : number = 0; lastClickTs : number = 0;
containingText : mobx.IObservableValue<string> = mobx.observable.box("");
componentDidMount() { componentDidMount() {
let inputModel = GlobalModel.inputModel; let inputModel = GlobalModel.inputModel;
let selNum = inputModel.historySelectedNum.get(); let hitem = inputModel.getHistorySelectedItem();
if (selNum != null) { if (hitem == null) {
inputModel.scrollHistoryItemIntoView(selNum); hitem = inputModel.getFirstHistoryItem();
}
if (hitem != null) {
inputModel.scrollHistoryItemIntoView(hitem.historynum);
} }
} }
@boundMethod @boundMethod
handleItemClick(hitem : HistoryItem) { handleItemClick(hitem : HistoryItem) {
let inputModel = GlobalModel.inputModel; let inputModel = GlobalModel.inputModel;
let selNum = inputModel.historySelectedNum.get(); let selItem = inputModel.getHistorySelectedItem();
if (this.lastClickHNum == hitem.historynum && selNum == hitem.historynum) { if (this.lastClickHNum == hitem.historynum && selItem != null && selItem.historynum == hitem.historynum) {
inputModel.grabSelectedHistoryItem(); inputModel.grabSelectedHistoryItem();
return; return;
} }
inputModel.focusCmdInput(); inputModel.giveFocus();
inputModel.setHistorySelectionNum(hitem.historynum); inputModel.setHistorySelectionNum(hitem.historynum);
let now = Date.now(); let now = Date.now();
this.lastClickHNum = hitem.historynum; this.lastClickHNum = hitem.historynum;
@ -578,13 +641,13 @@ class HistoryInfo extends React.Component<{}, {}> {
}, 3000); }, 3000);
} }
renderHItem(hitem : HistoryItem, selNum : string) : any { renderHItem(hitem : HistoryItem, isSelected : boolean) : any {
let lines = hitem.cmdstr.split("\n"); let lines = hitem.cmdstr.split("\n");
let line : string = ""; let line : string = "";
let idx = 0; let idx = 0;
return ( return (
<div key={hitem.historynum} className={cn("history-item", {"is-selected": selNum == hitem.historynum}, "hnum-" + hitem.historynum)} onClick={() => this.handleItemClick(hitem)}> <div key={hitem.historynum} className={cn("history-item", {"is-selected": isSelected}, "hnum-" + hitem.historynum)} onClick={() => this.handleItemClick(hitem)}>
<div className="history-line">{(selNum == hitem.historynum ? "*" : " ")}{sprintf("%5s", hitem.historynum)} {lines[0]}</div> <div className="history-line">{(isSelected ? "*" : " ")}{sprintf("%5s", hitem.historynum)} {lines[0]}</div>
<For each="line" index="index" of={lines.slice(1)}> <For each="line" index="index" of={lines.slice(1)}>
<div key={idx} className="history-line">{line}</div> <div key={idx} className="history-line">{line}</div>
</For> </For>
@ -600,7 +663,7 @@ class HistoryInfo extends React.Component<{}, {}> {
render() { render() {
let inputModel = GlobalModel.inputModel; let inputModel = GlobalModel.inputModel;
let idx : number = 0; let idx : number = 0;
let selNum = inputModel.historySelectedNum.get(); let selItem = inputModel.getHistorySelectedItem();
let hitems = inputModel.getFilteredHistoryItems(); let hitems = inputModel.getFilteredHistoryItems();
hitems = hitems.slice().reverse(); hitems = hitems.slice().reverse();
let hitem : HistoryItem = null; let hitem : HistoryItem = null;
@ -609,15 +672,15 @@ class HistoryInfo extends React.Component<{}, {}> {
<div className="history-title"> <div className="history-title">
history history
{" "} {" "}
<span className="term-bright-white">[containing '']</span> <span className="history-opt">[containing '']</span>
{" "} {" "}
<span className="term-bright-white">[this session &#x2318;S]</span> <span className="history-opt">[this session &#x2318;S]</span>
{" "} {" "}
<span className="term-bright-white">[this window &#x2318;W]</span> <span className="history-opt">[this window &#x2318;W]</span>
{" "} {" "}
<span className="term-bright-white">[this remote &#x2318;R]</span> <span className="history-opt">[this remote &#x2318;R]</span>
{" "} {" "}
<span className="term-bright-white">[including metacmds &#x2318;M]</span> <span className="history-opt">[including metacmds &#x2318;M]</span>
{" "} <span className="history-clickable-opt" onClick={this.handleClose}>(close ESC)</span> {" "} <span className="history-clickable-opt" onClick={this.handleClose}>(close ESC)</span>
</div> </div>
<div className="history-items"> <div className="history-items">
@ -626,7 +689,7 @@ class HistoryInfo extends React.Component<{}, {}> {
</If> </If>
<If condition={hitems.length > 0}> <If condition={hitems.length > 0}>
<For each="hitem" index="idx" of={hitems}> <For each="hitem" index="idx" of={hitems}>
{this.renderHItem(hitem, selNum)} {this.renderHItem(hitem, (hitem == selItem))}
</For> </For>
</If> </If>
</div> </div>
@ -728,9 +791,7 @@ class CmdInput extends React.Component<{}, {}> {
<div className="control cmd-quick-context"> <div className="control cmd-quick-context">
<div className="button is-static">{remoteStr}</div> <div className="button is-static">{remoteStr}</div>
</div> </div>
<div className="control cmd-input-control is-expanded">
<TextAreaInput/> <TextAreaInput/>
</div>
<div className="control cmd-exec"> <div className="control cmd-exec">
<div onClick={GlobalModel.inputModel.uiSubmitCommand} className="button"> <div onClick={GlobalModel.inputModel.uiSubmitCommand} className="button">
<span className="icon"> <span className="icon">

View File

@ -571,29 +571,120 @@ type HistoryQueryOpts = {
fromTs : number, fromTs : number,
}; };
function getDefaultHistoryQueryOpts() : HistoryQueryOpts {
return {
queryType: "window",
limitRemote: true,
limitRemoteInstance: true,
limitUser: true,
queryStr: "",
maxItems: 10000,
includeMeta: true,
fromTs: 0,
};
}
class InputModel { class InputModel {
historyShow : OV<boolean> = mobx.observable.box(false); historyShow : OV<boolean> = mobx.observable.box(false);
infoShow : OV<boolean> = mobx.observable.box(false); infoShow : OV<boolean> = mobx.observable.box(false);
loadId : string = null;
historyLoading : mobx.IObservableValue<boolean> = mobx.observable.box(false); historyLoading : mobx.IObservableValue<boolean> = mobx.observable.box(false);
historyAfterLoadIndex : number = 0;
historyItems : mobx.IObservableValue<HistoryItem[]> = mobx.observable.box(null, {name: "history-items", deep: false}); // sorted in reverse (most recent is index 0) historyItems : mobx.IObservableValue<HistoryItem[]> = mobx.observable.box(null, {name: "history-items", deep: false}); // sorted in reverse (most recent is index 0)
historyIndex : mobx.IObservableValue<number> = mobx.observable.box(0, {name: "history-index"}); // 1-indexed (because 0 is current) 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; historyQueryOpts : OV<HistoryQueryOpts> = mobx.observable.box(getDefaultHistoryQueryOpts());
queryOpts : OV<HistoryQueryOpts> = mobx.observable.box(null);
infoMsg : OV<InfoType> = mobx.observable.box(null); infoMsg : OV<InfoType> = mobx.observable.box(null);
infoTimeoutId : any = null; infoTimeoutId : any = null;
historySelectedNum : OV<string> = mobx.observable.box(null);
focusCmdInput() : void { _focusCmdInput() : void {
let elem = document.getElementById("main-cmd-input"); let elem = document.getElementById("main-cmd-input");
if (elem != null) { if (elem != null) {
elem.focus(); elem.focus();
} }
} }
_focusHistoryInput() : void {
let elem : HTMLElement = document.querySelector(".cmd-input input.history-input");
if (elem != null) {
elem.focus();
}
}
giveFocus() : void {
if (this.historyShow.get()) {
this._focusHistoryInput();
}
else {
this._focusCmdInput();
}
}
hasFocus() : boolean {
let mainInputElem = document.getElementById("main-cmd-input");
if (document.activeElement == mainInputElem) {
return true;
}
let historyInputElem = document.querySelector(".cmd-input input.history-input");
if (document.activeElement == historyInputElem) {
return true;
}
return false;
}
setHistoryShow(show : boolean) : void {
if (this.historyShow.get() == show) {
return;
}
mobx.action(() => {
this.historyShow.set(show);
if (this.hasFocus()) {
this.giveFocus();
}
})();
}
isHistoryLoaded() : boolean {
if (this.historyLoading.get()) {
return false;
}
let hitems = this.historyItems.get();
return (hitems != null);
}
loadHistory(show : boolean, afterLoadIndex : number) {
if (this.historyLoading.get()) {
return;
}
if (this.isHistoryLoaded()) {
return;
}
this.historyAfterLoadIndex = afterLoadIndex;
mobx.action(() => {
this.historyLoading.set(true);
})();
GlobalCommandRunner.loadHistory(show);
}
openHistory() : void {
if (this.historyLoading.get()) {
return;
}
if (!this.isHistoryLoaded()) {
this.loadHistory(true, 0);
return;
}
if (!this.historyShow.get()) {
mobx.action(() => {
this.setHistoryShow(true);
this.infoShow.set(false);
this.dropModHistory(true);
this.giveFocus();
})();
}
}
updateCmdLine(cmdLine : CmdLineUpdateType) : void { updateCmdLine(cmdLine : CmdLineUpdateType) : void {
mobx.action(() => { mobx.action(() => {
let curLine = this.getCurLine(); let curLine = this.getCurLine();
@ -606,19 +697,49 @@ class InputModel {
})(); })();
} }
showHistory(hinfo : HistoryInfoType) : void { getHistorySelectedItem() : HistoryItem {
let hidx = this.historyIndex.get();
if (hidx == 0) {
return null;
}
let hitems = this.getFilteredHistoryItems();
if (hidx > hitems.length) {
return null;
}
return hitems[hidx-1];
}
getFirstHistoryItem() : HistoryItem {
let hitems = this.getFilteredHistoryItems();
if (hitems.length == 0) {
return null;
}
return hitems[0];
}
setHistorySelectionNum(hnum : string) : void {
let hitems = this.getFilteredHistoryItems();
for (let i=0; i<hitems.length; i++) {
if (hitems[i].historynum == hnum) {
this.setHistoryIndex(i+1);
return;
}
}
}
setHistoryInfo(hinfo : HistoryInfoType) : void {
mobx.action(() => { mobx.action(() => {
if (this.infoShow.get()) { let hitems : HistoryItem[] = hinfo.items ?? [];
this.infoShow.set(false); this.historyItems.set(hitems);
this.historyLoading.set(false);
if (this.historyAfterLoadIndex) {
if (hitems.length >= this.historyAfterLoadIndex) {
this.setHistoryIndex(this.historyAfterLoadIndex);
} }
this.historyShow.set(true); this.historyAfterLoadIndex = 0;
let items = hinfo.items ?? [];
this.historyItems.set(items);
if (items.length == 0) {
this.historySelectedNum.set(null);
} }
else { if (hinfo.show) {
this.historySelectedNum.set(items[0].historynum); this.openHistory();
} }
})(); })();
} }
@ -628,17 +749,6 @@ class InputModel {
return hitems; return hitems;
} }
findCurrentHistoryIndex() : number {
let hitems = this.historyItems.get();
let selNum = this.historySelectedNum.get();
for (let i=0; i<hitems.length; i++) {
if (hitems[i].historynum == selNum) {
return i;
}
}
return -1;
}
scrollHistoryItemIntoView(hnum : string) : void { scrollHistoryItemIntoView(hnum : string) : void {
let elem : HTMLElement = document.querySelector(".cmd-history .hnum-" + hnum); let elem : HTMLElement = document.querySelector(".cmd-history .hnum-" + hnum);
if (elem == null) { if (elem == null) {
@ -672,59 +782,60 @@ class InputModel {
} }
} }
setHistorySelectionNum(hnum : string) : void { grabSelectedHistoryItem() : void {
let hitem = this.getHistorySelectedItem();
if (hitem == null) {
this.resetHistory();
return;
}
mobx.action(() => { mobx.action(() => {
this.historySelectedNum.set(hnum); this.resetInput();
this.scrollHistoryItemIntoView(hnum); this.setCurLine(hitem.cmdstr);
})(); })();
} }
grabSelectedHistoryItem() : void { setHistoryIndex(hidx : number) : void {
let idx = this.findCurrentHistoryIndex(); if (hidx < 0) {
if (idx == -1) { return;
}
if (this.historyIndex.get() == hidx) {
return; return;
} }
let hitem = this.historyItems.get()[idx];
mobx.action(() => { mobx.action(() => {
this.clearCurLine(); this.historyIndex.set(hidx);
this.setCurLine(hitem.cmdstr); if (this.historyShow.get()) {
this.historyShow.set(false); let hitem = this.getHistorySelectedItem();
if (hitem == null) {
hitem = this.getFirstHistoryItem();
}
if (hitem != null) {
this.scrollHistoryItemIntoView(hitem.historynum);
}
}
})(); })();
} }
moveHistorySelection(amt : number) : void { moveHistorySelection(amt : number) : void {
let hitems : HistoryItem[] = this.historyItems.get() ?? []; if (amt == 0) {
if (hitems.length == 0 || amt == 0) {
return; return;
} }
let idx = this.findCurrentHistoryIndex(); if (!this.isHistoryLoaded()) {
if (idx == -1) {
if (amt < 0) {
let hitem = hitems[hitems.length-1];
this.setHistorySelectionNum(hitem.historynum);
}
else {
let hitem = hitems[0];
this.setHistorySelectionNum(hitem.historynum);
}
return; return;
} }
idx += -amt; // negate because history array is sorted in reverse let hitems = this.getFilteredHistoryItems();
let idx = this.historyIndex.get();
idx += amt;
if (idx < 0) { if (idx < 0) {
idx = 0; idx = 0;
} }
if (idx >= hitems.length) { if (idx > hitems.length) {
idx = hitems.length-1; idx = hitems.length;
} }
let hitem = hitems[idx]; this.setHistoryIndex(idx);
this.setHistorySelectionNum(hitem.historynum);
} }
flashInfoMsg(info : InfoType, timeoutMs : number) : void { flashInfoMsg(info : InfoType, timeoutMs : number) : void {
if (this.infoTimeoutId != null) { this._clearInfoTimeout();
clearTimeout(this.infoTimeoutId);
this.infoTimeoutId = null;
}
mobx.action(() => { mobx.action(() => {
this.infoMsg.set(info); this.infoMsg.set(info);
if (info == null) { if (info == null) {
@ -732,7 +843,7 @@ class InputModel {
} }
else { else {
this.infoShow.set(true); this.infoShow.set(true);
this.historyShow.set(false); this.setHistoryShow(false);
} }
})(); })();
if (info != null && timeoutMs) { if (info != null && timeoutMs) {
@ -760,10 +871,17 @@ class InputModel {
return div.scrollHeight > div.clientHeight; return div.scrollHeight > div.clientHeight;
} }
clearInfoMsg(setNull : boolean) : void { _clearInfoTimeout() : void {
if (this.infoTimeoutId != null) {
clearTimeout(this.infoTimeoutId);
this.infoTimeoutId = null; this.infoTimeoutId = null;
}
}
clearInfoMsg(setNull : boolean) : void {
this._clearInfoTimeout();
mobx.action(() => { mobx.action(() => {
this.historyShow.set(false); this.setHistoryShow(false);
this.infoShow.set(false); this.infoShow.set(false);
if (setNull) { if (setNull) {
this.infoMsg.set(null); this.infoMsg.set(null);
@ -772,10 +890,10 @@ class InputModel {
} }
toggleInfoMsg() : void { toggleInfoMsg() : void {
this.infoTimeoutId = null; this._clearInfoTimeout();
mobx.action(() => { mobx.action(() => {
if (this.historyShow.get()) { if (this.historyShow.get()) {
this.historyShow.set(false); this.setHistoryShow(false);
return; return;
} }
let isShowing = this.infoShow.get(); let isShowing = this.infoShow.get();
@ -797,7 +915,7 @@ class InputModel {
if (commandStr.trim() == "") { if (commandStr.trim() == "") {
return; return;
} }
this.clearCurLine(); this.resetInput();
GlobalModel.submitRawCommand(commandStr, true, true); GlobalModel.submitRawCommand(commandStr, true, true);
})(); })();
} }
@ -812,70 +930,14 @@ class InputModel {
})(); })();
} }
loadHistory() : void { resetInput() : void {
if (this.historyLoading.get()) {
return;
}
let sessionId = GlobalModel.activeSessionId.get();
if (sessionId == null) {
this.setHIdx = 0;
return;
}
let win = GlobalModel.getActiveWindow();
if (win == null) {
this.setHIdx = 0;
return;
}
let loadId = uuidv4();
mobx.action(() => { mobx.action(() => {
this.loadId = loadId; this.setHistoryShow(false);
this.historyItems.set(null); this.infoShow.set(false);
this.historyLoading.set(true);
})();
let usp = new URLSearchParams({sessionid: sessionId, windowid: win.windowId});
let url = new URL("http://localhost:8080/api/get-history?" + usp.toString());
fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
if (loadId != this.loadId) {
return; // stale load
}
mobx.action(() => {
if (!this.historyLoading.get()) {
return;
}
if (sessionId != GlobalModel.activeSessionId.get()) {
this.resetHistory(); this.resetHistory();
return; this.dropModHistory(false);
} this.infoMsg.set(null);
if (data.data && data.data.history) { this._clearInfoTimeout();
let hitems : HistoryItem[] = data.data.history || [];
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) => {
let isStale = (loadId != this.loadId);
if (isStale) {
return;
}
GlobalModel.errorHandler("getting history items", err, false);
mobx.action(() => {
this.historyLoading.set(false);
this.historyIndex.set(0);
})();
});
}
clearCurLine() : void {
mobx.action(() => {
this.resetHistory();
this.modHistory.replace([""]);
})(); })();
} }
@ -885,7 +947,7 @@ 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 hitems = this.historyItems.get(); let hitems = this.getFilteredHistoryItems();
if (hidx == 0 || hitems == null || hidx > hitems.length) { if (hidx == 0 || hitems == null || hidx > hitems.length) {
return ""; return "";
} }
@ -896,52 +958,29 @@ class InputModel {
return hitem.cmdstr; return hitem.cmdstr;
} }
resetHistory() : void { dropModHistory(keepLine0 : boolean) : void {
mobx.action(() => { mobx.action(() => {
this.historyLoading.set(false); if (keepLine0) {
this.historyItems.set(null);
this.historyIndex.set(0);
if (this.modHistory.length > 1) { if (this.modHistory.length > 1) {
this.modHistory.splice(1, this.modHistory.length-1); this.modHistory.splice(1, this.modHistory.length-1);
} }
this.setHIdx = 0; }
else {
this.modHistory.replace([""]);
}
})(); })();
} }
prevHistoryItem() : void { resetHistory() : void {
let loading = this.historyLoading.get();
let hitems = this.historyItems.get();
if (loading || hitems == null) {
this.setHIdx += 1;
if (!loading) {
this.loadHistory();
}
return;
}
let hidx = this.historyIndex.get();
hidx += 1;
if (hidx > hitems.length) {
hidx = hitems.length;
}
mobx.action(() => { mobx.action(() => {
this.historyIndex.set(hidx); this.setHistoryShow(false);
this.historyLoading.set(false);
this.historyItems.set(null);
this.historyIndex.set(0);
this.historyQueryOpts.set(getDefaultHistoryQueryOpts());
this.historyAfterLoadIndex = 0;
this.dropModHistory(true);
})(); })();
return;
}
nextHistoryItem() : void {
let hidx = this.historyIndex.get();
if (hidx == 0) {
return;
}
hidx -= 1;
if (hidx < 0) {
hidx = 0;
}
mobx.action(() => {
this.historyIndex.set(hidx);
})();
return;
} }
}; };
@ -1025,19 +1064,18 @@ class Model {
} }
onICmd(e : any, mods : KeyModsType) { onICmd(e : any, mods : KeyModsType) {
this.inputModel.focusCmdInput(); this.inputModel.giveFocus();
} }
onHCmd(e : any, mods : KeyModsType) { onHCmd(e : any, mods : KeyModsType) {
let focusedLine = this.getFocusedLine(); let focusedLine = this.getFocusedLine();
if (focusedLine != null && focusedLine.cmdInputFocus) { if (focusedLine != null && focusedLine.cmdInputFocus) {
GlobalCommandRunner.openHistory(); this.inputModel.openHistory();
} }
} }
getFocusedLine() : LineFocusType { getFocusedLine() : LineFocusType {
let elem = document.getElementById("main-cmd-input"); if (this.inputModel.hasFocus()) {
if (document.activeElement == elem) {
return {cmdInputFocus: true}; return {cmdInputFocus: true};
} }
let lineElem : any = document.activeElement.closest(".line[data-lineid]"); let lineElem : any = document.activeElement.closest(".line[data-lineid]");
@ -1121,7 +1159,7 @@ class Model {
} }
let runningLines = win.getRunningCmdLines(); let runningLines = win.getRunningCmdLines();
if (runningLines.length == 0) { if (runningLines.length == 0) {
this.inputModel.focusCmdInput(); this.inputModel.giveFocus();
return; return;
} }
let foundIdx = -1; let foundIdx = -1;
@ -1132,7 +1170,7 @@ class Model {
} }
} }
if (foundIdx == -1 || foundIdx == runningLines.length - 1) { if (foundIdx == -1 || foundIdx == runningLines.length - 1) {
this.inputModel.focusCmdInput(); this.inputModel.giveFocus();
return; return;
} }
let switchLine = runningLines[foundIdx+1]; let switchLine = runningLines[foundIdx+1];
@ -1167,11 +1205,21 @@ class Model {
runUpdate(genUpdate : UpdateMessage, interactive : boolean) { runUpdate(genUpdate : UpdateMessage, interactive : boolean) {
mobx.action(() => { mobx.action(() => {
this.runUpdate_internal(genUpdate, interactive); let oldContext = this.getUIContext();
this.runUpdate_internal(genUpdate, oldContext, interactive);
let newContext = this.getUIContext()
if (oldContext.sessionid != newContext.sessionid
|| oldContext.screenid != newContext.screenid
|| oldContext.windowid != newContext.windowid) {
this.inputModel.resetInput();
}
else if (remotePtrToString(oldContext.remote) != remotePtrToString(newContext.remote)) {
this.inputModel.resetHistory();
}
})(); })();
} }
runUpdate_internal(genUpdate : UpdateMessage, interactive : boolean) { runUpdate_internal(genUpdate : UpdateMessage, uiContext : UIContextType, interactive : boolean) {
if ("ptydata64" in genUpdate) { if ("ptydata64" in genUpdate) {
let ptyMsg : PtyDataUpdateType = genUpdate; let ptyMsg : PtyDataUpdateType = genUpdate;
let activeScreen = this.getActiveScreen(); let activeScreen = this.getActiveScreen();
@ -1189,16 +1237,16 @@ class Model {
let newActiveScreen = this.getActiveScreen(); let newActiveScreen = this.getActiveScreen();
if (oldActiveScreen != newActiveScreen) { if (oldActiveScreen != newActiveScreen) {
if (newActiveScreen == null) { if (newActiveScreen == null) {
this.activateScreen(this.activeSessionId.get(), null, oldActiveScreen); this._activateScreen(this.activeSessionId.get(), null, oldActiveScreen);
} }
else { else {
this.activateScreen(newActiveScreen.sessionId, newActiveScreen.screenId, oldActiveScreen); this._activateScreen(newActiveScreen.sessionId, newActiveScreen.screenId, oldActiveScreen);
} }
} }
} }
} }
if ("activesessionid" in update) { if ("activesessionid" in update) {
this.activateSession(update.activesessionid); this._activateSession(update.activesessionid);
} }
if ("line" in update) { if ("line" in update) {
if (update.line != null) { if (update.line != null) {
@ -1218,12 +1266,14 @@ class Model {
let info : InfoType = update.info; let info : InfoType = update.info;
this.inputModel.flashInfoMsg(info, info.timeoutms); this.inputModel.flashInfoMsg(info, info.timeoutms);
} }
if (interactive && "history" in update) {
this.inputModel.showHistory(update.history);
}
if ("cmdline" in update) { if ("cmdline" in update) {
this.inputModel.updateCmdLine(update.cmdline); this.inputModel.updateCmdLine(update.cmdline);
} }
if (interactive && "history" in update) {
if (uiContext.sessionid == update.history.sessionid && uiContext.windowid == update.history.windowid) {
this.inputModel.setHistoryInfo(update.history);
}
}
// console.log("run-update>", Date.now(), interactive, update); // console.log("run-update>", Date.now(), interactive, update);
} }
@ -1333,24 +1383,6 @@ class Model {
}); });
} }
getClientKwargs() : Record<string, string> {
let session = this.getActiveSession();
let win = this.getActiveWindow();
let screen = this.getActiveScreen();
let rtn : Record<string, string> = {};
if (session != null) {
rtn.session = session.sessionId;
}
if (screen != null) {
rtn.screen = screen.screenId;
}
if (win != null) {
rtn.window = win.windowId;
rtn.remote = remotePtrToString(win.curRemote.get());
}
return rtn;
}
isInfoUpdate(update : UpdateMessage) : boolean { isInfoUpdate(update : UpdateMessage) : boolean {
if (update == null || "ptydata64" in update) { if (update == null || "ptydata64" in update) {
return false; return false;
@ -1381,7 +1413,7 @@ class Model {
metacmd: metaCmd, metacmd: metaCmd,
metasubcmd: metaSubCmd, metasubcmd: metaSubCmd,
args: args, args: args,
kwargs: Object.assign({}, this.getClientKwargs(), kwargs), kwargs: Object.assign({}, kwargs),
uicontext : this.getUIContext(), uicontext : this.getUIContext(),
}; };
this.submitCommandPacket(pk, interactive); this.submitCommandPacket(pk, interactive);
@ -1392,7 +1424,7 @@ class Model {
type: "fecmd", type: "fecmd",
metacmd: "eval", metacmd: "eval",
args: [cmdStr], args: [cmdStr],
kwargs: this.getClientKwargs(), kwargs: null,
uicontext : this.getUIContext(), uicontext : this.getUIContext(),
}; };
if (!addToHistory) { if (!addToHistory) {
@ -1414,7 +1446,7 @@ class Model {
}); });
} }
activateSession(sessionId : string) { _activateSession(sessionId : string) {
let oldActiveSession = this.getActiveSession(); let oldActiveSession = this.getActiveSession();
if (oldActiveSession != null && oldActiveSession.sessionId == sessionId) { if (oldActiveSession != null && oldActiveSession.sessionId == sessionId) {
return; return;
@ -1423,10 +1455,10 @@ class Model {
if (newSession == null) { if (newSession == null) {
return; return;
} }
this.activateScreen(sessionId, newSession.activeScreenId.get()); this._activateScreen(sessionId, newSession.activeScreenId.get());
} }
activateScreen(sessionId : string, screenId : string, oldActiveScreen? : Screen) { _activateScreen(sessionId : string, screenId : string, oldActiveScreen? : Screen) {
if (!oldActiveScreen) { if (!oldActiveScreen) {
oldActiveScreen = this.getActiveScreen(); oldActiveScreen = this.getActiveScreen();
} }
@ -1438,7 +1470,6 @@ class Model {
let curSessionId = this.activeSessionId.get(); let curSessionId = this.activeSessionId.get();
if (curSessionId != sessionId) { if (curSessionId != sessionId) {
this.activeSessionId.set(sessionId); this.activeSessionId.set(sessionId);
this.inputModel.resetHistory();
} }
this.getActiveSession().activeScreenId.set(screenId); this.getActiveSession().activeScreenId.set(screenId);
})(); })();
@ -1545,40 +1576,32 @@ class CommandRunner {
constructor() { constructor() {
} }
clearCmdInput() : void { loadHistory(show : boolean) {
mobx.action(() => { let kwargs = {"nohist": "1"};
GlobalModel.inputModel.clearInfoMsg(true); if (!show) {
GlobalModel.inputModel.clearCurLine(); kwargs["noshow"] = "1";
})();
} }
GlobalModel.submitCommand("history", null, null, kwargs, true);
openHistory() {
GlobalModel.submitCommand("history", null, null, {"nohist": "1"}, true);
} }
switchSession(session : string) { switchSession(session : string) {
GlobalModel.submitCommand("session", null, [session], {"nohist": "1"}, false); GlobalModel.submitCommand("session", null, [session], {"nohist": "1"}, false);
this.clearCmdInput();
} }
switchScreen(screen : string) { switchScreen(screen : string) {
GlobalModel.submitCommand("screen", null, [screen], {"nohist": "1"}, false); GlobalModel.submitCommand("screen", null, [screen], {"nohist": "1"}, false);
this.clearCmdInput();
} }
createNewSession() { createNewSession() {
GlobalModel.submitCommand("session", "open", null, {"nohist": "1"}, false); GlobalModel.submitCommand("session", "open", null, {"nohist": "1"}, false);
this.clearCmdInput();
} }
createNewScreen() { createNewScreen() {
GlobalModel.submitCommand("screen", "open", null, {"nohist": "1"}, false); GlobalModel.submitCommand("screen", "open", null, {"nohist": "1"}, false);
this.clearCmdInput();
} }
closeScreen(screen : string) { closeScreen(screen : string) {
GlobalModel.submitCommand("screen", "close", [screen], {"nohist": "1"}, false); GlobalModel.submitCommand("screen", "close", [screen], {"nohist": "1"}, false);
this.clearCmdInput();
} }
}; };

View File

@ -538,6 +538,7 @@ body .xterm .xterm-viewport {
&::-webkit-scrollbar { &::-webkit-scrollbar {
background-color: #777; background-color: #777;
width: 5px; width: 5px;
height: 5px;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
@ -591,6 +592,10 @@ body .xterm .xterm-viewport {
} }
.cmd-input-field { .cmd-input-field {
.cmd-input-control {
line-height: 0;
}
textarea { textarea {
color: white; color: white;
background-color: black; background-color: black;
@ -601,6 +606,16 @@ body .xterm .xterm-viewport {
&:active, &:focus { &:active, &:focus {
border-color: white !important; border-color: white !important;
} }
&.display-disabled {
background-color: #444;
}
}
input.history-input {
border: 0;
padding: 0;
height: 0;
} }
.cmd-quick-context .button { .cmd-quick-context .button {
@ -632,6 +647,9 @@ body .xterm .xterm-viewport {
color: #729fcf; color: #729fcf;
padding-bottom: 4px; padding-bottom: 4px;
.history-opt {
}
.history-clickable-opt { .history-clickable-opt {
cursor: pointer; cursor: pointer;
} }
@ -655,6 +673,11 @@ body .xterm .xterm-viewport {
.history-item { .history-item {
padding-left: 5px; padding-left: 5px;
cursor: pointer;
&:hover {
background-color: #222;
}
} }
.history-item.is-selected { .history-item.is-selected {

View File

@ -220,7 +220,10 @@ type ModelUpdateType = {
}; };
type HistoryInfoType = { type HistoryInfoType = {
sessionid : string,
windowid : string,
items : HistoryItem[], items : HistoryItem[],
show : boolean,
}; };
type CmdLineUpdateType = { type CmdLineUpdateType = {