mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-04-07 18:56:00 +02:00
history checkpoint
This commit is contained in:
parent
d037666ad1
commit
087c0c4f1f
@ -104,8 +104,13 @@ function createWindow(size : {width : number, height : number}) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (input.code == "KeyR" && input.meta && input.alt) {
|
//if (input.code == "KeyR" && input.meta && input.alt) {
|
||||||
createRemotesWindow();
|
// createRemotesWindow();
|
||||||
|
// e.preventDefault();
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
if (input.code == "KeyH" && input.meta) {
|
||||||
|
win.webContents.send("h-cmd", mods);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
75
src/main.tsx
75
src/main.tsx
@ -8,9 +8,9 @@ import dayjs from 'dayjs'
|
|||||||
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
|
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
|
||||||
import cn from "classnames"
|
import cn from "classnames"
|
||||||
import {TermWrap} from "./term";
|
import {TermWrap} from "./term";
|
||||||
import type {SessionDataType, LineType, CmdDataType, RemoteType, RemoteStateType, RemoteInstanceType, RemotePtrType} from "./types";
|
import type {SessionDataType, LineType, CmdDataType, RemoteType, RemoteStateType, RemoteInstanceType, RemotePtrType, HistoryItem} from "./types";
|
||||||
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||||
import {GlobalModel, GlobalInput, Session, Cmd, Window, Screen, ScreenWindow, riToRPtr} from "./model";
|
import {GlobalModel, GlobalCommandRunner, Session, Cmd, Window, Screen, ScreenWindow, riToRPtr} from "./model";
|
||||||
|
|
||||||
dayjs.extend(localizedFormat)
|
dayjs.extend(localizedFormat)
|
||||||
|
|
||||||
@ -441,6 +441,10 @@ 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;
|
||||||
@ -459,7 +463,16 @@ class TextAreaInput extends React.Component<{}, {}> {
|
|||||||
inputModel.clearCurLine();
|
inputModel.clearCurLine();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (e.code == "KeyR" && e.getModifierState("Control")) {
|
||||||
|
e.preventDefault();
|
||||||
|
GlobalCommandRunner.openHistory();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (e.code == "ArrowUp" || e.code == "ArrowDown") {
|
if (e.code == "ArrowUp" || e.code == "ArrowDown") {
|
||||||
|
if (inputModel.historyShow.get()) {
|
||||||
|
inputModel.moveHistorySelection(e.code == "ArrowUp" ? -1 : 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
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) {
|
||||||
@ -484,7 +497,11 @@ class TextAreaInput extends React.Component<{}, {}> {
|
|||||||
}
|
}
|
||||||
if (e.code == "PageUp" || e.code == "PageDown") {
|
if (e.code == "PageUp" || e.code == "PageDown") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let infoScroll = GlobalModel.inputModel.hasScrollingInfoMsg();
|
if (inputModel.historyShow.get()) {
|
||||||
|
inputModel.moveHistorySelection(e.code == "PageUp" ? -10 : 10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let infoScroll = inputModel.hasScrollingInfoMsg();
|
||||||
if (infoScroll) {
|
if (infoScroll) {
|
||||||
let div = document.querySelector(".cmd-input-info");
|
let div = document.querySelector(".cmd-input-info");
|
||||||
let amt = pageSize(div);
|
let amt = pageSize(div);
|
||||||
@ -529,23 +546,44 @@ class TextAreaInput extends React.Component<{}, {}> {
|
|||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class HistoryInfo extends React.Component<{}, {}> {
|
class HistoryInfo extends React.Component<{}, {}> {
|
||||||
|
lastClickHNum : string = null;
|
||||||
|
lastClickTs : number = 0;
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
let inputModel = GlobalModel.inputModel;
|
let inputModel = GlobalModel.inputModel;
|
||||||
let selNum = inputModel.historySelectedNum.get();
|
let selNum = inputModel.historySelectedNum.get();
|
||||||
if (selNum != null) {
|
if (selNum != null) {
|
||||||
let elem = document.querySelector(".cmd-history .hnum-" + selNum);
|
inputModel.scrollHistoryItemIntoView(selNum);
|
||||||
if (elem != null) {
|
|
||||||
elem.scrollIntoView({block: "nearest"});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHItem(hitem : HistoryItem, selNum : number) : any {
|
@boundMethod
|
||||||
|
handleItemClick(hitem : HistoryItem) {
|
||||||
|
let inputModel = GlobalModel.inputModel;
|
||||||
|
let selNum = inputModel.historySelectedNum.get();
|
||||||
|
if (this.lastClickHNum == hitem.historynum && selNum == hitem.historynum) {
|
||||||
|
inputModel.grabSelectedHistoryItem();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inputModel.focusCmdInput();
|
||||||
|
inputModel.setHistorySelectionNum(hitem.historynum);
|
||||||
|
let now = Date.now();
|
||||||
|
this.lastClickHNum = hitem.historynum;
|
||||||
|
this.lastClickTs = now;
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.lastClickTs == now) {
|
||||||
|
this.lastClickHNum = null;
|
||||||
|
this.lastClickTs = 0;
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHItem(hitem : HistoryItem, selNum : string) : 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)}>
|
<div key={hitem.historynum} className={cn("history-item", {"is-selected": selNum == hitem.historynum}, "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">{(selNum == hitem.historynum ? "*" : " ")}{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>
|
||||||
@ -554,16 +592,22 @@ class HistoryInfo extends React.Component<{}, {}> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@boundMethod
|
||||||
|
handleClose() {
|
||||||
|
GlobalModel.inputModel.toggleInfoMsg();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let inputModel = GlobalModel.inputModel;
|
let inputModel = GlobalModel.inputModel;
|
||||||
let idx : number = 0;
|
let idx : number = 0;
|
||||||
let hitems : HistoryItem[] = inputModel.historyItems.get() ?? [];
|
|
||||||
let selNum = inputModel.historySelectedNum.get();
|
let selNum = inputModel.historySelectedNum.get();
|
||||||
|
let hitems = inputModel.getFilteredHistoryItems();
|
||||||
hitems = hitems.slice().reverse();
|
hitems = hitems.slice().reverse();
|
||||||
|
let hitem : HistoryItem = null;
|
||||||
return (
|
return (
|
||||||
<div className="cmd-history">
|
<div className="cmd-history">
|
||||||
<div className="history-title">
|
<div className="history-title">
|
||||||
showing history for
|
history
|
||||||
{" "}
|
{" "}
|
||||||
<span className="term-bright-white">[containing '']</span>
|
<span className="term-bright-white">[containing '']</span>
|
||||||
{" "}
|
{" "}
|
||||||
@ -574,6 +618,7 @@ class HistoryInfo extends React.Component<{}, {}> {
|
|||||||
<span className="term-bright-white">[this remote ⌘R]</span>
|
<span className="term-bright-white">[this remote ⌘R]</span>
|
||||||
{" "}
|
{" "}
|
||||||
<span className="term-bright-white">[including metacmds ⌘M]</span>
|
<span className="term-bright-white">[including metacmds ⌘M]</span>
|
||||||
|
{" "} <span className="history-clickable-opt" onClick={this.handleClose}>(close ESC)</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="history-items">
|
<div className="history-items">
|
||||||
<If condition={hitems.length == 0}>
|
<If condition={hitems.length == 0}>
|
||||||
@ -937,7 +982,7 @@ class ScreenTabs extends React.Component<{session : Session}, {}> {
|
|||||||
@boundMethod
|
@boundMethod
|
||||||
handleNewScreen() {
|
handleNewScreen() {
|
||||||
let {session} = this.props;
|
let {session} = this.props;
|
||||||
GlobalInput.createNewScreen();
|
GlobalCommandRunner.createNewScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
@ -953,7 +998,7 @@ class ScreenTabs extends React.Component<{session : Session}, {}> {
|
|||||||
if (screen == null) {
|
if (screen == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GlobalInput.switchScreen(screenId);
|
GlobalCommandRunner.switchScreen(screenId);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleContextMenu(e : any, screenId : string) : void {
|
handleContextMenu(e : any, screenId : string) : void {
|
||||||
@ -1019,11 +1064,11 @@ class MainSideBar extends React.Component<{}, {}> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleSessionClick(sessionId : string) {
|
handleSessionClick(sessionId : string) {
|
||||||
GlobalInput.switchSession(sessionId);
|
GlobalCommandRunner.switchSession(sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNewSession() {
|
handleNewSession() {
|
||||||
GlobalInput.createNewSession();
|
GlobalCommandRunner.createNewSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
clickRemotes() {
|
clickRemotes() {
|
||||||
|
174
src/model.ts
174
src/model.ts
@ -51,6 +51,7 @@ type ElectronApi = {
|
|||||||
getId : () => string,
|
getId : () => string,
|
||||||
onTCmd : (callback : (mods : KeyModsType) => void) => void,
|
onTCmd : (callback : (mods : KeyModsType) => void) => void,
|
||||||
onICmd : (callback : (mods : KeyModsType) => void) => void,
|
onICmd : (callback : (mods : KeyModsType) => void) => void,
|
||||||
|
onHCmd : (callback : (mods : KeyModsType) => void) => void,
|
||||||
onMetaArrowUp : (callback : () => void) => void,
|
onMetaArrowUp : (callback : () => void) => void,
|
||||||
onMetaArrowDown : (callback : () => void) => void,
|
onMetaArrowDown : (callback : () => void) => void,
|
||||||
onBracketCmd : (callback : (event : any, arg : {relative : number}, mods : KeyModsType) => void) => void,
|
onBracketCmd : (callback : (event : any, arg : {relative : number}, mods : KeyModsType) => void) => void,
|
||||||
@ -574,9 +575,9 @@ 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);
|
||||||
historySessionId : string = null;
|
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});
|
|
||||||
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;
|
setHIdx : number = 0;
|
||||||
@ -586,6 +587,13 @@ class InputModel {
|
|||||||
infoTimeoutId : any = null;
|
infoTimeoutId : any = null;
|
||||||
historySelectedNum : OV<string> = mobx.observable.box(null);
|
historySelectedNum : OV<string> = mobx.observable.box(null);
|
||||||
|
|
||||||
|
focusCmdInput() : void {
|
||||||
|
let elem = document.getElementById("main-cmd-input");
|
||||||
|
if (elem != null) {
|
||||||
|
elem.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateCmdLine(cmdLine : CmdLineUpdateType) : void {
|
updateCmdLine(cmdLine : CmdLineUpdateType) : void {
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
let curLine = this.getCurLine();
|
let curLine = this.getCurLine();
|
||||||
@ -615,6 +623,103 @@ class InputModel {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFilteredHistoryItems() : HistoryItem[] {
|
||||||
|
let hitems : HistoryItem[] = this.historyItems.get() ?? [];
|
||||||
|
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 {
|
||||||
|
let elem : HTMLElement = document.querySelector(".cmd-history .hnum-" + hnum);
|
||||||
|
if (elem == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let historyDiv = elem.closest(".cmd-history");
|
||||||
|
if (historyDiv == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let buffer = 15;
|
||||||
|
let titleHeight = 24;
|
||||||
|
let elemOffset = elem.offsetTop;
|
||||||
|
let elemHeight = elem.clientHeight;
|
||||||
|
let topPos = historyDiv.scrollTop;
|
||||||
|
let endPos = topPos + historyDiv.clientHeight;
|
||||||
|
if (elemOffset + elemHeight + buffer > endPos) {
|
||||||
|
if (elemHeight + buffer > historyDiv.clientHeight - titleHeight) {
|
||||||
|
historyDiv.scrollTop = elemOffset - titleHeight;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
historyDiv.scrollTop = elemOffset - historyDiv.clientHeight + elemHeight + buffer;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (elemOffset < topPos + titleHeight) {
|
||||||
|
if (elemHeight + buffer > historyDiv.clientHeight - titleHeight) {
|
||||||
|
historyDiv.scrollTop = elemOffset - titleHeight;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
historyDiv.scrollTop = elemOffset - titleHeight - buffer;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setHistorySelectionNum(hnum : string) : void {
|
||||||
|
mobx.action(() => {
|
||||||
|
this.historySelectedNum.set(hnum);
|
||||||
|
this.scrollHistoryItemIntoView(hnum);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
grabSelectedHistoryItem() : void {
|
||||||
|
let idx = this.findCurrentHistoryIndex();
|
||||||
|
if (idx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let hitem = this.historyItems.get()[idx];
|
||||||
|
mobx.action(() => {
|
||||||
|
this.clearCurLine();
|
||||||
|
this.setCurLine(hitem.cmdstr);
|
||||||
|
this.historyShow.set(false);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
moveHistorySelection(amt : number) : void {
|
||||||
|
let hitems : HistoryItem[] = this.historyItems.get() ?? [];
|
||||||
|
if (hitems.length == 0 || amt == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let idx = this.findCurrentHistoryIndex();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
idx += -amt; // negate because history array is sorted in reverse
|
||||||
|
if (idx < 0) {
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
if (idx >= hitems.length) {
|
||||||
|
idx = hitems.length-1;
|
||||||
|
}
|
||||||
|
let hitem = hitems[idx];
|
||||||
|
this.setHistorySelectionNum(hitem.historynum);
|
||||||
|
}
|
||||||
|
|
||||||
flashInfoMsg(info : InfoType, timeoutMs : number) : void {
|
flashInfoMsg(info : InfoType, timeoutMs : number) : void {
|
||||||
if (this.infoTimeoutId != null) {
|
if (this.infoTimeoutId != null) {
|
||||||
clearTimeout(this.infoTimeoutId);
|
clearTimeout(this.infoTimeoutId);
|
||||||
@ -655,17 +760,6 @@ class InputModel {
|
|||||||
return div.scrollHeight > div.clientHeight;
|
return div.scrollHeight > div.clientHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasScrollingHistory() : boolean {
|
|
||||||
if (!this.historyShow.get()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let div = document.querySelector(".cmd-history");
|
|
||||||
if (div == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return div.scrollHeight > div.clientHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearInfoMsg(setNull : boolean) : void {
|
clearInfoMsg(setNull : boolean) : void {
|
||||||
this.infoTimeoutId = null;
|
this.infoTimeoutId = null;
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
@ -732,14 +826,18 @@ class InputModel {
|
|||||||
this.setHIdx = 0;
|
this.setHIdx = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let loadId = uuidv4();
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
this.historySessionId = sessionId;
|
this.loadId = loadId;
|
||||||
this.historyItems.set(null);
|
this.historyItems.set(null);
|
||||||
this.historyLoading.set(true);
|
this.historyLoading.set(true);
|
||||||
})();
|
})();
|
||||||
let usp = new URLSearchParams({sessionid: sessionId, windowid: win.windowId});
|
let usp = new URLSearchParams({sessionid: sessionId, windowid: win.windowId});
|
||||||
let url = new URL("http://localhost:8080/api/get-history?" + usp.toString());
|
let url = new URL("http://localhost:8080/api/get-history?" + usp.toString());
|
||||||
fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
||||||
|
if (loadId != this.loadId) {
|
||||||
|
return; // stale load
|
||||||
|
}
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
if (!this.historyLoading.get()) {
|
if (!this.historyLoading.get()) {
|
||||||
return;
|
return;
|
||||||
@ -750,7 +848,6 @@ class InputModel {
|
|||||||
}
|
}
|
||||||
if (data.data && data.data.history) {
|
if (data.data && data.data.history) {
|
||||||
let hitems : HistoryItem[] = data.data.history || [];
|
let hitems : HistoryItem[] = data.data.history || [];
|
||||||
this.historySessionId = sessionId;
|
|
||||||
this.historyItems.set(hitems);
|
this.historyItems.set(hitems);
|
||||||
this.historyLoading.set(false);
|
this.historyLoading.set(false);
|
||||||
let hlen = hitems.length;
|
let hlen = hitems.length;
|
||||||
@ -763,6 +860,10 @@ class InputModel {
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
let isStale = (loadId != this.loadId);
|
||||||
|
if (isStale) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
GlobalModel.errorHandler("getting history items", err, false);
|
GlobalModel.errorHandler("getting history items", err, false);
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
this.historyLoading.set(false);
|
this.historyLoading.set(false);
|
||||||
@ -873,6 +974,7 @@ class Model {
|
|||||||
this.inputModel = new InputModel();
|
this.inputModel = new InputModel();
|
||||||
getApi().onTCmd(this.onTCmd.bind(this));
|
getApi().onTCmd(this.onTCmd.bind(this));
|
||||||
getApi().onICmd(this.onICmd.bind(this));
|
getApi().onICmd(this.onICmd.bind(this));
|
||||||
|
getApi().onHCmd(this.onHCmd.bind(this));
|
||||||
getApi().onMetaArrowUp(this.onMetaArrowUp.bind(this));
|
getApi().onMetaArrowUp(this.onMetaArrowUp.bind(this));
|
||||||
getApi().onMetaArrowDown(this.onMetaArrowDown.bind(this));
|
getApi().onMetaArrowDown(this.onMetaArrowDown.bind(this));
|
||||||
getApi().onBracketCmd(this.onBracketCmd.bind(this));
|
getApi().onBracketCmd(this.onBracketCmd.bind(this));
|
||||||
@ -917,20 +1019,20 @@ class Model {
|
|||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
onTCmd(mods : KeyModsType) {
|
onTCmd(e : any, mods : KeyModsType) {
|
||||||
console.log("got cmd-t", mods);
|
console.log("got cmd-t", mods);
|
||||||
GlobalInput.createNewScreen();
|
GlobalCommandRunner.createNewScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
focusCmdInput() : void {
|
onICmd(e : any, mods : KeyModsType) {
|
||||||
let elem = document.getElementById("main-cmd-input");
|
this.inputModel.focusCmdInput();
|
||||||
if (elem != null) {
|
|
||||||
elem.focus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onICmd(mods : KeyModsType) {
|
onHCmd(e : any, mods : KeyModsType) {
|
||||||
this.focusCmdInput();
|
let focusedLine = this.getFocusedLine();
|
||||||
|
if (focusedLine != null && focusedLine.cmdInputFocus) {
|
||||||
|
GlobalCommandRunner.openHistory();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getFocusedLine() : LineFocusType {
|
getFocusedLine() : LineFocusType {
|
||||||
@ -1019,7 +1121,7 @@ class Model {
|
|||||||
}
|
}
|
||||||
let runningLines = win.getRunningCmdLines();
|
let runningLines = win.getRunningCmdLines();
|
||||||
if (runningLines.length == 0) {
|
if (runningLines.length == 0) {
|
||||||
this.focusCmdInput();
|
this.inputModel.focusCmdInput();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let foundIdx = -1;
|
let foundIdx = -1;
|
||||||
@ -1030,7 +1132,7 @@ class Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (foundIdx == -1 || foundIdx == runningLines.length - 1) {
|
if (foundIdx == -1 || foundIdx == runningLines.length - 1) {
|
||||||
this.focusCmdInput();
|
this.inputModel.focusCmdInput();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let switchLine = runningLines[foundIdx+1];
|
let switchLine = runningLines[foundIdx+1];
|
||||||
@ -1048,15 +1150,15 @@ class Model {
|
|||||||
|
|
||||||
onBracketCmd(e : any, arg : {relative: number}, mods : KeyModsType) {
|
onBracketCmd(e : any, arg : {relative: number}, mods : KeyModsType) {
|
||||||
if (arg.relative == 1) {
|
if (arg.relative == 1) {
|
||||||
GlobalInput.switchScreen("+");
|
GlobalCommandRunner.switchScreen("+");
|
||||||
}
|
}
|
||||||
else if (arg.relative == -1) {
|
else if (arg.relative == -1) {
|
||||||
GlobalInput.switchScreen("-");
|
GlobalCommandRunner.switchScreen("-");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDigitCmd(e : any, arg : {digit: number}, mods : KeyModsType) {
|
onDigitCmd(e : any, arg : {digit: number}, mods : KeyModsType) {
|
||||||
GlobalInput.switchScreen(String(arg.digit));
|
GlobalCommandRunner.switchScreen(String(arg.digit));
|
||||||
}
|
}
|
||||||
|
|
||||||
isConnected() : boolean {
|
isConnected() : boolean {
|
||||||
@ -1439,7 +1541,7 @@ class Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InputClass {
|
class CommandRunner {
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1450,6 +1552,10 @@ class InputClass {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
this.clearCmdInput();
|
||||||
@ -1477,14 +1583,14 @@ class InputClass {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let GlobalModel : Model = null;
|
let GlobalModel : Model = null;
|
||||||
let GlobalInput : InputClass = null;
|
let GlobalCommandRunner : CommandRunner = null;
|
||||||
if ((window as any).GlobalModal == null) {
|
if ((window as any).GlobalModal == null) {
|
||||||
(window as any).GlobalModel = new Model();
|
(window as any).GlobalModel = new Model();
|
||||||
(window as any).GlobalInput = new InputClass();
|
(window as any).GlobalCommandRunner = new CommandRunner();
|
||||||
}
|
}
|
||||||
GlobalModel = (window as any).GlobalModel;
|
GlobalModel = (window as any).GlobalModel;
|
||||||
GlobalInput = (window as any).GlobalInput;
|
GlobalCommandRunner = (window as any).GlobalCommandRunner;
|
||||||
|
|
||||||
export {Model, Session, Window, GlobalModel, GlobalInput, Cmd, Screen, ScreenWindow, riToRPtr};
|
export {Model, Session, Window, GlobalModel, GlobalCommandRunner, Cmd, Screen, ScreenWindow, riToRPtr};
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ contextBridge.exposeInMainWorld("api", {
|
|||||||
getId: () => ipcRenderer.sendSync("get-id"),
|
getId: () => ipcRenderer.sendSync("get-id"),
|
||||||
onTCmd: (callback) => ipcRenderer.on("t-cmd", callback),
|
onTCmd: (callback) => ipcRenderer.on("t-cmd", callback),
|
||||||
onICmd: (callback) => ipcRenderer.on("i-cmd", callback),
|
onICmd: (callback) => ipcRenderer.on("i-cmd", callback),
|
||||||
|
onHCmd: (callback) => ipcRenderer.on("h-cmd", callback),
|
||||||
onMetaArrowUp: (callback) => ipcRenderer.on("meta-arrowup", callback),
|
onMetaArrowUp: (callback) => ipcRenderer.on("meta-arrowup", callback),
|
||||||
onMetaArrowDown: (callback) => ipcRenderer.on("meta-arrowdown", callback),
|
onMetaArrowDown: (callback) => ipcRenderer.on("meta-arrowdown", callback),
|
||||||
onBracketCmd: (callback) => ipcRenderer.on("bracket-cmd", callback),
|
onBracketCmd: (callback) => ipcRenderer.on("bracket-cmd", callback),
|
||||||
|
@ -617,11 +617,12 @@ body .xterm .xterm-viewport {
|
|||||||
.cmd-history {
|
.cmd-history {
|
||||||
color: @term-white;
|
color: @term-white;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
overflow-y: auto;
|
overflow: auto;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
|
|
||||||
.history-title {
|
.history-title {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
left: 20px;
|
left: 20px;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
@ -630,6 +631,10 @@ body .xterm .xterm-viewport {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #729fcf;
|
color: #729fcf;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
|
|
||||||
|
.history-clickable-opt {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-items {
|
.history-items {
|
||||||
|
@ -129,6 +129,7 @@ type HistoryItem = {
|
|||||||
remove : boolean,
|
remove : boolean,
|
||||||
remote : RemotePtrType,
|
remote : RemotePtrType,
|
||||||
ismetacmd : boolean,
|
ismetacmd : boolean,
|
||||||
|
historynum : string,
|
||||||
};
|
};
|
||||||
|
|
||||||
type CmdRemoteStateType = {
|
type CmdRemoteStateType = {
|
||||||
|
Loading…
Reference in New Issue
Block a user