diff --git a/extensions/emmet/.vscode/settings.json b/extensions/emmet/.vscode/settings.json new file mode 100644 index 00000000000..505e7e4e316 --- /dev/null +++ b/extensions/emmet/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "emmet.excludeLanguages": [] +} \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 1df16a4716f..43b01031087 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -80,7 +80,7 @@ export function createApiFactory( // Addressable instances const extHostHeapService = threadService.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService()); - const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService)); + const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService, extensionService)); const extHostDocuments = threadService.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(threadService, extHostDocumentsAndEditors)); const extHostDocumentContentProviders = threadService.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(threadService, extHostDocumentsAndEditors)); const extHostDocumentSaveParticipant = threadService.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace))); diff --git a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts index da9cc09702c..8129a12b69a 100644 --- a/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts +++ b/src/vs/workbench/api/node/extHostDocumentsAndEditors.ts @@ -8,9 +8,10 @@ import Event, { Emitter } from 'vs/base/common/event'; import { dispose } from 'vs/base/common/lifecycle'; import { MainContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IMainContext } from './extHost.protocol'; import { ExtHostDocumentData } from './extHostDocumentData'; -import { ExtHostTextEditor } from './extHostTextEditor'; +import { ExtHostTextEditor, ExtHostTextEditor2 } from './extHostTextEditor'; import * as assert from 'assert'; import * as typeConverters from './extHostTypeConverters'; +import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape { @@ -29,7 +30,8 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha readonly onDidChangeActiveTextEditor: Event = this._onDidChangeActiveTextEditor.event; constructor( - private readonly _mainContext: IMainContext + private readonly _mainContext: IMainContext, + private readonly _extHostExtensions?: ExtHostExtensionService ) { } @@ -79,7 +81,9 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha assert.ok(!this._editors.has(data.id), `editor '${data.id}' already exists!`); const documentData = this._documents.get(data.document.toString()); - const editor = new ExtHostTextEditor( + const editor = new ExtHostTextEditor2( + this._extHostExtensions, + this._mainContext.get(MainContext.MainThreadTelemetry), this._mainContext.get(MainContext.MainThreadEditors), data.id, documentData, diff --git a/src/vs/workbench/api/node/extHostTextEditor.ts b/src/vs/workbench/api/node/extHostTextEditor.ts index 763969acc96..a3e9c45edae 100644 --- a/src/vs/workbench/api/node/extHostTextEditor.ts +++ b/src/vs/workbench/api/node/extHostTextEditor.ts @@ -6,17 +6,19 @@ import { ok } from 'vs/base/common/assert'; -import { readonly, illegalArgument } from 'vs/base/common/errors'; +import { readonly, illegalArgument, V8CallSite } from 'vs/base/common/errors'; import { IdGenerator } from 'vs/base/common/idGenerator'; import { TPromise } from 'vs/base/common/winjs.base'; import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData'; import { Selection, Range, Position, EndOfLine, TextEditorRevealType, TextEditorLineNumbersStyle, SnippetString } from './extHostTypes'; import { ISingleEditOperation } from 'vs/editor/common/editorCommon'; import * as TypeConverters from './extHostTypeConverters'; -import { MainThreadEditorsShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from './extHost.protocol'; +import { MainThreadEditorsShape, MainThreadTelemetryShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from './extHost.protocol'; import * as vscode from 'vscode'; import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions'; import { IRange } from 'vs/editor/common/core/range'; +import { containsCommandLink } from 'vs/base/common/htmlContent'; +import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; export class TextEditorDecorationType implements vscode.TextEditorDecorationType { @@ -550,6 +552,70 @@ export class ExtHostTextEditor implements vscode.TextEditor { } } +export class ExtHostTextEditor2 extends ExtHostTextEditor { + + constructor( + private readonly _extHostExtensions: ExtHostExtensionService, + private readonly _mainThreadTelemetry: MainThreadTelemetryShape, + proxy: MainThreadEditorsShape, + id: string, + document: ExtHostDocumentData, + selections: Selection[], + options: IResolvedTextEditorConfiguration, + viewColumn: vscode.ViewColumn + ) { + super(proxy, id, document, selections, options, viewColumn); + } + + setDecorations(decorationType: vscode.TextEditorDecorationType, rangesOrOptions: Range[] | vscode.DecorationOptions[]): void { + // (1) find out if this decoration is important for us + let usesCommandLink = false; + outer: for (const rangeOrOption of rangesOrOptions) { + if (Range.isRange(rangeOrOption)) { + break; + } + if (typeof rangeOrOption.hoverMessage === 'string' && containsCommandLink(rangeOrOption.hoverMessage)) { + usesCommandLink = true; + break; + } else if (Array.isArray(rangeOrOption.hoverMessage)) { + for (const message of rangeOrOption.hoverMessage) { + if (typeof message === 'string' && containsCommandLink(message)) { + usesCommandLink = true; + break outer; + } + } + } + } + // (2) send event for important decorations + if (usesCommandLink) { + let tag = new Error(); + this._extHostExtensions.getExtensionPathIndex().then(index => { + const oldHandler = (Error).prepareStackTrace; + (Error).prepareStackTrace = (error: Error, stackTrace: V8CallSite[]) => { + for (const call of stackTrace) { + const extension = index.findSubstr(call.getFileName()); + if (extension) { + this._mainThreadTelemetry.$publicLog('usesCommandLink', { + extension: extension.id, + from: 'decoration', + }); + return; + } + } + }; + // it all happens here... + // tslint:disable-next-line:no-unused-expression + tag.stack; + (Error).prepareStackTrace = oldHandler; + }); + } + + // (3) do it + super.setDecorations(decorationType, rangesOrOptions); + } +} + + function warnOnError(promise: TPromise): void { promise.then(null, (err) => { console.warn(err);