From c3626a6547368d4989edbb2b9bf192b4ce983e5b Mon Sep 17 00:00:00 2001 From: sawka Date: Mon, 20 Jun 2022 16:06:37 -0700 Subject: [PATCH] add session history --- src/main.tsx | 68 +++++++++-- src/session.ts | 38 +++++- src/sh2.less | 323 ++++++++++++++++++++++++------------------------- 3 files changed, 254 insertions(+), 175 deletions(-) diff --git a/src/main.tsx b/src/main.tsx index b8fc28e26..680980e80 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -174,39 +174,91 @@ class Line extends React.Component<{line : LineType, session : Session}, {}> { @mobxReact.observer class CmdInput extends React.Component<{session : Session, windowid : string}, {}> { - curLine : mobx.IObservableValue = mobx.observable("", {name: "command-line"}); + historyIndex : mobx.IObservableValue = mobx.observable.box(0, {name: "history-index"}); + modHistory : mobx.IObservableArray = mobx.observable.array([""], {name: "mod-history"}); @mobx.action @boundMethod onKeyDown(e : any) { mobx.action(() => { + let {session} = this.props; let ctrlMod = e.getModifierState("Control") || e.getModifierState("Meta") || e.getModifierState("Shift"); if (e.code == "Enter" && !ctrlMod) { e.preventDefault(); setTimeout(() => this.doSubmitCmd(), 0); return; } + if (e.code == "ArrowUp") { + e.preventDefault(); + let hidx = this.historyIndex.get(); + hidx += 1; + if (hidx > session.getNumHistoryItems()) { + hidx = session.getNumHistoryItems(); + } + this.historyIndex.set(hidx); + return; + } + if (e.code == "ArrowDown") { + e.preventDefault(); + let hidx = this.historyIndex.get(); + hidx -= 1; + if (hidx < 0) { + hidx = 0; + } + this.historyIndex.set(hidx); + return; + } // console.log(e.code, e.keyCode, e.key, event.which, ctrlMod, e); })(); } + @boundMethod + clearCurLine() { + mobx.action(() => { + this.historyIndex.set(0); + this.modHistory.clear(); + this.modHistory[0] = ""; + })(); + } + + @boundMethod + getCurLine() : string { + let {session} = this.props; + let hidx = this.historyIndex.get(); + if (hidx < this.modHistory.length && this.modHistory[hidx] != null) { + return this.modHistory[hidx]; + } + let hitem = session.getHistoryItem(-hidx); + if (hitem == null) { + return ""; + } + return hitem.cmdtext; + } + + @boundMethod + setCurLine(val : string) { + let hidx = this.historyIndex.get(); + this.modHistory[hidx] = val; + } + @boundMethod onChange(e : any) { mobx.action(() => { - this.curLine.set(e.target.value); + this.setCurLine(e.target.value); })(); } @boundMethod doSubmitCmd() { let {session, windowid} = this.props; - let commandStr = this.curLine.get(); - mobx.action(() => { - this.curLine.set(""); - })(); + let commandStr = this.getCurLine(); + let hitem = {cmdtext: commandStr}; + session.addToHistory(hitem); + this.clearCurLine(); session.submitCommand(windowid, commandStr); } render() { + let curLine = this.getCurLine(); return (
@@ -219,7 +271,7 @@ class CmdInput extends React.Component<{session : Session, windowid : string}, {
mike@local
- +
@@ -338,7 +390,7 @@ class MainSideBar extends React.Component<{}, {}> {
  • - + Michelle T
    2
  • diff --git a/src/session.ts b/src/session.ts index 86d995916..45e5cfdfe 100644 --- a/src/session.ts +++ b/src/session.ts @@ -38,10 +38,14 @@ function getLineId(line : LineType) : string { } type WindowType = { - sessionid : string; - windowid : string; - name : string; - lines : LineType[]; + sessionid : string, + windowid : string, + name : string, + lines : LineType[], +}; + +type HistoryItem = { + cmdtext : string, }; class Session { @@ -51,6 +55,7 @@ class Session { activeWindowId : string; termMap : Record = {}; termMapById : Record = {}; + history : HistoryItem[] = []; constructor() { } @@ -69,6 +74,31 @@ class Session { }); } + addToHistory(hitem : HistoryItem) { + this.history.push(hitem); + } + + getNumHistoryItems() : number { + return this.history.length; + } + + getHistoryItem(index : number) : HistoryItem { + if (index == 0) { + return null; + } + if (index > 0) { + if (index > this.history.length-1) { + return null; + } + return this.history[index]; + } + let absIndex = Math.abs(index); + if (absIndex > this.history.length) { + return null; + } + return this.history[this.history.length-absIndex]; + } + getTermWrapByLine(line : LineType) : TermWrap { let termKey = makeTermKey(line.sessionid, line.cmdid, line.windowid, line.lineid); let termWrap = this.termMap[termKey]; diff --git a/src/sh2.less b/src/sh2.less index df8265861..3fb6c6aba 100644 --- a/src/sh2.less +++ b/src/sh2.less @@ -2,30 +2,6 @@ height: 100vh; display: flex; flex-direction: column; - - .title.scripthaus-logo-small { - padding-left: 10px; - padding-top: 8px; - padding-bottom: 8px; - margin-bottom: 0; - font-family: 'JetBrains Mono', monospace; - font-weight: 400; - background-color: black; - color: rgb(0, 177, 10); - position: relative; - font-size: 1.5rem; - border-bottom: 2px solid #ddd; - - .title-cursor { - position: absolute; - left: 157px; - bottom: 12px; - color: rgb(0, 177, 10); - font-family: 'JetBrains Mono', monospace; - font-weight: 400; - font-size: 1rem; - } - } .main-content { display: flex; @@ -33,145 +9,6 @@ background-color: black; flex-grow: 1; - .main-sidebar { - border-right: 1px solid #aaa; - padding: 0 5px 5px 5px; - width: 200px; - overflow-x: auto; - display: flex; - flex-direction: column; - color: #ddd; - position: relative; - - .menu { - padding-top: 10px; - display: flex; - flex-direction: column; - height: 100%; - - .spacer { - flex-grow: 1; - } - - .bottom-spacer { - height: 10px; - } - } - - .menu-label { - color: #bbb; - } - - p.menu-label { - margin-bottom: 0px; - } - - .menu-list li.new-session { - a.new-session { - color: #666; - font-size: 13px; - } - - .fa { - font-size: 10px; - } - } - - .menu-list li a { - color: #bbb; - white-space: nowrap; - padding: 5px 5px 5px 12px; - vertical-align: middle; - position: relative; - - - - .user-status { - position: absolute !important; - top: 24px !important; - left: 32px !important; - } - - .avatar { - width: 24px; - height: 24px; - margin-right: 5px; - vertical-align: middle; - } - - &.is-active { - color: #ddd; - font-weight: bold; - } - - .sub-label { - font-size: 12px; - font-style: italic; - } - - &.activity { - font-weight: bold; - color: #ddd; - - .tag { - margin-left: 4px; - padding: 0 5px 0 5px; - position: relative; - top: -1px; - } - } - - &.is-active:hover { - background-color: #3273dc; - } - - &:hover { - background-color: #444; - color: #ddd; - } - - .status { - font-size: 8px; - margin-right: 5px; - position: relative; - top: -3px; - color: #4e9a06; - - &.offline { - color: #cc0000; - } - } - } - - &.collapsed { - width: 50px; - - .collapse-container { - right: 12px; - } - - .menu { - display: none; - } - } - - .collapse-container { - position: absolute; - right: 3px; - top: -4px; - - .arrow-container { - color: #777; - padding: 5px; - cursor: pointer; - - &:hover { - color: #ddd; - } - } - } - } - .session-view { flex-grow: 1; @@ -181,7 +18,167 @@ } } +.title.scripthaus-logo-small { + padding-left: 10px; + padding-top: 8px; + padding-bottom: 8px; + margin-bottom: 0; + font-family: 'JetBrains Mono', monospace; + font-weight: 400; + background-color: darken(rgb(0, 177, 10), 30%); + color: rgb(0, 177, 10); + position: relative; + font-size: 1.5rem; + border-bottom: 2px solid #ddd; + + .title-cursor { + position: absolute; + left: 157px; + bottom: 12px; + color: rgb(0, 177, 10); + font-family: 'JetBrains Mono', monospace; + font-weight: 400; + font-size: 1rem; + } +} + .main-sidebar { + border-right: 1px solid #aaa; + padding: 0 5px 5px 5px; + width: 200px; + overflow-x: auto; + display: flex; + flex-direction: column; + color: #ddd; + position: relative; + background-color: darken(rgb(0, 177, 10), 30%); + + .menu { + padding-top: 10px; + display: flex; + flex-direction: column; + height: 100%; + + .spacer { + flex-grow: 1; + } + + .bottom-spacer { + height: 10px; + } + } + + .menu-label { + color: #bbb; + } + + p.menu-label { + margin-bottom: 0px; + } + + .menu-list li.new-session { + a.new-session { + color: #666; + font-size: 13px; + } + + .fa { + font-size: 10px; + } + } + + .menu-list li a { + color: #bbb; + white-space: nowrap; + padding: 3px 5px 3px 12px; + vertical-align: middle; + position: relative; + font-size: 13px; + + .user-status { + position: absolute !important; + top: 24px !important; + left: 32px !important; + } + + .avatar { + width: 24px; + height: 24px; + margin-right: 5px; + vertical-align: middle; + } + + &.is-active { + color: #ddd; + font-weight: bold; + } + + .sub-label { + font-size: 12px; + font-style: italic; + } + + &.activity { + font-weight: bold; + color: #ddd; + + .tag { + margin-left: 4px; + padding: 0 5px 0 5px; + position: relative; + top: -1px; + } + } + + &.is-active:hover { + background-color: #3273dc; + } + + &:hover { + background-color: #444; + color: #ddd; + } + + .status { + font-size: 8px; + margin-right: 5px; + position: relative; + top: -3px; + color: #4e9a06; + + &.offline { + color: #cc0000; + } + } + } + + &.collapsed { + width: 50px; + + .collapse-container { + right: 12px; + } + + .menu { + display: none; + } + } + + .collapse-container { + position: absolute; + right: 3px; + top: -4px; + + .arrow-container { + color: #777; + padding: 5px; + cursor: pointer; + + &:hover { + color: #ddd; + } + } + } } .line {