提交 066dfef8 编写于 作者: R Rob DeLine 提交者: Johannes Rieken

Add Code Inset Feature

上级 292d51fc
...@@ -600,6 +600,11 @@ export interface IEditorOptions { ...@@ -600,6 +600,11 @@ export interface IEditorOptions {
* Defaults to true. * Defaults to true.
*/ */
codeLens?: boolean; codeLens?: boolean;
/**
* Show code insets
* Defaults to true.
*/
codeInsets?: boolean;
/** /**
* Control the behavior and rendering of the code action lightbulb. * Control the behavior and rendering of the code action lightbulb.
*/ */
...@@ -996,6 +1001,7 @@ export interface EditorContribOptions { ...@@ -996,6 +1001,7 @@ export interface EditorContribOptions {
readonly selectionHighlight: boolean; readonly selectionHighlight: boolean;
readonly occurrencesHighlight: boolean; readonly occurrencesHighlight: boolean;
readonly codeLens: boolean; readonly codeLens: boolean;
readonly codeInsets: boolean;
readonly folding: boolean; readonly folding: boolean;
readonly foldingStrategy: 'auto' | 'indentation'; readonly foldingStrategy: 'auto' | 'indentation';
readonly showFoldingControls: 'always' | 'mouseover'; readonly showFoldingControls: 'always' | 'mouseover';
...@@ -2051,6 +2057,7 @@ export class EditorOptionsValidator { ...@@ -2051,6 +2057,7 @@ export class EditorOptionsValidator {
selectionHighlight: _boolean(opts.selectionHighlight, defaults.selectionHighlight), selectionHighlight: _boolean(opts.selectionHighlight, defaults.selectionHighlight),
occurrencesHighlight: _boolean(opts.occurrencesHighlight, defaults.occurrencesHighlight), occurrencesHighlight: _boolean(opts.occurrencesHighlight, defaults.occurrencesHighlight),
codeLens: _boolean(opts.codeLens, defaults.codeLens), codeLens: _boolean(opts.codeLens, defaults.codeLens),
codeInsets: _boolean(opts.codeInsets, defaults.codeInsets),
folding: _boolean(opts.folding, defaults.folding), folding: _boolean(opts.folding, defaults.folding),
foldingStrategy: _stringSet<'auto' | 'indentation'>(opts.foldingStrategy, defaults.foldingStrategy, ['auto', 'indentation']), foldingStrategy: _stringSet<'auto' | 'indentation'>(opts.foldingStrategy, defaults.foldingStrategy, ['auto', 'indentation']),
showFoldingControls: _stringSet<'always' | 'mouseover'>(opts.showFoldingControls, defaults.showFoldingControls, ['always', 'mouseover']), showFoldingControls: _stringSet<'always' | 'mouseover'>(opts.showFoldingControls, defaults.showFoldingControls, ['always', 'mouseover']),
...@@ -2164,6 +2171,7 @@ export class InternalEditorOptionsFactory { ...@@ -2164,6 +2171,7 @@ export class InternalEditorOptionsFactory {
selectionHighlight: (accessibilityIsOn ? false : opts.contribInfo.selectionHighlight), // DISABLED WHEN SCREEN READER IS ATTACHED selectionHighlight: (accessibilityIsOn ? false : opts.contribInfo.selectionHighlight), // DISABLED WHEN SCREEN READER IS ATTACHED
occurrencesHighlight: (accessibilityIsOn ? false : opts.contribInfo.occurrencesHighlight), // DISABLED WHEN SCREEN READER IS ATTACHED occurrencesHighlight: (accessibilityIsOn ? false : opts.contribInfo.occurrencesHighlight), // DISABLED WHEN SCREEN READER IS ATTACHED
codeLens: (accessibilityIsOn ? false : opts.contribInfo.codeLens), // DISABLED WHEN SCREEN READER IS ATTACHED codeLens: (accessibilityIsOn ? false : opts.contribInfo.codeLens), // DISABLED WHEN SCREEN READER IS ATTACHED
codeInsets: (accessibilityIsOn ? false : opts.contribInfo.codeInsets),
folding: (accessibilityIsOn ? false : opts.contribInfo.folding), // DISABLED WHEN SCREEN READER IS ATTACHED folding: (accessibilityIsOn ? false : opts.contribInfo.folding), // DISABLED WHEN SCREEN READER IS ATTACHED
foldingStrategy: opts.contribInfo.foldingStrategy, foldingStrategy: opts.contribInfo.foldingStrategy,
showFoldingControls: opts.contribInfo.showFoldingControls, showFoldingControls: opts.contribInfo.showFoldingControls,
...@@ -2653,6 +2661,7 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = { ...@@ -2653,6 +2661,7 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = {
selectionHighlight: true, selectionHighlight: true,
occurrencesHighlight: true, occurrencesHighlight: true,
codeLens: true, codeLens: true,
codeInsets: true,
folding: true, folding: true,
foldingStrategy: 'auto', foldingStrategy: 'auto',
showFoldingControls: 'mouseover', showFoldingControls: 'mouseover',
......
...@@ -9,7 +9,7 @@ import { Event } from 'vs/base/common/event'; ...@@ -9,7 +9,7 @@ import { Event } from 'vs/base/common/event';
import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IMarkdownString } from 'vs/base/common/htmlContent';
import { IDisposable } from 'vs/base/common/lifecycle'; import { IDisposable } from 'vs/base/common/lifecycle';
import { isObject } from 'vs/base/common/types'; import { isObject } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { Position } from 'vs/editor/common/core/position'; import { Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range'; import { IRange, Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection'; import { Selection } from 'vs/editor/common/core/selection';
...@@ -1321,6 +1321,19 @@ export interface CodeLensProvider { ...@@ -1321,6 +1321,19 @@ export interface CodeLensProvider {
resolveCodeLens?(model: model.ITextModel, codeLens: ICodeLensSymbol, token: CancellationToken): ProviderResult<ICodeLensSymbol>; resolveCodeLens?(model: model.ITextModel, codeLens: ICodeLensSymbol, token: CancellationToken): ProviderResult<ICodeLensSymbol>;
} }
export interface ICodeInsetSymbol {
range: IRange;
id?: string;
height?: number;
webviewHandle?: string;
}
export interface CodeInsetProvider {
onDidChange?: Event<this>;
extensionLocation: UriComponents;
provideCodeInsets(model: model.ITextModel, token: CancellationToken): ProviderResult<ICodeInsetSymbol[]>;
resolveCodeInset?(model: model.ITextModel, codeInset: ICodeInsetSymbol, token: CancellationToken): ProviderResult<ICodeInsetSymbol>;
}
// --- feature registries ------ // --- feature registries ------
/** /**
...@@ -1383,6 +1396,11 @@ export const TypeDefinitionProviderRegistry = new LanguageFeatureRegistry<TypeDe ...@@ -1383,6 +1396,11 @@ export const TypeDefinitionProviderRegistry = new LanguageFeatureRegistry<TypeDe
*/ */
export const CodeLensProviderRegistry = new LanguageFeatureRegistry<CodeLensProvider>(); export const CodeLensProviderRegistry = new LanguageFeatureRegistry<CodeLensProvider>();
/**
* @internal
*/
export const CodeInsetProviderRegistry = new LanguageFeatureRegistry<CodeInsetProvider>();
/** /**
* @internal * @internal
*/ */
......
...@@ -188,7 +188,7 @@ export class MarkerNavigationWidget extends ZoneWidget { ...@@ -188,7 +188,7 @@ export class MarkerNavigationWidget extends ZoneWidget {
} }
private _applyTheme(theme: ITheme) { private _applyTheme(theme: ITheme) {
this._backgroundColor = theme.getColor(editorMarkerNavigationBackground); this._backgroundColor = theme.getColor(editorMarkerNavigationBackground) || undefined;
let colorId = editorMarkerNavigationError; let colorId = editorMarkerNavigationError;
if (this._severity === MarkerSeverity.Warning) { if (this._severity === MarkerSeverity.Warning) {
colorId = editorMarkerNavigationWarning; colorId = editorMarkerNavigationWarning;
......
...@@ -279,8 +279,8 @@ export class ReferenceWidget extends PeekViewWidget { ...@@ -279,8 +279,8 @@ export class ReferenceWidget extends PeekViewWidget {
arrowColor: borderColor, arrowColor: borderColor,
frameColor: borderColor, frameColor: borderColor,
headerBackgroundColor: theme.getColor(peekViewTitleBackground) || Color.transparent, headerBackgroundColor: theme.getColor(peekViewTitleBackground) || Color.transparent,
primaryHeadingColor: theme.getColor(peekViewTitleForeground), primaryHeadingColor: theme.getColor(peekViewTitleForeground) || undefined,
secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground) secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground) || undefined
}); });
} }
......
...@@ -2934,6 +2934,11 @@ declare namespace monaco.editor { ...@@ -2934,6 +2934,11 @@ declare namespace monaco.editor {
* Defaults to true. * Defaults to true.
*/ */
codeLens?: boolean; codeLens?: boolean;
/**
* Show code insets
* Defaults to true.
*/
codeInsets?: boolean;
/** /**
* Control the behavior and rendering of the code action lightbulb. * Control the behavior and rendering of the code action lightbulb.
*/ */
...@@ -3271,6 +3276,7 @@ declare namespace monaco.editor { ...@@ -3271,6 +3276,7 @@ declare namespace monaco.editor {
readonly selectionHighlight: boolean; readonly selectionHighlight: boolean;
readonly occurrencesHighlight: boolean; readonly occurrencesHighlight: boolean;
readonly codeLens: boolean; readonly codeLens: boolean;
readonly codeInsets: boolean;
readonly folding: boolean; readonly folding: boolean;
readonly foldingStrategy: 'auto' | 'indentation'; readonly foldingStrategy: 'auto' | 'indentation';
readonly showFoldingControls: 'always' | 'mouseover'; readonly showFoldingControls: 'always' | 'mouseover';
...@@ -5414,6 +5420,20 @@ declare namespace monaco.languages { ...@@ -5414,6 +5420,20 @@ declare namespace monaco.languages {
resolveCodeLens?(model: editor.ITextModel, codeLens: ICodeLensSymbol, token: CancellationToken): ProviderResult<ICodeLensSymbol>; resolveCodeLens?(model: editor.ITextModel, codeLens: ICodeLensSymbol, token: CancellationToken): ProviderResult<ICodeLensSymbol>;
} }
export interface ICodeInsetSymbol {
range: IRange;
id?: string;
height?: number;
webviewHandle?: string;
}
export interface CodeInsetProvider {
onDidChange?: IEvent<this>;
extensionLocation: UriComponents;
provideCodeInsets(model: editor.ITextModel, token: CancellationToken): ProviderResult<ICodeInsetSymbol[]>;
resolveCodeInset?(model: editor.ITextModel, codeInset: ICodeInsetSymbol, token: CancellationToken): ProviderResult<ICodeInsetSymbol>;
}
export interface ILanguageExtensionPoint { export interface ILanguageExtensionPoint {
id: string; id: string;
extensions?: string[]; extensions?: string[];
......
...@@ -2235,6 +2235,24 @@ declare module 'vscode' { ...@@ -2235,6 +2235,24 @@ declare module 'vscode' {
resolveCodeLens?(codeLens: CodeLens, token: CancellationToken): ProviderResult<CodeLens>; resolveCodeLens?(codeLens: CodeLens, token: CancellationToken): ProviderResult<CodeLens>;
} }
/**
*/
export class CodeInset {
range: Range;
height?: number;
constructor(range: Range, height?: number);
}
export interface CodeInsetProvider {
onDidChangeCodeInsets?: Event<void>;
provideCodeInsets(document: TextDocument, token: CancellationToken): ProviderResult<CodeInset[]>;
resolveCodeInset?(codeInset: CodeInset, webview: Webview, token: CancellationToken): ProviderResult<CodeInset>;
}
/** /**
* Information about where a symbol is defined. * Information about where a symbol is defined.
* *
...@@ -7855,6 +7873,12 @@ declare module 'vscode' { ...@@ -7855,6 +7873,12 @@ declare module 'vscode' {
*/ */
export function registerCodeLensProvider(selector: DocumentSelector, provider: CodeLensProvider): Disposable; export function registerCodeLensProvider(selector: DocumentSelector, provider: CodeLensProvider): Disposable;
/**
* Register a code inset provider.
*
*/
export function registerCodeInsetProvider(selector: DocumentSelector, provider: CodeInsetProvider): Disposable;
/** /**
* Register a definition provider. * Register a definition provider.
* *
......
...@@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search'; ...@@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { Position as EditorPosition } from 'vs/editor/common/core/position'; import { Position as EditorPosition } from 'vs/editor/common/core/position';
import { Range as EditorRange } from 'vs/editor/common/core/range'; import { Range as EditorRange } from 'vs/editor/common/core/range';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata } from '../node/extHost.protocol'; import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata, CodeInsetDto } from '../node/extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration'; import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { IHeapService } from './mainThreadHeapService'; import { IHeapService } from './mainThreadHeapService';
...@@ -20,6 +20,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostC ...@@ -20,6 +20,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostC
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters'; import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { Selection } from 'vs/editor/common/core/selection'; import { Selection } from 'vs/editor/common/core/selection';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures) @extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape { export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
...@@ -160,6 +161,36 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha ...@@ -160,6 +161,36 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
} }
} }
// -- code inset
$registerCodeInsetSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number, extension: IExtensionDescription): void {
const provider = <modes.CodeInsetProvider>{
provideCodeInsets: (model: ITextModel, token: CancellationToken): CodeInsetDto[] | Thenable<CodeInsetDto[]> => {
return this._proxy.$provideCodeInsets(handle, model.uri, token).then(dto => {
if (dto) { dto.forEach(obj => this._heapService.trackObject(obj)); }
return dto;
});
},
resolveCodeInset: (model: ITextModel, codeInset: CodeInsetDto, token: CancellationToken): CodeInsetDto | Thenable<CodeInsetDto> => {
return this._proxy.$resolveCodeInset(handle, model.uri, codeInset, token).then(obj => {
this._heapService.trackObject(obj);
return obj;
});
},
extensionLocation: extension.extensionLocation
};
if (typeof eventHandle === 'number') {
const emitter = new Emitter<modes.CodeInsetProvider>();
this._registrations[eventHandle] = emitter;
provider.onDidChange = emitter.event;
}
const langSelector = typeConverters.LanguageSelector.from(selector);
this._registrations[handle] = modes.CodeInsetProviderRegistry.register(langSelector, provider);
}
// --- declaration // --- declaration
$registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void { $registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
......
...@@ -22,9 +22,14 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; ...@@ -22,9 +22,14 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
export let mainThreadWebviews: MainThreadWebviews;
@extHostNamedCustomer(MainContext.MainThreadWebviews) @extHostNamedCustomer(MainContext.MainThreadWebviews)
export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviver { export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviver {
_serviceBrand: any;
private static readonly viewType = 'mainThreadWebview'; private static readonly viewType = 'mainThreadWebview';
private static readonly standardSupportedLinkSchemes = ['http', 'https', 'mailto']; private static readonly standardSupportedLinkSchemes = ['http', 'https', 'mailto'];
...@@ -49,6 +54,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv ...@@ -49,6 +54,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
@IExtensionService private readonly _extensionService: IExtensionService, @IExtensionService private readonly _extensionService: IExtensionService,
@ITelemetryService private readonly _telemetryService: ITelemetryService @ITelemetryService private readonly _telemetryService: ITelemetryService
) { ) {
mainThreadWebviews = this;
this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews); this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews);
_editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this, this._toDispose); _editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this, this._toDispose);
_editorService.onDidVisibleEditorsChange(this.onVisibleEditorsChanged, this, this._toDispose); _editorService.onDidVisibleEditorsChange(this.onVisibleEditorsChanged, this, this._toDispose);
...@@ -64,7 +70,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv ...@@ -64,7 +70,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._toDispose = dispose(this._toDispose); this._toDispose = dispose(this._toDispose);
} }
public $createWebviewPanel( public $createWebview(
handle: WebviewPanelHandle, handle: WebviewPanelHandle,
viewType: string, viewType: string,
title: string, title: string,
...@@ -96,6 +102,23 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv ...@@ -96,6 +102,23 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId.value }); this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId.value });
} }
public createInsetWebview(
handle: WebviewPanelHandle,
parent: HTMLElement,
options: WebviewInputOptions,
extensionLocation: UriComponents
): WebviewEditorInput {
const webview = this._webviewService.createInsetWebview(parent, reviveWebviewOptions(options), URI.revive(extensionLocation), this.createWebviewEventDelegate(handle));
webview.state = {
viewType: webview.viewType,
state: undefined
};
this._webviews.set(handle, webview);
this._activeWebview = handle;
return webview;
}
public $disposeWebview(handle: WebviewPanelHandle): void { public $disposeWebview(handle: WebviewPanelHandle): void {
const webview = this.getWebview(handle); const webview = this.getWebview(handle);
webview.dispose(); webview.dispose();
...@@ -289,7 +312,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv ...@@ -289,7 +312,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
} }
} }
private getWebview(handle: WebviewPanelHandle): WebviewEditorInput { public getWebview(handle: WebviewPanelHandle): WebviewEditorInput {
const webview = this._webviews.get(handle); const webview = this._webviews.get(handle);
if (!webview) { if (!webview) {
throw new Error('Unknown webview handle:' + handle); throw new Error('Unknown webview handle:' + handle);
......
...@@ -304,6 +304,9 @@ export function createApiFactory( ...@@ -304,6 +304,9 @@ export function createApiFactory(
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable { registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider); return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider);
}, },
registerCodeInsetProvider(selector: vscode.DocumentSelector, provider: vscode.CodeInsetProvider): vscode.Disposable {
return extHostLanguageFeatures.registerCodeInsetProvider(extension, checkSelector(selector), provider);
},
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable { registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
return extHostLanguageFeatures.registerDefinitionProvider(extension, checkSelector(selector), provider); return extHostLanguageFeatures.registerDefinitionProvider(extension, checkSelector(selector), provider);
}, },
...@@ -754,6 +757,7 @@ export function createApiFactory( ...@@ -754,6 +757,7 @@ export function createApiFactory(
CodeActionKind: extHostTypes.CodeActionKind, CodeActionKind: extHostTypes.CodeActionKind,
CodeActionTrigger: extHostTypes.CodeActionTrigger, CodeActionTrigger: extHostTypes.CodeActionTrigger,
CodeLens: extHostTypes.CodeLens, CodeLens: extHostTypes.CodeLens,
CodeInset: extHostTypes.CodeInset,
Color: extHostTypes.Color, Color: extHostTypes.Color,
ColorInformation: extHostTypes.ColorInformation, ColorInformation: extHostTypes.ColorInformation,
ColorPresentation: extHostTypes.ColorPresentation, ColorPresentation: extHostTypes.ColorPresentation,
......
...@@ -299,6 +299,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { ...@@ -299,6 +299,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$unregister(handle: number): void; $unregister(handle: number): void;
$registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], label: string): void; $registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], label: string): void;
$registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void; $registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void;
$registerCodeInsetSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number, extension: IExtensionDescription): void;
$emitCodeLensEvent(eventHandle: number, event?: any): void; $emitCodeLensEvent(eventHandle: number, event?: any): void;
$registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void; $registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void; $registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
...@@ -473,7 +474,7 @@ export interface WebviewPanelShowOptions { ...@@ -473,7 +474,7 @@ export interface WebviewPanelShowOptions {
} }
export interface MainThreadWebviewsShape extends IDisposable { export interface MainThreadWebviewsShape extends IDisposable {
$createWebviewPanel(handle: WebviewPanelHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: vscode.WebviewPanelOptions & vscode.WebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): void; $createWebview(handle: WebviewPanelHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: vscode.WebviewPanelOptions & vscode.WebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): void;
$disposeWebview(handle: WebviewPanelHandle): void; $disposeWebview(handle: WebviewPanelHandle): void;
$reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void; $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void;
$setTitle(handle: WebviewPanelHandle, value: string): void; $setTitle(handle: WebviewPanelHandle, value: string): void;
...@@ -499,6 +500,18 @@ export interface ExtHostWebviewsShape { ...@@ -499,6 +500,18 @@ export interface ExtHostWebviewsShape {
$deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: vscode.WebviewOptions): Promise<void>; $deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: vscode.WebviewOptions): Promise<void>;
} }
// export type CodeInsetWebviewHandle = string;
// export interface ExtHostCodeInsetWebviewsShape {
// }
// export interface ExtHostCodeInsetWebviewShape extends IDisposable {
// $setHtml(handle: WebviewPanelHandle, value: string): void;
// $setOptions(handle: WebviewPanelHandle, options: vscode.WebviewOptions): void;
// $postMessage(handle: WebviewPanelHandle, value: any): Promise<boolean>;
// }
export interface MainThreadUrlsShape extends IDisposable { export interface MainThreadUrlsShape extends IDisposable {
$registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise<void>; $registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise<void>;
$unregisterUriHandler(handle: number): Promise<void>; $unregisterUriHandler(handle: number): Promise<void>;
...@@ -892,10 +905,14 @@ export interface CodeLensDto extends ObjectIdentifier { ...@@ -892,10 +905,14 @@ export interface CodeLensDto extends ObjectIdentifier {
command?: CommandDto; command?: CommandDto;
} }
export type CodeInsetDto = ObjectIdentifier & modes.ICodeInsetSymbol;
export interface ExtHostLanguageFeaturesShape { export interface ExtHostLanguageFeaturesShape {
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined>; $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined>;
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<CodeLensDto[]>; $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<CodeLensDto[]>;
$resolveCodeLens(handle: number, resource: UriComponents, symbol: CodeLensDto, token: CancellationToken): Promise<CodeLensDto>; $resolveCodeLens(handle: number, resource: UriComponents, symbol: CodeLensDto, token: CancellationToken): Promise<CodeLensDto>;
$provideCodeInsets(handle: number, resource: UriComponents, token: CancellationToken): Promise<CodeInsetDto[]>;
$resolveCodeInset(handle: number, resource: UriComponents, symbol: CodeInsetDto, token: CancellationToken): Promise<CodeInsetDto>;
$provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<DefinitionLinkDto[]>; $provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<DefinitionLinkDto[]>;
$provideDeclaration(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<DefinitionLinkDto[]>; $provideDeclaration(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<DefinitionLinkDto[]>;
$provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<DefinitionLinkDto[]>; $provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<DefinitionLinkDto[]>;
...@@ -1157,6 +1174,7 @@ export const ExtHostContext = { ...@@ -1157,6 +1174,7 @@ export const ExtHostContext = {
ExtHostWorkspace: createExtId<ExtHostWorkspaceShape>('ExtHostWorkspace'), ExtHostWorkspace: createExtId<ExtHostWorkspaceShape>('ExtHostWorkspace'),
ExtHostWindow: createExtId<ExtHostWindowShape>('ExtHostWindow'), ExtHostWindow: createExtId<ExtHostWindowShape>('ExtHostWindow'),
ExtHostWebviews: createExtId<ExtHostWebviewsShape>('ExtHostWebviews'), ExtHostWebviews: createExtId<ExtHostWebviewsShape>('ExtHostWebviews'),
// ExtHostCodeInsetWebviews: createExtId<ExtHostCodeInsetWebviewsShape>('ExtHostWebviews'),
ExtHostProgress: createMainId<ExtHostProgressShape>('ExtHostProgress'), ExtHostProgress: createMainId<ExtHostProgressShape>('ExtHostProgress'),
ExtHostComments: createMainId<ExtHostCommentsShape>('ExtHostComments'), ExtHostComments: createMainId<ExtHostCommentsShape>('ExtHostComments'),
ExtHostStorage: createMainId<ExtHostStorageShape>('ExtHostStorage'), ExtHostStorage: createMainId<ExtHostStorageShape>('ExtHostStorage'),
......
...@@ -146,6 +146,13 @@ export class ExtHostApiCommands { ...@@ -146,6 +146,13 @@ export class ExtHostApiCommands {
], ],
returns: 'A promise that resolves to an array of CodeLens-instances.' returns: 'A promise that resolves to an array of CodeLens-instances.'
}); });
this._register('vscode.executeCodeInsetProvider', this._executeCodeInsetProvider, {
description: 'Execute CodeInset provider.',
args: [
{ name: 'uri', description: 'Uri of a text document', constraint: URI }
],
returns: 'A promise that resolves to an array of CodeInset-instances.'
});
this._register('vscode.executeFormatDocumentProvider', this._executeFormatDocumentProvider, { this._register('vscode.executeFormatDocumentProvider', this._executeFormatDocumentProvider, {
description: 'Execute document format provider.', description: 'Execute document format provider.',
args: [ args: [
...@@ -514,6 +521,14 @@ export class ExtHostApiCommands { ...@@ -514,6 +521,14 @@ export class ExtHostApiCommands {
} }
private _executeCodeInsetProvider(resource: URI): Thenable<vscode.CodeInset[]> {
const args = { resource };
return this._commands.executeCommand<modes.ICodeInsetSymbol[]>('_executeCodeInsetProvider', args)
.then(tryMapWith(item =>
new types.CodeInset(
typeConverters.Range.to(item.range))));
}
private _executeFormatDocumentProvider(resource: URI, options: vscode.FormattingOptions): Promise<vscode.TextEdit[]> { private _executeFormatDocumentProvider(resource: URI, options: vscode.FormattingOptions): Promise<vscode.TextEdit[]> {
const args = { const args = {
resource, resource,
......
...@@ -15,7 +15,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; ...@@ -15,7 +15,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics'; import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { asPromise } from 'vs/base/common/async'; import { asPromise } from 'vs/base/common/async';
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CodeLensDto } from './extHost.protocol'; import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CodeLensDto, MainThreadWebviewsShape } from './extHost.protocol';
import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings'; import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings';
import { IPosition } from 'vs/editor/common/core/position'; import { IPosition } from 'vs/editor/common/core/position';
import { IRange, Range as EditorRange } from 'vs/editor/common/core/range'; import { IRange, Range as EditorRange } from 'vs/editor/common/core/range';
...@@ -26,6 +26,7 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e ...@@ -26,6 +26,7 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtHostWebview } from 'vs/workbench/api/node/extHostWebview';
// --- adapter // --- adapter
...@@ -144,6 +145,52 @@ class CodeLensAdapter { ...@@ -144,6 +145,52 @@ class CodeLensAdapter {
} }
} }
class CodeInsetAdapter {
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _heapService: ExtHostHeapService,
private readonly _provider: vscode.CodeInsetProvider
) { }
provideCodeInsets(resource: URI, token: CancellationToken): Promise<modes.ICodeInsetSymbol[]> {
const doc = this._documents.getDocumentData(resource).document;
return asPromise(() => this._provider.provideCodeInsets(doc, token)).then(insets => {
if (Array.isArray(insets)) {
return insets.map(inset => {
const id = this._heapService.keep(inset);
return ObjectIdentifier.mixin({
range: typeConvert.Range.from(inset.range),
height: inset.height
}, id);
});
} else {
return undefined;
}
});
}
resolveCodeInset(symbol: modes.ICodeInsetSymbol, webview: vscode.Webview, token: CancellationToken): Promise<modes.ICodeInsetSymbol> {
const inset = this._heapService.get<vscode.CodeInset>(ObjectIdentifier.of(symbol));
if (!inset) {
return undefined;
}
let resolve: Promise<vscode.CodeInset>;
if (typeof this._provider.resolveCodeInset !== 'function') {
resolve = Promise.resolve(inset);
} else {
resolve = asPromise(() => this._provider.resolveCodeInset(inset, webview, token));
}
return resolve.then(newInset => {
newInset = newInset || inset;
return symbol;
});
}
}
function convertToLocationLinks(value: vscode.Definition): modes.LocationLink[] { function convertToLocationLinks(value: vscode.Definition): modes.LocationLink[] {
if (Array.isArray(value)) { if (Array.isArray(value)) {
return (value as (vscode.DefinitionLink | vscode.Location)[]).map(typeConvert.DefinitionLink.from); return (value as (vscode.DefinitionLink | vscode.Location)[]).map(typeConvert.DefinitionLink.from);
...@@ -916,7 +963,7 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov ...@@ -916,7 +963,7 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter | DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter | RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter | SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter
| ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter | SelectionRangeAdapter; | ColorProviderAdapter | FoldingProviderAdapter | CodeInsetAdapter | DeclarationAdapter | SelectionRangeAdapter;
class AdapterData { class AdapterData {
constructor( constructor(
...@@ -941,6 +988,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { ...@@ -941,6 +988,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
private _diagnostics: ExtHostDiagnostics; private _diagnostics: ExtHostDiagnostics;
private _adapter = new Map<number, AdapterData>(); private _adapter = new Map<number, AdapterData>();
private readonly _logService: ILogService; private readonly _logService: ILogService;
private _webviewProxy: MainThreadWebviewsShape;
constructor( constructor(
mainContext: IMainContext, mainContext: IMainContext,
...@@ -958,6 +1006,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { ...@@ -958,6 +1006,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
this._heapService = heapMonitor; this._heapService = heapMonitor;
this._diagnostics = diagnostics; this._diagnostics = diagnostics;
this._logService = logService; this._logService = logService;
this._webviewProxy = mainContext.getProxy(MainContext.MainThreadWebviews);
} }
private _transformDocumentSelector(selector: vscode.DocumentSelector): ISerializedDocumentFilter[] { private _transformDocumentSelector(selector: vscode.DocumentSelector): ISerializedDocumentFilter[] {
...@@ -1084,6 +1133,38 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { ...@@ -1084,6 +1133,38 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(URI.revive(resource), symbol, token)); return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(URI.revive(resource), symbol, token));
} }
// --- code insets
registerCodeInsetProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CodeInsetProvider): vscode.Disposable {
const handle = this._nextHandle();
const eventHandle = typeof provider.onDidChangeCodeInsets === 'function' ? this._nextHandle() : undefined;
this._adapter.set(handle, new AdapterData(new CodeInsetAdapter(this._documents, this._heapService, provider), extension));
this._proxy.$registerCodeInsetSupport(handle, this._transformDocumentSelector(selector), eventHandle, extension);
let result = this._createDisposable(handle);
if (eventHandle !== undefined) {
const subscription = provider.onDidChangeCodeInsets(_ => this._proxy.$emitCodeLensEvent(eventHandle));
result = Disposable.from(result, subscription);
}
return result;
}
$provideCodeInsets(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.ICodeInsetSymbol[]> {
return this._withAdapter(handle, CodeInsetAdapter, adapter => adapter.provideCodeInsets(URI.revive(resource), token));
}
$resolveCodeInset(handle: number, resource: UriComponents, symbol: modes.ICodeInsetSymbol, token: CancellationToken): Promise<modes.ICodeInsetSymbol> {
const webview = new ExtHostWebview(symbol.webviewHandle, this._webviewProxy, { enableScripts: true });
webview.html = '<html><body></body></html>';
const x = this._withAdapter(handle, CodeInsetAdapter, adapter => adapter.resolveCodeInset(symbol, webview, token));
return x;
}
$createCodeInsetWebview(handle: number) {
}
// --- declaration // --- declaration
registerDefinitionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable { registerDefinitionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
......
...@@ -1136,6 +1136,21 @@ export class CodeLens { ...@@ -1136,6 +1136,21 @@ export class CodeLens {
} }
} }
export class CodeInset {
range: Range;
isResolved: boolean;
height?: number;
constructor(range: Range, height?: number) {
this.range = range;
this.isResolved = false;
this.height = height;
}
}
@es5ClassCompat @es5ClassCompat
export class MarkdownString { export class MarkdownString {
......
...@@ -257,7 +257,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape { ...@@ -257,7 +257,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
}; };
const handle = ExtHostWebviews.newHandle(); const handle = ExtHostWebviews.newHandle();
this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, options, extension.identifier, extension.extensionLocation); this._proxy.$createWebview(handle, viewType, title, webviewShowOptions, options, extension.identifier, extension.extensionLocation);
const webview = new ExtHostWebview(handle, this._proxy, options); const webview = new ExtHostWebview(handle, this._proxy, options);
const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview); const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview);
......
...@@ -100,18 +100,18 @@ export class QuickInputBox { ...@@ -100,18 +100,18 @@ export class QuickInputBox {
style(theme: ITheme) { style(theme: ITheme) {
this.inputBox.style({ this.inputBox.style({
inputForeground: theme.getColor(inputForeground), inputForeground: theme.getColor(inputForeground) || undefined,
inputBackground: theme.getColor(inputBackground), inputBackground: theme.getColor(inputBackground) || undefined,
inputBorder: theme.getColor(inputBorder), inputBorder: theme.getColor(inputBorder) || undefined,
inputValidationInfoBackground: theme.getColor(inputValidationInfoBackground), inputValidationInfoBackground: theme.getColor(inputValidationInfoBackground) || undefined,
inputValidationInfoForeground: theme.getColor(inputValidationInfoForeground), inputValidationInfoForeground: theme.getColor(inputValidationInfoForeground) || undefined,
inputValidationInfoBorder: theme.getColor(inputValidationInfoBorder), inputValidationInfoBorder: theme.getColor(inputValidationInfoBorder) || undefined,
inputValidationWarningBackground: theme.getColor(inputValidationWarningBackground), inputValidationWarningBackground: theme.getColor(inputValidationWarningBackground) || undefined,
inputValidationWarningForeground: theme.getColor(inputValidationWarningForeground), inputValidationWarningForeground: theme.getColor(inputValidationWarningForeground) || undefined,
inputValidationWarningBorder: theme.getColor(inputValidationWarningBorder), inputValidationWarningBorder: theme.getColor(inputValidationWarningBorder) || undefined,
inputValidationErrorBackground: theme.getColor(inputValidationErrorBackground), inputValidationErrorBackground: theme.getColor(inputValidationErrorBackground) || undefined,
inputValidationErrorForeground: theme.getColor(inputValidationErrorForeground), inputValidationErrorForeground: theme.getColor(inputValidationErrorForeground) || undefined,
inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder), inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder) || undefined,
}); });
} }
......
...@@ -344,6 +344,11 @@ export class ExplorerView extends ViewletPanel { ...@@ -344,6 +344,11 @@ export class ExplorerView extends ViewletPanel {
if (e.browserEvent instanceof MouseEvent) { if (e.browserEvent instanceof MouseEvent) {
isDoubleClick = e.browserEvent.detail === 2; isDoubleClick = e.browserEvent.detail === 2;
if (!this.tree.openOnSingleClick && !isDoubleClick) {
return;
}
isMiddleClick = e.browserEvent.button === 1; isMiddleClick = e.browserEvent.button === 1;
const isLeftButton = e.browserEvent.button === 0; const isLeftButton = e.browserEvent.button === 0;
......
...@@ -365,8 +365,8 @@ class DirtyDiffWidget extends PeekViewWidget { ...@@ -365,8 +365,8 @@ class DirtyDiffWidget extends PeekViewWidget {
arrowColor: borderColor, arrowColor: borderColor,
frameColor: borderColor, frameColor: borderColor,
headerBackgroundColor: theme.getColor(peekViewTitleBackground) || Color.transparent, headerBackgroundColor: theme.getColor(peekViewTitleBackground) || Color.transparent,
primaryHeadingColor: theme.getColor(peekViewTitleForeground), primaryHeadingColor: theme.getColor(peekViewTitleForeground) || undefined,
secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground) secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground) || undefined
}); });
} }
......
...@@ -243,7 +243,7 @@ ...@@ -243,7 +243,7 @@
delete window.frameElement; delete window.frameElement;
`; `;
newDocument.head.prepend(defaultScript, newDocument.head.firstChild); newDocument.head.prepend(defaultScript);
} }
// apply default styles // apply default styles
......
...@@ -12,6 +12,8 @@ import * as vscode from 'vscode'; ...@@ -12,6 +12,8 @@ import * as vscode from 'vscode';
import { WebviewEditorInput } from './webviewEditorInput'; import { WebviewEditorInput } from './webviewEditorInput';
import { GroupIdentifier } from 'vs/workbench/common/editor'; import { GroupIdentifier } from 'vs/workbench/common/editor';
import { equals } from 'vs/base/common/arrays'; import { equals } from 'vs/base/common/arrays';
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
export const IWebviewEditorService = createDecorator<IWebviewEditorService>('webviewEditorService'); export const IWebviewEditorService = createDecorator<IWebviewEditorService>('webviewEditorService');
...@@ -32,6 +34,13 @@ export interface IWebviewEditorService { ...@@ -32,6 +34,13 @@ export interface IWebviewEditorService {
events: WebviewEvents events: WebviewEvents
): WebviewEditorInput; ): WebviewEditorInput;
createInsetWebview(
parent: HTMLElement,
options: vscode.WebviewOptions,
extensionLocation: URI,
events: WebviewEvents
): WebviewEditorInput;
reviveWebview( reviveWebview(
viewType: string, viewType: string,
id: number, id: number,
...@@ -97,6 +106,7 @@ export class WebviewEditorService implements IWebviewEditorService { ...@@ -97,6 +106,7 @@ export class WebviewEditorService implements IWebviewEditorService {
@IEditorService private readonly _editorService: IEditorService, @IEditorService private readonly _editorService: IEditorService,
@IInstantiationService private readonly _instantiationService: IInstantiationService, @IInstantiationService private readonly _instantiationService: IInstantiationService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
@IPartService private readonly _partService: IPartService,
) { } ) { }
createWebview( createWebview(
...@@ -112,6 +122,21 @@ export class WebviewEditorService implements IWebviewEditorService { ...@@ -112,6 +122,21 @@ export class WebviewEditorService implements IWebviewEditorService {
return webviewInput; return webviewInput;
} }
createInsetWebview(
parent: HTMLElement,
options: vscode.WebviewOptions,
extensionLocation: URI,
events: WebviewEvents
): WebviewEditorInput {
const webviewEditorInput = this._instantiationService.createInstance(WebviewEditorInput, 'codeinset', undefined, '', options, {}, events, extensionLocation, undefined);
webviewEditorInput.webview = this._instantiationService.createInstance(WebviewElement,
this._partService.getContainer(Parts.EDITOR_PART),
{ allowSvgs: true, useSameOriginForRoot: true },
{ allowScripts: true, disableFindView: true });
webviewEditorInput.webview.mountTo(parent);
return webviewEditorInput;
}
revealWebview( revealWebview(
webview: WebviewEditorInput, webview: WebviewEditorInput,
group: IEditorGroup, group: IEditorGroup,
......
...@@ -13,12 +13,12 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti ...@@ -13,12 +13,12 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; import * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
import { DARK, ITheme, IThemeService, LIGHT } from 'vs/platform/theme/common/themeService'; import { DARK, ITheme, IThemeService, LIGHT } from 'vs/platform/theme/common/themeService';
import { registerFileProtocol, WebviewProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols'; import { registerFileProtocol, WebviewProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols';
import { areWebviewInputOptionsEqual } from './webviewEditorService';
import { WebviewFindWidget } from './webviewFindWidget'; import { WebviewFindWidget } from './webviewFindWidget';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { endsWith } from 'vs/base/common/strings'; import { endsWith } from 'vs/base/common/strings';
import { isMacintosh } from 'vs/base/common/platform'; import { isMacintosh } from 'vs/base/common/platform';
import { equals } from 'vs/base/common/arrays';
export interface WebviewOptions { export interface WebviewOptions {
readonly allowSvgs?: boolean; readonly allowSvgs?: boolean;
...@@ -30,8 +30,23 @@ export interface WebviewContentOptions { ...@@ -30,8 +30,23 @@ export interface WebviewContentOptions {
readonly allowScripts?: boolean; readonly allowScripts?: boolean;
readonly svgWhiteList?: string[]; readonly svgWhiteList?: string[];
readonly localResourceRoots?: ReadonlyArray<URI>; readonly localResourceRoots?: ReadonlyArray<URI>;
readonly disableFindView?: boolean;
} }
export function areWebviewContentOptionsEqual(a: WebviewContentOptions, b: WebviewContentOptions): boolean {
const sameArray = <T>(a1: ReadonlyArray<T>, a2: ReadonlyArray<T>) =>
(a.localResourceRoots === b.localResourceRoots
|| (Array.isArray(a.localResourceRoots) && Array.isArray(b.localResourceRoots)
&& equals(a.localResourceRoots, b.localResourceRoots, (a, b) => a.toString() === b.toString())));
return a.allowScripts === b.allowScripts
&& a.disableFindView === b.disableFindView
&& sameArray(a.svgWhiteList, b.svgWhiteList)
&& sameArray(a.localResourceRoots, b.localResourceRoots);
}
interface IKeydownEvent { interface IKeydownEvent {
key: string; key: string;
keyCode: number; keyCode: number;
...@@ -248,6 +263,7 @@ export class WebviewElement extends Disposable { ...@@ -248,6 +263,7 @@ export class WebviewElement extends Disposable {
this._webview.setAttribute('partition', `webview${Date.now()}`); this._webview.setAttribute('partition', `webview${Date.now()}`);
this._webview.setAttribute('webpreferences', 'contextIsolation=yes'); this._webview.setAttribute('webpreferences', 'contextIsolation=yes');
this._webview.setAttribute('autosize', 'on');
this._webview.style.flex = '0 1'; this._webview.style.flex = '0 1';
this._webview.style.width = '0'; this._webview.style.width = '0';
...@@ -347,14 +363,18 @@ export class WebviewElement extends Disposable { ...@@ -347,14 +363,18 @@ export class WebviewElement extends Disposable {
this._send('devtools-opened'); this._send('devtools-opened');
})); }));
if (!this.options || !this.options.disableFindView) {
this._webviewFindWidget = this._register(instantiationService.createInstance(WebviewFindWidget, this)); this._webviewFindWidget = this._register(instantiationService.createInstance(WebviewFindWidget, this));
}
this.style(this._themeService.getTheme()); this.style(this._themeService.getTheme());
this._register(this._themeService.onThemeChange(this.style, this)); this._register(this._themeService.onThemeChange(this.style, this));
} }
public mountTo(parent: HTMLElement) { public mountTo(parent: HTMLElement) {
parent.appendChild(this._webviewFindWidget.getDomNode()!); if (this._webviewFindWidget) {
parent.appendChild(this._webviewFindWidget.getDomNode());
}
parent.appendChild(this._webview); parent.appendChild(this._webview);
} }
...@@ -382,6 +402,9 @@ export class WebviewElement extends Disposable { ...@@ -382,6 +402,9 @@ export class WebviewElement extends Disposable {
private readonly _onMessage = this._register(new Emitter<any>()); private readonly _onMessage = this._register(new Emitter<any>());
public readonly onMessage = this._onMessage.event; public readonly onMessage = this._onMessage.event;
private readonly _onLayout = this._register(new Emitter<{ width: number, height: number }>());
public readonly onLayout = this._onLayout.event;
private _send(channel: string, ...args: any[]): void { private _send(channel: string, ...args: any[]): void {
this._ready this._ready
.then(() => this._webview.send(channel, ...args)) .then(() => this._webview.send(channel, ...args))
...@@ -397,7 +420,7 @@ export class WebviewElement extends Disposable { ...@@ -397,7 +420,7 @@ export class WebviewElement extends Disposable {
} }
public set options(value: WebviewContentOptions) { public set options(value: WebviewContentOptions) {
if (this._contentOptions && areWebviewInputOptionsEqual(value, this._contentOptions)) { if (this._contentOptions && areWebviewContentOptionsEqual(value, this._contentOptions)) {
return; return;
} }
...@@ -419,7 +442,7 @@ export class WebviewElement extends Disposable { ...@@ -419,7 +442,7 @@ export class WebviewElement extends Disposable {
} }
public update(value: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { public update(value: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) {
if (retainContextWhenHidden && value === this._contents && this._contentOptions && areWebviewInputOptionsEqual(options, this._contentOptions)) { if (retainContextWhenHidden && value === this._contents && this._contentOptions && areWebviewContentOptionsEqual(options, this._contentOptions)) {
return; return;
} }
this._contents = value; this._contents = value;
...@@ -482,8 +505,9 @@ export class WebviewElement extends Disposable { ...@@ -482,8 +505,9 @@ export class WebviewElement extends Disposable {
const activeTheme = ApiThemeClassName.fromTheme(theme); const activeTheme = ApiThemeClassName.fromTheme(theme);
this._send('styles', styles, activeTheme); this._send('styles', styles, activeTheme);
if (this._webviewFindWidget) {
this._webviewFindWidget.updateTheme(theme); this._webviewFindWidget.updateTheme(theme);
}
} }
public layout(): void { public layout(): void {
...@@ -501,6 +525,11 @@ export class WebviewElement extends Disposable { ...@@ -501,6 +525,11 @@ export class WebviewElement extends Disposable {
} }
contents.setZoomFactor(factor); contents.setZoomFactor(factor);
if (!this._webview || !this._webview.parentElement) {
return;
}
this._onLayout.fire({ width: this._webview.clientWidth, height: this._webview.clientHeight });
}); });
} }
...@@ -551,12 +580,16 @@ export class WebviewElement extends Disposable { ...@@ -551,12 +580,16 @@ export class WebviewElement extends Disposable {
} }
public showFind() { public showFind() {
if (this._webviewFindWidget) {
this._webviewFindWidget.reveal(); this._webviewFindWidget.reveal();
} }
}
public hideFind() { public hideFind() {
if (this._webviewFindWidget) {
this._webviewFindWidget.hide(); this._webviewFindWidget.hide();
} }
}
public reload() { public reload() {
this.contents = this._contents; this.contents = this._contents;
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// import { Registry } from 'vs/platform/registry/common/platform';
// import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
// import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { CancelablePromise, createCancelablePromise, RunOnceScheduler } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors';
import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { StableEditorScrollState } from 'vs/editor/browser/core/editorState';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { IModelDecorationsChangeAccessor } from 'vs/editor/common/model';
import { CodeInsetProviderRegistry } from 'vs/editor/common/modes';
import { CodeInsetWidget, CodeInsetHelper } from './codeInsetWidget';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { getCodeInsetData, ICodeInsetData } from './codeinset';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { MainThreadWebviews } from 'vs/workbench/api/electron-browser/mainThreadWebview';
export class CodeInsetController implements editorCommon.IEditorContribution {
private static readonly ID: string = 'css.editor.codeInset';
private _isEnabled: boolean;
private _globalToDispose: IDisposable[];
private _localToDispose: IDisposable[];
private _insetWidgets: CodeInsetWidget[];
private _currentFindCodeInsetSymbolsPromise: CancelablePromise<ICodeInsetData[]>;
private _modelChangeCounter: number;
private _currentResolveCodeInsetSymbolsPromise: CancelablePromise<any>;
private _detectVisibleInsets: RunOnceScheduler;
private _mainThreadWebviews: MainThreadWebviews;
constructor(
private _editor: editorBrowser.ICodeEditor,
@ICommandService private readonly _commandService: ICommandService,
@INotificationService private readonly _notificationService: INotificationService,
@IExtensionService private readonly _extensionService: IExtensionService
) {
this._isEnabled = this._editor.getConfiguration().contribInfo.codeInsets;
this._globalToDispose = [];
this._localToDispose = [];
this._insetWidgets = [];
this._currentFindCodeInsetSymbolsPromise = null;
this._modelChangeCounter = 0;
this._globalToDispose.push(this._editor.onDidChangeModel(() => this._onModelChange()));
this._globalToDispose.push(this._editor.onDidChangeModelLanguage(() => this._onModelChange()));
this._globalToDispose.push(this._editor.onDidChangeConfiguration(() => {
let prevIsEnabled = this._isEnabled;
this._isEnabled = this._editor.getConfiguration().contribInfo.codeInsets;
if (prevIsEnabled !== this._isEnabled) {
this._onModelChange();
}
}));
this._globalToDispose.push(CodeInsetProviderRegistry.onDidChange(this._onModelChange, this));
this._onModelChange();
}
dispose(): void {
this._localDispose();
this._globalToDispose = dispose(this._globalToDispose);
}
private _localDispose(): void {
if (this._currentFindCodeInsetSymbolsPromise) {
this._currentFindCodeInsetSymbolsPromise.cancel();
this._currentFindCodeInsetSymbolsPromise = null;
this._modelChangeCounter++;
}
if (this._currentResolveCodeInsetSymbolsPromise) {
this._currentResolveCodeInsetSymbolsPromise.cancel();
this._currentResolveCodeInsetSymbolsPromise = null;
}
this._localToDispose = dispose(this._localToDispose);
}
getId(): string {
return CodeInsetController.ID;
}
private _onModelChange(): void {
this._localDispose();
const model = this._editor.getModel();
if (!model || !this._isEnabled || !CodeInsetProviderRegistry.has(model)) {
return;
}
for (const provider of CodeInsetProviderRegistry.all(model)) {
if (typeof provider.onDidChange === 'function') {
let registration = provider.onDidChange(() => scheduler.schedule());
this._localToDispose.push(registration);
}
}
this._detectVisibleInsets = new RunOnceScheduler(() => {
this._onViewportChanged();
}, 500);
const scheduler = new RunOnceScheduler(() => {
const counterValue = ++this._modelChangeCounter;
if (this._currentFindCodeInsetSymbolsPromise) {
this._currentFindCodeInsetSymbolsPromise.cancel();
}
this._currentFindCodeInsetSymbolsPromise = createCancelablePromise(token => getCodeInsetData(model, token));
this._currentFindCodeInsetSymbolsPromise.then(codeInsetData => {
if (counterValue === this._modelChangeCounter) { // only the last one wins
this._renderCodeInsetSymbols(codeInsetData);
this._detectVisibleInsets.schedule();
}
}, onUnexpectedError);
}, 250);
this._localToDispose.push(scheduler);
this._localToDispose.push(this._detectVisibleInsets);
this._localToDispose.push(this._editor.onDidChangeModelContent(() => {
this._editor.changeDecorations(changeAccessor => {
this._editor.changeViewZones(viewAccessor => {
let toDispose: CodeInsetWidget[] = [];
let lastInsetLineNumber: number = -1;
this._insetWidgets.forEach(inset => {
if (!inset.isValid() || lastInsetLineNumber === inset.getLineNumber()) {
// invalid -> Inset collapsed, attach range doesn't exist anymore
// line_number -> insets should never be on the same line
toDispose.push(inset);
}
else {
inset.reposition(viewAccessor);
lastInsetLineNumber = inset.getLineNumber();
}
});
let helper = new CodeInsetHelper();
toDispose.forEach((l) => {
l.dispose(helper, viewAccessor);
this._insetWidgets.splice(this._insetWidgets.indexOf(l), 1);
});
helper.commit(changeAccessor);
});
});
// Compute new `visible` code insets
this._detectVisibleInsets.schedule();
// Ask for all references again
scheduler.schedule();
}));
this._localToDispose.push(this._editor.onDidScrollChange(e => {
if (e.scrollTopChanged && this._insetWidgets.length > 0) {
this._detectVisibleInsets.schedule();
}
}));
this._localToDispose.push(this._editor.onDidLayoutChange(() => {
this._detectVisibleInsets.schedule();
}));
this._localToDispose.push(toDisposable(() => {
if (this._editor.getModel()) {
const scrollState = StableEditorScrollState.capture(this._editor);
this._editor.changeDecorations((changeAccessor) => {
this._editor.changeViewZones((accessor) => {
this._disposeAllInsets(changeAccessor, accessor);
});
});
scrollState.restore(this._editor);
} else {
// No accessors available
this._disposeAllInsets(null, null);
}
}));
scheduler.schedule();
}
private _disposeAllInsets(decChangeAccessor: IModelDecorationsChangeAccessor, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor): void {
let helper = new CodeInsetHelper();
this._insetWidgets.forEach((Inset) => Inset.dispose(helper, viewZoneChangeAccessor));
if (decChangeAccessor) {
helper.commit(decChangeAccessor);
}
this._insetWidgets = [];
}
private _renderCodeInsetSymbols(symbols: ICodeInsetData[]): void {
if (!this._editor.getModel()) {
return;
}
let maxLineNumber = this._editor.getModel().getLineCount();
let groups: ICodeInsetData[][] = [];
let lastGroup: ICodeInsetData[];
for (let symbol of symbols) {
let line = symbol.symbol.range.startLineNumber;
if (line < 1 || line > maxLineNumber) {
// invalid code Inset
continue;
} else if (lastGroup && lastGroup[lastGroup.length - 1].symbol.range.startLineNumber === line) {
// on same line as previous
lastGroup.push(symbol);
} else {
// on later line as previous
lastGroup = [symbol];
groups.push(lastGroup);
}
}
const scrollState = StableEditorScrollState.capture(this._editor);
this._editor.changeDecorations(changeAccessor => {
this._editor.changeViewZones(accessor => {
let codeInsetIndex = 0, groupsIndex = 0, helper = new CodeInsetHelper();
while (groupsIndex < groups.length && codeInsetIndex < this._insetWidgets.length) {
let symbolsLineNumber = groups[groupsIndex][0].symbol.range.startLineNumber;
let codeInsetLineNumber = this._insetWidgets[codeInsetIndex].getLineNumber();
if (codeInsetLineNumber < symbolsLineNumber) {
this._insetWidgets[codeInsetIndex].dispose(helper, accessor);
this._insetWidgets.splice(codeInsetIndex, 1);
} else if (codeInsetLineNumber === symbolsLineNumber) {
this._insetWidgets[codeInsetIndex].updateCodeInsetSymbols(groups[groupsIndex], helper);
groupsIndex++;
codeInsetIndex++;
} else {
this._insetWidgets.splice(codeInsetIndex, 0,
new CodeInsetWidget(groups[groupsIndex],
this._editor, helper,
this._commandService, this._notificationService,
() => this._detectVisibleInsets.schedule()));
codeInsetIndex++;
groupsIndex++;
}
}
// Delete extra code insets
while (codeInsetIndex < this._insetWidgets.length) {
this._insetWidgets[codeInsetIndex].dispose(helper, accessor);
this._insetWidgets.splice(codeInsetIndex, 1);
}
// Create extra symbols
while (groupsIndex < groups.length) {
this._insetWidgets.push(
new CodeInsetWidget(groups[groupsIndex],
this._editor, helper,
this._commandService, this._notificationService,
() => this._detectVisibleInsets.schedule()));
groupsIndex++;
}
helper.commit(changeAccessor);
});
});
scrollState.restore(this._editor);
}
private getWebviewService(): MainThreadWebviews {
if (!this._mainThreadWebviews) {
this._mainThreadWebviews = this._extensionService.getNamedCustomer('MainThreadWebviews');
}
return this._mainThreadWebviews;
}
private _onViewportChanged(): void {
if (this._currentResolveCodeInsetSymbolsPromise) {
this._currentResolveCodeInsetSymbolsPromise.cancel();
this._currentResolveCodeInsetSymbolsPromise = null;
}
const model = this._editor.getModel();
if (!model) {
return;
}
const allWidgetRequests: ICodeInsetData[][] = [];
const insetWidgets: CodeInsetWidget[] = [];
this._insetWidgets.forEach(inset => {
const widgetRequests = inset.computeIfNecessary(model);
if (widgetRequests) {
allWidgetRequests.push(widgetRequests);
insetWidgets.push(inset);
}
});
if (allWidgetRequests.length === 0) {
return;
}
this._currentResolveCodeInsetSymbolsPromise = createCancelablePromise(token => {
const allPromises = allWidgetRequests.map((widgetRequests, r) => {
const widgetPromises = widgetRequests.map(request => {
const symbol = request.symbol;
if (typeof request.provider.resolveCodeInset === 'function') {
const mainThreadWebviews = this.getWebviewService();
symbol.webviewHandle = insetWidgets[r].createWebview(mainThreadWebviews, request.provider.extensionLocation);
return request.provider.resolveCodeInset(model, symbol, token);
}
return Promise.resolve(void 0);
});
return Promise.all(widgetPromises);
});
return Promise.all(allPromises);
});
this._currentResolveCodeInsetSymbolsPromise.then(() => {
this._currentResolveCodeInsetSymbolsPromise = null;
}).catch(err => {
this._currentResolveCodeInsetSymbolsPromise = null;
onUnexpectedError(err);
});
}
}
registerEditorContribution(CodeInsetController);
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions';
import { ICodeInsetSymbol, CodeInsetProvider, CodeInsetProviderRegistry } from 'vs/editor/common/modes';
import { ITextModel } from 'vs/editor/common/model';
import { onUnexpectedExternalError, illegalArgument } from 'vs/base/common/errors';
import { mergeSort } from 'vs/base/common/arrays';
import { URI } from 'vs/base/common/uri';
import { IModelService } from 'vs/editor/common/services/modelService';
import { CancellationToken } from 'vs/base/common/cancellation';
export interface ICodeInsetData {
symbol: ICodeInsetSymbol;
provider: CodeInsetProvider;
}
export function getCodeInsetData(model: ITextModel, token: CancellationToken): Promise<ICodeInsetData[]> {
const symbols: ICodeInsetData[] = [];
const providers = CodeInsetProviderRegistry.ordered(model);
const promises = providers.map(provider =>
Promise.resolve(provider.provideCodeInsets(model, token)).then(result => {
if (Array.isArray(result)) {
for (let symbol of result) {
symbols.push({ symbol, provider });
}
}
}).catch(onUnexpectedExternalError));
return Promise.all(promises).then(() => {
return mergeSort(symbols, (a, b) => {
// sort by lineNumber, provider-rank, and column
if (a.symbol.range.startLineNumber < b.symbol.range.startLineNumber) {
return -1;
} else if (a.symbol.range.startLineNumber > b.symbol.range.startLineNumber) {
return 1;
} else if (providers.indexOf(a.provider) < providers.indexOf(b.provider)) {
return -1;
} else if (providers.indexOf(a.provider) > providers.indexOf(b.provider)) {
return 1;
} else if (a.symbol.range.startColumn < b.symbol.range.startColumn) {
return -1;
} else if (a.symbol.range.startColumn > b.symbol.range.startColumn) {
return 1;
} else {
return 0;
}
});
});
}
registerLanguageCommand('_executeCodeInsetProvider', function (accessor, args) {
let { resource, itemResolveCount } = args;
if (!(resource instanceof URI)) {
throw illegalArgument();
}
const model = accessor.get(IModelService).getModel(resource);
if (!model) {
throw illegalArgument();
}
const result: ICodeInsetSymbol[] = [];
return getCodeInsetData(model, CancellationToken.None).then(value => {
let resolve: Thenable<any>[] = [];
for (const item of value) {
if (typeof itemResolveCount === 'undefined') {
result.push(item.symbol);
} else if (itemResolveCount-- > 0) {
resolve.push(Promise.resolve(item.provider.resolveCodeInset(model, item.symbol, CancellationToken.None))
.then(symbol => result.push(symbol)));
}
}
return Promise.all(resolve);
}).then(() => {
return result;
});
});
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .codelens-decoration {
overflow: hidden;
display: inline-block;
text-overflow: ellipsis;
}
.monaco-editor .codelens-decoration > span,
.monaco-editor .codelens-decoration > a {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
white-space: nowrap;
vertical-align: sub;
}
.monaco-editor .codelens-decoration > a {
text-decoration: none;
}
.monaco-editor .codelens-decoration > a:hover {
text-decoration: underline;
cursor: pointer;
}
.monaco-editor .codelens-decoration.invisible-cl {
opacity: 0;
}
@keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } }
@-moz-keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } }
@-o-keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } }
@-webkit-keyframes fadein { 0% { opacity:0; visibility:visible;} 100% { opacity:1; } }
.monaco-editor .codelens-decoration.fadein {
-webkit-animation: fadein 0.5s linear;
-moz-animation: fadein 0.5s linear;
-o-animation: fadein 0.5s linear;
animation: fadein 0.5s linear;
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./codeInsetWidget';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { Range } from 'vs/editor/common/core/range';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import { ICodeInsetData } from './codeInset';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { IModelDeltaDecoration, IModelDecorationsChangeAccessor, ITextModel } from 'vs/editor/common/model';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { WebviewEditorInput } from 'vs/workbench/contrib/webview/electron-browser/webviewEditorInput';
import { mainThreadWebviews, MainThreadWebviews } from 'vs/workbench/api/electron-browser/mainThreadWebview';
import { UriComponents } from 'vs/base/common/uri';
export interface IDecorationIdCallback {
(decorationId: string): void;
}
export class CodeInsetHelper {
private _removeDecorations: string[];
private _addDecorations: IModelDeltaDecoration[];
private _addDecorationsCallbacks: IDecorationIdCallback[];
constructor() {
this._removeDecorations = [];
this._addDecorations = [];
this._addDecorationsCallbacks = [];
}
addDecoration(decoration: IModelDeltaDecoration, callback: IDecorationIdCallback): void {
this._addDecorations.push(decoration);
this._addDecorationsCallbacks.push(callback);
}
removeDecoration(decorationId: string): void {
this._removeDecorations.push(decorationId);
}
commit(changeAccessor: IModelDecorationsChangeAccessor): void {
let resultingDecorations = changeAccessor.deltaDecorations(this._removeDecorations, this._addDecorations);
for (let i = 0, len = resultingDecorations.length; i < len; i++) {
this._addDecorationsCallbacks[i](resultingDecorations[i]);
}
}
}
export class CodeInsetWidget {
private readonly _editor: editorBrowser.ICodeEditor;
private _viewZone: editorBrowser.IViewZone;
private _viewZoneId?: number = undefined;
private _decorationIds: string[];
private _data: ICodeInsetData[];
private _webview: WebviewEditorInput | undefined;
private _webviewHandle: string | undefined;
private _range: Range;
constructor(
data: ICodeInsetData[], // all the insets on the same line (often just one)
editor: editorBrowser.ICodeEditor,
helper: CodeInsetHelper,
commandService: ICommandService,
notificationService: INotificationService,
updateCallabck: Function
) {
this._editor = editor;
this._data = data;
this._decorationIds = new Array<string>(this._data.length);
this._data.forEach((codeInsetData, i) => {
helper.addDecoration({
range: codeInsetData.symbol.range,
options: ModelDecorationOptions.EMPTY
}, id => this._decorationIds[i] = id);
// the range contains all insets on this line
if (!this._range) {
this._range = Range.lift(codeInsetData.symbol.range);
} else {
this._range = Range.plusRange(this._range, codeInsetData.symbol.range);
}
});
}
public dispose(helper: CodeInsetHelper, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor): void {
console.log('DISPOSE');
while (this._decorationIds.length) {
helper.removeDecoration(this._decorationIds.pop());
}
if (viewZoneChangeAccessor) {
viewZoneChangeAccessor.removeZone(this._viewZoneId);
this._viewZone = undefined;
}
}
public isValid(): boolean {
return this._decorationIds.some((id, i) => {
const range = this._editor.getModel().getDecorationRange(id);
const symbol = this._data[i].symbol;
return range && Range.isEmpty(symbol.range) === range.isEmpty();
});
}
public updateCodeInsetSymbols(data: ICodeInsetData[], helper: CodeInsetHelper): void {
while (this._decorationIds.length) {
helper.removeDecoration(this._decorationIds.pop());
}
this._data = data;
this._decorationIds = new Array<string>(this._data.length);
this._data.forEach((codeInsetData, i) => {
helper.addDecoration({
range: codeInsetData.symbol.range,
options: ModelDecorationOptions.EMPTY
}, id => this._decorationIds[i] = id);
});
}
public computeIfNecessary(model: ITextModel): ICodeInsetData[] {
// Read editor current state
for (let i = 0; i < this._decorationIds.length; i++) {
const range = model.getDecorationRange(this._decorationIds[i]);
if (range) {
this._data[i].symbol.range = range;
}
}
return this._data;
}
public getLineNumber(): number {
const range = this._editor.getModel().getDecorationRange(this._decorationIds[0]);
if (range) {
return range.startLineNumber;
}
return -1;
}
public get webview() { return this._webview; }
static webviewPool = 1;
public createWebview(mainThreadWebview: MainThreadWebviews, extensionLocation: UriComponents) {
if (this._webviewHandle) { return this._webviewHandle; }
const lineNumber = this._range.endLineNumber;
this._editor.changeViewZones(accessor => {
if (this._viewZoneId) {
this._webview.dispose();
accessor.removeZone(this._viewZoneId);
}
const div = document.createElement('div');
this._webviewHandle = CodeInsetWidget.webviewPool++ + '';
this._webview = mainThreadWebviews.createInsetWebview(this._webviewHandle, div, { enableScripts: true }, extensionLocation);
const webview = this._webview.webview;
webview.mountTo(div);
webview.onMessage((e: { type: string, payload: any }) => {
// The webview contents can use a "size-info" message to report its size.
if (e && e.type === 'size-info') {
const margin = e.payload.height > 0 ? 5 : 0;
this._viewZone.heightInPx = e.payload.height + margin;
this._editor.changeViewZones(accessor => {
accessor.layoutZone(this._viewZoneId);
});
}
});
this._viewZone = {
afterLineNumber: lineNumber,
heightInPx: 50,
domNode: div
};
this._viewZoneId = accessor.addZone(this._viewZone);
});
return this._webviewHandle;
}
public reposition(viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor): void {
if (this.isValid() && this._editor.hasModel()) {
const range = this._editor.getModel().getDecorationRange(this._decorationIds[0]);
this._viewZone.afterLineNumber = range.endLineNumber;
viewZoneChangeAccessor.layoutZone(this._viewZoneId);
}
}
}
...@@ -222,6 +222,9 @@ export interface IExtensionService extends ICpuProfilerTarget { ...@@ -222,6 +222,9 @@ export interface IExtensionService extends ICpuProfilerTarget {
* Stops the extension host. * Stops the extension host.
*/ */
stopExtensionHost(): void; stopExtensionHost(): void;
getNamedCustomer?(sid: string): any;
} }
export interface ICpuProfilerTarget { export interface ICpuProfilerTarget {
......
...@@ -48,6 +48,7 @@ export class ExtensionHostProcessManager extends Disposable { ...@@ -48,6 +48,7 @@ export class ExtensionHostProcessManager extends Disposable {
private _extensionHostProcessRPCProtocol: RPCProtocol; private _extensionHostProcessRPCProtocol: RPCProtocol;
private readonly _extensionHostProcessCustomers: IDisposable[]; private readonly _extensionHostProcessCustomers: IDisposable[];
private readonly _extensionHostProcessWorker: IExtensionHostStarter; private readonly _extensionHostProcessWorker: IExtensionHostStarter;
private readonly _namedCustomerById: { [sid: string]: any } = {};
/** /**
* winjs believes a proxy is a promise because it has a `then` method, so wrap the result in an object. * winjs believes a proxy is a promise because it has a `then` method, so wrap the result in an object.
*/ */
...@@ -183,6 +184,7 @@ export class ExtensionHostProcessManager extends Disposable { ...@@ -183,6 +184,7 @@ export class ExtensionHostProcessManager extends Disposable {
const instance = this._instantiationService.createInstance(ctor, extHostContext); const instance = this._instantiationService.createInstance(ctor, extHostContext);
this._extensionHostProcessCustomers.push(instance); this._extensionHostProcessCustomers.push(instance);
this._extensionHostProcessRPCProtocol.set(id, instance); this._extensionHostProcessRPCProtocol.set(id, instance);
this._namedCustomerById[id.sid] = instance;
} }
// Customers // Customers
...@@ -205,6 +207,10 @@ export class ExtensionHostProcessManager extends Disposable { ...@@ -205,6 +207,10 @@ export class ExtensionHostProcessManager extends Disposable {
}); });
} }
public getNamedCustomer(sid: string): any {
return this._namedCustomerById[sid];
}
public activateByEvent(activationEvent: string): Promise<void> { public activateByEvent(activationEvent: string): Promise<void> {
if (this._extensionHostProcessFinishedActivateEvents[activationEvent] || !this._extensionHostProcessProxy) { if (this._extensionHostProcessFinishedActivateEvents[activationEvent] || !this._extensionHostProcessProxy) {
return NO_OP_VOID_PROMISE; return NO_OP_VOID_PROMISE;
......
...@@ -417,6 +417,11 @@ export class ExtensionService extends Disposable implements IExtensionService { ...@@ -417,6 +417,11 @@ export class ExtensionService extends Disposable implements IExtensionService {
this._stopExtensionHostProcess(); this._stopExtensionHostProcess();
} }
public getNamedCustomer(sid: string): any {
const ncs = this._extensionHostProcessManagers.map(m => m.getNamedCustomer(sid)).filter(c => c);
return ncs.length ? ncs[0] : undefined;
}
private _stopExtensionHostProcess(): void { private _stopExtensionHostProcess(): void {
let previouslyActivatedExtensionIds: ExtensionIdentifier[] = []; let previouslyActivatedExtensionIds: ExtensionIdentifier[] = [];
this._extensionHostActiveExtensions.forEach((value) => { this._extensionHostActiveExtensions.forEach((value) => {
......
...@@ -175,6 +175,10 @@ import 'vs/workbench/contrib/outline/browser/outline.contribution'; ...@@ -175,6 +175,10 @@ import 'vs/workbench/contrib/outline/browser/outline.contribution';
// Experiments // Experiments
import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution'; import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution';
// Code Insets
import 'vs/workbench/parts/codeinset/codeInset.contribution';
//#endregion
// Issues // Issues
import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; import 'vs/workbench/contrib/issue/electron-browser/issue.contribution';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册