From 34837aabaeb900a686d7e2030382da1e17b90097 Mon Sep 17 00:00:00 2001 From: Red Adaya Date: Mon, 6 May 2024 20:32:43 +0800 Subject: [PATCH] save work --- src/app/sidebar/aichat.tsx | 83 ++++++++++++------- src/app/workspace/cmdinput/aichat.tsx | 4 +- src/app/workspace/cmdinput/cmdinput.less | 6 +- src/app/workspace/cmdinput/cmdinput.tsx | 8 +- src/app/workspace/cmdinput/textareainput.tsx | 2 + src/models/aichat.ts | 86 +++++++------------- src/models/input.ts | 16 ++-- src/models/model.ts | 1 - src/plugins/code/code.tsx | 6 +- 9 files changed, 110 insertions(+), 102 deletions(-) diff --git a/src/app/sidebar/aichat.tsx b/src/app/sidebar/aichat.tsx index 365ec0106..b632c96e8 100644 --- a/src/app/sidebar/aichat.tsx +++ b/src/app/sidebar/aichat.tsx @@ -11,6 +11,7 @@ import { Markdown } from "@/elements"; import type { OverlayScrollbars } from "overlayscrollbars"; import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react"; import tinycolor from "tinycolor2"; +import * as appconst from "@/app/appconst"; import "./aichat.less"; @@ -54,10 +55,9 @@ class AIChatKeybindings extends React.Component<{ AIChatObject: AIChat }, {}> { } @mobxReact.observer -class ChatContent extends React.Component<{}, {}> { +class ChatContent extends React.Component<{ chatWindowRef }, {}> { chatListKeyCount: number = 0; containerRef: React.RefObject = React.createRef(); - chatWindowRef: React.RefObject = React.createRef(); osInstance: OverlayScrollbars = null; componentDidUpdate() { @@ -66,7 +66,7 @@ class ChatContent extends React.Component<{}, {}> { const { viewport } = this.osInstance.elements(); viewport.scrollTo({ behavior: "auto", - top: this.chatWindowRef.current.scrollHeight, + top: this.props.chatWindowRef.current.scrollHeight, }); } } @@ -84,7 +84,7 @@ class ChatContent extends React.Component<{}, {}> { const { viewport } = instance.elements(); viewport.scrollTo({ behavior: "auto", - top: this.chatWindowRef.current.scrollHeight, + top: this.props.chatWindowRef.current.scrollHeight, }); } @@ -116,7 +116,7 @@ class ChatContent extends React.Component<{}, {}> { @@ -148,7 +148,7 @@ class ChatContent extends React.Component<{}, {}> { options={{ scrollbars: { autoHide: "leave" } }} events={{ initialized: this.onScrollbarInitialized }} > -
+
{this.renderChatMessage(chitem)} @@ -162,13 +162,39 @@ class ChatContent extends React.Component<{}, {}> { @mobxReact.observer class AIChat extends React.Component<{}, {}> { textAreaRef: React.RefObject = React.createRef(); + chatWindowRef: React.RefObject = React.createRef(); termFontSize: number = 14; + // Adjust the height of the textarea to fit the text + @boundMethod + onTextAreaChange(e: any) { + if (this.textAreaRef.current == null) { + return; + } + // Calculate the bounding height of the text area + const textAreaMaxLines = 4; + const textAreaLineHeight = this.termFontSize * 1.5; + const textAreaMinHeight = textAreaLineHeight; + const textAreaMaxHeight = textAreaLineHeight * textAreaMaxLines; + + // Get the height of the wrapped text area content. Courtesy of https://stackoverflow.com/questions/995168/textarea-to-resize-based-on-content-length + this.textAreaRef.current.style.height = "1px"; + const scrollHeight: number = this.textAreaRef.current.scrollHeight; + + // Set the new height of the text area, bounded by the min and max height. + const newHeight = Math.min(Math.max(scrollHeight, textAreaMinHeight), textAreaMaxHeight); + this.textAreaRef.current.style.height = newHeight + "px"; + GlobalModel.inputModel.codeSelectDeselectAll(); + } + componentDidMount() { const inputModel = GlobalModel.inputModel; + + inputModel.openAIAssistantChat(); + if (this.textAreaRef.current != null) { this.textAreaRef.current.focus(); - // inputModel.setCmdInfoChatRefs(this.textAreaRef, this.chatWindowScrollRef); + inputModel.setCmdInfoChatRefs(this.textAreaRef, this.chatWindowRef); } this.requestChatUpdate(); this.onTextAreaChange(null); @@ -183,7 +209,6 @@ class AIChat extends React.Component<{}, {}> { submitChatMessage(messageStr: string) { const curLine = GlobalModel.inputModel.curLine; - console.log("enter key pressed", messageStr, "curLine: ", curLine); const prtn = GlobalModel.submitChatInfoCommand(messageStr, curLine, false); prtn.then((rtn) => { if (!rtn.success) { @@ -198,9 +223,13 @@ class AIChat extends React.Component<{}, {}> { return { numLines, linePos }; } - @mobx.action.bound + @mobx.action + @boundMethod onTextAreaFocused(e: any) { + console.log("focused"); GlobalModel.inputModel.setAuxViewFocus(true); + GlobalModel.inputModel.setActiveAuxView(appconst.InputAuxView_AIChat); + this.onTextAreaChange(e); } @@ -211,22 +240,8 @@ class AIChat extends React.Component<{}, {}> { })(); } - // Adjust the height of the textarea to fit the text @boundMethod - onTextAreaChange(e: any) { - // Calculate the bounding height of the text area - const textAreaMaxLines = 4; - const textAreaLineHeight = this.termFontSize * 1.5; - const textAreaMinHeight = textAreaLineHeight; - const textAreaMaxHeight = textAreaLineHeight * textAreaMaxLines; - - // Get the height of the wrapped text area content. Courtesy of https://stackoverflow.com/questions/995168/textarea-to-resize-based-on-content-length - this.textAreaRef.current.style.height = "1px"; - const scrollHeight: number = this.textAreaRef.current.scrollHeight; - - // Set the new height of the text area, bounded by the min and max height. - const newHeight = Math.min(Math.max(scrollHeight, textAreaMinHeight), textAreaMaxHeight); - this.textAreaRef.current.style.height = newHeight + "px"; + onTextAreaInput(e: any) { GlobalModel.inputModel.codeSelectDeselectAll(); } @@ -272,6 +287,7 @@ class AIChat extends React.Component<{}, {}> { } onArrowDownPressed(): boolean { + console.log("got here"); const currentRef = this.textAreaRef.current; const inputModel = GlobalModel.inputModel; if (currentRef == null) { @@ -294,15 +310,22 @@ class AIChat extends React.Component<{}, {}> { } render() { - const chatMessageItems = GlobalModel.aichatModel.aiCmdInfoChatItems.slice(); + const chatMessageItems = GlobalModel.inputModel.AICmdInfoChatItems.slice(); + const renderAIChatKeybindings = GlobalModel.inputModel.shouldRenderAuxViewKeybindings( + appconst.InputAuxView_AIChat, + "sidebar" + ); + console.log("renderAIChatKeybindings=====", renderAIChatKeybindings); return (
- + + +
Wave AI
0}> - +
diff --git a/src/app/workspace/cmdinput/aichat.tsx b/src/app/workspace/cmdinput/aichat.tsx index 5c67d5799..e9769df18 100644 --- a/src/app/workspace/cmdinput/aichat.tsx +++ b/src/app/workspace/cmdinput/aichat.tsx @@ -245,6 +245,7 @@ class AIChat extends React.Component<{}, {}> { const chatMessageItems = GlobalModel.inputModel.AICmdInfoChatItems.slice(); const chitem: OpenAICmdInfoChatMessageType = null; const renderKeybindings = GlobalModel.inputModel.shouldRenderAuxViewKeybindings(appconst.InputAuxView_AIChat); + console.log("renderKeybindings", renderKeybindings); return ( { ref={this.textAreaRef} autoComplete="off" autoCorrect="off" - id="chat-cmd-input" + className="chat-cmd-input chat-textarea" onFocus={this.onTextAreaFocused} onBlur={this.onTextAreaBlur} onChange={this.onTextAreaChange} onInput={this.onTextAreaInput} onKeyDown={this.onKeyDown} style={{ fontSize: this.termFontSize }} - className="chat-textarea" placeholder="Send a Message..." >
diff --git a/src/app/workspace/cmdinput/cmdinput.less b/src/app/workspace/cmdinput/cmdinput.less index 865ef728c..aa3c87048 100644 --- a/src/app/workspace/cmdinput/cmdinput.less +++ b/src/app/workspace/cmdinput/cmdinput.less @@ -12,7 +12,7 @@ // Apply a border between the base cmdinput and any views shown above it // TODO: use a generic selector for this - &.has-aichat, + // &.has-aichat, &.has-history, &.has-info, &.has-suggestions { @@ -21,8 +21,8 @@ } } - &.has-history, - &.has-aichat { + // &.has-aichat, + &.has-history { height: max(300px, 70%); } diff --git a/src/app/workspace/cmdinput/cmdinput.tsx b/src/app/workspace/cmdinput/cmdinput.tsx index c6b108bf7..cb13cbbd8 100644 --- a/src/app/workspace/cmdinput/cmdinput.tsx +++ b/src/app/workspace/cmdinput/cmdinput.tsx @@ -86,9 +86,9 @@ class CmdInput extends React.Component<{}, {}> { e.stopPropagation(); const inputModel = GlobalModel.inputModel; if (inputModel.getActiveAuxView() === appconst.InputAuxView_AIChat) { - inputModel.closeAuxView(); + // inputModel.closeAuxView(); } else { - inputModel.openAIAssistantChat(); + // inputModel.openAIAssistantChat(); } } @@ -191,10 +191,10 @@ class CmdInput extends React.Component<{}, {}> {
- + {/*
-
+
*/} diff --git a/src/app/workspace/cmdinput/textareainput.tsx b/src/app/workspace/cmdinput/textareainput.tsx index a12628dd1..ced0f7cec 100644 --- a/src/app/workspace/cmdinput/textareainput.tsx +++ b/src/app/workspace/cmdinput/textareainput.tsx @@ -620,6 +620,8 @@ class TextAreaInput extends React.Component<{ screen: Screen; onHeightChange: () const renderCmdInputKeybindings = inputModel.shouldRenderAuxViewKeybindings(null); const renderHistoryKeybindings = inputModel.shouldRenderAuxViewKeybindings(appconst.InputAuxView_History); + console.log("renderCmdInputKeybindings", renderCmdInputKeybindings); + console.log("renderHistoryKeybindings", renderHistoryKeybindings); return (
; - aiChatWindowRef: React.RefObject; + chatTextAreaRef: React.RefObject; + chatWindowRef: React.RefObject; codeSelectBlockRefArray: Array>; codeSelectSelectedIndex: OV = mobx.observable.box(-1); codeSelectUuid: string; - aiCmdInfoChatItems: mobx.IObservableArray = mobx.observable.array([], { name: "aicmdinfo-chat", }); + isFocused: OV = mobx.observable.box(false, { + name: "isFocused", + }); readonly codeSelectTop: number = -2; readonly codeSelectBottom: number = -1; - // focus - physicalInputFocused: OV = mobx.observable.box(false); - constructor(globalModel: Model) { this.globalModel = globalModel; mobx.makeObservable(this); @@ -33,39 +32,20 @@ class AIChatModel { this.codeSelectUuid = ""; } - // Focuses the main input or the auxiliary view, depending on the active auxiliary view @mobx.action - giveFocus(): void { - // focus aichat sidebar input + focus(): void { + if (this.chatTextAreaRef?.current != null) { + this.chatTextAreaRef.current.focus(); + } + this.isFocused.set(true); } @mobx.action - setPhysicalInputFocused(isFocused: boolean): void { - this.physicalInputFocused.set(isFocused); - if (isFocused) { - const screen = this.globalModel.getActiveScreen(); - if (screen != null) { - if (screen.focusType.get() != "input") { - GlobalCommandRunner.screenSetFocus("input"); - } - } + unFocus() { + if (this.chatTextAreaRef?.current != null) { + this.chatTextAreaRef.current.blur(); } - } - - hasFocus(): boolean { - const mainInputElem = document.getElementById("main-cmd-input"); - if (document.activeElement == mainInputElem) { - return true; - } - const historyInputElem = document.querySelector(".cmd-input input.history-input"); - if (document.activeElement == historyInputElem) { - return true; - } - let aiChatInputElem = document.querySelector(".cmd-input chat-cmd-input"); - if (document.activeElement == aiChatInputElem) { - return true; - } - return false; + this.isFocused.set(false); } @mobx.action @@ -74,27 +54,23 @@ class AIChatModel { this.codeSelectBlockRefArray = []; } - closeAuxView(): void { + close(): void { // close and give focus back to main input } - shouldRenderAuxViewKeybindings(view: InputAuxViewType): boolean { + shouldRenderKeybindings(view: InputAuxViewType): boolean { // when aichat sidebar is mounted, it will render the keybindings return true; } - setCmdInfoChatRefs( - textAreaRef: React.RefObject, - chatWindowRef: React.RefObject - ) { - this.aiChatTextAreaRef = textAreaRef; - this.aiChatWindowRef = chatWindowRef; + setRefs(textAreaRef: React.RefObject, chatWindowRef: React.RefObject) { + this.chatTextAreaRef = textAreaRef; + this.chatWindowRef = chatWindowRef; } - setAIChatFocus() { - if (this.aiChatTextAreaRef?.current != null) { - this.aiChatTextAreaRef.current.focus(); - } + unsetRefs() { + this.chatTextAreaRef = null; + this.chatWindowRef = null; } addCodeBlockToCodeSelect(blockRef: React.RefObject, uuid: string): number { @@ -113,14 +89,14 @@ class AIChatModel { if (blockIndex >= 0 && blockIndex < this.codeSelectBlockRefArray.length) { this.codeSelectSelectedIndex.set(blockIndex); const currentRef = this.codeSelectBlockRefArray[blockIndex].current; - if (currentRef != null && this.aiChatWindowRef?.current != null) { - const chatWindowTop = this.aiChatWindowRef.current.scrollTop; - const chatWindowBottom = chatWindowTop + this.aiChatWindowRef.current.clientHeight - 100; + if (currentRef != null && this.chatWindowRef?.current != null) { + const chatWindowTop = this.chatWindowRef.current.scrollTop; + const chatWindowBottom = chatWindowTop + this.chatWindowRef.current.clientHeight - 100; const elemTop = currentRef.offsetTop; let elemBottom = elemTop - currentRef.offsetHeight; const elementIsInView = elemBottom < chatWindowBottom && elemTop > chatWindowTop; if (!elementIsInView) { - this.aiChatWindowRef.current.scrollTop = elemBottom - this.aiChatWindowRef.current.clientHeight / 3; + this.chatWindowRef.current.scrollTop = elemBottom - this.chatWindowRef.current.clientHeight / 3; } } } @@ -139,8 +115,8 @@ class AIChatModel { const incBlockIndex = this.codeSelectSelectedIndex.get() + 1; if (this.codeSelectSelectedIndex.get() == this.codeSelectBlockRefArray.length - 1) { this.codeSelectDeselectAll(); - if (this.aiChatWindowRef?.current != null) { - this.aiChatWindowRef.current.scrollTop = this.aiChatWindowRef.current.scrollHeight; + if (this.chatWindowRef?.current != null) { + this.chatWindowRef.current.scrollTop = this.chatWindowRef.current.scrollHeight; } } if (incBlockIndex >= 0 && incBlockIndex < this.codeSelectBlockRefArray.length) { @@ -162,8 +138,8 @@ class AIChatModel { const decBlockIndex = this.codeSelectSelectedIndex.get() - 1; if (decBlockIndex < 0) { this.codeSelectDeselectAll(this.codeSelectTop); - if (this.aiChatWindowRef?.current != null) { - this.aiChatWindowRef.current.scrollTop = 0; + if (this.chatWindowRef?.current != null) { + this.chatWindowRef.current.scrollTop = 0; } } if (decBlockIndex >= 0 && decBlockIndex < this.codeSelectBlockRefArray.length) { diff --git a/src/models/input.ts b/src/models/input.ts index e1f187005..7b2bc8d94 100644 --- a/src/models/input.ts +++ b/src/models/input.ts @@ -139,6 +139,7 @@ class InputModel { giveFocus(): void { // Override active view to the main input if aux view does not have focus const activeAuxView = this.getAuxViewFocus() ? this.getActiveAuxView() : null; + console.log("activeAuxView", activeAuxView); switch (activeAuxView) { case appconst.InputAuxView_History: { const elem: HTMLElement = document.querySelector(".cmd-input input.history-input"); @@ -190,7 +191,7 @@ class InputModel { if (document.activeElement == historyInputElem) { return true; } - let aiChatInputElem = document.querySelector(".cmd-input chat-cmd-input"); + let aiChatInputElem = document.querySelector(".cmd-input .chat-cmd-input"); if (document.activeElement == aiChatInputElem) { return true; } @@ -459,17 +460,22 @@ class InputModel { this.giveFocus(); } - shouldRenderAuxViewKeybindings(view: InputAuxViewType): boolean { + shouldRenderAuxViewKeybindings(view: InputAuxViewType, test?: string): boolean { + console.log("view", view, this.getAuxViewFocus(), this.getActiveAuxView()); if (GlobalModel.activeMainView.get() != "session") { + console.log("1"); return false; } if (GlobalModel.getActiveScreen()?.getFocusType() != "input") { + console.log("2"); return false; } // (view == null) means standard cmdinput keybindings if (view == null) { + console.log("3"); return !this.getAuxViewFocus(); } else { + console.log("4"); return this.getAuxViewFocus() && view == this.getActiveAuxView(); } } @@ -659,6 +665,7 @@ class InputModel { @mobx.action openAIAssistantChat(): void { + console.log("openAIAssistantChat"); this.setActiveAuxView(appconst.InputAuxView_AIChat); this.setAuxViewFocus(true); this.globalModel.sendActivity("aichat-open"); @@ -759,23 +766,18 @@ class InputModel { @mobx.computed get curLine(): string { - console.log("triggered get curLine"); const hidx = this.historyIndex.get(); if (hidx < this.modHistory.length && this.modHistory[hidx] != null) { - console.log("this.modHistory[hidx]", this.modHistory[hidx]); return this.modHistory[hidx]; } const hitems = this.filteredHistoryItems; if (hidx == 0 || hitems == null || hidx > hitems.length) { - console.log("returning empty string 1"); return ""; } const hitem = hitems[hidx - 1]; if (hitem == null) { - console.log("returning empty string 2"); return ""; } - console.log("returning hitem.cmdstr", hitem.cmdstr); return hitem.cmdstr; } diff --git a/src/models/model.ts b/src/models/model.ts index 0e95c6445..bad25d6eb 100644 --- a/src/models/model.ts +++ b/src/models/model.ts @@ -1345,7 +1345,6 @@ class Model { interactive: boolean, runUpdate: boolean = true ): Promise { - console.log("cmdPk", cmdPk); if (this.debugCmds > 0) { console.log("[cmd]", cmdPacketString(cmdPk)); if (this.debugCmds > 1) { diff --git a/src/plugins/code/code.tsx b/src/plugins/code/code.tsx index 21742e227..a35cda954 100644 --- a/src/plugins/code/code.tsx +++ b/src/plugins/code/code.tsx @@ -461,7 +461,11 @@ class SourceCodeRenderer extends React.Component< ref={this.markdownRef} onScroll={() => this.handleDivScroll()} > - +
); }