Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support at-mentions context on edits #3091

Merged
merged 8 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
64 changes: 49 additions & 15 deletions lib/ui/src/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,11 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
: messageAtIndex?.text
if (inputText) {
setFormInput(inputText)
if (messageAtIndex.contextFiles) {
useOldChatMessageContext(messageAtIndex.contextFiles)
}
}
// move focus back to chatbox
setInputFocus(true)
},
[messageBeingEdited, setFormInput, setMessageBeingEdited, transcript]
Expand All @@ -315,19 +319,30 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
* Calls setEditMessageState() to reset any in-progress edit state.
* Sends a 'reset' command to postMessage to reset the chat on the server.
*/
const onChatResetClick = useCallback(() => {
setEditMessageState()
postMessage?.({ command: 'reset' })
}, [postMessage, setEditMessageState])
const onChatResetClick = useCallback(
(eventType: 'keyDown' | 'click' = 'click') => {
setEditMessageState()
postMessage?.({ command: 'reset' })
postMessage?.({
command: 'event',
eventName: 'CodyVSCodeExtension:chatActions:reset:executed',
properties: { source: 'chat', eventType },
})
},
[postMessage, setEditMessageState]
)

/**
* Resets the context selection and query state.
*/
const resetContextSelection = useCallback(() => {
setSelectedChatContext(0)
setCurrentChatContextQuery(undefined)
setContextSelection(null)
}, [setContextSelection])
const resetContextSelection = useCallback(
(eventType?: 'keyDown' | 'click') => {
setSelectedChatContext(0)
setCurrentChatContextQuery(undefined)
setContextSelection(null)
},
[setContextSelection]
)

/**
* Gets the display text for a context file to be completed into the chat when a user
Expand All @@ -345,6 +360,15 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
return `@${displayPath(contextFile.uri)}${range}${symbolName}`
}

// Add old context files from the transcript to the map
const useOldChatMessageContext = (oldContextFiles: ContextFile[]) => {
const contextFilesMap = new Map<string, ContextFile>()
for (const file of oldContextFiles) {
contextFilesMap.set(getContextFileDisplayText(file), file)
}
setChatContextFiles(contextFilesMap)
}

/**
* Callback function called when a chat context file is selected from the context selector.
* This updates the chat input with the selected file context.
Expand Down Expand Up @@ -558,14 +582,20 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
if (event.key === '/') {
event.preventDefault()
event.stopPropagation()
onChatResetClick()
onChatResetClick('keyDown')
return
}
// Ctrl/Cmd + K - When not already editing, edits the last human message
if (messageBeingEdited === undefined && event.key === 'k') {
event.preventDefault()
event.stopPropagation()
setEditMessageState(lastHumanMessageIndex)

postMessage?.({
command: 'event',
eventName: 'CodyVSCodeExtension:chatActions:editLast:executed',
properties: { source: 'chat', eventType: 'keyDown' },
})
return
}
}
Expand Down Expand Up @@ -693,12 +723,14 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
} else {
setFormInput(newHistoryInput.inputText)
// chatContextFiles uses a map but history only stores a simple array.
const contextFilesMap = new Map<string, ContextFile>()
for (const file of newHistoryInput.inputContextFiles) {
contextFilesMap.set(getContextFileDisplayText(file), file)
}
setChatContextFiles(contextFilesMap)
useOldChatMessageContext(newHistoryInput.inputContextFiles)
}

postMessage?.({
command: 'event',
eventName: 'CodyVSCodeExtension:chatInputHistory:executed',
properties: { source: 'chat' },
})
}
}
},
Expand All @@ -718,6 +750,8 @@ export const Chat: React.FunctionComponent<ChatProps> = ({
onChatContextSelected,
enableNewChatMode,
resetContextSelection,
useOldChatMessageContext,
postMessage,
]
)

Expand Down
3 changes: 2 additions & 1 deletion vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ This is a log of all notable changes to Cody for VS Code. [Unreleased] changes a

### Added

- Chat: Added support for `@-mentioned files` in mid sentences. [pull/3043](https://github.com/sourcegraph/cody/pull/3043)
- Chat: Support `@-mentioned` in mid sentences. [pull/3043](https://github.com/sourcegraph/cody/pull/3043)
- Chat: Support `@-mentioned` in editing mode. [pull/3091](https://github.com/sourcegraph/cody/pull/3091)

### Fixed

Expand Down
42 changes: 17 additions & 25 deletions vscode/test/e2e/chat-edits.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from '@playwright/test'

import { sidebarSignin } from './common'
import { test } from './helpers'
import { test, withPlatformSlashes } from './helpers'

const isPlatform = (platform: string) => process.platform === platform
const isMac = isPlatform('darwin')
Expand Down Expand Up @@ -104,34 +104,26 @@ test('editing follow-up messages in chat view', async ({ page, sidebar }) => {
await expect(cancelEditButton).not.toBeVisible()
await expect(chatInput).toBeEmpty()
await expect(chatFrame.getByText('Explain @Main.java')).toBeVisible()
await chatInput.press('Escape')

// Add a new at-file to an old messages
await chatInput.press(`${osKey}+k`)
await chatInput.type('and @vgo', { delay: 50 })
await chatInput.press('Tab')
await expect(chatInput).toHaveValue(
withPlatformSlashes('Explain @Main.java and @lib/batches/env/var.go ')
)
await chatInput.press('Enter')
// both main.java and var.go should be used
await expect(chatFrame.getByText(/Context: 2 files/)).toBeVisible()
await chatFrame.getByText(/Context: 2 files/).click()
await expect(chatFrame.getByRole('button', { name: 'Main.java' })).toBeVisible()
await expect(
chatFrame.getByRole('button', { name: withPlatformSlashes('lib/batches/env/var.go') })
).toBeVisible()

// Meta+/ also creates a new chat session
await chatInput.press(`${osKey}+/`)
await expect(chatFrame.getByText('The End')).not.toBeVisible()

// TODO (bee) - update after switching to the new keybinding for toggling "New Chat Mode"
await expect(startNewChatButton).not.toBeVisible()
// // "MetaKey(MacOS)/Control" + "Shift" to toggle "New Chat Mode" on and off
// // When it's on, the submit button will be replaced with "Start New Chat" button
// await expect(submitMessageButton).toBeVisible()
// await chatInput.press(`${osKey}+Shift`)
// await expect(submitMessageButton).not.toBeVisible()
// await expect(startNewChatButton).toBeVisible()
// await chatInput.press(`${osKey}+Shift`)
// await expect(startNewChatButton).not.toBeVisible()
// await chatInput.press(`${osKey}+Shift`)
// await expect(startNewChatButton).toBeVisible()

// // With "New Chat Mode" enabled, submit a new message to start a new chat
// // The new message should be "The End"
// // And the last message should not be visible anymore
// await chatInput.fill('The End')
// await chatInput.press('Enter')
// await expect(chatFrame.getByText('The End')).toBeVisible()
// await expect(chatFrame.getByText('Explain @Main.java')).not.toBeVisible()

// // Meta+/ also creates a new chat session
// await chatInput.press(`${osKey}+/`)
// await expect(chatFrame.getByText('The End')).not.toBeVisible()
})
11 changes: 9 additions & 2 deletions vscode/webviews/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { EnhancedContextSettings } from './Components/EnhancedContextSettings'
import { FileLink } from './Components/FileLink'
import { SymbolLink } from './SymbolLink'
import { UserContextSelectorComponent } from './UserContextSelector'
import type { VSCodeWrapper } from './utils/VSCodeApi'
import { getVSCodeAPI, type VSCodeWrapper } from './utils/VSCodeApi'

import styles from './Chat.module.css'

Expand Down Expand Up @@ -427,7 +427,14 @@ const EditButton: React.FunctionComponent<EditButtonProps> = ({
title={disabled ? 'Cannot Edit Command' : 'Edit Your Message'}
type="button"
disabled={disabled}
onClick={() => setMessageBeingEdited(messageBeingEdited)}
onClick={() => {
setMessageBeingEdited(messageBeingEdited)
getVSCodeAPI().postMessage({
command: 'event',
eventName: 'CodyVSCodeExtension:chatEditButton:clicked',
properties: { source: 'chat' },
})
}}
>
<i className="codicon codicon-edit" />
</VSCodeButton>
Expand Down
Loading