Skip to content

Commit

Permalink
feat(autoedits): make it reactive to config changes (#6537)
Browse files Browse the repository at this point in the history
## Context
Currently `auto-edits` is not reactive to config changes and hence
requires vscode reloading. If the user doesn't reload vscode
`auto-edits` suggestion doesn't do away because the `auto-edits`
provider is not `disposed` on the config change.
This results into:
1. If the user turns off the suggestion mode: they will keep on seeing
the `auto-edits` suggestions.
2. If user switches from the `auto-edits` to `autocomplete` mode, they
will see the suggestion from both `autocomplete` and `auto-edits`.
3. The PR makes `auto-edits` reactive to the `authStatus` and `config`
change similar to `autocomplete`, so that `auto-edits` is reactive and
destroyed/created on the config changes without reloading vscode.
4. Build on top of: #6523

Example image below:
<img width="607" alt="image"
src="https://github.com/user-attachments/assets/c87a06d6-063e-46f1-b87e-8ef9ba59f519"
/>


## Test plan
1. Add the breakpoints at `dispose` function and
`provideInlineCompletion` function for `autocomplete` and `auto-edits`
and make sure they are disposed and created upon config changes without
reloading vscode.
2. CI
  • Loading branch information
hitesh-1997 authored Jan 8, 2025
1 parent 059b5d5 commit dc16680
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 25 deletions.
56 changes: 56 additions & 0 deletions vscode/src/autoedits/create-autoedits-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Observable, map } from 'observable-fns'
import * as vscode from 'vscode'

import {
type AuthenticatedAuthStatus,
type ChatClient,
NEVER,
type PickResolvedConfiguration,
type UnauthenticatedAuthStatus,
createDisposables,
skipPendingOperation,
} from '@sourcegraph/cody-shared'
import { AutoeditsProvider } from './autoedits-provider'
import { autoeditsOutputChannelLogger } from './output-channel-logger'

interface AutoeditsItemProviderArgs {
config: PickResolvedConfiguration<{ configuration: true }>
authStatus: UnauthenticatedAuthStatus | Pick<AuthenticatedAuthStatus, 'authenticated' | 'endpoint'>
chatClient: ChatClient
}

export function createAutoEditsProvider({
config: { configuration },
authStatus,
chatClient,
}: AutoeditsItemProviderArgs): Observable<void> {
if (!configuration.experimentalAutoeditsEnabled) {
return NEVER
}

if (!authStatus.authenticated) {
if (!authStatus.pendingValidation) {
autoeditsOutputChannelLogger.logDebug('createProvider', 'You are not signed in.')
}
return NEVER
}

return Observable.of(undefined).pipe(
skipPendingOperation(),
createDisposables(() => {
const provider = new AutoeditsProvider(chatClient)
return [
vscode.commands.registerCommand('cody.command.autoedits-manual-trigger', async () => {
await vscode.commands.executeCommand('editor.action.inlineSuggest.hide')
await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
}),
vscode.languages.registerInlineCompletionItemProvider(
[{ scheme: 'file', language: '*' }, { notebookType: '*' }],
provider
),
provider,
]
}),
map(() => undefined)
)
}
11 changes: 10 additions & 1 deletion vscode/src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,20 @@ export function getConfiguration(
debugRegex = /.*/
}

const codyAutoSuggestionsMode = config.get<string>(
let codyAutoSuggestionsMode = config.get<string>(
CONFIG_KEY.suggestionsMode,
CodyAutoSuggestionMode.Autocomplete
)

// Backward compatibility with the older config for autocomplete. If autocomplete was turned off - override the suggestion mode to "off".
// TODO (Hitesh): Remove the manual override once the updated config is communicated after experimental release
if (
codyAutoSuggestionsMode === CodyAutoSuggestionMode.Autocomplete &&
vscode.workspace.getConfiguration().get<boolean>('cody.autocomplete.enabled') === false
) {
codyAutoSuggestionsMode = CodyAutoSuggestionMode.Off
}

return {
net: {
mode: config.get<string | null | undefined>(CONFIG_KEY.netMode, undefined),
Expand Down
45 changes: 21 additions & 24 deletions vscode/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import { isReinstalling } from '../uninstall/reinstall'
import type { CommandResult } from './CommandResult'
import { showAccountMenu } from './auth/account-menu'
import { showSignInMenu, showSignOutMenu, tokenCallbackHandler } from './auth/auth'
import { AutoeditsProvider } from './autoedits/autoedits-provider'
import { createAutoEditsProvider } from './autoedits/create-autoedits-provider'
import { autoeditsOutputChannelLogger } from './autoedits/output-channel-logger'
import { registerAutoEditTestRenderCommand } from './autoedits/renderer/mock-renderer'
import type { MessageProviderOptions } from './chat/MessageProvider'
import { CodyToolProvider } from './chat/agentic/CodyToolProvider'
Expand Down Expand Up @@ -710,30 +711,26 @@ function registerAutoEdits(chatClient: ChatClient, disposables: vscode.Disposabl
)
)
.pipe(
map(([config, authStatus, autoeditEnabled]) => {
if (shouldEnableExperimentalAutoedits(config, autoeditEnabled, authStatus)) {
const provider = new AutoeditsProvider(chatClient)
const completionRegistration =
vscode.languages.registerInlineCompletionItemProvider(
[{ scheme: 'file', language: '*' }, { notebookType: '*' }],
provider
)

// Command used to trigger autoedits manually via command palette and is also used by e2e test
vscode.commands.registerCommand(
'cody.command.autoedits-manual-trigger',
async () => {
await vscode.commands.executeCommand(
'editor.action.inlineSuggest.hide'
)
await vscode.commands.executeCommand(
'editor.action.inlineSuggest.trigger'
)
}
)
return vscode.Disposable.from(provider, completionRegistration)
distinctUntilChanged((a, b) => {
return (
isEqual(a[0].configuration, b[0].configuration) &&
isEqual(a[1], b[1]) &&
isEqual(a[2], b[2])
)
}),
switchMap(([config, authStatus, autoeditEnabled]) => {
if (!shouldEnableExperimentalAutoedits(config, autoeditEnabled, authStatus)) {
return NEVER
}
return []
return createAutoEditsProvider({
config,
authStatus,
chatClient,
})
}),
catchError(error => {
autoeditsOutputChannelLogger.logError('registerAutoedits', 'Error', error)
return NEVER
})
)
.subscribe({})
Expand Down

0 comments on commit dc16680

Please sign in to comment.