diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 0f14b8fd7..c6f07d95e 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -28,7 +28,7 @@ import * as fs from 'fs'; import * as os from 'os'; import { SourceFileConfiguration, SourceFileConfigurationItem, Version, WorkspaceBrowseConfiguration } from 'vscode-cpptools'; import { IntelliSenseStatus, Status } from 'vscode-cpptools/out/testApi'; -import { CloseAction, ErrorAction, LanguageClientOptions, NotificationType, Position, Range, RequestType, ResponseError, TextDocumentIdentifier, TextDocumentPositionParams } from 'vscode-languageclient'; +import { CloseAction, DidOpenTextDocumentParams, ErrorAction, LanguageClientOptions, NotificationType, Position, Range, RequestType, ResponseError, TextDocumentIdentifier, TextDocumentPositionParams } from 'vscode-languageclient'; import { LanguageClient, ServerOptions } from 'vscode-languageclient/node'; import * as nls from 'vscode-nls'; import { DebugConfigurationProvider } from '../Debugger/configurationProvider'; @@ -517,10 +517,15 @@ interface TagParseStatus { isPaused: boolean; } +interface VisibleEditorInfo { + visibleRanges: Range[]; + originalEncoding: string; +} + interface DidChangeVisibleTextEditorsParams { activeUri?: string; activeSelection?: Range; - visibleRanges?: { [uri: string]: Range[] }; + visibleEditorInfo?: { [uri: string]: VisibleEditorInfo }; } interface DidChangeTextEditorVisibleRangesParams { @@ -590,18 +595,11 @@ export interface CopilotCompletionContextParams { doAggregateSnippets: boolean; } -export interface TextDocumentItemWithOriginalEncoding { +export interface SetOpenFileOriginalEncodingParams { uri: string; - languageId: string; - version: number; - text: string; originalEncoding: string; } -export interface DidOpenTextDocumentParamsWithOriginalEncoding { - textDocument: TextDocumentItemWithOriginalEncoding; -} - // Requests const PreInitializationRequest: RequestType = new RequestType('cpptools/preinitialize'); const InitializationRequest: RequestType = new RequestType('cpptools/initialize'); @@ -626,8 +624,7 @@ const CppContextRequest: RequestType = new RequestType('cpptools/getCompletionContext'); // Notifications to the server -const DidOpenNotification: NotificationType = new NotificationType('cpptools/didOpen'); -const FileCreatedNotification: NotificationType = new NotificationType('cpptools/fileCreated'); +const DidOpenNotification: NotificationType = new NotificationType('textDocument/didOpen'); const FileCreatedNotification: NotificationType = new NotificationType('cpptools/fileCreated'); const FileChangedNotification: NotificationType = new NotificationType('cpptools/fileChanged'); const FileDeletedNotification: NotificationType = new NotificationType('cpptools/fileDeleted'); const ResetDatabaseNotification: NotificationType = new NotificationType('cpptools/resetDatabase'); @@ -650,6 +647,7 @@ const FinishedRequestCustomConfig: NotificationType = new NotificationType('cpptools/didChangeSettings'); const DidChangeVisibleTextEditorsNotification: NotificationType = new NotificationType('cpptools/didChangeVisibleTextEditors'); const DidChangeTextEditorVisibleRangesNotification: NotificationType = new NotificationType('cpptools/didChangeTextEditorVisibleRanges'); +const SetOpenFileOriginalEncodingNotification: NotificationType = new NotificationType('cpptools/setOpenFileOriginalEncoding'); const CodeAnalysisNotification: NotificationType = new NotificationType('cpptools/runCodeAnalysis'); const PauseCodeAnalysisNotification: NotificationType = new NotificationType('cpptools/pauseCodeAnalysis'); @@ -1831,32 +1829,35 @@ export class DefaultClient implements Client { return changedSettings; } - private prepareVisibleRanges(editors: readonly vscode.TextEditor[]): { [uri: string]: Range[] } { - const visibleRanges: { [uri: string]: Range[] } = {}; + private prepareVisibleEditorInfo(editors: readonly vscode.TextEditor[]): { [uri: string]: VisibleEditorInfo } { + const visibileEditorInfo: { [uri: string]: VisibleEditorInfo } = {}; editors.forEach(editor => { // Use a map, to account for multiple editors for the same file. // First, we just concat all ranges for the same file. const uri: string = editor.document.uri.toString(); - if (!visibleRanges[uri]) { - visibleRanges[uri] = []; + if (!visibileEditorInfo[uri]) { + visibileEditorInfo[uri] = { + visibleRanges: [], + originalEncoding: editor.document.encoding + }; } - visibleRanges[uri] = visibleRanges[uri].concat(editor.visibleRanges.map(makeLspRange)); + visibileEditorInfo[uri].visibleRanges = visibileEditorInfo[uri].visibleRanges.concat(editor.visibleRanges.map(makeLspRange)); }); // We may need to merge visible ranges, if there are multiple editors for the same file, // and some of the ranges overlap. - Object.keys(visibleRanges).forEach(uri => { - visibleRanges[uri] = util.mergeOverlappingRanges(visibleRanges[uri]); + Object.keys(visibileEditorInfo).forEach(uri => { + visibileEditorInfo[uri].visibleRanges = util.mergeOverlappingRanges(visibileEditorInfo[uri].visibleRanges); }); - return visibleRanges; + return visibileEditorInfo; } // Handles changes to visible files/ranges, changes to current selection/position, // and changes to the active text editor. Should only be called on the primary client. public async onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]): Promise { const params: DidChangeVisibleTextEditorsParams = { - visibleRanges: this.prepareVisibleRanges(editors) + visibleEditorInfo: this.prepareVisibleEditorInfo(editors) }; if (vscode.window.activeTextEditor) { if (util.isCpp(vscode.window.activeTextEditor.document)) { @@ -2339,19 +2340,25 @@ export class DefaultClient implements Client { // Only used in crash recovery. Otherwise, VS Code sends didOpen directly to native process (through the protocolFilter). public async sendDidOpen(document: vscode.TextDocument): Promise { - const params: DidOpenTextDocumentParamsWithOriginalEncoding = { + const params: DidOpenTextDocumentParams = { textDocument: { uri: document.uri.toString(), languageId: document.languageId, version: document.version, - text: document.getText(), - originalEncoding: document.encoding + text: document.getText() } }; - await this.ready; await this.languageClient.sendNotification(DidOpenNotification, params); } + public async sendOpenFileOriginalEncoding(document: vscode.TextDocument): Promise { + const params: SetOpenFileOriginalEncodingParams = { + uri: document.uri.toString(), + originalEncoding: document.encoding + }; + await this.languageClient.sendNotification(SetOpenFileOriginalEncodingNotification, params); + } + /** * Copilot completion-related requests (e.g. getIncludes and getProjectContext) will have their cancellation tokens cancelled * if the current request times out (showing the user completion results without context info), diff --git a/Extension/src/LanguageServer/protocolFilter.ts b/Extension/src/LanguageServer/protocolFilter.ts index f87eee070..d6462072e 100644 --- a/Extension/src/LanguageServer/protocolFilter.ts +++ b/Extension/src/LanguageServer/protocolFilter.ts @@ -19,7 +19,7 @@ export const ServerCancelled: number = -32802; export function createProtocolFilter(): Middleware { return { - didOpen: async (document, _sendMessage) => { + didOpen: async (document, sendMessage) => { if (!util.isCpp(document)) { return; } @@ -44,8 +44,8 @@ export function createProtocolFilter(): Middleware { } // client.takeOwnership() will call client.TrackedDocuments.add() again, but that's ok. It's a Set. client.takeOwnership(document); + void sendMessage(document); client.ready.then(() => { - client.sendDidOpen(document).catch(logAndReturn.undefined); const cppEditors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => util.isCpp(e.document)); client.onDidChangeVisibleTextEditors(cppEditors).catch(logAndReturn.undefined); }).catch(logAndReturn.undefined);