Loading src/common/language_server/language_client_middleware.ts +6 −2 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import { COMMAND_CODE_SUGGESTION_STREAM_ACCEPTED } from '../code_suggestions/com import { CompletionStream, getStreamContextId } from './completion_stream'; import { FeatureFlag, isEnabled } from '../feature_flags'; import { CONFIG_NAMESPACE } from '../constants'; import { serializeInlineCompletionContext, serializePosition } from './serialization_utils'; // We need to wait just a bit after cancellation, otherwise the loading icon flickers while someone types const CANCELLATION_DELAY = 150; Loading Loading @@ -106,7 +107,10 @@ export class LanguageClientMiddleware implements Middleware { .then(() => []); try { return await Promise.race([shortCircuit, next(document, position, context, token)]); return await Promise.race([ shortCircuit, next(document, position, serializeInlineCompletionContext(context), token), ]); } finally { this.#stateManager.setLoading(false); } Loading Loading @@ -248,7 +252,7 @@ export class LanguageClientMiddleware implements Middleware { try { intentTypeResponse = await this.#client?.sendRequest(GET_COMPLETION_INTENT_REQUEST, { documentUri: document.uri.toString(), position, position: serializePosition(position), }); } catch (error) { log.warn(`Failed to detect completion intent`, error); Loading src/common/language_server/register_language_server.test.ts +12 −1 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ describe('registerLanguageServer', () => { jest.mocked(LanguageClientWrapper).mockReturnValue(clientWrapper); client = createFakePartial<BaseLanguageClient>({}); languageClientFactory = createFakePartial<LanguageClientFactory>({ createLanguageClient: () => client, createLanguageClient: jest.fn(() => client), }); gitlabPlatformManager = createFakePartial<GitLabPlatformManager>({ onAccountChange: jest.fn(), Loading @@ -50,6 +50,17 @@ describe('registerLanguageServer', () => { await registerLanguageServer(context, languageClientFactory, gitlabPlatformManager); }); it('creates a language client and provides a baseAssetsUrl', () => { expect(languageClientFactory.createLanguageClient).toHaveBeenCalledWith( context, expect.objectContaining({ initializationOptions: expect.objectContaining({ baseAssetsUrl: 'https://localhost/assets/language-server/', }), }), ); }); it('initializes the language client wrapper', async () => { expect(clientWrapper.initAndStart).toHaveBeenCalled(); }); Loading src/common/language_server/register_language_server.ts +8 −1 Original line number Diff line number Diff line Loading @@ -34,10 +34,17 @@ export const registerLanguageServer = async ( const statusBarItem = new CodeSuggestionsStatusBarItem(stateManager); const gutterIcon = new CodeSuggestionsGutterIcon(context, stateManager); const middleware = new LanguageClientMiddleware(stateManager); const baseAssetsUrl = vscode.Uri.joinPath( context.extensionUri, './assets/language-server/', ).toString(); const client = clientFactory.createLanguageClient(context, { ...LANGUAGE_CLIENT_OPTIONS, initializationOptions: getClientContext(), initializationOptions: { ...getClientContext(), baseAssetsUrl, }, middleware, }); middleware.client = client; Loading src/common/language_server/serialization_utils.test.ts 0 → 100644 +49 −0 Original line number Diff line number Diff line import * as vscode from 'vscode'; import { serializeInlineCompletionContext, serializePosition, serializeRange, } from './serialization_utils'; describe('serializationUtils', () => { describe('serializePosition', () => { it('converts a vscode.Position object into a plain js object', () => { const result = serializePosition(new vscode.Position(1, 1)); expect(result).not.toBeInstanceOf(vscode.Position); expect(result).toEqual({ line: 1, character: 1 }); }); }); describe('serializeRange', () => { it('converts a vscode.Range object into a plain js object', () => { const result = serializeRange( new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 2)), ); expect(result).not.toBeInstanceOf(vscode.Range); expect(result).toEqual({ start: { line: 1, character: 1 }, end: { line: 1, character: 2 } }); }); }); describe('serializeInlineCompletionContext', () => { it('transforms the selectedCompletionInfo range object into a plain js object', () => { const result = serializeInlineCompletionContext({ triggerKind: vscode.InlineCompletionTriggerKind.Automatic, selectedCompletionInfo: { range: new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 2)), text: 'text', }, }); expect(result.selectedCompletionInfo?.range).not.toBeInstanceOf(vscode.Range); expect(result).toEqual({ triggerKind: vscode.InlineCompletionTriggerKind.Automatic, selectedCompletionInfo: { range: { start: { line: 1, character: 1 }, end: { line: 1, character: 2 } }, text: 'text', }, }); }); }); }); src/common/language_server/serialization_utils.ts 0 → 100644 +35 −0 Original line number Diff line number Diff line import * as vscode from 'vscode'; export const serializePosition = (position: vscode.Position): vscode.Position => ({ line: position.line, character: position.character, }) as vscode.Position; export const serializeRange = (range: vscode.Range): vscode.Range => ({ start: serializePosition(range.start), end: serializePosition(range.end), }) as vscode.Range; const serializeSelectedCompletionInfo = ( selectedCompletionInfo?: vscode.SelectedCompletionInfo, ): vscode.SelectedCompletionInfo | undefined => { if (!selectedCompletionInfo) { return undefined; } return { text: selectedCompletionInfo.text, range: serializeRange(selectedCompletionInfo.range), } as unknown as vscode.SelectedCompletionInfo; }; export const serializeInlineCompletionContext = ( inlineCompletionContext: vscode.InlineCompletionContext, ): vscode.InlineCompletionContext => ({ triggerKind: inlineCompletionContext.triggerKind, selectedCompletionInfo: serializeSelectedCompletionInfo( inlineCompletionContext.selectedCompletionInfo, ), }); Loading
src/common/language_server/language_client_middleware.ts +6 −2 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import { COMMAND_CODE_SUGGESTION_STREAM_ACCEPTED } from '../code_suggestions/com import { CompletionStream, getStreamContextId } from './completion_stream'; import { FeatureFlag, isEnabled } from '../feature_flags'; import { CONFIG_NAMESPACE } from '../constants'; import { serializeInlineCompletionContext, serializePosition } from './serialization_utils'; // We need to wait just a bit after cancellation, otherwise the loading icon flickers while someone types const CANCELLATION_DELAY = 150; Loading Loading @@ -106,7 +107,10 @@ export class LanguageClientMiddleware implements Middleware { .then(() => []); try { return await Promise.race([shortCircuit, next(document, position, context, token)]); return await Promise.race([ shortCircuit, next(document, position, serializeInlineCompletionContext(context), token), ]); } finally { this.#stateManager.setLoading(false); } Loading Loading @@ -248,7 +252,7 @@ export class LanguageClientMiddleware implements Middleware { try { intentTypeResponse = await this.#client?.sendRequest(GET_COMPLETION_INTENT_REQUEST, { documentUri: document.uri.toString(), position, position: serializePosition(position), }); } catch (error) { log.warn(`Failed to detect completion intent`, error); Loading
src/common/language_server/register_language_server.test.ts +12 −1 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ describe('registerLanguageServer', () => { jest.mocked(LanguageClientWrapper).mockReturnValue(clientWrapper); client = createFakePartial<BaseLanguageClient>({}); languageClientFactory = createFakePartial<LanguageClientFactory>({ createLanguageClient: () => client, createLanguageClient: jest.fn(() => client), }); gitlabPlatformManager = createFakePartial<GitLabPlatformManager>({ onAccountChange: jest.fn(), Loading @@ -50,6 +50,17 @@ describe('registerLanguageServer', () => { await registerLanguageServer(context, languageClientFactory, gitlabPlatformManager); }); it('creates a language client and provides a baseAssetsUrl', () => { expect(languageClientFactory.createLanguageClient).toHaveBeenCalledWith( context, expect.objectContaining({ initializationOptions: expect.objectContaining({ baseAssetsUrl: 'https://localhost/assets/language-server/', }), }), ); }); it('initializes the language client wrapper', async () => { expect(clientWrapper.initAndStart).toHaveBeenCalled(); }); Loading
src/common/language_server/register_language_server.ts +8 −1 Original line number Diff line number Diff line Loading @@ -34,10 +34,17 @@ export const registerLanguageServer = async ( const statusBarItem = new CodeSuggestionsStatusBarItem(stateManager); const gutterIcon = new CodeSuggestionsGutterIcon(context, stateManager); const middleware = new LanguageClientMiddleware(stateManager); const baseAssetsUrl = vscode.Uri.joinPath( context.extensionUri, './assets/language-server/', ).toString(); const client = clientFactory.createLanguageClient(context, { ...LANGUAGE_CLIENT_OPTIONS, initializationOptions: getClientContext(), initializationOptions: { ...getClientContext(), baseAssetsUrl, }, middleware, }); middleware.client = client; Loading
src/common/language_server/serialization_utils.test.ts 0 → 100644 +49 −0 Original line number Diff line number Diff line import * as vscode from 'vscode'; import { serializeInlineCompletionContext, serializePosition, serializeRange, } from './serialization_utils'; describe('serializationUtils', () => { describe('serializePosition', () => { it('converts a vscode.Position object into a plain js object', () => { const result = serializePosition(new vscode.Position(1, 1)); expect(result).not.toBeInstanceOf(vscode.Position); expect(result).toEqual({ line: 1, character: 1 }); }); }); describe('serializeRange', () => { it('converts a vscode.Range object into a plain js object', () => { const result = serializeRange( new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 2)), ); expect(result).not.toBeInstanceOf(vscode.Range); expect(result).toEqual({ start: { line: 1, character: 1 }, end: { line: 1, character: 2 } }); }); }); describe('serializeInlineCompletionContext', () => { it('transforms the selectedCompletionInfo range object into a plain js object', () => { const result = serializeInlineCompletionContext({ triggerKind: vscode.InlineCompletionTriggerKind.Automatic, selectedCompletionInfo: { range: new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 2)), text: 'text', }, }); expect(result.selectedCompletionInfo?.range).not.toBeInstanceOf(vscode.Range); expect(result).toEqual({ triggerKind: vscode.InlineCompletionTriggerKind.Automatic, selectedCompletionInfo: { range: { start: { line: 1, character: 1 }, end: { line: 1, character: 2 } }, text: 'text', }, }); }); }); });
src/common/language_server/serialization_utils.ts 0 → 100644 +35 −0 Original line number Diff line number Diff line import * as vscode from 'vscode'; export const serializePosition = (position: vscode.Position): vscode.Position => ({ line: position.line, character: position.character, }) as vscode.Position; export const serializeRange = (range: vscode.Range): vscode.Range => ({ start: serializePosition(range.start), end: serializePosition(range.end), }) as vscode.Range; const serializeSelectedCompletionInfo = ( selectedCompletionInfo?: vscode.SelectedCompletionInfo, ): vscode.SelectedCompletionInfo | undefined => { if (!selectedCompletionInfo) { return undefined; } return { text: selectedCompletionInfo.text, range: serializeRange(selectedCompletionInfo.range), } as unknown as vscode.SelectedCompletionInfo; }; export const serializeInlineCompletionContext = ( inlineCompletionContext: vscode.InlineCompletionContext, ): vscode.InlineCompletionContext => ({ triggerKind: inlineCompletionContext.triggerKind, selectedCompletionInfo: serializeSelectedCompletionInfo( inlineCompletionContext.selectedCompletionInfo, ), });