/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Emitter } from 'vs/base/common/event'; import * as vscode from 'vscode'; import { IReadOnlyModel, ISingleEditOperation } from 'vs/editor/common/editorCommon'; import * as modes from 'vs/editor/common/modes'; import { WorkspaceSymbolProviderRegistry, IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search'; import { wireCancellationToken } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Position as EditorPosition } from 'vs/editor/common/core/position'; import { Range as EditorRange } from 'vs/editor/common/core/range'; import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, IRawColorFormatMap, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration'; import { IHeapService } from './mainThreadHeapService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ColorFormatter, CombinedColorFormatter } from 'vs/editor/contrib/colorPicker/common/colorFormatter'; import { extHostNamedCustomer } from "vs/workbench/api/electron-browser/extHostCustomers"; @extHostNamedCustomer(MainContext.MainThreadLanguageFeatures) export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape { private _proxy: ExtHostLanguageFeaturesShape; private _heapService: IHeapService; private _modeService: IModeService; private _registrations: { [handle: number]: IDisposable; } = Object.create(null); private _formatters: Map; constructor( extHostContext: IExtHostContext, @IHeapService heapService: IHeapService, @IModeService modeService: IModeService, ) { this._proxy = extHostContext.get(ExtHostContext.ExtHostLanguageFeatures); this._heapService = heapService; this._modeService = modeService; this._formatters = new Map(); } dispose(): void { for (const key in this._registrations) { this._registrations[key].dispose(); } } $unregister(handle: number): TPromise { let registration = this._registrations[handle]; if (registration) { registration.dispose(); delete this._registrations[handle]; } return undefined; } // --- outline $registerOutlineSupport(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(selector, { provideDocumentSymbols: (model: IReadOnlyModel, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.uri)); } }); return undefined; } // --- code lens $registerCodeLensSupport(handle: number, selector: vscode.DocumentSelector, eventHandle: number): TPromise { const provider = { provideCodeLenses: (model: IReadOnlyModel, token: CancellationToken): modes.ICodeLensSymbol[] | Thenable => { return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeLenses(handle, model.uri))); }, resolveCodeLens: (model: IReadOnlyModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): modes.ICodeLensSymbol | Thenable => { return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$resolveCodeLens(handle, model.uri, codeLens))); } }; if (typeof eventHandle === 'number') { const emitter = new Emitter(); this._registrations[eventHandle] = emitter; provider.onDidChange = emitter.event; } this._registrations[handle] = modes.CodeLensProviderRegistry.register(selector, provider); return undefined; } $emitCodeLensEvent(eventHandle: number, event?: any): TPromise { const obj = this._registrations[eventHandle]; if (obj instanceof Emitter) { obj.fire(event); } return undefined; } // --- declaration $registerDeclaractionSupport(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.DefinitionProviderRegistry.register(selector, { provideDefinition: (model, position, token): Thenable => { return wireCancellationToken(token, this._proxy.$provideDefinition(handle, model.uri, position)); } }); return undefined; } $registerImplementationSupport(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.ImplementationProviderRegistry.register(selector, { provideImplementation: (model, position, token): Thenable => { return wireCancellationToken(token, this._proxy.$provideImplementation(handle, model.uri, position)); } }); return undefined; } $registerTypeDefinitionSupport(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(selector, { provideTypeDefinition: (model, position, token): Thenable => { return wireCancellationToken(token, this._proxy.$provideTypeDefinition(handle, model.uri, position)); } }); return undefined; } // --- extra info $registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.HoverProviderRegistry.register(selector, { provideHover: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$provideHover(handle, model.uri, position)); } }); return undefined; } // --- occurrences $registerDocumentHighlightProvider(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(selector, { provideDocumentHighlights: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$provideDocumentHighlights(handle, model.uri, position)); } }); return undefined; } // --- references $registerReferenceSupport(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.ReferenceProviderRegistry.register(selector, { provideReferences: (model: IReadOnlyModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$provideReferences(handle, model.uri, position, context)); } }); return undefined; } // --- quick fix $registerQuickFixSupport(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.CodeActionProviderRegistry.register(selector, { provideCodeActions: (model: IReadOnlyModel, range: EditorRange, token: CancellationToken): Thenable => { return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeActions(handle, model.uri, range))); } }); return undefined; } // --- formatting $registerDocumentFormattingSupport(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(selector, { provideDocumentFormattingEdits: (model: IReadOnlyModel, options: modes.FormattingOptions, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options)); } }); return undefined; } $registerRangeFormattingSupport(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(selector, { provideDocumentRangeFormattingEdits: (model: IReadOnlyModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options)); } }); return undefined; } $registerOnTypeFormattingSupport(handle: number, selector: vscode.DocumentSelector, autoFormatTriggerCharacters: string[]): TPromise { this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(selector, { autoFormatTriggerCharacters, provideOnTypeFormattingEdits: (model: IReadOnlyModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options)); } }); return undefined; } // --- navigate type $registerNavigateTypeSupport(handle: number): TPromise { this._registrations[handle] = WorkspaceSymbolProviderRegistry.register({ provideWorkspaceSymbols: (search: string): TPromise => { return this._heapService.trackRecursive(this._proxy.$provideWorkspaceSymbols(handle, search)); }, resolveWorkspaceSymbol: (item: modes.SymbolInformation): TPromise => { return this._proxy.$resolveWorkspaceSymbol(handle, item); } }); return undefined; } // --- rename $registerRenameSupport(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.RenameProviderRegistry.register(selector, { provideRenameEdits: (model: IReadOnlyModel, position: EditorPosition, newName: string, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$provideRenameEdits(handle, model.uri, position, newName)); } }); return undefined; } // --- suggest $registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[]): TPromise { this._registrations[handle] = modes.SuggestRegistry.register(selector, { triggerCharacters, provideCompletionItems: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable => { return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position))); }, resolveCompletionItem: (model: IReadOnlyModel, position: EditorPosition, suggestion: modes.ISuggestion, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion)); } }); return undefined; } // --- parameter hints $registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): TPromise { this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(selector, { signatureHelpTriggerCharacters: triggerCharacter, provideSignatureHelp: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable => { return wireCancellationToken(token, this._proxy.$provideSignatureHelp(handle, model.uri, position)); } }); return undefined; } // --- links $registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): TPromise { this._registrations[handle] = modes.LinkProviderRegistry.register(selector, { provideLinks: (model, token) => { return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideDocumentLinks(handle, model.uri))); }, resolveLink: (link, token) => { return wireCancellationToken(token, this._proxy.$resolveDocumentLink(handle, link)); } }); return undefined; } // --- colors $registerDocumentColorProvider(handle: number, selector: vscode.DocumentSelector): TPromise { const proxy = this._proxy; this._registrations[handle] = modes.ColorProviderRegistry.register(selector, { provideColorRanges: (model, token) => { return wireCancellationToken(token, proxy.$provideDocumentColors(handle, model.uri)) .then(documentColors => { return documentColors.map(documentColor => { const formatters = documentColor.availableFormats.map(f => { if (typeof f === 'number') { return this._formatters.get(f); } else { return new CombinedColorFormatter(this._formatters.get(f[0]), this._formatters.get(f[1])); } }); const [red, green, blue, alpha] = documentColor.color; const color = { red: red / 255.0, green: green / 255.0, blue: blue / 255.0, alpha }; return { color, formatters, range: documentColor.range }; }); }); } }); return TPromise.as(null); } $registerColorFormats(formats: IRawColorFormatMap): TPromise { formats.forEach(f => this._formatters.set(f[0], new ColorFormatter(f[1]))); return TPromise.as(null); } // --- configuration $setLanguageConfiguration(handle: number, languageId: string, _configuration: vscode.LanguageConfiguration): TPromise { let configuration: LanguageConfiguration = { comments: _configuration.comments, brackets: _configuration.brackets, wordPattern: _configuration.wordPattern, indentationRules: _configuration.indentationRules, onEnterRules: _configuration.onEnterRules, autoClosingPairs: null, surroundingPairs: null, __electricCharacterSupport: null }; if (_configuration.__characterPairSupport) { // backwards compatibility configuration.autoClosingPairs = _configuration.__characterPairSupport.autoClosingPairs; } if (_configuration.__electricCharacterSupport && _configuration.__electricCharacterSupport.docComment) { configuration.__electricCharacterSupport = { docComment: { open: _configuration.__electricCharacterSupport.docComment.open, close: _configuration.__electricCharacterSupport.docComment.close } }; } let languageIdentifier = this._modeService.getLanguageIdentifier(languageId); if (languageIdentifier) { this._registrations[handle] = LanguageConfigurationRegistry.register(languageIdentifier, configuration); } return undefined; } }