Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@
"command": "roo-cline.focusInput",
"title": "%command.focusInput.title%",
"category": "%extension.displayName%"
},
{
"command": "roo.acceptInput",
"title": "%command.acceptInput.title%",
"category": "%extension.displayName%"
}
],
"menus": {
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"command.terminal.explainCommand.title": "Explain This Command",
"command.terminal.fixCommandInCurrentTask.title": "Fix This Command (Current Task)",
"command.terminal.explainCommandInCurrentTask.title": "Explain This Command (Current Task)",
"command.acceptInput.title": "Roo: Accept Input/Suggestion",
"configuration.title": "Roo Code",
"commands.allowedCommands.description": "Commands that can be auto-executed when 'Always approve execute operations' is enabled",
"settings.vsCodeLmModelSelector.description": "Settings for VSCode Language Model API",
Expand Down
5 changes: 5 additions & 0 deletions src/activate/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
"roo-cline.focusInput": () => {
provider.postMessageToWebview({ type: "action", action: "focusInput" })
},
"roo.acceptInput": () => {
const visibleProvider = getVisibleProviderOrLog(outputChannel)
if (!visibleProvider) return
visibleProvider.postMessageToWebview({ type: "acceptInput" })
},
}
}

Expand Down
1 change: 1 addition & 0 deletions src/shared/ExtensionMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export interface ExtensionMessage {
| "maxReadFileLine"
| "fileSearchResults"
| "toggleApiConfigPin"
| "acceptInput"
text?: string
action?:
| "chatButtonClicked"
Expand Down
8 changes: 7 additions & 1 deletion webview-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import TranslationProvider from "./i18n/TranslationContext"
import { vscode } from "./utils/vscode"
import { telemetryClient } from "./utils/TelemetryClient"
import { ExtensionStateContextProvider, useExtensionState } from "./context/ExtensionStateContext"
import ChatView from "./components/chat/ChatView"
import ChatView, { ChatViewRef } from "./components/chat/ChatView"
import HistoryView from "./components/history/HistoryView"
import SettingsView, { SettingsViewRef } from "./components/settings/SettingsView"
import WelcomeView from "./components/welcome/WelcomeView"
Expand Down Expand Up @@ -44,6 +44,7 @@ const App = () => {
})

const settingsRef = useRef<SettingsViewRef>(null)
const chatViewRef = useRef<ChatViewRef>(null)

const switchTab = useCallback((newTab: Tab) => {
setCurrentSection(undefined)
Expand Down Expand Up @@ -75,6 +76,10 @@ const App = () => {
const { requestId, promptText } = message
setHumanRelayDialogState({ isOpen: true, requestId, promptText })
}

if (message.type === "acceptInput") {
chatViewRef.current?.acceptInput()
}
},
[switchTab],
)
Expand Down Expand Up @@ -114,6 +119,7 @@ const App = () => {
<SettingsView ref={settingsRef} onDone={() => setTab("chat")} targetSection={currentSection} />
)}
<ChatView
ref={chatViewRef}
isHidden={tab !== "chat"}
showAnnouncement={showAnnouncement}
hideAnnouncement={() => setShowAnnouncement(false)}
Expand Down
23 changes: 21 additions & 2 deletions webview-ui/src/components/chat/ChatView.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import debounce from "debounce"
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react"
import { useDeepCompareEffect, useEvent, useMount } from "react-use"
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
import styled from "styled-components"
Expand Down Expand Up @@ -40,11 +40,18 @@ interface ChatViewProps {
showHistoryView: () => void
}

export interface ChatViewRef {
acceptInput: () => void
}

export const MAX_IMAGES_PER_MESSAGE = 20 // Anthropic limits to 20 images

const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0

const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryView }: ChatViewProps) => {
const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewProps> = (
{ isHidden, showAnnouncement, hideAnnouncement, showHistoryView },
ref,
) => {
const { t } = useAppTranslation()
const modeShortcutText = `${isMac ? "⌘" : "Ctrl"} + . ${t("chat:forNextMode")}`
const {
Expand Down Expand Up @@ -1162,6 +1169,16 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
}
}, [handleKeyDown])

useImperativeHandle(ref, () => ({
acceptInput: () => {
if (enableButtons && primaryButtonText) {
handlePrimaryButtonClick(inputValue, selectedImages)
} else if (!textAreaDisabled && (inputValue.trim() || selectedImages.length > 0)) {
handleSendMessage(inputValue, selectedImages)
}
},
}))

return (
<div
style={{
Expand Down Expand Up @@ -1386,6 +1403,8 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
)
}

const ChatView = forwardRef(ChatViewComponent)

const ScrollToBottomButton = styled.div`
background-color: color-mix(in srgb, var(--vscode-toolbar-hoverBackground) 55%, transparent);
border-radius: 3px;
Expand Down