mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-15 18:46:36 -05:00
Merge from vscode cfc1ab4c5f816765b91fb7ead3c3427a7c8581a3
This commit is contained in:
@@ -89,7 +89,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const webview = this._webviewService.createWebview('' + handle, {
|
||||
const webview = this._webviewService.createWebviewElement('' + handle, {
|
||||
enableFindWidget: false,
|
||||
}, {
|
||||
allowScripts: options.enableScripts,
|
||||
|
||||
@@ -75,7 +75,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
}
|
||||
|
||||
runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise<number | undefined> {
|
||||
return Promise.resolve(this._proxy.$runInTerminal(args));
|
||||
return this._proxy.$runInTerminal(args);
|
||||
}
|
||||
|
||||
// RPC methods (MainThreadDebugServiceShape)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICodeEditor, isCodeEditor, isDiffEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
@@ -22,7 +21,7 @@ import { MainThreadTextEditors } from 'vs/workbench/api/browser/mainThreadEditor
|
||||
import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IExtHostContext, IModelAddedData, ITextEditorAddData, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { EditorViewColumn, editorGroupToViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
import { IEditor as IWorkbenchEditor } from 'vs/workbench/common/editor';
|
||||
import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
@@ -110,8 +109,8 @@ class DocumentAndEditorState {
|
||||
static compute(before: DocumentAndEditorState | undefined, after: DocumentAndEditorState): DocumentAndEditorStateDelta {
|
||||
if (!before) {
|
||||
return new DocumentAndEditorStateDelta(
|
||||
[], values(after.documents),
|
||||
[], values(after.textEditors),
|
||||
[], [...after.documents.values()],
|
||||
[], [...after.textEditors.values()],
|
||||
undefined, after.activeEditor
|
||||
);
|
||||
}
|
||||
@@ -291,11 +290,11 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
}
|
||||
|
||||
private _getActiveEditorFromEditorPart(): IEditor | undefined {
|
||||
let result = this._editorService.activeTextEditorWidget;
|
||||
if (isDiffEditor(result)) {
|
||||
result = result.getModifiedEditor();
|
||||
let activeTextEditorControl = this._editorService.activeTextEditorControl;
|
||||
if (isDiffEditor(activeTextEditorControl)) {
|
||||
activeTextEditorControl = activeTextEditorControl.getModifiedEditor();
|
||||
}
|
||||
return result;
|
||||
return activeTextEditorControl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,17 +435,17 @@ export class MainThreadDocumentsAndEditors {
|
||||
}
|
||||
|
||||
private _findEditorPosition(editor: MainThreadTextEditor): EditorViewColumn | undefined {
|
||||
for (const workbenchEditor of this._editorService.visibleControls) {
|
||||
if (editor.matches(workbenchEditor)) {
|
||||
return editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group);
|
||||
for (const editorPane of this._editorService.visibleEditorPanes) {
|
||||
if (editor.matches(editorPane)) {
|
||||
return editorGroupToViewColumn(this._editorGroupService, editorPane.group);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
findTextEditorIdFor(inputEditor: IWorkbenchEditor): string | undefined {
|
||||
findTextEditorIdFor(editorPane: IEditorPane): string | undefined {
|
||||
for (const [id, editor] of this._textEditors) {
|
||||
if (editor.matches(inputEditor)) {
|
||||
if (editor.matches(editorPane)) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ISingleEditOperation, ITextModel, ITextModelUpdateOptions, IIdentifiedS
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
|
||||
import { IApplyEditsOptions, IEditorPropertiesChangeData, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, IUndoStopOptions, TextEditorRevealType } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IEditor } from 'vs/workbench/common/editor';
|
||||
import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
|
||||
@@ -413,7 +413,7 @@ export class MainThreadTextEditor {
|
||||
return false;
|
||||
}
|
||||
|
||||
public matches(editor: IEditor): boolean {
|
||||
public matches(editor: IEditorPane): boolean {
|
||||
if (!editor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { ISelection } from 'vs/editor/common/core/selection';
|
||||
import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IEditorOptions, ITextEditorOptions, IResourceInput, EditorActivation } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorOptions, ITextEditorOptions, IResourceEditorInput, EditorActivation } from 'vs/platform/editor/common/editor';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
|
||||
@@ -101,10 +101,10 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
|
||||
private _getTextEditorPositionData(): ITextEditorPositionData {
|
||||
const result: ITextEditorPositionData = Object.create(null);
|
||||
for (let workbenchEditor of this._editorService.visibleControls) {
|
||||
const id = this._documentsAndEditors.findTextEditorIdFor(workbenchEditor);
|
||||
for (let editorPane of this._editorService.visibleEditorPanes) {
|
||||
const id = this._documentsAndEditors.findTextEditorIdFor(editorPane);
|
||||
if (id) {
|
||||
result[id] = editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group);
|
||||
result[id] = editorGroupToViewColumn(this._editorGroupService, editorPane.group);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -124,7 +124,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined
|
||||
};
|
||||
|
||||
const input: IResourceInput = {
|
||||
const input: IResourceEditorInput = {
|
||||
resource: uri,
|
||||
options: editorOptions
|
||||
};
|
||||
@@ -151,10 +151,10 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
async $tryHideEditor(id: string): Promise<void> {
|
||||
const mainThreadEditor = this._documentsAndEditors.getEditor(id);
|
||||
if (mainThreadEditor) {
|
||||
const editors = this._editorService.visibleControls;
|
||||
for (let editor of editors) {
|
||||
if (mainThreadEditor.matches(editor)) {
|
||||
return editor.group.closeEditor(editor.input);
|
||||
const editorPanes = this._editorService.visibleEditorPanes;
|
||||
for (let editorPane of editorPanes) {
|
||||
if (mainThreadEditor.matches(editorPane)) {
|
||||
return editorPane.group.closeEditor(editorPane.input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { ITextModel, ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
@@ -367,8 +367,21 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
// --- semantic tokens
|
||||
|
||||
$registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void {
|
||||
this._registrations.set(handle, modes.DocumentSemanticTokensProviderRegistry.register(selector, new MainThreadDocumentSemanticTokensProvider(this._proxy, handle, legend)));
|
||||
$registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend, eventHandle: number | undefined): void {
|
||||
let event: Event<void> | undefined = undefined;
|
||||
if (typeof eventHandle === 'number') {
|
||||
const emitter = new Emitter<void>();
|
||||
this._registrations.set(eventHandle, emitter);
|
||||
event = emitter.event;
|
||||
}
|
||||
this._registrations.set(handle, modes.DocumentSemanticTokensProviderRegistry.register(selector, new MainThreadDocumentSemanticTokensProvider(this._proxy, handle, legend, event)));
|
||||
}
|
||||
|
||||
$emitDocumentSemanticTokensEvent(eventHandle: number): void {
|
||||
const obj = this._registrations.get(eventHandle);
|
||||
if (obj instanceof Emitter) {
|
||||
obj.fire(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
$registerDocumentRangeSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void {
|
||||
@@ -662,6 +675,7 @@ export class MainThreadDocumentSemanticTokensProvider implements modes.DocumentS
|
||||
private readonly _proxy: ExtHostLanguageFeaturesShape,
|
||||
private readonly _handle: number,
|
||||
private readonly _legend: modes.SemanticTokensLegend,
|
||||
public readonly onDidChange: Event<void> | undefined,
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../commo
|
||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { Command } from 'vs/editor/common/modes';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadStatusBar)
|
||||
export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||
@@ -24,7 +25,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||
this.entries.clear();
|
||||
}
|
||||
|
||||
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: string | undefined, color: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined): void {
|
||||
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined): void {
|
||||
const entry: IStatusbarEntry = { text, tooltip, command, color };
|
||||
|
||||
if (typeof priority === 'undefined') {
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
RunOptionsDTO
|
||||
} from 'vs/workbench/api/common/shared/tasks';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
namespace TaskExecutionDTO {
|
||||
export function from(value: TaskExecution): TaskExecutionDTO {
|
||||
@@ -604,7 +605,7 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
return URI.parse(`${info.scheme}://${info.authority}${path}`);
|
||||
},
|
||||
context: this._extHostContext,
|
||||
resolveVariables: (workspaceFolder: IWorkspaceFolder, toResolve: ResolveSet): Promise<ResolvedVariables> => {
|
||||
resolveVariables: (workspaceFolder: IWorkspaceFolder, toResolve: ResolveSet, target: ConfigurationTarget): Promise<ResolvedVariables> => {
|
||||
const vars: string[] = [];
|
||||
toResolve.variables.forEach(item => vars.push(item));
|
||||
return Promise.resolve(this._proxy.$resolveVariables(workspaceFolder.uri, { process: toResolve.process, variables: vars })).then(values => {
|
||||
@@ -613,7 +614,7 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
partiallyResolvedVars.push(entry.value);
|
||||
});
|
||||
return new Promise<ResolvedVariables>((resolve, reject) => {
|
||||
this._configurationResolverService.resolveWithInteraction(workspaceFolder, partiallyResolvedVars, 'tasks').then(resolvedVars => {
|
||||
this._configurationResolverService.resolveWithInteraction(workspaceFolder, partiallyResolvedVars, 'tasks', undefined, target).then(resolvedVars => {
|
||||
const result: ResolvedVariables = {
|
||||
process: undefined,
|
||||
variables: new Map<string, string>()
|
||||
|
||||
@@ -22,8 +22,8 @@ export class MainThreadTheming implements MainThreadThemingShape {
|
||||
this._themeService = themeService;
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTheming);
|
||||
|
||||
this._themeChangeListener = this._themeService.onThemeChange(e => {
|
||||
this._proxy.$onColorThemeChange(this._themeService.getTheme().type);
|
||||
this._themeChangeListener = this._themeService.onDidColorThemeChange(e => {
|
||||
this._proxy.$onColorThemeChange(this._themeService.getColorTheme().type);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { MainContext, MainThreadTimelineShape, IExtHostContext, ExtHostTimelineShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, ITimelineService } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||
import { TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, ITimelineService, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTimeline)
|
||||
export class MainThreadTimeline implements MainThreadTimelineShape {
|
||||
@@ -39,7 +39,7 @@ export class MainThreadTimeline implements MainThreadTimelineShape {
|
||||
this._timelineService.registerTimelineProvider({
|
||||
...provider,
|
||||
onDidChange: onDidChange.event,
|
||||
provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }) {
|
||||
provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions) {
|
||||
return proxy.$getTimeline(provider.id, uri, options, token, internalOptions);
|
||||
},
|
||||
dispose() {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { MainThreadTunnelServiceShape, IExtHostContext, MainContext, ExtHostContext, ExtHostTunnelServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { IRemoteExplorerService, MakeAddress } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { ITunnelProvider, ITunnelService, TunnelOptions } from 'vs/platform/remote/common/tunnel';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import type { TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
@@ -51,6 +51,10 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
|
||||
this.remoteExplorerService.registerCandidateFinder(() => this._proxy.$findCandidatePorts());
|
||||
}
|
||||
|
||||
async $tunnelServiceReady(): Promise<void> {
|
||||
return this.remoteExplorerService.restore();
|
||||
}
|
||||
|
||||
async $setTunnelProvider(): Promise<void> {
|
||||
const tunnelProvider: ITunnelProvider = {
|
||||
forwardPort: (tunnelOptions: TunnelOptions) => {
|
||||
@@ -60,9 +64,12 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
|
||||
return {
|
||||
tunnelRemotePort: tunnel.remoteAddress.port,
|
||||
tunnelRemoteHost: tunnel.remoteAddress.host,
|
||||
localAddress: tunnel.localAddress,
|
||||
dispose: () => {
|
||||
this._proxy.$closeTunnel({ host: tunnel.remoteAddress.host, port: tunnel.remoteAddress.port });
|
||||
localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : MakeAddress(tunnel.localAddress.host, tunnel.localAddress.port),
|
||||
tunnelLocalPort: typeof tunnel.localAddress !== 'string' ? tunnel.localAddress.port : undefined,
|
||||
dispose: (silent: boolean) => {
|
||||
if (!silent) {
|
||||
this._proxy.$closeTunnel({ host: tunnel.remoteAddress.host, port: tunnel.remoteAddress.port });
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -3,32 +3,38 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createCancelablePromise } from 'vs/base/common/async';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore, IDisposable, IReference, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
|
||||
import { IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IEditorInput, IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { CustomEditorInput, ModelType } from 'vs/workbench/contrib/customEditor/browser/customEditorInput';
|
||||
import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput';
|
||||
import { ICustomEditorModel, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { WebviewExtensionDescription } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { CustomTextEditorModel } from 'vs/workbench/contrib/customEditor/common/customTextEditorModel';
|
||||
import { WebviewExtensionDescription, WebviewIcons } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { ICreateWebViewShowOptions, IWebviewWorkbenchService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IWorkingCopy, IWorkingCopyBackup, IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
|
||||
/**
|
||||
@@ -74,12 +80,17 @@ class WebviewViewTypeTransformer {
|
||||
}
|
||||
|
||||
public toExternal(viewType: string): string | undefined {
|
||||
return startsWith(viewType, this.prefix)
|
||||
return viewType.startsWith(this.prefix)
|
||||
? viewType.substr(this.prefix.length)
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const enum ModelType {
|
||||
Custom,
|
||||
Text,
|
||||
}
|
||||
|
||||
const webviewPanelViewType = new WebviewViewTypeTransformer('mainThreadWebview-');
|
||||
|
||||
@extHostNamedCustomer(extHostProtocol.MainContext.MainThreadWebviews)
|
||||
@@ -97,7 +108,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
private readonly _webviewInputs = new WebviewInputStore();
|
||||
private readonly _revivers = new Map<string, IDisposable>();
|
||||
private readonly _editorProviders = new Map<string, IDisposable>();
|
||||
private readonly _customEditorModels = new Map<string, { referenceCount: number }>();
|
||||
private readonly _webviewFromDiffEditorHandles = new Set<string>();
|
||||
|
||||
constructor(
|
||||
context: extHostProtocol.IExtHostContext,
|
||||
@@ -109,13 +120,24 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviews);
|
||||
this._register(_editorService.onDidActiveEditorChange(this.updateWebviewViewStates, this));
|
||||
this._register(_editorService.onDidVisibleEditorsChange(this.updateWebviewViewStates, this));
|
||||
|
||||
this._register(_editorService.onDidActiveEditorChange(() => {
|
||||
const activeInput = this._editorService.activeEditor;
|
||||
if (activeInput instanceof DiffEditorInput && activeInput.master instanceof WebviewInput && activeInput.details instanceof WebviewInput) {
|
||||
this.registerWebviewFromDiffEditorListeners(activeInput);
|
||||
}
|
||||
|
||||
this.updateWebviewViewStates(activeInput);
|
||||
}));
|
||||
|
||||
this._register(_editorService.onDidVisibleEditorsChange(() => {
|
||||
this.updateWebviewViewStates(this._editorService.activeEditor);
|
||||
}));
|
||||
|
||||
// This reviver's only job is to activate webview panel extensions
|
||||
// This should trigger the real reviver to be registered from the extension host side.
|
||||
@@ -264,7 +286,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
return this.registerEditorProvider(ModelType.Custom, extensionData, viewType, options);
|
||||
}
|
||||
|
||||
public registerEditorProvider(
|
||||
private registerEditorProvider(
|
||||
modelType: ModelType,
|
||||
extensionData: extHostProtocol.WebviewExtensionDescription,
|
||||
viewType: string,
|
||||
@@ -287,16 +309,13 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
|
||||
webviewInput.webview.options = options;
|
||||
webviewInput.webview.extension = extension;
|
||||
webviewInput.modelType = modelType;
|
||||
|
||||
const resource = webviewInput.resource;
|
||||
|
||||
if (modelType === ModelType.Custom) {
|
||||
const model = await this.retainCustomEditorModel(webviewInput, resource, viewType);
|
||||
webviewInput.onDisposeWebview(() => {
|
||||
this.releaseCustomEditorModel(model);
|
||||
});
|
||||
}
|
||||
const modelRef = await this.getOrCreateCustomEditorModel(modelType, webviewInput, resource, viewType);
|
||||
webviewInput.webview.onDispose(() => {
|
||||
modelRef.dispose();
|
||||
});
|
||||
|
||||
try {
|
||||
await this._proxy.$resolveWebviewEditor(
|
||||
@@ -328,71 +347,27 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
this._customEditorService.models.disposeAllModelsForView(viewType);
|
||||
}
|
||||
|
||||
private async retainCustomEditorModel(webviewInput: WebviewInput, resource: URI, viewType: string) {
|
||||
const model = await this._customEditorService.models.resolve(webviewInput.resource, webviewInput.viewType);
|
||||
|
||||
const key = viewType + resource.toString();
|
||||
const existingEntry = this._customEditorModels.get(key);
|
||||
if (existingEntry) {
|
||||
++existingEntry.referenceCount;
|
||||
// no need to hook up listeners again
|
||||
return model;
|
||||
}
|
||||
this._customEditorModels.set(key, { referenceCount: 1 });
|
||||
const { editable } = await this._proxy.$createWebviewCustomEditorDocument(resource, viewType);
|
||||
|
||||
if (editable) {
|
||||
model.onUndo(() => {
|
||||
this._proxy.$undo(resource, viewType);
|
||||
});
|
||||
|
||||
model.onRedo(() => {
|
||||
this._proxy.$redo(resource, viewType);
|
||||
});
|
||||
|
||||
model.onWillSave(e => {
|
||||
e.waitUntil(this._proxy.$onSave(resource.toJSON(), viewType));
|
||||
});
|
||||
private async getOrCreateCustomEditorModel(
|
||||
modelType: ModelType,
|
||||
webviewInput: WebviewInput,
|
||||
resource: URI,
|
||||
viewType: string,
|
||||
): Promise<IReference<ICustomEditorModel>> {
|
||||
const existingModel = this._customEditorService.models.tryRetain(webviewInput.resource, webviewInput.viewType);
|
||||
if (existingModel) {
|
||||
return existingModel;
|
||||
}
|
||||
|
||||
// Save as should always be implemented even if the model is readonly
|
||||
model.onWillSaveAs(e => {
|
||||
if (editable) {
|
||||
e.waitUntil(this._proxy.$onSaveAs(e.resource.toJSON(), viewType, e.targetResource.toJSON()));
|
||||
} else {
|
||||
// Since the editor is readonly, just copy the file over
|
||||
e.waitUntil(this._fileService.copy(e.resource, e.targetResource, false /* overwrite */));
|
||||
}
|
||||
});
|
||||
const model = modelType === ModelType.Text
|
||||
? CustomTextEditorModel.create(this._instantiationService, viewType, resource)
|
||||
: MainThreadCustomEditorModel.create(this._instantiationService, this._proxy, viewType, resource);
|
||||
|
||||
model.onBackup(() => {
|
||||
return createCancelablePromise(token =>
|
||||
this._proxy.$backup(model.resource.toJSON(), viewType, token));
|
||||
});
|
||||
|
||||
return model;
|
||||
return this._customEditorService.models.add(resource, viewType, model);
|
||||
}
|
||||
|
||||
private async releaseCustomEditorModel(model: ICustomEditorModel) {
|
||||
const key = model.viewType + model.resource;
|
||||
const entry = this._customEditorModels.get(key);
|
||||
if (!entry) {
|
||||
throw new Error('Model not found');
|
||||
}
|
||||
|
||||
--entry.referenceCount;
|
||||
if (entry.referenceCount <= 0) {
|
||||
this._proxy.$disposeWebviewCustomEditorDocument(model.resource, model.viewType);
|
||||
this._customEditorService.models.disposeModel(model);
|
||||
this._customEditorModels.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public $onDidChangeCustomDocumentState(resource: UriComponents, viewType: string, state: { dirty: boolean }) {
|
||||
const model = this._customEditorService.models.get(URI.revive(resource), viewType);
|
||||
if (!model) {
|
||||
public async $onDidChangeCustomDocumentState(resource: UriComponents, viewType: string, state: { dirty: boolean }) {
|
||||
const model = await this._customEditorService.models.get(URI.revive(resource), viewType);
|
||||
if (!model || !(model instanceof MainThreadCustomEditorModel)) {
|
||||
throw new Error('Could not find model for webview editor');
|
||||
}
|
||||
model.setDirty(state.dirty);
|
||||
@@ -408,19 +383,39 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
input.onDispose(() => {
|
||||
disposables.dispose();
|
||||
});
|
||||
input.onDisposeWebview(() => {
|
||||
input.webview.onDispose(() => {
|
||||
this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => {
|
||||
this._webviewInputs.delete(handle);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private updateWebviewViewStates() {
|
||||
private registerWebviewFromDiffEditorListeners(diffEditorInput: DiffEditorInput): void {
|
||||
const master = diffEditorInput.master as WebviewInput;
|
||||
const details = diffEditorInput.details as WebviewInput;
|
||||
|
||||
if (this._webviewFromDiffEditorHandles.has(master.id) || this._webviewFromDiffEditorHandles.has(details.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._webviewFromDiffEditorHandles.add(master.id);
|
||||
this._webviewFromDiffEditorHandles.add(details.id);
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
disposables.add(master.webview.onDidFocus(() => this.updateWebviewViewStates(master)));
|
||||
disposables.add(details.webview.onDidFocus(() => this.updateWebviewViewStates(details)));
|
||||
disposables.add(diffEditorInput.onDispose(() => {
|
||||
this._webviewFromDiffEditorHandles.delete(master.id);
|
||||
this._webviewFromDiffEditorHandles.delete(details.id);
|
||||
dispose(disposables);
|
||||
}));
|
||||
}
|
||||
|
||||
private updateWebviewViewStates(activeEditorInput: IEditorInput | undefined) {
|
||||
if (!this._webviewInputs.size) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeInput = this._editorService.activeControl && this._editorService.activeControl.input;
|
||||
const viewStates: extHostProtocol.WebviewPanelViewStateData = {};
|
||||
|
||||
const updateViewStatesForInput = (group: IEditorGroup, topLevelInput: IEditorInput, editorInput: IEditorInput) => {
|
||||
@@ -434,7 +429,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
if (handle) {
|
||||
viewStates[handle] = {
|
||||
visible: topLevelInput === group.activeEditor,
|
||||
active: topLevelInput === activeInput,
|
||||
active: editorInput === activeEditorInput,
|
||||
position: editorGroupToViewColumn(this._editorGroupService, group.id),
|
||||
};
|
||||
}
|
||||
@@ -476,7 +471,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
private getWebviewInput(handle: extHostProtocol.WebviewPanelHandle): WebviewInput {
|
||||
const webview = this.tryGetWebviewInput(handle);
|
||||
if (!webview) {
|
||||
throw new Error('Unknown webview handle:' + handle);
|
||||
throw new Error(`Unknown webview handle:${handle}`);
|
||||
}
|
||||
return webview;
|
||||
}
|
||||
@@ -492,7 +487,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none';">
|
||||
</head>
|
||||
<body>${localize('errorMessage', "An error occurred while restoring view:{0}", viewType)}</body>
|
||||
<body>${localize('errorMessage', "An error occurred while restoring view:{0}", escape(viewType))}</body>
|
||||
</html>`;
|
||||
}
|
||||
}
|
||||
@@ -511,13 +506,179 @@ function reviveWebviewOptions(options: modes.IWebviewOptions): WebviewInputOptio
|
||||
|
||||
function reviveWebviewIcon(
|
||||
value: { light: UriComponents, dark: UriComponents; } | undefined
|
||||
): { light: URI, dark: URI; } | undefined {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
): WebviewIcons | undefined {
|
||||
return value
|
||||
? { light: URI.revive(value.light), dark: URI.revive(value.dark) }
|
||||
: undefined;
|
||||
}
|
||||
|
||||
namespace HotExitState {
|
||||
export const enum Type {
|
||||
Allowed,
|
||||
NotAllowed,
|
||||
Pending,
|
||||
}
|
||||
|
||||
return {
|
||||
light: URI.revive(value.light),
|
||||
dark: URI.revive(value.dark)
|
||||
};
|
||||
export const Allowed = Object.freeze({ type: Type.Allowed } as const);
|
||||
export const NotAllowed = Object.freeze({ type: Type.NotAllowed } as const);
|
||||
|
||||
export class Pending {
|
||||
readonly type = Type.Pending;
|
||||
|
||||
constructor(
|
||||
public readonly operation: CancelablePromise<void>,
|
||||
) { }
|
||||
}
|
||||
|
||||
export type State = typeof Allowed | typeof NotAllowed | Pending;
|
||||
}
|
||||
|
||||
class MainThreadCustomEditorModel extends Disposable implements ICustomEditorModel, IWorkingCopy {
|
||||
|
||||
private _hotExitState: HotExitState.State = HotExitState.Allowed;
|
||||
private _dirty = false;
|
||||
|
||||
public static async create(
|
||||
instantiationService: IInstantiationService,
|
||||
proxy: extHostProtocol.ExtHostWebviewsShape,
|
||||
viewType: string,
|
||||
resource: URI
|
||||
) {
|
||||
const { editable } = await proxy.$createWebviewCustomEditorDocument(resource, viewType);
|
||||
return instantiationService.createInstance(MainThreadCustomEditorModel, proxy, viewType, resource, editable);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: extHostProtocol.ExtHostWebviewsShape,
|
||||
private readonly _viewType: string,
|
||||
private readonly _resource: URI,
|
||||
private readonly _editable: boolean,
|
||||
@IWorkingCopyService workingCopyService: IWorkingCopyService,
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
) {
|
||||
super();
|
||||
this._register(workingCopyService.registerWorkingCopy(this));
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._proxy.$disposeWebviewCustomEditorDocument(this.resource, this._viewType);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
//#region IWorkingCopy
|
||||
|
||||
public get resource() { return this._resource; }
|
||||
|
||||
public get name() {
|
||||
return basename(this._labelService.getUriLabel(this._resource));
|
||||
}
|
||||
|
||||
public get capabilities(): WorkingCopyCapabilities {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public isDirty(): boolean {
|
||||
return this._dirty;
|
||||
}
|
||||
|
||||
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeDirty: Event<void> = this._onDidChangeDirty.event;
|
||||
|
||||
private readonly _onDidChangeContent: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeContent: Event<void> = this._onDidChangeContent.event;
|
||||
|
||||
//#endregion
|
||||
|
||||
public get viewType() {
|
||||
return this._viewType;
|
||||
}
|
||||
|
||||
public setDirty(dirty: boolean): void {
|
||||
this._onDidChangeContent.fire();
|
||||
|
||||
if (this._dirty !== dirty) {
|
||||
this._dirty = dirty;
|
||||
this._onDidChangeDirty.fire();
|
||||
}
|
||||
}
|
||||
|
||||
public async revert(_options?: IRevertOptions) {
|
||||
if (this._editable) {
|
||||
this._proxy.$revert(this.resource, this.viewType);
|
||||
}
|
||||
}
|
||||
|
||||
public undo() {
|
||||
if (this._editable) {
|
||||
this._proxy.$undo(this.resource, this.viewType);
|
||||
}
|
||||
}
|
||||
|
||||
public redo() {
|
||||
if (this._editable) {
|
||||
this._proxy.$redo(this.resource, this.viewType);
|
||||
}
|
||||
}
|
||||
|
||||
public async save(_options?: ISaveOptions): Promise<boolean> {
|
||||
if (!this._editable) {
|
||||
return false;
|
||||
}
|
||||
await createCancelablePromise(token => this._proxy.$onSave(this.resource, this.viewType, token));
|
||||
this.setDirty(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async saveAs(resource: URI, targetResource: URI, _options?: ISaveOptions): Promise<boolean> {
|
||||
if (this._editable) {
|
||||
await this._proxy.$onSaveAs(this.resource, this.viewType, targetResource);
|
||||
this.setDirty(false);
|
||||
return true;
|
||||
} else {
|
||||
// Since the editor is readonly, just copy the file over
|
||||
await this._fileService.copy(resource, targetResource, false /* overwrite */);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public async backup(): Promise<IWorkingCopyBackup> {
|
||||
const backupData: IWorkingCopyBackup = {
|
||||
meta: {
|
||||
viewType: this.viewType,
|
||||
}
|
||||
};
|
||||
|
||||
if (!this._editable) {
|
||||
return backupData;
|
||||
}
|
||||
|
||||
if (this._hotExitState.type === HotExitState.Type.Pending) {
|
||||
this._hotExitState.operation.cancel();
|
||||
}
|
||||
|
||||
const pendingState = new HotExitState.Pending(
|
||||
createCancelablePromise(token =>
|
||||
this._proxy.$backup(this.resource.toJSON(), this.viewType, token)));
|
||||
this._hotExitState = pendingState;
|
||||
|
||||
try {
|
||||
await pendingState.operation;
|
||||
// Make sure state has not changed in the meantime
|
||||
if (this._hotExitState === pendingState) {
|
||||
this._hotExitState = HotExitState.Allowed;
|
||||
}
|
||||
} catch (e) {
|
||||
// Make sure state has not changed in the meantime
|
||||
if (this._hotExitState === pendingState) {
|
||||
this._hotExitState = HotExitState.NotAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._hotExitState === HotExitState.Allowed) {
|
||||
return backupData;
|
||||
}
|
||||
|
||||
throw new Error('Cannot back up in this state');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { isNative } from 'vs/base/common/platform';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/workbench/services/search/common/search';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspace, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -138,7 +138,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
}
|
||||
|
||||
const query = this._queryBuilder.file(
|
||||
includeFolder ? [includeFolder] : workspace.folders.map(f => f.uri),
|
||||
includeFolder ? [toWorkspaceFolder(includeFolder)] : workspace.folders,
|
||||
{
|
||||
maxResults: withNullAsUndefined(maxResults),
|
||||
disregardExcludeSettings: (excludePatternOrDisregardExcludes === false) || undefined,
|
||||
@@ -190,7 +190,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
|
||||
$checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise<boolean> {
|
||||
const queryBuilder = this._instantiationService.createInstance(QueryBuilder);
|
||||
const query = queryBuilder.file(folders.map(folder => URI.revive(folder)), {
|
||||
const query = queryBuilder.file(folders.map(folder => toWorkspaceFolder(URI.revive(folder))), {
|
||||
_reason: 'checkExists',
|
||||
includePattern: includes.join(', '),
|
||||
expandPatterns: true,
|
||||
|
||||
@@ -9,7 +9,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { ExtensionMessageCollector, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { ViewContainer, IViewsRegistry, ITreeViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, TEST_VIEW_CONTAINER_ID, IViewDescriptor, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { CustomTreeViewPane, CustomTreeView } from 'vs/workbench/browser/parts/views/customView';
|
||||
import { TreeViewPane, CustomTreeView } from 'vs/workbench/browser/parts/views/treeView';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { coalesce, } from 'vs/base/common/arrays';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
@@ -396,7 +396,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
const viewDescriptor = <ICustomViewDescriptor>{
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
ctorDescriptor: new SyncDescriptor(CustomTreeViewPane),
|
||||
ctorDescriptor: new SyncDescriptor(TreeViewPane),
|
||||
when: ContextKeyExpr.deserialize(item.when),
|
||||
canToggleVisibility: true,
|
||||
canMoveView: true,
|
||||
|
||||
@@ -146,7 +146,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostClipboard = new ExtHostClipboard(rpcProtocol);
|
||||
const extHostMessageService = new ExtHostMessageService(rpcProtocol, extHostLogService);
|
||||
const extHostDialogs = new ExtHostDialogs(rpcProtocol);
|
||||
const extHostStatusBar = new ExtHostStatusBar(rpcProtocol);
|
||||
const extHostStatusBar = new ExtHostStatusBar(rpcProtocol, extHostCommands.converter);
|
||||
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments);
|
||||
|
||||
// Register API-ish commands
|
||||
@@ -188,12 +188,21 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
registerAuthenticationProvider(provider: vscode.AuthenticationProvider): vscode.Disposable {
|
||||
return extHostAuthentication.registerAuthenticationProvider(provider);
|
||||
},
|
||||
get providers() {
|
||||
return extHostAuthentication.providers(extension);
|
||||
},
|
||||
get onDidChangeAuthenticationProviders(): Event<vscode.AuthenticationProvidersChangeEvent> {
|
||||
return extHostAuthentication.onDidChangeAuthenticationProviders;
|
||||
}
|
||||
},
|
||||
get providerIds(): string[] {
|
||||
return extHostAuthentication.providerIds;
|
||||
},
|
||||
getSessions(providerId: string, scopes: string[]): Thenable<readonly vscode.AuthenticationSession[]> {
|
||||
return extHostAuthentication.getSessions(extension, providerId, scopes);
|
||||
},
|
||||
login(providerId: string, scopes: string[]): Thenable<vscode.AuthenticationSession> {
|
||||
return extHostAuthentication.login(extension, providerId, scopes);
|
||||
},
|
||||
get onDidChangeSessions(): Event<string[]> {
|
||||
return extHostAuthentication.onDidChangeSessions;
|
||||
},
|
||||
};
|
||||
|
||||
// namespace: commands
|
||||
@@ -769,11 +778,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostTunnelService.onDidChangeTunnels(listener, thisArg, disposables);
|
||||
|
||||
},
|
||||
onDidTunnelsChange: (listener, thisArg?, disposables?) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostTunnelService.onDidChangeTunnels(listener, thisArg, disposables);
|
||||
|
||||
},
|
||||
registerTimelineProvider: (scheme: string | string[], provider: vscode.TimelineProvider) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
@@ -1037,6 +1041,7 @@ class Extension<T> implements vscode.Extension<T> {
|
||||
private _identifier: ExtensionIdentifier;
|
||||
|
||||
readonly id: string;
|
||||
readonly extensionUri: URI;
|
||||
readonly extensionPath: string;
|
||||
readonly packageJSON: IExtensionDescription;
|
||||
readonly extensionKind: vscode.ExtensionKind;
|
||||
@@ -1046,6 +1051,7 @@ class Extension<T> implements vscode.Extension<T> {
|
||||
this._originExtensionId = originExtensionId;
|
||||
this._identifier = description.identifier;
|
||||
this.id = description.identifier.value;
|
||||
this.extensionUri = description.extensionLocation;
|
||||
this.extensionPath = path.normalize(originalFSPath(description.extensionLocation));
|
||||
this.packageJSON = description;
|
||||
this.extensionKind = kind;
|
||||
|
||||
@@ -49,7 +49,7 @@ import { SaveReason } from 'vs/workbench/common/editor';
|
||||
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
|
||||
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { Dto } from 'vs/base/common/types';
|
||||
@@ -371,7 +371,8 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void;
|
||||
$registerNavigateTypeSupport(handle: number): void;
|
||||
$registerRenameSupport(handle: number, selector: IDocumentFilterDto[], supportsResolveInitialValues: boolean): void;
|
||||
$registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void;
|
||||
$registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend, eventHandle: number | undefined): void;
|
||||
$emitDocumentSemanticTokensEvent(eventHandle: number): void;
|
||||
$registerDocumentRangeSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void;
|
||||
$registerSuggestSupport(handle: number, selector: IDocumentFilterDto[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void;
|
||||
$registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void;
|
||||
@@ -536,7 +537,7 @@ export interface MainThreadQuickOpenShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadStatusBarShape extends IDisposable {
|
||||
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: string | undefined, color: string | ThemeColor | undefined, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void;
|
||||
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: ICommandDto | undefined, color: string | ThemeColor | undefined, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void;
|
||||
$dispose(id: number): void;
|
||||
}
|
||||
|
||||
@@ -621,7 +622,7 @@ export interface ExtHostWebviewsShape {
|
||||
$undo(resource: UriComponents, viewType: string): void;
|
||||
$redo(resource: UriComponents, viewType: string): void;
|
||||
$revert(resource: UriComponents, viewType: string): void;
|
||||
$onSave(resource: UriComponents, viewType: string): Promise<void>;
|
||||
$onSave(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;
|
||||
$onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents): Promise<void>;
|
||||
|
||||
$backup(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;
|
||||
@@ -804,6 +805,7 @@ export interface MainThreadTunnelServiceShape extends IDisposable {
|
||||
$registerCandidateFinder(): Promise<void>;
|
||||
$setTunnelProvider(): Promise<void>;
|
||||
$setCandidateFilter(): Promise<void>;
|
||||
$tunnelServiceReady(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadTimelineShape extends IDisposable {
|
||||
@@ -1472,7 +1474,7 @@ export interface ExtHostTunnelServiceShape {
|
||||
}
|
||||
|
||||
export interface ExtHostTimelineShape {
|
||||
$getTimeline(source: string, uri: UriComponents, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise<Timeline | undefined>;
|
||||
$getTimeline(source: string, uri: UriComponents, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions): Promise<Timeline | undefined>;
|
||||
}
|
||||
|
||||
// --- proxy identifiers
|
||||
|
||||
@@ -174,7 +174,7 @@ const newCommands: ApiCommand[] = [
|
||||
// -- selection range
|
||||
new ApiCommand(
|
||||
'vscode.executeSelectionRangeProvider', '_executeSelectionRangeProvider', 'Execute selection range provider.',
|
||||
[ApiCommandArgument.Uri, new ApiCommandArgument('position', 'A positions in a text document', v => Array.isArray(v) && v.every(v => types.Position.isPosition(v)), v => v.map(typeConverters.Position.from))],
|
||||
[ApiCommandArgument.Uri, new ApiCommandArgument<types.Position[], IPosition[]>('position', 'A positions in a text document', v => Array.isArray(v) && v.every(v => types.Position.isPosition(v)), v => v.map(typeConverters.Position.from))],
|
||||
new ApiCommandResult<IRange[][], types.SelectionRange[]>('A promise that resolves to an array of ranges.', result => {
|
||||
return result.map(ranges => {
|
||||
let node: types.SelectionRange | undefined;
|
||||
|
||||
@@ -10,61 +10,6 @@ import { IMainContext, MainContext, MainThreadAuthenticationShape, ExtHostAuthen
|
||||
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
export class AuthenticationProviderWrapper implements vscode.AuthenticationProvider {
|
||||
readonly onDidChangeSessions: vscode.Event<void>;
|
||||
|
||||
constructor(private _requestingExtension: IExtensionDescription,
|
||||
private _provider: vscode.AuthenticationProvider,
|
||||
private _proxy: MainThreadAuthenticationShape) {
|
||||
|
||||
this.onDidChangeSessions = this._provider.onDidChangeSessions;
|
||||
}
|
||||
|
||||
get id(): string {
|
||||
return this._provider.id;
|
||||
}
|
||||
|
||||
get displayName(): string {
|
||||
return this._provider.displayName;
|
||||
}
|
||||
|
||||
async getSessions(): Promise<ReadonlyArray<vscode.AuthenticationSession>> {
|
||||
return (await this._provider.getSessions()).map(session => {
|
||||
return {
|
||||
id: session.id,
|
||||
accountName: session.accountName,
|
||||
scopes: session.scopes,
|
||||
getAccessToken: async () => {
|
||||
const isAllowed = await this._proxy.$getSessionsPrompt(
|
||||
this._provider.id,
|
||||
this.displayName,
|
||||
ExtensionIdentifier.toKey(this._requestingExtension.identifier),
|
||||
this._requestingExtension.displayName || this._requestingExtension.name);
|
||||
|
||||
if (!isAllowed) {
|
||||
throw new Error('User did not consent to token access.');
|
||||
}
|
||||
|
||||
return session.getAccessToken();
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async login(scopes: string[]): Promise<vscode.AuthenticationSession> {
|
||||
const isAllowed = await this._proxy.$loginPrompt(this._provider.id, this.displayName, ExtensionIdentifier.toKey(this._requestingExtension.identifier), this._requestingExtension.displayName || this._requestingExtension.name);
|
||||
if (!isAllowed) {
|
||||
throw new Error('User did not consent to login.');
|
||||
}
|
||||
|
||||
return this._provider.login(scopes);
|
||||
}
|
||||
|
||||
logout(sessionId: string): Thenable<void> {
|
||||
return this._provider.logout(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
private _proxy: MainThreadAuthenticationShape;
|
||||
private _authenticationProviders: Map<string, vscode.AuthenticationProvider> = new Map<string, vscode.AuthenticationProvider>();
|
||||
@@ -72,14 +17,65 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
private _onDidChangeAuthenticationProviders = new Emitter<vscode.AuthenticationProvidersChangeEvent>();
|
||||
readonly onDidChangeAuthenticationProviders: Event<vscode.AuthenticationProvidersChangeEvent> = this._onDidChangeAuthenticationProviders.event;
|
||||
|
||||
private _onDidChangeSessions = new Emitter<string[]>();
|
||||
readonly onDidChangeSessions: Event<string[]> = this._onDidChangeSessions.event;
|
||||
|
||||
constructor(mainContext: IMainContext) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadAuthentication);
|
||||
}
|
||||
|
||||
providers(requestingExtension: IExtensionDescription): vscode.AuthenticationProvider[] {
|
||||
let providers: vscode.AuthenticationProvider[] = [];
|
||||
this._authenticationProviders.forEach(provider => providers.push(new AuthenticationProviderWrapper(requestingExtension, provider, this._proxy)));
|
||||
return providers;
|
||||
get providerIds(): string[] {
|
||||
const ids: string[] = [];
|
||||
this._authenticationProviders.forEach(provider => {
|
||||
ids.push(provider.id);
|
||||
});
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
async getSessions(requestingExtension: IExtensionDescription, providerId: string, scopes: string[]): Promise<readonly vscode.AuthenticationSession[]> {
|
||||
const provider = this._authenticationProviders.get(providerId);
|
||||
if (!provider) {
|
||||
throw new Error(`No authentication provider with id '${providerId}' is currently registered.`);
|
||||
}
|
||||
|
||||
const orderedScopes = scopes.sort().join(' ');
|
||||
return (await provider.getSessions())
|
||||
.filter(session => session.scopes.sort().join(' ') === orderedScopes)
|
||||
.map(session => {
|
||||
return {
|
||||
id: session.id,
|
||||
accountName: session.accountName,
|
||||
scopes: session.scopes,
|
||||
getAccessToken: async () => {
|
||||
const isAllowed = await this._proxy.$getSessionsPrompt(
|
||||
provider.id,
|
||||
provider.displayName,
|
||||
ExtensionIdentifier.toKey(requestingExtension.identifier),
|
||||
requestingExtension.displayName || requestingExtension.name);
|
||||
|
||||
if (!isAllowed) {
|
||||
throw new Error('User did not consent to token access.');
|
||||
}
|
||||
|
||||
return session.getAccessToken();
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async login(requestingExtension: IExtensionDescription, providerId: string, scopes: string[]): Promise<vscode.AuthenticationSession> {
|
||||
const provider = this._authenticationProviders.get(providerId);
|
||||
if (!provider) {
|
||||
throw new Error(`No authentication provider with id '${providerId}' is currently registered.`);
|
||||
}
|
||||
|
||||
const isAllowed = await this._proxy.$loginPrompt(provider.id, provider.displayName, ExtensionIdentifier.toKey(requestingExtension.identifier), requestingExtension.displayName || requestingExtension.name);
|
||||
if (!isAllowed) {
|
||||
throw new Error('User did not consent to login.');
|
||||
}
|
||||
|
||||
return provider.login(scopes);
|
||||
}
|
||||
|
||||
registerAuthenticationProvider(provider: vscode.AuthenticationProvider): vscode.Disposable {
|
||||
@@ -91,6 +87,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
|
||||
const listener = provider.onDidChangeSessions(_ => {
|
||||
this._proxy.$onDidChangeSessions(provider.id);
|
||||
this._onDidChangeSessions.fire([provider.id]);
|
||||
});
|
||||
|
||||
this._proxy.$registerAuthenticationProvider(provider.id, provider.displayName);
|
||||
|
||||
@@ -12,7 +12,6 @@ import { DiagnosticSeverity } from './extHostTypes';
|
||||
import * as converter from './extHostTypeConverters';
|
||||
import { mergeSort } from 'vs/base/common/arrays';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { keys } from 'vs/base/common/map';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
@@ -36,7 +35,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
|
||||
dispose(): void {
|
||||
if (!this._isDisposed) {
|
||||
this._onDidChangeDiagnostics.fire(keys(this._data));
|
||||
this._onDidChangeDiagnostics.fire([...this._data.keys()]);
|
||||
if (this._proxy) {
|
||||
this._proxy.$clear(this._owner);
|
||||
}
|
||||
@@ -169,7 +168,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
|
||||
clear(): void {
|
||||
this._checkDisposed();
|
||||
this._onDidChangeDiagnostics.fire(keys(this._data));
|
||||
this._onDidChangeDiagnostics.fire([...this._data.keys()]);
|
||||
this._data.clear();
|
||||
if (this._proxy) {
|
||||
this._proxy.$clear(this._owner);
|
||||
|
||||
@@ -252,7 +252,15 @@ export class ExtensionsActivator {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentExtension = this._registry.getExtensionDescription(currentActivation.id)!;
|
||||
const currentExtension = this._registry.getExtensionDescription(currentActivation.id);
|
||||
if (!currentExtension) {
|
||||
// Error condition 0: unknown extension
|
||||
this._host.onExtensionActivationError(currentActivation.id, new MissingDependencyError(currentActivation.id.value));
|
||||
const error = new Error(`Unknown dependency '${currentActivation.id.value}'`);
|
||||
this._activatedExtensions.set(ExtensionIdentifier.toKey(currentActivation.id), new FailedExtension(error));
|
||||
return;
|
||||
}
|
||||
|
||||
const depIds = (typeof currentExtension.extensionDependencies === 'undefined' ? [] : currentExtension.extensionDependencies);
|
||||
let currentExtensionGetsGreenLight = true;
|
||||
|
||||
|
||||
@@ -366,6 +366,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
||||
globalState,
|
||||
workspaceState,
|
||||
subscriptions: [],
|
||||
get extensionUri() { return extensionDescription.extensionLocation; },
|
||||
get extensionPath() { return extensionDescription.extensionLocation.fsPath; },
|
||||
get storagePath() { return that._storagePath.workspaceValue(extensionDescription); },
|
||||
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); },
|
||||
|
||||
@@ -148,7 +148,16 @@ class ConsumerFileSystem implements vscode.FileSystem {
|
||||
}
|
||||
|
||||
// file system error
|
||||
throw new FileSystemError(err.message, err.name as files.FileSystemProviderErrorCode);
|
||||
switch (err.name) {
|
||||
case files.FileSystemProviderErrorCode.FileExists: throw FileSystemError.FileExists(err.message);
|
||||
case files.FileSystemProviderErrorCode.FileNotFound: throw FileSystemError.FileNotFound(err.message);
|
||||
case files.FileSystemProviderErrorCode.FileNotADirectory: throw FileSystemError.FileNotADirectory(err.message);
|
||||
case files.FileSystemProviderErrorCode.FileIsADirectory: throw FileSystemError.FileIsADirectory(err.message);
|
||||
case files.FileSystemProviderErrorCode.NoPermissions: throw FileSystemError.NoPermissions(err.message);
|
||||
case files.FileSystemProviderErrorCode.Unavailable: throw FileSystemError.Unavailable(err.message);
|
||||
|
||||
default: throw new FileSystemError(err.message, err.name as files.FileSystemProviderErrorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1702,9 +1702,19 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
||||
//#region semantic coloring
|
||||
|
||||
registerDocumentSemanticTokensProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentSemanticTokensProvider, legend: vscode.SemanticTokensLegend): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new DocumentSemanticTokensAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerDocumentSemanticTokensProvider(handle, this._transformDocumentSelector(selector), legend);
|
||||
return this._createDisposable(handle);
|
||||
const handle = this._nextHandle();
|
||||
const eventHandle = (typeof provider.onDidChangeSemanticTokens === 'function' ? this._nextHandle() : undefined);
|
||||
|
||||
this._adapter.set(handle, new AdapterData(new DocumentSemanticTokensAdapter(this._documents, provider), extension));
|
||||
this._proxy.$registerDocumentSemanticTokensProvider(handle, this._transformDocumentSelector(selector), legend, eventHandle);
|
||||
let result = this._createDisposable(handle);
|
||||
|
||||
if (eventHandle) {
|
||||
const subscription = provider.onDidChangeSemanticTokens!(_ => this._proxy.$emitDocumentSemanticTokensEvent(eventHandle));
|
||||
result = Disposable.from(result, subscription);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
$provideDocumentSemanticTokens(handle: number, resource: UriComponents, previousResultId: number, token: CancellationToken): Promise<VSBuffer | null> {
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
|
||||
import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable, ThemeColor } from './extHostTypes';
|
||||
import { StatusBarItem, StatusBarAlignment } from 'vscode';
|
||||
import { MainContext, MainThreadStatusBarShape, IMainContext } from './extHost.protocol';
|
||||
import type * as vscode from 'vscode';
|
||||
import { MainContext, MainThreadStatusBarShape, IMainContext, ICommandDto } from './extHost.protocol';
|
||||
import { localize } from 'vs/nls';
|
||||
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
|
||||
export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
|
||||
private static ID_GEN = 0;
|
||||
|
||||
private _id: number;
|
||||
@@ -24,14 +26,20 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
private _text: string = '';
|
||||
private _tooltip?: string;
|
||||
private _color?: string | ThemeColor;
|
||||
private _command?: string;
|
||||
private readonly _internalCommandRegistration = new DisposableStore();
|
||||
private _command?: {
|
||||
readonly fromApi: string | vscode.Command,
|
||||
readonly internal: ICommandDto,
|
||||
};
|
||||
|
||||
private _timeoutHandle: any;
|
||||
private _proxy: MainThreadStatusBarShape;
|
||||
private _commands: CommandsConverter;
|
||||
|
||||
constructor(proxy: MainThreadStatusBarShape, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) {
|
||||
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) {
|
||||
this._id = ExtHostStatusBarEntry.ID_GEN++;
|
||||
this._proxy = proxy;
|
||||
this._commands = commands;
|
||||
this._statusId = id;
|
||||
this._statusName = name;
|
||||
this._alignment = alignment;
|
||||
@@ -42,7 +50,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get alignment(): StatusBarAlignment {
|
||||
public get alignment(): vscode.StatusBarAlignment {
|
||||
return this._alignment;
|
||||
}
|
||||
|
||||
@@ -62,8 +70,8 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
return this._color;
|
||||
}
|
||||
|
||||
public get command(): string | undefined {
|
||||
return this._command;
|
||||
public get command(): string | vscode.Command | undefined {
|
||||
return this._command?.fromApi;
|
||||
}
|
||||
|
||||
public set text(text: string) {
|
||||
@@ -81,8 +89,25 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
this.update();
|
||||
}
|
||||
|
||||
public set command(command: string | undefined) {
|
||||
this._command = command;
|
||||
public set command(command: string | vscode.Command | undefined) {
|
||||
if (this._command?.fromApi === command) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._internalCommandRegistration.clear();
|
||||
if (typeof command === 'string') {
|
||||
this._command = {
|
||||
fromApi: command,
|
||||
internal: this._commands.toInternal({ title: '', command }, this._internalCommandRegistration),
|
||||
};
|
||||
} else if (command) {
|
||||
this._command = {
|
||||
fromApi: command,
|
||||
internal: this._commands.toInternal(command, this._internalCommandRegistration),
|
||||
};
|
||||
} else {
|
||||
this._command = undefined;
|
||||
}
|
||||
this.update();
|
||||
}
|
||||
|
||||
@@ -109,7 +134,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
this._timeoutHandle = undefined;
|
||||
|
||||
// Set to status bar
|
||||
this._proxy.$setEntry(this.id, this._statusId, this._statusName, this.text, this.tooltip, this.command, this.color,
|
||||
this._proxy.$setEntry(this.id, this._statusId, this._statusName, this.text, this.tooltip, this._command?.internal, this.color,
|
||||
this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT,
|
||||
this._priority);
|
||||
}, 0);
|
||||
@@ -123,7 +148,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
|
||||
class StatusBarMessage {
|
||||
|
||||
private _item: StatusBarItem;
|
||||
private _item: vscode.StatusBarItem;
|
||||
private _messages: { message: string }[] = [];
|
||||
|
||||
constructor(statusBar: ExtHostStatusBar) {
|
||||
@@ -161,16 +186,18 @@ class StatusBarMessage {
|
||||
|
||||
export class ExtHostStatusBar {
|
||||
|
||||
private _proxy: MainThreadStatusBarShape;
|
||||
private readonly _proxy: MainThreadStatusBarShape;
|
||||
private readonly _commands: CommandsConverter;
|
||||
private _statusMessage: StatusBarMessage;
|
||||
|
||||
constructor(mainContext: IMainContext) {
|
||||
constructor(mainContext: IMainContext, commands: CommandsConverter) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadStatusBar);
|
||||
this._commands = commands;
|
||||
this._statusMessage = new StatusBarMessage(this);
|
||||
}
|
||||
|
||||
createStatusBarEntry(id: string, name: string, alignment?: ExtHostStatusBarAlignment, priority?: number): StatusBarItem {
|
||||
return new ExtHostStatusBarEntry(this._proxy, id, name, alignment, priority);
|
||||
createStatusBarEntry(id: string, name: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem {
|
||||
return new ExtHostStatusBarEntry(this._proxy, this._commands, id, name, alignment, priority);
|
||||
}
|
||||
|
||||
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): Disposable {
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as vscode from 'vscode';
|
||||
import { UriComponents, URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ExtHostTimelineShape, MainThreadTimelineShape, IMainContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { Timeline, TimelineItem, TimelineOptions, TimelineProvider } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||
import { Timeline, TimelineItem, TimelineOptions, TimelineProvider, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
|
||||
import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
@@ -16,21 +16,19 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
export interface IExtHostTimeline extends ExtHostTimelineShape {
|
||||
readonly _serviceBrand: undefined;
|
||||
$getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise<Timeline | undefined>;
|
||||
$getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: InternalTimelineOptions): Promise<Timeline | undefined>;
|
||||
}
|
||||
|
||||
export const IExtHostTimeline = createDecorator<IExtHostTimeline>('IExtHostTimeline');
|
||||
|
||||
export class ExtHostTimeline implements IExtHostTimeline {
|
||||
private static handlePool = 0;
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private _proxy: MainThreadTimelineShape;
|
||||
|
||||
private _providers = new Map<string, TimelineProvider>();
|
||||
|
||||
private _itemsBySourceByUriMap = new Map<string | undefined, Map<string, Map<string, vscode.TimelineItem>>>();
|
||||
private _itemsBySourceAndUriMap = new Map<string, Map<string | undefined, Map<string, vscode.TimelineItem>>>();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
@@ -42,7 +40,7 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
processArgument: arg => {
|
||||
if (arg && arg.$mid === 11) {
|
||||
const uri = arg.uri === undefined ? undefined : URI.revive(arg.uri);
|
||||
return this._itemsBySourceByUriMap.get(getUriKey(uri))?.get(arg.source)?.get(arg.handle);
|
||||
return this._itemsBySourceAndUriMap.get(arg.source)?.get(getUriKey(uri))?.get(arg.handle);
|
||||
}
|
||||
|
||||
return arg;
|
||||
@@ -50,7 +48,7 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
});
|
||||
}
|
||||
|
||||
async $getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: { cacheResults?: boolean }): Promise<Timeline | undefined> {
|
||||
async $getTimeline(id: string, uri: UriComponents, options: vscode.TimelineOptions, token: vscode.CancellationToken, internalOptions?: InternalTimelineOptions): Promise<Timeline | undefined> {
|
||||
const provider = this._providers.get(id);
|
||||
return provider?.provideTimeline(URI.revive(uri), options, token, internalOptions);
|
||||
}
|
||||
@@ -62,26 +60,21 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
|
||||
let disposable: IDisposable | undefined;
|
||||
if (provider.onDidChange) {
|
||||
disposable = provider.onDidChange(this.emitTimelineChangeEvent(provider.id), this);
|
||||
disposable = provider.onDidChange(e => this._proxy.$emitTimelineChangeEvent({ ...e, id: provider.id }), this);
|
||||
}
|
||||
|
||||
const itemsBySourceByUriMap = this._itemsBySourceByUriMap;
|
||||
const itemsBySourceAndUriMap = this._itemsBySourceAndUriMap;
|
||||
return this.registerTimelineProviderCore({
|
||||
...provider,
|
||||
scheme: scheme,
|
||||
onDidChange: undefined,
|
||||
async provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: { cacheResults?: boolean }) {
|
||||
// For now, only allow the caching of a single Uri
|
||||
if (internalOptions?.cacheResults) {
|
||||
if (options.cursor === undefined) {
|
||||
timelineDisposables.clear();
|
||||
}
|
||||
|
||||
if (!itemsBySourceByUriMap.has(getUriKey(uri))) {
|
||||
itemsBySourceByUriMap.clear();
|
||||
}
|
||||
} else {
|
||||
async provideTimeline(uri: URI, options: TimelineOptions, token: CancellationToken, internalOptions?: InternalTimelineOptions) {
|
||||
if (internalOptions?.resetCache) {
|
||||
timelineDisposables.clear();
|
||||
|
||||
// For now, only allow the caching of a single Uri
|
||||
// itemsBySourceAndUriMap.get(provider.id)?.get(getUriKey(uri))?.clear();
|
||||
itemsBySourceAndUriMap.get(provider.id)?.clear();
|
||||
}
|
||||
|
||||
const result = await provider.provideTimeline(uri, options, token);
|
||||
@@ -91,8 +84,9 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// TODO: Determine if we should cache dependent on who calls us (internal vs external)
|
||||
const convertItem = convertTimelineItem(uri, internalOptions?.cacheResults ?? false);
|
||||
// TODO: Should we bother converting all the data if we aren't caching? Meaning it is being requested by an extension?
|
||||
|
||||
const convertItem = convertTimelineItem(uri, internalOptions);
|
||||
return {
|
||||
...result,
|
||||
source: provider.id,
|
||||
@@ -100,6 +94,10 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
};
|
||||
},
|
||||
dispose() {
|
||||
for (const sourceMap of itemsBySourceAndUriMap.values()) {
|
||||
sourceMap.get(provider.id)?.clear();
|
||||
}
|
||||
|
||||
disposable?.dispose();
|
||||
timelineDisposables.dispose();
|
||||
}
|
||||
@@ -107,29 +105,28 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
}
|
||||
|
||||
private convertTimelineItem(source: string, commandConverter: CommandsConverter, disposables: DisposableStore) {
|
||||
return (uri: URI, cacheResults: boolean) => {
|
||||
let itemsMap: Map<string, vscode.TimelineItem> | undefined;
|
||||
if (cacheResults) {
|
||||
const uriKey = getUriKey(uri);
|
||||
|
||||
let sourceMap = this._itemsBySourceByUriMap.get(uriKey);
|
||||
if (sourceMap === undefined) {
|
||||
sourceMap = new Map();
|
||||
this._itemsBySourceByUriMap.set(uriKey, sourceMap);
|
||||
return (uri: URI, options?: InternalTimelineOptions) => {
|
||||
let items: Map<string, vscode.TimelineItem> | undefined;
|
||||
if (options?.cacheResults) {
|
||||
let itemsByUri = this._itemsBySourceAndUriMap.get(source);
|
||||
if (itemsByUri === undefined) {
|
||||
itemsByUri = new Map();
|
||||
this._itemsBySourceAndUriMap.set(source, itemsByUri);
|
||||
}
|
||||
|
||||
itemsMap = sourceMap.get(source);
|
||||
if (itemsMap === undefined) {
|
||||
itemsMap = new Map();
|
||||
sourceMap.set(source, itemsMap);
|
||||
const uriKey = getUriKey(uri);
|
||||
items = itemsByUri.get(uriKey);
|
||||
if (items === undefined) {
|
||||
items = new Map();
|
||||
itemsByUri.set(uriKey, items);
|
||||
}
|
||||
}
|
||||
|
||||
return (item: vscode.TimelineItem): TimelineItem => {
|
||||
const { iconPath, ...props } = item;
|
||||
|
||||
const handle = `${source}|${item.id ?? `${item.timestamp}-${ExtHostTimeline.handlePool++}`}`;
|
||||
itemsMap?.set(handle, item);
|
||||
const handle = `${source}|${item.id ?? item.timestamp}`;
|
||||
items?.set(handle, item);
|
||||
|
||||
let icon;
|
||||
let iconDark;
|
||||
@@ -161,22 +158,6 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
};
|
||||
}
|
||||
|
||||
private emitTimelineChangeEvent(id: string) {
|
||||
return (e: vscode.TimelineChangeEvent) => {
|
||||
// Clear caches
|
||||
if (e?.uri === undefined) {
|
||||
for (const sourceMap of this._itemsBySourceByUriMap.values()) {
|
||||
sourceMap.get(id)?.clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._itemsBySourceByUriMap.get(getUriKey(e.uri))?.clear();
|
||||
}
|
||||
|
||||
this._proxy.$emitTimelineChangeEvent({ ...e, id: id });
|
||||
};
|
||||
}
|
||||
|
||||
private registerTimelineProviderCore(provider: TimelineProvider): IDisposable {
|
||||
// console.log(`ExtHostTimeline#registerTimelineProvider: id=${provider.id}`);
|
||||
|
||||
@@ -193,7 +174,7 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
this._providers.set(provider.id, provider);
|
||||
|
||||
return toDisposable(() => {
|
||||
for (const sourceMap of this._itemsBySourceByUriMap.values()) {
|
||||
for (const sourceMap of this._itemsBySourceAndUriMap.values()) {
|
||||
sourceMap.get(provider.id)?.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,16 +3,17 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtHostTunnelServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostTunnelServiceShape, MainContext, MainThreadTunnelServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import * as vscode from 'vscode';
|
||||
import { RemoteTunnel, TunnelOptions } from 'vs/platform/remote/common/tunnel';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export interface TunnelDto {
|
||||
remoteAddress: { port: number, host: string };
|
||||
localAddress: string;
|
||||
localAddress: { port: number, host: string } | string;
|
||||
}
|
||||
|
||||
export namespace TunnelDto {
|
||||
@@ -42,6 +43,13 @@ export const IExtHostTunnelService = createDecorator<IExtHostTunnelService>('IEx
|
||||
export class ExtHostTunnelService implements IExtHostTunnelService {
|
||||
_serviceBrand: undefined;
|
||||
onDidChangeTunnels: vscode.Event<void> = (new Emitter<void>()).event;
|
||||
private readonly _proxy: MainThreadTunnelServiceShape;
|
||||
|
||||
constructor(
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService,
|
||||
) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTunnelService);
|
||||
}
|
||||
|
||||
async openTunnel(forward: TunnelOptions): Promise<vscode.Tunnel | undefined> {
|
||||
return undefined;
|
||||
@@ -55,7 +63,10 @@ export class ExtHostTunnelService implements IExtHostTunnelService {
|
||||
async $filterCandidates(candidates: { host: string, port: number, detail: string }[]): Promise<boolean[]> {
|
||||
return candidates.map(() => true);
|
||||
}
|
||||
async setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable> { return { dispose: () => { } }; }
|
||||
async setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable> {
|
||||
await this._proxy.$tunnelServiceReady();
|
||||
return { dispose: () => { } };
|
||||
}
|
||||
$forwardPort(tunnelOptions: TunnelOptions): Promise<TunnelDto> | undefined { return undefined; }
|
||||
async $closeTunnel(remote: { host: string, port: number }): Promise<void> { }
|
||||
async $onDidTunnelsChange(): Promise<void> { }
|
||||
|
||||
@@ -7,7 +7,6 @@ import { coalesce, equals } from 'vs/base/common/arrays';
|
||||
import { illegalArgument } from 'vs/base/common/errors';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { isMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
@@ -44,16 +43,16 @@ export class Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private _callOnDispose?: () => any;
|
||||
#callOnDispose?: () => any;
|
||||
|
||||
constructor(callOnDispose: () => any) {
|
||||
this._callOnDispose = callOnDispose;
|
||||
this.#callOnDispose = callOnDispose;
|
||||
}
|
||||
|
||||
dispose(): any {
|
||||
if (typeof this._callOnDispose === 'function') {
|
||||
this._callOnDispose();
|
||||
this._callOnDispose = undefined;
|
||||
if (typeof this.#callOnDispose === 'function') {
|
||||
this.#callOnDispose();
|
||||
this.#callOnDispose = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -661,7 +660,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
textEdit[1].push(candidate.edit);
|
||||
}
|
||||
}
|
||||
return values(textEdits);
|
||||
return [...textEdits.values()];
|
||||
}
|
||||
|
||||
allEntries(): ReadonlyArray<IFileTextEdit | IFileOperation> {
|
||||
@@ -2334,9 +2333,13 @@ export class FileSystemError extends Error {
|
||||
return new FileSystemError(messageOrUri, FileSystemProviderErrorCode.Unavailable, FileSystemError.Unavailable);
|
||||
}
|
||||
|
||||
readonly code?: string;
|
||||
|
||||
constructor(uriOrMessage?: string | URI, code: FileSystemProviderErrorCode = FileSystemProviderErrorCode.Unknown, terminator?: Function) {
|
||||
super(URI.isUri(uriOrMessage) ? uriOrMessage.toString(true) : uriOrMessage);
|
||||
|
||||
this.code = terminator?.name;
|
||||
|
||||
// mark the error as file system provider error so that
|
||||
// we can extract the error code on the receiving side
|
||||
markAsFileSystemProviderError(this, code);
|
||||
|
||||
@@ -104,19 +104,20 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
|
||||
private _title: string;
|
||||
private _iconPath?: IconPath;
|
||||
|
||||
private readonly _options: vscode.WebviewPanelOptions;
|
||||
private readonly _webview: ExtHostWebview;
|
||||
private _viewColumn: vscode.ViewColumn | undefined;
|
||||
private _visible: boolean = true;
|
||||
private _active: boolean = true;
|
||||
readonly #options: vscode.WebviewPanelOptions;
|
||||
readonly #webview: ExtHostWebview;
|
||||
|
||||
_isDisposed: boolean = false;
|
||||
#viewColumn: vscode.ViewColumn | undefined = undefined;
|
||||
#visible: boolean = true;
|
||||
#active: boolean = true;
|
||||
|
||||
readonly _onDisposeEmitter = this._register(new Emitter<void>());
|
||||
public readonly onDidDispose: Event<void> = this._onDisposeEmitter.event;
|
||||
#isDisposed: boolean = false;
|
||||
|
||||
readonly _onDidChangeViewStateEmitter = this._register(new Emitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
|
||||
public readonly onDidChangeViewState: Event<vscode.WebviewPanelOnDidChangeViewStateEvent> = this._onDidChangeViewStateEmitter.event;
|
||||
readonly #onDidDispose = this._register(new Emitter<void>());
|
||||
public readonly onDidDispose = this.#onDidDispose.event;
|
||||
|
||||
readonly #onDidChangeViewState = this._register(new Emitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
|
||||
public readonly onDidChangeViewState = this.#onDidChangeViewState.event;
|
||||
|
||||
constructor(
|
||||
handle: WebviewPanelHandle,
|
||||
@@ -131,27 +132,28 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
|
||||
this._handle = handle;
|
||||
this._proxy = proxy;
|
||||
this._viewType = viewType;
|
||||
this._options = editorOptions;
|
||||
this._viewColumn = viewColumn;
|
||||
this.#options = editorOptions;
|
||||
this.#viewColumn = viewColumn;
|
||||
this._title = title;
|
||||
this._webview = webview;
|
||||
this.#webview = webview;
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
if (this._isDisposed) {
|
||||
if (this.#isDisposed) {
|
||||
return;
|
||||
}
|
||||
this._isDisposed = true;
|
||||
this._onDisposeEmitter.fire();
|
||||
|
||||
this.#isDisposed = true;
|
||||
this.#onDidDispose.fire();
|
||||
this._proxy.$disposeWebview(this._handle);
|
||||
this._webview.dispose();
|
||||
this.#webview.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
get webview() {
|
||||
this.assertNotDisposed();
|
||||
return this._webview;
|
||||
return this.#webview;
|
||||
}
|
||||
|
||||
get viewType(): string {
|
||||
@@ -187,42 +189,40 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
|
||||
}
|
||||
|
||||
get options() {
|
||||
return this._options;
|
||||
return this.#options;
|
||||
}
|
||||
|
||||
get viewColumn(): vscode.ViewColumn | undefined {
|
||||
this.assertNotDisposed();
|
||||
if (typeof this._viewColumn === 'number' && this._viewColumn < 0) {
|
||||
if (typeof this.#viewColumn === 'number' && this.#viewColumn < 0) {
|
||||
// We are using a symbolic view column
|
||||
// Return undefined instead to indicate that the real view column is currently unknown but will be resolved.
|
||||
return undefined;
|
||||
}
|
||||
return this._viewColumn;
|
||||
}
|
||||
|
||||
_setViewColumn(value: vscode.ViewColumn) {
|
||||
this.assertNotDisposed();
|
||||
this._viewColumn = value;
|
||||
return this.#viewColumn;
|
||||
}
|
||||
|
||||
public get active(): boolean {
|
||||
this.assertNotDisposed();
|
||||
return this._active;
|
||||
}
|
||||
|
||||
_setActive(value: boolean) {
|
||||
this.assertNotDisposed();
|
||||
this._active = value;
|
||||
return this.#active;
|
||||
}
|
||||
|
||||
public get visible(): boolean {
|
||||
this.assertNotDisposed();
|
||||
return this._visible;
|
||||
return this.#visible;
|
||||
}
|
||||
|
||||
_setVisible(value: boolean) {
|
||||
this.assertNotDisposed();
|
||||
this._visible = value;
|
||||
_updateViewState(newState: { active: boolean; visible: boolean; viewColumn: vscode.ViewColumn; }) {
|
||||
if (this.#isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.active !== newState.active || this.visible !== newState.visible || this.viewColumn !== newState.viewColumn) {
|
||||
this.#active = newState.active;
|
||||
this.#visible = newState.visible;
|
||||
this.#viewColumn = newState.viewColumn;
|
||||
this.#onDidChangeViewState.fire({ webviewPanel: this });
|
||||
}
|
||||
}
|
||||
|
||||
public postMessage(message: any): Promise<boolean> {
|
||||
@@ -239,7 +239,7 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
|
||||
}
|
||||
|
||||
private assertNotDisposed() {
|
||||
if (this._isDisposed) {
|
||||
if (this.#isDisposed) {
|
||||
throw new Error('Webview is disposed');
|
||||
}
|
||||
}
|
||||
@@ -303,23 +303,26 @@ class CustomDocument extends Disposable implements vscode.CustomDocument {
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal*/ _revert() {
|
||||
/** @internal*/ async _revert() {
|
||||
const editing = this.getEditingCapability();
|
||||
if (this.#currentEditIndex === this.#savePoint) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
let undoneEdits: EditType[] = [];
|
||||
let appliedEdits: EditType[] = [];
|
||||
if (this.#currentEditIndex >= this.#savePoint) {
|
||||
const editsToUndo = this.#edits.slice(this.#savePoint, this.#currentEditIndex);
|
||||
editing.undoEdits(editsToUndo.reverse());
|
||||
undoneEdits = this.#edits.slice(this.#savePoint, this.#currentEditIndex).reverse();
|
||||
} else if (this.#currentEditIndex < this.#savePoint) {
|
||||
const editsToRedo = this.#edits.slice(this.#currentEditIndex, this.#savePoint);
|
||||
editing.applyEdits(editsToRedo);
|
||||
appliedEdits = this.#edits.slice(this.#currentEditIndex, this.#savePoint);
|
||||
}
|
||||
|
||||
this.#currentEditIndex = this.#savePoint;
|
||||
this.spliceEdits();
|
||||
|
||||
await editing.revert({ undoneEdits, appliedEdits });
|
||||
|
||||
this.updateState();
|
||||
return true;
|
||||
}
|
||||
@@ -350,8 +353,8 @@ class CustomDocument extends Disposable implements vscode.CustomDocument {
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
/** @internal*/ _save() {
|
||||
return this.getEditingCapability().save();
|
||||
/** @internal*/ _save(cancellation: CancellationToken) {
|
||||
return this.getEditingCapability().save(cancellation);
|
||||
}
|
||||
|
||||
/** @internal*/ _saveAs(target: vscode.Uri) {
|
||||
@@ -585,18 +588,16 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
|
||||
for (const handle of handles) {
|
||||
const panel = this.getWebviewPanel(handle);
|
||||
if (!panel || panel._isDisposed) {
|
||||
if (!panel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newState = newStates[handle];
|
||||
const viewColumn = typeConverters.ViewColumn.to(newState.position);
|
||||
if (panel.active !== newState.active || panel.visible !== newState.visible || panel.viewColumn !== viewColumn) {
|
||||
panel._setActive(newState.active);
|
||||
panel._setVisible(newState.visible);
|
||||
panel._setViewColumn(viewColumn);
|
||||
panel._onDidChangeViewStateEmitter.fire({ webviewPanel: panel });
|
||||
}
|
||||
panel._updateViewState({
|
||||
active: newState.active,
|
||||
visible: newState.visible,
|
||||
viewColumn: typeConverters.ViewColumn.to(newState.position),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,7 +660,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
}
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
const document = this.getDocument(viewType, revivedResource);
|
||||
const document = this.getCustomDocument(viewType, revivedResource);
|
||||
this._documents.delete(document);
|
||||
document.dispose();
|
||||
}
|
||||
@@ -686,12 +687,11 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
switch (entry.type) {
|
||||
case WebviewEditorType.Custom:
|
||||
{
|
||||
const document = this.getDocument(viewType, revivedResource);
|
||||
const document = this.getCustomDocument(viewType, revivedResource);
|
||||
return entry.provider.resolveCustomEditor(document, revivedPanel);
|
||||
}
|
||||
case WebviewEditorType.Text:
|
||||
{
|
||||
await this._extHostDocuments.ensureDocumentData(revivedResource);
|
||||
const document = this._extHostDocuments.getDocument(revivedResource);
|
||||
return entry.provider.resolveCustomTextEditor(document, revivedPanel);
|
||||
}
|
||||
@@ -703,32 +703,32 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
}
|
||||
|
||||
async $undo(resourceComponents: UriComponents, viewType: string): Promise<void> {
|
||||
const document = this.getDocument(viewType, resourceComponents);
|
||||
const document = this.getCustomDocument(viewType, resourceComponents);
|
||||
document._undo();
|
||||
}
|
||||
|
||||
async $redo(resourceComponents: UriComponents, viewType: string): Promise<void> {
|
||||
const document = this.getDocument(viewType, resourceComponents);
|
||||
const document = this.getCustomDocument(viewType, resourceComponents);
|
||||
document._redo();
|
||||
}
|
||||
|
||||
async $revert(resourceComponents: UriComponents, viewType: string): Promise<void> {
|
||||
const document = this.getDocument(viewType, resourceComponents);
|
||||
const document = this.getCustomDocument(viewType, resourceComponents);
|
||||
document._revert();
|
||||
}
|
||||
|
||||
async $onSave(resourceComponents: UriComponents, viewType: string): Promise<void> {
|
||||
const document = this.getDocument(viewType, resourceComponents);
|
||||
document._save();
|
||||
async $onSave(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {
|
||||
const document = this.getCustomDocument(viewType, resourceComponents);
|
||||
document._save(cancellation);
|
||||
}
|
||||
|
||||
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents): Promise<void> {
|
||||
const document = this.getDocument(viewType, resourceComponents);
|
||||
const document = this.getCustomDocument(viewType, resourceComponents);
|
||||
return document._saveAs(URI.revive(targetResource));
|
||||
}
|
||||
|
||||
async $backup(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {
|
||||
const document = this.getDocument(viewType, resourceComponents);
|
||||
const document = this.getCustomDocument(viewType, resourceComponents);
|
||||
return document._backup(cancellation);
|
||||
}
|
||||
|
||||
@@ -736,7 +736,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
return this._webviewPanels.get(handle);
|
||||
}
|
||||
|
||||
private getDocument(viewType: string, resource: UriComponents): CustomDocument {
|
||||
private getCustomDocument(viewType: string, resource: UriComponents): CustomDocument {
|
||||
const document = this._documents.get(viewType, URI.revive(resource));
|
||||
if (!document) {
|
||||
throw new Error('No webview editor custom document found');
|
||||
|
||||
@@ -473,7 +473,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
|
||||
ignoreSymlinks: typeof options.followSymlinks === 'boolean' ? !options.followSymlinks : undefined,
|
||||
disregardIgnoreFiles: typeof options.useIgnoreFiles === 'boolean' ? !options.useIgnoreFiles : undefined,
|
||||
disregardGlobalIgnoreFiles: typeof options.useGlobalIgnoreFiles === 'boolean' ? !options.useGlobalIgnoreFiles : undefined,
|
||||
disregardExcludeSettings: options.exclude === null,
|
||||
disregardExcludeSettings: typeof options.useDefaultExcludes === 'boolean' ? !options.useDefaultExcludes : true,
|
||||
fileEncoding: options.encoding,
|
||||
maxResults: options.maxResults,
|
||||
previewOptions,
|
||||
|
||||
@@ -7,9 +7,10 @@ import * as nls from 'vs/nls';
|
||||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { isString } from 'vs/base/common/types';
|
||||
|
||||
interface IJSONValidationExtensionPoint {
|
||||
fileMatch: string;
|
||||
fileMatch: string | string[];
|
||||
url: string;
|
||||
}
|
||||
|
||||
@@ -25,8 +26,11 @@ const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IJSONVal
|
||||
defaultSnippets: [{ body: { fileMatch: '${1:file.json}', url: '${2:url}' } }],
|
||||
properties: {
|
||||
fileMatch: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.jsonValidation.fileMatch', 'The file pattern to match, for example "package.json" or "*.launch".'),
|
||||
type: ['string', 'array'],
|
||||
description: nls.localize('contributes.jsonValidation.fileMatch', 'The file pattern (or an array of patterns) to match, for example "package.json" or "*.launch". Exclusion patterns start with \'!\''),
|
||||
items: {
|
||||
type: ['string']
|
||||
}
|
||||
},
|
||||
url: {
|
||||
description: nls.localize('contributes.jsonValidation.url', 'A schema URL (\'http:\', \'https:\') or relative path to the extension folder (\'./\').'),
|
||||
@@ -51,12 +55,12 @@ export class JSONValidationExtensionPoint {
|
||||
return;
|
||||
}
|
||||
extensionValue.forEach(extension => {
|
||||
if (typeof extension.fileMatch !== 'string') {
|
||||
collector.error(nls.localize('invalid.fileMatch', "'configuration.jsonValidation.fileMatch' must be defined"));
|
||||
if (!isString(extension.fileMatch) && !(Array.isArray(extension.fileMatch) && extension.fileMatch.every(isString))) {
|
||||
collector.error(nls.localize('invalid.fileMatch', "'configuration.jsonValidation.fileMatch' must be defined as a string or an array of strings."));
|
||||
return;
|
||||
}
|
||||
let uri = extension.url;
|
||||
if (typeof extension.url !== 'string') {
|
||||
if (!isString(uri)) {
|
||||
collector.error(nls.localize('invalid.url', "'configuration.jsonValidation.url' must be a URL or relative path"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
|
||||
} else if (args.kind === 'external') {
|
||||
|
||||
runInExternalTerminal(args, await this._configurationService.getConfigProvider());
|
||||
return runInExternalTerminal(args, await this._configurationService.getConfigProvider());
|
||||
}
|
||||
return super.$runInTerminal(args);
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ class ExtensionTunnel implements vscode.Tunnel {
|
||||
onDidDispose: Event<void> = this._onDispose.event;
|
||||
|
||||
constructor(
|
||||
public readonly remoteAddress: { port: number; host: string; },
|
||||
public readonly localAddress: string,
|
||||
public readonly remoteAddress: { port: number, host: string },
|
||||
public readonly localAddress: { port: number, host: string } | string,
|
||||
private readonly _dispose: () => void) { }
|
||||
|
||||
dispose(): void {
|
||||
@@ -52,6 +52,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
|
||||
this.registerCandidateFinder();
|
||||
}
|
||||
}
|
||||
|
||||
async openTunnel(forward: TunnelOptions): Promise<vscode.Tunnel | undefined> {
|
||||
const tunnel = await this._proxy.$openTunnel(forward);
|
||||
if (tunnel) {
|
||||
@@ -91,6 +92,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
|
||||
} else {
|
||||
this._forwardPortProvider = undefined;
|
||||
}
|
||||
await this._proxy.$tunnelServiceReady();
|
||||
return toDisposable(() => {
|
||||
this._forwardPortProvider = undefined;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user