Merge from vscode 2cd495805cf99b31b6926f08ff4348124b2cf73d

This commit is contained in:
ADS Merger
2020-06-30 04:40:21 +00:00
committed by AzureDataStudio
parent a8a7559229
commit 1388493cc1
602 changed files with 16375 additions and 12940 deletions

View File

@@ -18,7 +18,7 @@ import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { fromNow } from 'vs/base/common/date';
const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline'];
const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline', 'vscode.github-browser'];
interface IAccountUsage {
extensionId: string;
@@ -104,7 +104,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
return {
label: extension.name,
description: usage
? nls.localize('accountLastUsedDate', "Last used this account {0}", fromNow(usage.lastUsed, true))
? nls.localize({ key: 'accountLastUsedDate', comment: ['The placeholder {0} is a string with time information, such as "3 days ago"'] }, "Last used this account {0}", fromNow(usage.lastUsed, true))
: nls.localize('notUsed', "Has not used this account"),
extension
};
@@ -336,7 +336,14 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
});
quickPick.items = items;
quickPick.title = nls.localize('selectAccount', "The extension '{0}' wants to access a {1} account", extensionName, providerName);
quickPick.title = nls.localize(
{
key: 'selectAccount',
comment: ['The placeholder {0} is the name of an extension. {1} is the name of the type of account, such as Microsoft or GitHub.']
},
"The extension '{0}' wants to access a {1} account",
extensionName,
providerName);
quickPick.placeholder = nls.localize('getSessionPlateholder', "Select an account for '{0}' to use or Esc to cancel", extensionName);
quickPick.onDidAccept(async _ => {

View File

@@ -6,7 +6,6 @@
import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { keys } from 'vs/base/common/map';
import { URI, UriComponents } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { IRange } from 'vs/editor/common/core/range';
@@ -284,7 +283,7 @@ export class MainThreadCommentController {
async getDocumentComments(resource: URI, token: CancellationToken) {
let ret: modes.CommentThread[] = [];
for (let thread of keys(this._threads)) {
for (let thread of [...this._threads.keys()]) {
const commentThread = this._threads.get(thread)!;
if (commentThread.resource === resource.toString()) {
ret.push(commentThread);
@@ -315,7 +314,7 @@ export class MainThreadCommentController {
getAllComments(): MainThreadCommentThread[] {
let ret: MainThreadCommentThread[] = [];
for (let thread of keys(this._threads)) {
for (let thread of [...this._threads.keys()]) {
ret.push(this._threads.get(thread)!);
}
@@ -486,7 +485,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
if (!commentsPanelAlreadyConstructed && !this._openViewListener) {
this._openViewListener = this._viewsService.onDidChangeViewVisibility(e => {
if (e.id === COMMENTS_VIEW_ID && e.visible) {
keys(this._commentControllers).forEach(handle => {
[...this._commentControllers.keys()].forEach(handle => {
let threads = this._commentControllers.get(handle)!.getAllComments();
if (threads.length) {

View File

@@ -231,7 +231,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
const debugOptions: IDebugSessionOptions = {
noDebug: options.noDebug,
parentSession: this.getSession(options.parentSessionID),
repl: options.repl
repl: options.repl,
noCompact: options.noCompact
};
return this.debugService.startDebugging(launch, nameOrConfig, debugOptions).then(success => {
return success;

View File

@@ -9,33 +9,33 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainContext, IExtHostContext, MainThreadDecorationsShape, ExtHostDecorationsShape, DecorationData, DecorationRequest } from '../common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations';
import { values } from 'vs/base/common/collections';
import { CancellationToken } from 'vs/base/common/cancellation';
class DecorationRequestsQueue {
private _idPool = 0;
private _requests: { [id: number]: DecorationRequest } = Object.create(null);
private _resolver: { [id: number]: (data: DecorationData) => any } = Object.create(null);
private _requests = new Map<number, DecorationRequest>();
private _resolver = new Map<number, (data: DecorationData) => any>();
private _timer: any;
constructor(
private readonly _proxy: ExtHostDecorationsShape
private readonly _proxy: ExtHostDecorationsShape,
private readonly _handle: number
) {
//
}
enqueue(handle: number, uri: URI, token: CancellationToken): Promise<DecorationData> {
enqueue(uri: URI, token: CancellationToken): Promise<DecorationData> {
const id = ++this._idPool;
const result = new Promise<DecorationData>(resolve => {
this._requests[id] = { id, handle, uri };
this._resolver[id] = resolve;
this._requests.set(id, { id, uri });
this._resolver.set(id, resolve);
this._processQueue();
});
token.onCancellationRequested(() => {
delete this._requests[id];
delete this._resolver[id];
this._requests.delete(id);
this._resolver.delete(id);
});
return result;
}
@@ -49,15 +49,15 @@ class DecorationRequestsQueue {
// make request
const requests = this._requests;
const resolver = this._resolver;
this._proxy.$provideDecorations(values(requests), CancellationToken.None).then(data => {
for (const id in resolver) {
resolver[id](data[id]);
this._proxy.$provideDecorations(this._handle, [...requests.values()], CancellationToken.None).then(data => {
for (let [id, resolve] of resolver) {
resolve(data[id]);
}
});
// reset
this._requests = [];
this._resolver = [];
this._requests = new Map();
this._resolver = new Map();
this._timer = undefined;
}, 0);
}
@@ -68,14 +68,12 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
private readonly _provider = new Map<number, [Emitter<URI[]>, IDisposable]>();
private readonly _proxy: ExtHostDecorationsShape;
private readonly _requestQueue: DecorationRequestsQueue;
constructor(
context: IExtHostContext,
@IDecorationsService private readonly _decorationsService: IDecorationsService
) {
this._proxy = context.getProxy(ExtHostContext.ExtHostDecorations);
this._requestQueue = new DecorationRequestsQueue(this._proxy);
}
dispose() {
@@ -85,23 +83,23 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
$registerDecorationProvider(handle: number, label: string): void {
const emitter = new Emitter<URI[]>();
const queue = new DecorationRequestsQueue(this._proxy, handle);
const registration = this._decorationsService.registerDecorationsProvider({
label,
onDidChange: emitter.event,
provideDecorations: (uri, token) => {
return this._requestQueue.enqueue(handle, uri, token).then(data => {
if (!data) {
return undefined;
}
const [weight, bubble, tooltip, letter, themeColor] = data;
return <IDecorationData>{
weight: weight || 0,
bubble: bubble || false,
color: themeColor && themeColor.id,
tooltip,
letter
};
});
provideDecorations: async (uri, token) => {
const data = await queue.enqueue(uri, token);
if (!data) {
return undefined;
}
const [weight, bubble, tooltip, letter, themeColor] = data;
return <IDecorationData>{
weight: weight ?? 0,
bubble: bubble ?? false,
color: themeColor?.id,
tooltip,
letter
};
}
});
this._provider.set(handle, [emitter, registration]);

View File

@@ -126,8 +126,12 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
}));
this._toDispose.add(workingCopyFileService.onDidRunWorkingCopyFileOperation(e => {
if (e.source && (e.operation === FileOperation.MOVE || e.operation === FileOperation.DELETE)) {
this._modelReferenceCollection.remove(e.source);
if (e.operation === FileOperation.MOVE || e.operation === FileOperation.DELETE) {
for (const { source } of e.files) {
if (source) {
this._modelReferenceCollection.remove(source);
}
}
}
}));

View File

@@ -24,9 +24,9 @@ import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContex
import { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { openEditorWith } from 'vs/workbench/contrib/files/common/openWith';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith';
export class MainThreadTextEditors implements MainThreadTextEditorsShape {

View File

@@ -4,10 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import { DisposableStore } from 'vs/base/common/lifecycle';
import { FileChangeType, IFileService, FileOperation } from 'vs/platform/files/common/files';
import { FileChangeType, IFileService } from 'vs/platform/files/common/files';
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ExtHostContext, FileSystemEvents, IExtHostContext } from '../common/extHost.protocol';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { localize } from 'vs/nls';
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
@@ -21,7 +20,6 @@ export class MainThreadFileSystemEventService {
constructor(
extHostContext: IExtHostContext,
@IFileService fileService: IFileService,
@ITextFileService textFileService: ITextFileService,
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService
) {
@@ -57,14 +55,13 @@ export class MainThreadFileSystemEventService {
// BEFORE file operation
workingCopyFileService.addFileOperationParticipant({
participate: (target, source, operation, progress, timeout, token) => {
return proxy.$onWillRunFileOperation(operation, target, source, timeout, token);
participate: (files, operation, progress, timeout, token) => {
return proxy.$onWillRunFileOperation(operation, files, timeout, token);
}
});
// AFTER file operation
this._listener.add(textFileService.onDidCreateTextFile(e => proxy.$onDidRunFileOperation(FileOperation.CREATE, e.resource, undefined)));
this._listener.add(workingCopyFileService.onDidRunWorkingCopyFileOperation(e => proxy.$onDidRunFileOperation(e.operation, e.target, e.source)));
this._listener.add(workingCopyFileService.onDidRunWorkingCopyFileOperation(e => proxy.$onDidRunFileOperation(e.operation, e.files)));
}
dispose(): void {

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as DOM from 'vs/base/browser/dom';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext, INotebookDocumentsAndEditorsDelta, INotebookModelAddedData } from '../common/extHost.protocol';
import { Disposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
@@ -40,7 +41,7 @@ export class MainThreadNotebookDocument extends Disposable {
) {
super();
this._textModel = new NotebookTextModel(handle, viewType, supportBackup, uri);
this._textModel = new NotebookTextModel(handle, viewType, supportBackup, uri, undoRedoService);
this._register(this._textModel.onDidModelChangeProxy(e => {
this._proxy.$acceptModelChanged(this.uri, e);
this._proxy.$acceptEditorPropertiesChanged(uri, { selections: { selections: this._textModel.selections }, metadata: null });
@@ -51,9 +52,18 @@ export class MainThreadNotebookDocument extends Disposable {
}));
}
async applyEdit(modelVersionId: number, edits: ICellEditOperation[], emitToExtHost: boolean): Promise<boolean> {
async applyEdit(modelVersionId: number, edits: ICellEditOperation[], emitToExtHost: boolean, synchronous: boolean): Promise<boolean> {
await this.notebookService.transformEditsOutputs(this.textModel, edits);
return this._textModel.$applyEdit(modelVersionId, edits);
if (synchronous) {
return this._textModel.$applyEdit(modelVersionId, edits, emitToExtHost, synchronous);
} else {
return new Promise(resolve => {
this._register(DOM.scheduleAtNextAnimationFrame(() => {
const ret = this._textModel.$applyEdit(modelVersionId, edits, emitToExtHost, true);
resolve(ret);
}));
});
}
}
async spliceNotebookCellOutputs(cellHandle: number, splices: NotebookCellOutputsSplice[]) {
@@ -250,10 +260,10 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
private _emitDelta(delta: INotebookDocumentsAndEditorsDelta) {
if (this._isDeltaEmpty(delta)) {
return;
return undefined; // {{SQL CARBON EDIT}} strict-null-checks
}
this._proxy.$acceptDocumentAndEditorsDelta(delta);
return this._proxy.$acceptDocumentAndEditorsDelta(delta);
}
registerListeners() {
@@ -476,16 +486,11 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return this._proxy.$executeNotebook(viewType, uri, undefined, useAttachedKernel, token);
}
async $postMessage(handle: number, value: any): Promise<boolean> {
const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
if (activeEditorPane?.isNotebookEditor) {
const notebookEditor = (activeEditorPane.getControl() as INotebookEditor);
if (notebookEditor.viewModel?.handle === handle) {
notebookEditor.postMessage(value);
return true;
}
async $postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean> {
const editor = this._notebookService.getNotebookEditor(editorId) as INotebookEditor | undefined;
if (editor?.isNotebookEditor) {
editor.postMessage(forRendererId, value);
return true;
}
return false;
@@ -533,7 +538,7 @@ export class MainThreadNotebookController implements IMainNotebookController {
await mainthreadNotebook.applyEdit(mainthreadNotebook.textModel.versionId, [
{ editType: CellEditType.Delete, count: mainthreadNotebook.textModel.cells.length, index: 0 },
{ editType: CellEditType.Insert, index: 0, cells: data.cells }
], true);
], true, false);
}
return mainthreadNotebook.textModel;
}
@@ -553,7 +558,7 @@ export class MainThreadNotebookController implements IMainNotebookController {
index: 0,
cells: backup.cells || []
}
], false);
], false, true);
// create document in ext host with cells data
await this._mainThreadNotebook.addNotebookDocument({
@@ -630,7 +635,7 @@ export class MainThreadNotebookController implements IMainNotebookController {
let mainthreadNotebook = this._mapping.get(URI.from(resource).toString());
if (mainthreadNotebook) {
return await mainthreadNotebook.applyEdit(modelVersionId, edits, true);
return await mainthreadNotebook.applyEdit(modelVersionId, edits, true, true);
}
return false;
@@ -645,8 +650,8 @@ export class MainThreadNotebookController implements IMainNotebookController {
return this._mainThreadNotebook.executeNotebook(viewType, uri, useAttachedKernel, token);
}
onDidReceiveMessage(editorId: string, message: any): void {
this._proxy.$onDidReceiveMessage(editorId, message);
onDidReceiveMessage(editorId: string, rendererType: string | undefined, message: unknown): void {
this._proxy.$onDidReceiveMessage(editorId, rendererType, message);
}
async removeNotebookDocument(notebook: INotebookTextModel): Promise<void> {

View File

@@ -6,7 +6,7 @@
import { URI, UriComponents } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { assign } from 'vs/base/common/objects';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation } from 'vs/workbench/contrib/scm/common/scm';
import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../common/extHost.protocol';
import { Command } from 'vs/editor/common/modes';
@@ -264,7 +264,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
private readonly _proxy: ExtHostSCMShape;
private _repositories = new Map<number, ISCMRepository>();
private _inputDisposables = new Map<number, IDisposable>();
private _repositoryDisposables = new Map<number, IDisposable>();
private readonly _disposables = new DisposableStore();
constructor(
@@ -272,17 +272,14 @@ export class MainThreadSCM implements MainThreadSCMShape {
@ISCMService private readonly scmService: ISCMService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSCM);
Event.debounce(scmService.onDidChangeSelectedRepositories, (_, e) => e, 100)
(this.onDidChangeSelectedRepositories, this, this._disposables);
}
dispose(): void {
this._repositories.forEach(r => r.dispose());
this._repositories.clear();
this._inputDisposables.forEach(d => d.dispose());
this._inputDisposables.clear();
this._repositoryDisposables.forEach(d => d.dispose());
this._repositoryDisposables.clear();
this._disposables.dispose();
}
@@ -292,8 +289,16 @@ export class MainThreadSCM implements MainThreadSCMShape {
const repository = this.scmService.registerSCMProvider(provider);
this._repositories.set(handle, repository);
const inputDisposable = repository.input.onDidChange(value => this._proxy.$onInputBoxValueChange(handle, value));
this._inputDisposables.set(handle, inputDisposable);
const disposable = combinedDisposable(
Event.filter(repository.onDidChangeSelection, selected => selected)(_ => this._proxy.$setSelectedSourceControl(handle)),
repository.input.onDidChange(value => this._proxy.$onInputBoxValueChange(handle, value))
);
if (repository.selected) {
setTimeout(() => this._proxy.$setSelectedSourceControl(handle), 0);
}
this._repositoryDisposables.set(handle, disposable);
}
$updateSourceControl(handle: number, features: SCMProviderFeatures): void {
@@ -314,8 +319,8 @@ export class MainThreadSCM implements MainThreadSCMShape {
return;
}
this._inputDisposables.get(handle)!.dispose();
this._inputDisposables.delete(handle);
this._repositoryDisposables.get(handle)!.dispose();
this._repositoryDisposables.delete(handle);
repository.dispose();
this._repositories.delete(handle);
@@ -422,12 +427,4 @@ export class MainThreadSCM implements MainThreadSCMShape {
repository.input.validateInput = async () => undefined;
}
}
private onDidChangeSelectedRepositories(repositories: ISCMRepository[]): void {
const handles = repositories
.filter(r => r.provider instanceof MainThreadSCMProvider)
.map(r => (r.provider as MainThreadSCMProvider).handle);
this._proxy.$setSelectedSourceControls(handles);
}
}

View File

@@ -15,6 +15,7 @@ import { IAccessibilityInformation } from 'vs/platform/accessibility/common/acce
export class MainThreadStatusBar implements MainThreadStatusBarShape {
private readonly entries: Map<number, { accessor: IStatusbarEntryAccessor, alignment: MainThreadStatusBarAlignment, priority: number }> = new Map();
static readonly CODICON_REGEXP = /\$\((.*?)\)/g;
constructor(
_extHostContext: IExtHostContext,
@@ -32,7 +33,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
if (accessibilityInformation) {
ariaLabel = accessibilityInformation.label;
} else {
ariaLabel = text && text.indexOf('$(') === -1 ? text : tooltip || text;
ariaLabel = text ? text.replace(MainThreadStatusBar.CODICON_REGEXP, (_match, codiconName) => codiconName) : '';
}
const entry: IStatusbarEntry = { text, tooltip, command, color, ariaLabel };

View File

@@ -328,10 +328,10 @@ namespace TaskDTO {
result.detail = task.configurationProperties.detail;
}
if (!ConfiguringTask.is(task) && task.command) {
if (task.command.runtime === RuntimeType.Process) {
result.execution = ProcessExecutionDTO.from(task.command);
} else if (task.command.runtime === RuntimeType.Shell) {
result.execution = ShellExecutionDTO.from(task.command);
switch (task.command.runtime) {
case RuntimeType.Process: result.execution = ProcessExecutionDTO.from(task.command); break;
case RuntimeType.Shell: result.execution = ShellExecutionDTO.from(task.command); break;
case RuntimeType.CustomExecution: result.execution = CustomExecutionDTO.from(task.command); break;
}
}
if (task.configurationProperties.problemMatchers) {

View File

@@ -9,7 +9,7 @@ import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceS
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri';
import { StopWatch } from 'vs/base/common/stopwatch';
import { ITerminalInstanceService, ITerminalService, ITerminalInstance, ITerminalBeforeHandleLinkEvent } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalInstanceService, ITerminalService, ITerminalInstance, ITerminalBeforeHandleLinkEvent, ITerminalExternalLinkProvider, ITerminalLink } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
@@ -25,6 +25,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
private readonly _terminalProcessProxies = new Map<number, ITerminalProcessExtHostProxy>();
private _dataEventTracker: TerminalDataEventTracker | undefined;
private _linkHandler: IDisposable | undefined;
/**
* A single shared terminal link provider for the exthost. When an ext registers a link
* provider, this is registered with the terminal on the renderer side and all links are
* provided through this, even from multiple ext link providers. Xterm should remove lower
* priority intersecting links itself.
*/
private _linkProvider: IDisposable | undefined;
constructor(
extHostContext: IExtHostContext,
@@ -81,11 +88,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$initEnvironmentVariableCollections(serializedCollections);
}
this._terminalService.extHostReady(extHostContext.remoteAuthority);
this._terminalService.extHostReady(extHostContext.remoteAuthority!); // TODO@Tyriar: remove null assertion
}
public dispose(): void {
this._toDispose.dispose();
this._linkHandler?.dispose();
this._linkProvider?.dispose();
// TODO@Daniel: Should all the previously created terminals be disposed
// when the extension host process goes down ?
@@ -162,6 +171,17 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
public $stopHandlingLinks(): void {
this._linkHandler?.dispose();
this._linkHandler = undefined;
}
public $startLinkProvider(): void {
this._linkProvider?.dispose();
this._linkProvider = this._terminalService.registerLinkProvider(new ExtensionTerminalLinkProvider(this._proxy));
}
public $stopLinkProvider(): void {
this._linkProvider?.dispose();
this._linkProvider = undefined;
}
private async _handleLink(e: ITerminalBeforeHandleLinkEvent): Promise<boolean> {
@@ -395,3 +415,22 @@ class TerminalDataEventTracker extends Disposable {
this._register(this._bufferer.startBuffering(instance.id, instance.onData));
}
}
class ExtensionTerminalLinkProvider implements ITerminalExternalLinkProvider {
constructor(
private readonly _proxy: ExtHostTerminalServiceShape
) {
}
async provideLinks(instance: ITerminalInstance, line: string): Promise<ITerminalLink[] | undefined> {
const proxy = this._proxy;
const extHostLinks = await proxy.$provideLinks(instance.id, line);
return extHostLinks.map(dto => ({
id: dto.id,
startIndex: dto.startIndex,
length: dto.length,
label: dto.label,
activate: () => proxy.$activateLink(instance.id, dto.id)
}));
}
}

View File

@@ -5,7 +5,7 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions } from 'vs/workbench/common/views';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions, ResolvableTreeItem } from 'vs/workbench/common/views';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { distinct } from 'vs/base/common/arrays';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -165,12 +165,14 @@ export type TreeItemHandle = string;
export class TreeViewDataProvider implements ITreeViewDataProvider {
private readonly itemsMap: Map<TreeItemHandle, ITreeItem> = new Map<TreeItemHandle, ITreeItem>();
private hasResolve: Promise<boolean>;
// {{SQL CARBON EDIT}}
constructor(protected readonly treeViewId: string,
protected readonly _proxy: ExtHostTreeViewsShape,
private readonly notificationService: INotificationService
) {
this.hasResolve = this._proxy.$hasResolve(this.treeViewId);
}
getChildren(treeItem?: ITreeItem): Promise<ITreeItem[]> {
@@ -217,12 +219,16 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
return this.itemsMap.size === 0;
}
private postGetChildren(elements: ITreeItem[]): ITreeItem[] {
const result: ITreeItem[] = [];
private async postGetChildren(elements: ITreeItem[]): Promise<ResolvableTreeItem[]> {
const result: ResolvableTreeItem[] = [];
const hasResolve = await this.hasResolve;
if (elements) {
for (const element of elements) {
const resolvable = new ResolvableTreeItem(element, hasResolve ? () => {
return this._proxy.$resolve(this.treeViewId, element.handle);
} : undefined);
this.itemsMap.set(element.handle, element);
result.push(element);
result.push(resolvable);
}
}
return result;

View File

@@ -141,7 +141,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
this._register(_editorService.onDidActiveEditorChange(() => {
const activeInput = this._editorService.activeEditor;
if (activeInput instanceof DiffEditorInput && activeInput.master instanceof WebviewInput && activeInput.details instanceof WebviewInput) {
if (activeInput instanceof DiffEditorInput && activeInput.primary instanceof WebviewInput && activeInput.secondary instanceof WebviewInput) {
this.registerWebviewFromDiffEditorListeners(activeInput);
}
@@ -185,6 +185,15 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
});
}
dispose() {
super.dispose();
for (const disposable of this._editorProviders.values()) {
disposable.dispose();
}
this._editorProviders.clear();
}
public $createWebviewPanel(
extensionData: extHostProtocol.WebviewExtensionDescription,
handle: extHostProtocol.WebviewPanelHandle,
@@ -320,7 +329,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
options: modes.IWebviewPanelOptions,
capabilities: extHostProtocol.CustomTextEditorCapabilities,
supportsMultipleEditorsPerDocument: boolean,
): DisposableStore {
): void {
if (this._editorProviders.has(viewType)) {
throw new Error(`Provider for ${viewType} already registered`);
}
@@ -396,8 +405,6 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
}));
this._editorProviders.set(viewType, disposables);
return disposables;
}
public $unregisterEditorProvider(viewType: string): void {
@@ -468,22 +475,22 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
}
private registerWebviewFromDiffEditorListeners(diffEditorInput: DiffEditorInput): void {
const master = diffEditorInput.master as WebviewInput;
const details = diffEditorInput.details as WebviewInput;
const primary = diffEditorInput.primary as WebviewInput;
const secondary = diffEditorInput.secondary as WebviewInput;
if (this._webviewFromDiffEditorHandles.has(master.id) || this._webviewFromDiffEditorHandles.has(details.id)) {
if (this._webviewFromDiffEditorHandles.has(primary.id) || this._webviewFromDiffEditorHandles.has(secondary.id)) {
return;
}
this._webviewFromDiffEditorHandles.add(master.id);
this._webviewFromDiffEditorHandles.add(details.id);
this._webviewFromDiffEditorHandles.add(primary.id);
this._webviewFromDiffEditorHandles.add(secondary.id);
const disposables = new DisposableStore();
disposables.add(master.webview.onDidFocus(() => this.updateWebviewViewStates(master)));
disposables.add(details.webview.onDidFocus(() => this.updateWebviewViewStates(details)));
disposables.add(primary.webview.onDidFocus(() => this.updateWebviewViewStates(primary)));
disposables.add(secondary.webview.onDidFocus(() => this.updateWebviewViewStates(secondary)));
disposables.add(diffEditorInput.onDispose(() => {
this._webviewFromDiffEditorHandles.delete(master.id);
this._webviewFromDiffEditorHandles.delete(details.id);
this._webviewFromDiffEditorHandles.delete(primary.id);
this._webviewFromDiffEditorHandles.delete(secondary.id);
dispose(disposables);
}));
}
@@ -515,8 +522,8 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
for (const group of this._editorGroupService.groups) {
for (const input of group.editors) {
if (input instanceof DiffEditorInput) {
updateViewStatesForInput(group, input, input.master);
updateViewStatesForInput(group, input, input.details);
updateViewStatesForInput(group, input, input.primary);
updateViewStatesForInput(group, input, input.secondary);
} else {
updateViewStatesForInput(group, input, input);
}

View File

@@ -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 { TreeViewPane, CustomTreeView } from 'vs/workbench/browser/parts/views/treeView';
import { TreeViewPane } 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';
@@ -32,6 +32,7 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { Codicon } from 'vs/base/common/codicons';
import { CustomTreeView } from 'vs/workbench/contrib/views/browser/treeView';
export interface IUserFriendlyViewsContainerDescriptor {
id: string;

View File

@@ -46,7 +46,7 @@ import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls';
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
import { ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
import { IExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { throwProposedApiError, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
@@ -98,6 +98,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostLogService = accessor.get(ILogService);
const extHostTunnelService = accessor.get(IExtHostTunnelService);
const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService);
const extHostWindow = accessor.get(IExtHostWindow);
// register addressable instances
rpcProtocol.set(ExtHostContext.ExtHostLogService, <ExtHostLogServiceShape><any>extHostLogService);
@@ -106,6 +107,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
rpcProtocol.set(ExtHostContext.ExtHostTunnelService, extHostTunnelService);
rpcProtocol.set(ExtHostContext.ExtHostWindow, extHostWindow);
// automatically create and register addressable instances
const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, accessor.get(IExtHostDecorations));
@@ -132,10 +134,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extensionStoragePaths));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, initData.uiKind === UIKind.Web ? new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment) : new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extensionStoragePaths));
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
@@ -208,12 +209,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
getSession(providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions) {
return extHostAuthentication.getSession(extension, providerId, scopes, options as any);
},
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);
},
logout(providerId: string, sessionId: string): Thenable<void> {
return extHostAuthentication.logout(providerId, sessionId);
},
@@ -589,6 +584,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostTerminalService.registerLinkHandler(handler);
},
registerTerminalLinkProvider(handler: vscode.TerminalLinkProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostTerminalService.registerLinkProvider(handler);
},
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
},
@@ -1119,7 +1118,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
CellKind: extHostTypes.CellKind,
CellOutputKind: extHostTypes.CellOutputKind,
NotebookCellRunState: extHostTypes.NotebookCellRunState,
AuthenticationSession2: extHostTypes.AuthenticationSession
AuthenticationSession: extHostTypes.AuthenticationSession
};
};
}

View File

@@ -112,7 +112,7 @@ export interface IConfigurationInitData extends IConfigurationData {
}
export interface IExtHostContext extends IRPCProtocol {
remoteAuthority: string;
remoteAuthority: string | null;
}
export interface IMainContext extends IRPCProtocol {
@@ -454,6 +454,8 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
$stopSendingDataEvents(): void;
$startHandlingLinks(): void;
$stopHandlingLinks(): void;
$startLinkProvider(): void;
$stopLinkProvider(): void;
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void;
// Process
@@ -713,7 +715,7 @@ export interface MainThreadNotebookShape extends IDisposable {
$updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata): Promise<void>;
$updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata | undefined): Promise<void>;
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void>;
$postMessage(handle: number, value: any): Promise<boolean>;
$postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean>;
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
$onContentChange(resource: UriComponents, viewType: string): void;
@@ -860,6 +862,7 @@ export interface IStartDebuggingOptions {
parentSessionID?: DebugSessionUUID;
repl?: IDebugSessionReplMode;
noDebug?: boolean;
noCompact?: boolean;
}
export interface MainThreadDebugServiceShape extends IDisposable {
@@ -990,6 +993,8 @@ export interface ExtHostTreeViewsShape {
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
$setSelection(treeViewId: string, treeItemHandles: string[]): void;
$setVisible(treeViewId: string, visible: boolean): void;
$hasResolve(treeViewId: string): Promise<boolean>;
$resolve(treeViewId: string, treeItemHandle: string): Promise<ITreeItem | undefined>;
}
export interface ExtHostWorkspaceShape {
@@ -1071,10 +1076,15 @@ export interface FileSystemEvents {
deleted: UriComponents[];
}
export interface SourceTargetPair {
source?: UriComponents;
target: UriComponents;
}
export interface ExtHostFileSystemEventServiceShape {
$onFileEvent(events: FileSystemEvents): void;
$onWillRunFileOperation(operation: files.FileOperation, target: UriComponents, source: UriComponents | undefined, timeout: number, token: CancellationToken): Promise<any>;
$onDidRunFileOperation(operation: files.FileOperation, target: UriComponents, source: UriComponents | undefined): void;
$onWillRunFileOperation(operation: files.FileOperation, files: SourceTargetPair[], timeout: number, token: CancellationToken): Promise<any>;
$onDidRunFileOperation(operation: files.FileOperation, files: SourceTargetPair[]): void;
}
export interface ObjectIdentifier {
@@ -1385,6 +1395,17 @@ export interface IShellAndArgsDto {
args: string[] | string | undefined;
}
export interface ITerminalLinkDto {
/** The ID of the link to enable activation and disposal. */
id: number;
/** The startIndex of the link in the line. */
startIndex: number;
/** The length of the link in the line. */
length: number;
/** The descriptive label for what the link does when activated. */
label?: string;
}
export interface ITerminalDimensionsDto {
columns: number;
rows: number;
@@ -1411,6 +1432,8 @@ export interface ExtHostTerminalServiceShape {
$getAvailableShells(): Promise<IShellDefinitionDto[]>;
$getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
$handleLink(id: number, link: string): Promise<boolean>;
$provideLinks(id: number, line: string): Promise<ITerminalLinkDto[]>;
$activateLink(id: number, linkId: number): void;
$initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
}
@@ -1419,7 +1442,7 @@ export interface ExtHostSCMShape {
$onInputBoxValueChange(sourceControlHandle: number, value: string): void;
$executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number, preserveFocus: boolean): Promise<void>;
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Promise<[string, number] | undefined>;
$setSelectedSourceControls(selectedSourceControlHandles: number[]): Promise<void>;
$setSelectedSourceControl(selectedSourceControlHandle: number | undefined): Promise<void>;
}
export interface ExtHostTaskShape {
@@ -1514,7 +1537,6 @@ export interface ExtHostDebugServiceShape {
export interface DecorationRequest {
readonly id: number;
readonly handle: number;
readonly uri: UriComponents;
}
@@ -1522,7 +1544,7 @@ export type DecorationData = [number, boolean, string, string, ThemeColor];
export type DecorationReply = { [id: number]: DecorationData; };
export interface ExtHostDecorationsShape {
$provideDecorations(requests: DecorationRequest[], token: CancellationToken): Promise<DecorationReply>;
$provideDecorations(handle: number, requests: DecorationRequest[], token: CancellationToken): Promise<DecorationReply>;
}
export interface ExtHostWindowShape {
@@ -1599,7 +1621,7 @@ export interface ExtHostNotebookShape {
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
$renderOutputs(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<UriComponents>): Promise<IOutputRenderResponse<UriComponents> | undefined>;
$renderOutputs2<T>(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<T>): Promise<IOutputRenderResponse<T> | undefined>;
$onDidReceiveMessage(editorId: string, message: any): void;
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void;
$acceptEditorPropertiesChanged(uriComponents: UriComponents, data: INotebookEditorPropertiesChangeData): void;
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): Promise<void>;

View File

@@ -56,8 +56,8 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
return !!(sessions.filter(session => session.scopes.sort().join(' ') === orderedScopes).length);
}
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions & { createIfNone: true }): Promise<vscode.AuthenticationSession2>;
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions): Promise<vscode.AuthenticationSession2 | undefined> {
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions & { createIfNone: true }): Promise<vscode.AuthenticationSession>;
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions): Promise<vscode.AuthenticationSession | undefined> {
const provider = this._authenticationProviders.get(providerId);
const extensionName = requestingExtension.displayName || requestingExtension.name;
const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier);
@@ -100,71 +100,6 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
}
}
async getSessions(requestingExtension: IExtensionDescription, providerId: string, scopes: string[]): Promise<readonly vscode.AuthenticationSession[]> {
const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier);
const orderedScopes = scopes.sort().join(' ');
const sessions = await this.resolveSessions(providerId);
return sessions
.filter(session => session.scopes.sort().join(' ') === orderedScopes)
.map(session => {
return {
id: session.id,
account: session.account,
scopes: session.scopes,
getAccessToken: async () => {
const isAllowed = await this._proxy.$getSessionsPrompt(
providerId,
session.account.displayName,
'', // TODO
// provider.displayName,
extensionId,
requestingExtension.displayName || requestingExtension.name);
if (!isAllowed) {
throw new Error('User did not consent to token access.');
}
return session.accessToken;
}
};
});
}
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 extensionName = requestingExtension.displayName || requestingExtension.name;
const isAllowed = await this._proxy.$loginPrompt(provider.displayName, extensionName);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
const session = await provider.login(scopes);
await this._proxy.$setTrustedExtension(provider.id, session.account.displayName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
return {
id: session.id,
account: session.account,
scopes: session.scopes,
getAccessToken: async () => {
const isAllowed = await this._proxy.$getSessionsPrompt(
provider.id,
session.account.displayName,
provider.displayName,
ExtensionIdentifier.toKey(requestingExtension.identifier),
requestingExtension.displayName || requestingExtension.name);
if (!isAllowed) {
throw new Error('User did not consent to token access.');
}
return session.accessToken;
}
};
}
async logout(providerId: string, sessionId: string): Promise<void> {
const provider = this._authenticationProviders.get(providerId);
if (!provider) {

View File

@@ -296,7 +296,8 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig, {
parentSessionID: options.parentSession ? options.parentSession.id : undefined,
repl: options.consoleMode === DebugConsoleMode.MergeWithParent ? 'mergeWithParent' : 'separate',
noDebug: options.noDebug
noDebug: options.noDebug,
noCompact: options.noCompact
});
}

View File

@@ -52,17 +52,20 @@ export class ExtHostDecorations implements IExtHostDecorations {
});
}
$provideDecorations(requests: DecorationRequest[], token: CancellationToken): Promise<DecorationReply> {
async $provideDecorations(handle: number, requests: DecorationRequest[], token: CancellationToken): Promise<DecorationReply> {
if (!this._provider.has(handle)) {
// might have been unregistered in the meantime
return Object.create(null);
}
const result: DecorationReply = Object.create(null);
return Promise.all(requests.map(request => {
const { handle, uri, id } = request;
const entry = this._provider.get(handle);
if (!entry) {
// might have been unregistered in the meantime
return undefined;
}
const { provider, extensionId } = entry;
return Promise.resolve(provider.provideDecoration(URI.revive(uri), token)).then(data => {
const { provider, extensionId } = this._provider.get(handle)!;
await Promise.all(requests.map(async request => {
try {
const { uri, id } = request;
const data = await Promise.resolve(provider.provideDecoration(URI.revive(uri), token));
if (!data) {
return;
}
@@ -72,13 +75,12 @@ export class ExtHostDecorations implements IExtHostDecorations {
} catch (e) {
this._logService.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`);
}
}, err => {
} catch (err) {
this._logService.error(err);
});
}
}));
})).then(() => {
return result;
});
return result;
}
}

View File

@@ -5,10 +5,10 @@
import { AsyncEmitter, Emitter, Event, IWaitUntil } from 'vs/base/common/event';
import { IRelativePattern, parse } from 'vs/base/common/glob';
import { URI, UriComponents } from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import type * as vscode from 'vscode';
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, MainContext, MainThreadTextEditorsShape, IWorkspaceFileEditDto, IWorkspaceTextEditDto } from './extHost.protocol';
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, MainContext, MainThreadTextEditorsShape, IWorkspaceFileEditDto, IWorkspaceTextEditDto, SourceTargetPair } from './extHost.protocol';
import * as typeConverter from './extHostTypeConverters';
import { Disposable, WorkspaceEdit } from './extHostTypes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@@ -142,16 +142,16 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
//--- file operations
$onDidRunFileOperation(operation: FileOperation, target: UriComponents, source: UriComponents | undefined): void {
$onDidRunFileOperation(operation: FileOperation, files: SourceTargetPair[]): void {
switch (operation) {
case FileOperation.MOVE:
this._onDidRenameFile.fire(Object.freeze({ files: [{ oldUri: URI.revive(source!), newUri: URI.revive(target) }] }));
this._onDidRenameFile.fire(Object.freeze({ files: files.map(f => ({ oldUri: URI.revive(f.source!), newUri: URI.revive(f.target) })) }));
break;
case FileOperation.DELETE:
this._onDidDeleteFile.fire(Object.freeze({ files: [URI.revive(target)] }));
this._onDidDeleteFile.fire(Object.freeze({ files: files.map(f => URI.revive(f.target)) }));
break;
case FileOperation.CREATE:
this._onDidCreateFile.fire(Object.freeze({ files: [URI.revive(target)] }));
this._onDidCreateFile.fire(Object.freeze({ files: files.map(f => URI.revive(f.target)) }));
break;
default:
//ignore, dont send
@@ -179,16 +179,16 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
};
}
async $onWillRunFileOperation(operation: FileOperation, target: UriComponents, source: UriComponents | undefined, timeout: number, token: CancellationToken): Promise<any> {
async $onWillRunFileOperation(operation: FileOperation, files: SourceTargetPair[], timeout: number, token: CancellationToken): Promise<any> {
switch (operation) {
case FileOperation.MOVE:
await this._fireWillEvent(this._onWillRenameFile, { files: [{ oldUri: URI.revive(source!), newUri: URI.revive(target) }] }, timeout, token);
await this._fireWillEvent(this._onWillRenameFile, { files: files.map(f => ({ oldUri: URI.revive(f.source!), newUri: URI.revive(f.target) })) }, timeout, token);
break;
case FileOperation.DELETE:
await this._fireWillEvent(this._onWillDeleteFile, { files: [URI.revive(target)] }, timeout, token);
await this._fireWillEvent(this._onWillDeleteFile, { files: files.map(f => URI.revive(f.target)) }, timeout, token);
break;
case FileOperation.CREATE:
await this._fireWillEvent(this._onWillCreateFile, { files: [URI.revive(target)] }, timeout, token);
await this._fireWillEvent(this._onWillCreateFile, { files: files.map(f => URI.revive(f.target)) }, timeout, token);
break;
default:
//ignore, dont send

View File

@@ -73,7 +73,7 @@ class DocumentSymbolAdapter {
const element: modes.DocumentSymbol = {
name: info.name || '!!MISSING: name!!',
kind: typeConvert.SymbolKind.from(info.kind),
tags: info.tags ? info.tags.map(typeConvert.SymbolTag.from) : [],
tags: info.tags?.map(typeConvert.SymbolTag.from) || [],
detail: '',
containerName: info.containerName,
range: typeConvert.Range.from(info.location.range),
@@ -1287,6 +1287,7 @@ class CallHierarchyAdapter {
uri: item.uri,
range: typeConvert.Range.from(item.range),
selectionRange: typeConvert.Range.from(item.selectionRange),
tags: item.tags?.map(typeConvert.SymbolTag.from)
};
map.set(dto._itemId, item);
return dto;

View File

@@ -553,27 +553,48 @@ export class NotebookEditorCellEditBuilder implements vscode.NotebookEditorCellE
}
}
class ExtHostWebviewComm extends Disposable {
onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
class ExtHostWebviewCommWrapper extends Disposable {
private readonly _onDidReceiveDocumentMessage = new Emitter<any>();
private readonly _rendererIdToEmitters = new Map<string, Emitter<any>>();
constructor(
readonly id: string,
private _editorId: string,
public uri: URI,
private _proxy: MainThreadNotebookShape,
private _onDidReceiveMessage: Emitter<any>,
private _webviewInitData: WebviewInitData,
public document: ExtHostNotebookDocument,
) {
super();
}
async postMessage(message: any): Promise<boolean> {
return this._proxy.$postMessage(this.document.handle, message);
public onDidReceiveMessage(forRendererId: string | undefined, message: any) {
this._onDidReceiveDocumentMessage.fire(message);
if (forRendererId !== undefined) {
this._rendererIdToEmitters.get(forRendererId)?.fire(message);
}
}
asWebviewUri(localResource: vscode.Uri): vscode.Uri {
return asWebviewUri(this._webviewInitData, this.id, localResource);
public readonly contentProviderComm: vscode.NotebookCommunication = {
editorId: this._editorId,
onDidReceiveMessage: this._onDidReceiveDocumentMessage.event,
postMessage: (message: any) => this._proxy.$postMessage(this._editorId, undefined, message),
asWebviewUri: (uri: vscode.Uri) => this._asWebviewUri(uri),
};
public getRendererComm(rendererId: string): vscode.NotebookCommunication {
const emitter = new Emitter<any>();
this._rendererIdToEmitters.set(rendererId, emitter);
return {
editorId: this._editorId,
onDidReceiveMessage: emitter.event,
postMessage: (message: any) => this._proxy.$postMessage(this._editorId, rendererId, message),
asWebviewUri: (uri: vscode.Uri) => this._asWebviewUri(uri),
};
}
private _asWebviewUri(localResource: vscode.Uri): vscode.Uri {
return asWebviewUri(this._webviewInitData, this._editorId, localResource);
}
}
@@ -618,7 +639,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
readonly id: string,
public uri: URI,
private _proxy: MainThreadNotebookShape,
private _webComm: ExtHostWebviewComm,
private _webComm: vscode.NotebookCommunication,
public document: ExtHostNotebookDocument,
private _documentsAndEditors: ExtHostDocumentsAndEditors
) {
@@ -721,6 +742,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
export class ExtHostNotebookOutputRenderer {
private static _handlePool: number = 0;
private resolvedComms = new WeakSet<ExtHostWebviewCommWrapper>();
readonly handle = ExtHostNotebookOutputRenderer._handlePool++;
constructor(
@@ -740,13 +762,19 @@ export class ExtHostNotebookOutputRenderer {
return false;
}
resolveNotebook(document: ExtHostNotebookDocument, comm: ExtHostWebviewCommWrapper) {
if (!this.resolvedComms.has(comm) && this.renderer.resolveNotebook) {
this.renderer.resolveNotebook(document, comm.getRendererComm(this.type));
this.resolvedComms.add(comm);
}
}
render(document: ExtHostNotebookDocument, output: vscode.CellDisplayOutput, outputId: string, mimeType: string): string {
let html = this.renderer.render(document, { output, outputId, mimeType });
return html;
}
}
export interface ExtHostNotebookOutputRenderingHandler {
outputDisplayOrder: INotebookDisplayOrder | undefined;
findBestMatchedRenderer(mimeType: string): ExtHostNotebookOutputRenderer[];
@@ -759,8 +787,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private readonly _documents = new Map<string, ExtHostNotebookDocument>();
private readonly _unInitializedDocuments = new Map<string, ExtHostNotebookDocument>();
private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor }>();
private readonly _webviewComm = new Map<string, { comm: ExtHostWebviewComm, onDidReceiveMessage: Emitter<any> }>();
private readonly _webviewComm = new Map<string, ExtHostWebviewCommWrapper>();
private readonly _notebookOutputRenderers = new Map<string, ExtHostNotebookOutputRenderer>();
private readonly _renderersUsedInNotebooks = new WeakMap<ExtHostNotebookDocument, Set<ExtHostNotebookOutputRenderer>>();
private readonly _onDidChangeNotebookCells = new Emitter<vscode.NotebookCellsChangeEvent>();
readonly onDidChangeNotebookCells = this._onDidChangeNotebookCells.event;
private readonly _onDidChangeCellOutputs = new Emitter<vscode.NotebookCellOutputsChangeEvent>();
@@ -854,6 +883,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
const renderer = this._notebookOutputRenderers.get(id)!;
this.provideCommToNotebookRenderers(document, renderer);
const cellsResponse: IOutputRenderResponseCellInfo<UriComponents>[] = request.items.map(cellInfo => {
const cell = document.getCell2(cellInfo.key)!;
const outputResponse: IOutputRenderResponseOutputInfo[] = cellInfo.outputs.map(output => {
@@ -890,6 +921,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
const renderer = this._notebookOutputRenderers.get(id)!;
this.provideCommToNotebookRenderers(document, renderer);
const cellsResponse: IOutputRenderResponseCellInfo<T>[] = request.items.map(cellInfo => {
const outputResponse: IOutputRenderResponseOutputInfo[] = cellInfo.outputs.map(output => {
return {
@@ -1035,19 +1068,36 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
return;
}
let webComm = this._webviewComm.get(editorId);
if (!webComm) {
webComm = new ExtHostWebviewCommWrapper(editorId, revivedUri, this._proxy, this._webviewInitData, document);
this._webviewComm.set(editorId, webComm);
}
if (!provider.provider.resolveNotebook) {
return;
}
let webComm = this._webviewComm.get(editorId)?.comm;
await provider.provider.resolveNotebook(document, webComm.contentProviderComm);
}
if (webComm) {
await provider.provider.resolveNotebook(document, webComm);
} else {
const onDidReceiveMessage = new Emitter<any>();
webComm = new ExtHostWebviewComm(editorId, revivedUri, this._proxy, onDidReceiveMessage, this._webviewInitData, document);
this._webviewComm.set(editorId, { comm: webComm, onDidReceiveMessage });
await provider.provider.resolveNotebook(document, webComm);
private provideCommToNotebookRenderers(document: ExtHostNotebookDocument, renderer: ExtHostNotebookOutputRenderer) {
let alreadyRegistered = this._renderersUsedInNotebooks.get(document);
if (!alreadyRegistered) {
alreadyRegistered = new Set();
this._renderersUsedInNotebooks.set(document, alreadyRegistered);
}
if (alreadyRegistered.has(renderer)) {
return;
}
alreadyRegistered.add(renderer);
for (const editorId of this._editors.keys()) {
const comm = this._webviewComm.get(editorId);
if (comm) {
renderer.resolveNotebook(document, comm);
}
}
}
@@ -1101,12 +1151,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
if (this._notebookContentProviders.has(viewType)) {
try {
await this._notebookContentProviders.get(viewType)!.provider.saveNotebook(document, token);
} catch (e) {
return false;
}
await this._notebookContentProviders.get(viewType)!.provider.saveNotebook(document, token);
return true;
}
@@ -1120,12 +1165,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
if (this._notebookContentProviders.has(viewType)) {
try {
await this._notebookContentProviders.get(viewType)!.provider.saveNotebookAs(URI.revive(target), document, token);
} catch (e) {
return false;
}
await this._notebookContentProviders.get(viewType)!.provider.saveNotebookAs(URI.revive(target), document, token);
return true;
}
@@ -1182,12 +1222,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
return editor;
}
$onDidReceiveMessage(editorId: string, message: any): void {
let messageEmitter = this._webviewComm.get(editorId)?.onDidReceiveMessage;
if (messageEmitter) {
messageEmitter.fire(message);
}
$onDidReceiveMessage(editorId: string, forRendererType: string | undefined, message: any): void {
this._webviewComm.get(editorId)?.onDidReceiveMessage(forRendererType, message);
}
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void {
@@ -1226,12 +1262,11 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, selections: number[]) {
const revivedUri = document.uri;
let webComm = this._webviewComm.get(editorId)?.comm;
let webComm = this._webviewComm.get(editorId);
if (!webComm) {
const onDidReceiveMessage = new Emitter<any>();
webComm = new ExtHostWebviewComm(editorId, revivedUri, this._proxy, onDidReceiveMessage, this._webviewInitData, document);
this._webviewComm.set(editorId, { comm: webComm!, onDidReceiveMessage });
webComm = new ExtHostWebviewCommWrapper(editorId, revivedUri, this._proxy, this._webviewInitData, document);
this._webviewComm.set(editorId, webComm);
}
let editor = new ExtHostNotebookEditor(
@@ -1239,7 +1274,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
editorId,
revivedUri,
this._proxy,
webComm,
webComm.contentProviderComm,
document,
this._documentsAndEditors
);
@@ -1255,6 +1290,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
this._editors.get(editorId)?.editor.dispose();
for (const renderer of this._renderersUsedInNotebooks.get(document) ?? []) {
renderer.resolveNotebook(document, webComm);
}
this._editors.set(editorId, { editor });
}

View File

@@ -12,7 +12,7 @@ import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'
import { DisposableStore } from 'vs/base/common/lifecycle';
import { score } from 'vs/editor/common/modes/languageSelector';
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { isEqual } from 'vs/base/common/resources';
import { ResourceMap } from 'vs/base/common/map';
export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextDocument {
@@ -20,6 +20,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
private _isClosed = false;
private _cells!: ExtHostCell[];
private _cellUris!: ResourceMap<number>;
private _cellLengths!: PrefixSumComputer;
private _cellLines!: PrefixSumComputer;
private _versionId = 0;
@@ -36,8 +37,8 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
this._init();
this._disposables.add(extHostDocuments.onDidChangeDocument(e => {
let cellIdx = this._cells.findIndex(cell => isEqual(cell.uri, e.document.uri));
if (cellIdx >= 0) {
let cellIdx = this._cellUris.get(e.document.uri);
if (cellIdx !== undefined) {
this._cellLengths.changeValue(cellIdx, this._cells[cellIdx].document.getText().length + 1);
this._cellLines.changeValue(cellIdx, this._cells[cellIdx].document.lineCount);
this._versionId += 1;
@@ -53,7 +54,6 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
};
this._disposables.add(extHostNotebooks.onDidChangeCellLanguage(e => documentChange(e.document)));
this._disposables.add(extHostNotebooks.onDidChangeCellOutputs(e => documentChange(e.document)));
this._disposables.add(extHostNotebooks.onDidChangeNotebookCells(e => documentChange(e.document)));
}
@@ -68,10 +68,12 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
private _init() {
this._cells = [];
this._cellUris = new ResourceMap();
const cellLengths: number[] = [];
const cellLineCounts: number[] = [];
for (let cell of this._notebook.cells) {
if (cell.cellKind === CellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) {
this._cellUris.set(cell.uri, this._cells.length);
this._cells.push(<ExtHostCell>cell);
cellLengths.push(cell.document.getText().length + 1);
cellLineCounts.push(cell.document.lineCount);
@@ -103,8 +105,8 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
// get start and end locations and create substrings
const start = this.locationAt(range.start);
const end = this.locationAt(range.end);
const startCell = this._cells.find(cell => isEqual(cell.uri, start.uri));
const endCell = this._cells.find(cell => isEqual(cell.uri, end.uri));
const startCell = this._cells[this._cellUris.get(start.uri) ?? -1];
const endCell = this._cells[this._cellUris.get(end.uri) ?? -1];
if (!startCell || !endCell) {
return '';
@@ -131,8 +133,8 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
return this._cells[idx.index].document.positionAt(idx.remainder).translate(lineCount);
}
const idx = this._cells.findIndex(cell => isEqual(cell.uri, locationOrOffset.uri));
if (idx >= 0) {
const idx = this._cellUris.get(locationOrOffset.uri);
if (idx !== undefined) {
let line = this._cellLines.getAccumulatedValue(idx - 1);
return new types.Position(line + locationOrOffset.range.start.line, locationOrOffset.range.start.character);
}
@@ -159,4 +161,24 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
const startCell = this._cells[startIdx.index];
return new types.Location(startCell.uri, <types.Range>startCell.document.validateRange(range));
}
contains(uri: vscode.Uri): boolean {
return this._cellUris.has(uri);
}
validateRange(range: vscode.Range): vscode.Range {
const start = this.validatePosition(range.start);
const end = this.validatePosition(range.end);
return range.with(start, end);
}
validatePosition(position: vscode.Position): vscode.Position {
const startIdx = this._cellLines.getIndexOf(position.line);
const cellPosition = new types.Position(startIdx.remainder, position.character);
const validCellPosition = this._cells[startIdx.index].document.validatePosition(cellPosition);
const line = this._cellLines.getAccumulatedValue(startIdx.index - 1);
return new types.Position(line + validCellPosition.line, validCellPosition.character);
}
}

View File

@@ -536,7 +536,7 @@ export class ExtHostSCM implements ExtHostSCMShape {
private readonly _onDidChangeActiveProvider = new Emitter<vscode.SourceControl>();
get onDidChangeActiveProvider(): Event<vscode.SourceControl> { return this._onDidChangeActiveProvider.event; }
private _selectedSourceControlHandles = new Set<number>();
private _selectedSourceControlHandle: number | undefined;
constructor(
mainContext: IMainContext,
@@ -681,40 +681,18 @@ export class ExtHostSCM implements ExtHostSCMShape {
});
}
$setSelectedSourceControls(selectedSourceControlHandles: number[]): Promise<void> {
this.logService.trace('ExtHostSCM#$setSelectedSourceControls', selectedSourceControlHandles);
$setSelectedSourceControl(selectedSourceControlHandle: number | undefined): Promise<void> {
this.logService.trace('ExtHostSCM#$setSelectedSourceControl', selectedSourceControlHandle);
const set = new Set<number>();
for (const handle of selectedSourceControlHandles) {
set.add(handle);
if (selectedSourceControlHandle !== undefined) {
this._sourceControls.get(selectedSourceControlHandle)?.setSelectionState(true);
}
set.forEach(handle => {
if (!this._selectedSourceControlHandles.has(handle)) {
const sourceControl = this._sourceControls.get(handle);
if (this._selectedSourceControlHandle !== undefined) {
this._sourceControls.get(this._selectedSourceControlHandle)?.setSelectionState(false);
}
if (!sourceControl) {
return;
}
sourceControl.setSelectionState(true);
}
});
this._selectedSourceControlHandles.forEach(handle => {
if (!set.has(handle)) {
const sourceControl = this._sourceControls.get(handle);
if (!sourceControl) {
return;
}
sourceControl.setSelectionState(false);
}
});
this._selectedSourceControlHandles = set;
this._selectedSourceControlHandle = selectedSourceControlHandle;
return Promise.resolve(undefined);
}
}

View File

@@ -5,7 +5,7 @@
import type * as vscode from 'vscode';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto, ITerminalLinkDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI, UriComponents } from 'vs/base/common/uri';
@@ -39,6 +39,7 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable;
registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable;
getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
}
@@ -293,6 +294,13 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
}
}
let nextLinkId = 1;
interface ICachedLinkEntry {
provider: vscode.TerminalLinkProvider;
link: vscode.TerminalLink;
}
export abstract class BaseExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape {
readonly _serviceBrand: undefined;
@@ -307,6 +315,8 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
private readonly _bufferer: TerminalDataBufferer;
private readonly _linkHandlers: Set<vscode.TerminalLinkHandler> = new Set();
private readonly _linkProviders: Set<vscode.TerminalLinkProvider> = new Set();
private readonly _terminalLinkCache: Map<number, Map<number, ICachedLinkEntry>> = new Map();
public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
public get terminals(): ExtHostTerminal[] { return this._terminals; }
@@ -547,17 +557,30 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
public registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable {
this._linkHandlers.add(handler);
if (this._linkHandlers.size === 1) {
if (this._linkHandlers.size === 1 && this._linkProviders.size === 0) {
this._proxy.$startHandlingLinks();
}
return new VSCodeDisposable(() => {
this._linkHandlers.delete(handler);
if (this._linkHandlers.size === 0) {
if (this._linkHandlers.size === 0 && this._linkProviders.size === 0) {
this._proxy.$stopHandlingLinks();
}
});
}
public registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable {
this._linkProviders.add(provider);
if (this._linkProviders.size === 1) {
this._proxy.$startLinkProvider();
}
return new VSCodeDisposable(() => {
this._linkProviders.delete(provider);
if (this._linkProviders.size === 0) {
this._proxy.$stopLinkProvider();
}
});
}
public async $handleLink(id: number, link: string): Promise<boolean> {
const terminal = this._getTerminalById(id);
if (!terminal) {
@@ -577,6 +600,60 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
return false;
}
public async $provideLinks(terminalId: number, line: string): Promise<ITerminalLinkDto[]> {
const terminal = this._getTerminalById(terminalId);
if (!terminal) {
return [];
}
// Discard any cached links the terminal has been holding, currently all links are released
// when new links are provided.
this._terminalLinkCache.delete(terminalId);
const result: ITerminalLinkDto[] = [];
const context: vscode.TerminalLinkContext = { terminal, line };
const promises: vscode.ProviderResult<{ provider: vscode.TerminalLinkProvider, links: vscode.TerminalLink[] }>[] = [];
for (const provider of this._linkProviders) {
promises.push(new Promise(async r => {
const links = (await provider.provideTerminalLinks(context)) || [];
r({ provider, links });
}));
}
const provideResults = await Promise.all(promises);
const cacheLinkMap = new Map<number, ICachedLinkEntry>();
for (const provideResult of provideResults) {
if (provideResult && provideResult.links.length > 0) {
result.push(...provideResult.links.map(providerLink => {
const endIndex = Math.max(providerLink.endIndex, providerLink.startIndex + 1);
const link = {
id: nextLinkId++,
startIndex: providerLink.startIndex,
length: endIndex - providerLink.startIndex,
label: providerLink.tooltip
};
cacheLinkMap.set(link.id, {
provider: provideResult.provider,
link: providerLink
});
return link;
}));
}
}
this._terminalLinkCache.set(terminalId, cacheLinkMap);
return result;
}
$activateLink(terminalId: number, linkId: number): void {
const cachedLink = this._terminalLinkCache.get(terminalId)?.get(linkId);
if (!cachedLink) {
return;
}
cachedLink.provider.handleTerminalLink(cachedLink.link);
}
private _onProcessExit(id: number, exitCode: number | undefined): void {
this._bufferer.stopBuffering(id);

View File

@@ -19,6 +19,8 @@ import { equals, coalesce } from 'vs/base/common/arrays';
import { ILogService } from 'vs/platform/log/common/log';
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { MarkdownString } from 'vs/workbench/api/common/extHostTypeConverters';
import { IMarkdownString } from 'vs/base/common/htmlContent';
// {{SQL CARBON EDIT}}
import * as azdata from 'azdata';
@@ -119,6 +121,22 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
return treeView.getChildren(treeItemHandle);
}
async $hasResolve(treeViewId: string): Promise<boolean> {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
throw new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId));
}
return treeView.hasResolve;
}
$resolve(treeViewId: string, treeItemHandle: string): Promise<ITreeItem | undefined> {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
throw new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId));
}
return treeView.resolveTreeItem(treeItemHandle);
}
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
@@ -160,6 +178,7 @@ type TreeData<T> = { message: boolean, element: T | Root | false };
export interface TreeNode extends IDisposable { // {{SQL CARBON EDIT}} export interface
item: ITreeItem;
extensionItem: vscode.TreeItem2;
parent: TreeNode | Root;
children?: TreeNode[];
}
@@ -334,8 +353,28 @@ export class ExtHostTreeView<T> extends Disposable {
}
}
// {{SQL CARBON EDIT}}
protected resolveUnknownParentChain(element: T): Promise<TreeNode[]> {
get hasResolve(): boolean {
return !!this.dataProvider.resolveTreeItem;
}
async resolveTreeItem(treeItemHandle: string): Promise<ITreeItem | undefined> {
if (!this.dataProvider.resolveTreeItem) {
return undefined; // {{SQL CARBON EDIT}} strict-null-checks
}
const element = this.elements.get(treeItemHandle);
if (element) {
const node = this.nodes.get(element);
if (node) {
const resolve = await this.dataProvider.resolveTreeItem(element, node.extensionItem);
// Resolvable elements. Currently only tooltip.
node.item.tooltip = resolve.tooltip;
return node.item;
}
}
return undefined; // {{SQL CARBON EDIT}} strict-null-checks
}
protected resolveUnknownParentChain(element: T): Promise<TreeNode[]> { // {{SQL CARBON EDIT}}
return this.resolveParent(element)
.then((parent) => {
if (!parent) {
@@ -498,7 +537,18 @@ export class ExtHostTreeView<T> extends Disposable {
return node;
}
protected createTreeNode(element: T, extensionTreeItem: azdata.TreeItem2, parent: TreeNode | Root): TreeNode { // {{SQL CARBON EDIT}} change to protected, change to azdata.TreeItem
private getTooltip(tooltip?: string | vscode.MarkdownString): string | IMarkdownString | undefined {
if (typeof tooltip === 'string') {
return tooltip;
} else if (tooltip === undefined) {
return undefined;
} else {
checkProposedApiEnabled(this.extension);
return MarkdownString.from(tooltip);
}
}
protected createTreeNode(element: T, extensionTreeItem: azdata.TreeItem2, parent: TreeNode | Root): TreeNode { // {{SQL CARBON EDIT}} change to protected, change to azdata.TreeItem
const disposable = new DisposableStore();
const handle = this.createHandle(element, extensionTreeItem, parent);
const icon = this.getLightIconPath(extensionTreeItem);
@@ -508,7 +558,7 @@ export class ExtHostTreeView<T> extends Disposable {
label: toTreeItemLabel(extensionTreeItem.label, this.extension),
description: extensionTreeItem.description,
resourceUri: extensionTreeItem.resourceUri,
tooltip: typeof extensionTreeItem.tooltip === 'string' ? extensionTreeItem.tooltip : undefined,
tooltip: this.getTooltip(extensionTreeItem.tooltip),
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command, disposable) : undefined,
contextValue: extensionTreeItem.contextValue,
icon,
@@ -523,6 +573,7 @@ export class ExtHostTreeView<T> extends Disposable {
return {
item,
extensionItem: extensionTreeItem,
parent,
children: undefined,
dispose(): void { disposable.dispose(); }

View File

@@ -646,7 +646,7 @@ export namespace DocumentSymbol {
range: Range.from(info.range),
selectionRange: Range.from(info.selectionRange),
kind: SymbolKind.from(info.kind),
tags: info.tags ? info.tags.map(SymbolTag.from) : []
tags: info.tags?.map(SymbolTag.from) ?? []
};
if (info.children) {
result.children = info.children.map(from);
@@ -911,7 +911,7 @@ export namespace CompletionItem {
result.insertText = suggestion.insertText;
result.kind = CompletionItemKind.to(suggestion.kind);
result.tags = suggestion.tags && suggestion.tags.map(CompletionItemTag.to);
result.tags = suggestion.tags?.map(CompletionItemTag.to);
result.detail = suggestion.detail;
result.documentation = htmlContent.isMarkdownString(suggestion.documentation) ? MarkdownString.to(suggestion.documentation) : suggestion.documentation;
result.sortText = suggestion.sortText;

View File

@@ -1252,7 +1252,7 @@ export class MarkdownString {
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
this.value += (this.supportThemeIcons ? escapeCodicons(value) : value)
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
.replace('\n', '\n\n');
.replace(/\n/, '\n\n');
return this;
}
@@ -2101,7 +2101,7 @@ export class TreeItem {
iconPath?: string | URI | { light: string | URI; dark: string | URI; };
command?: vscode.Command;
contextValue?: string;
tooltip?: string;
tooltip?: string | vscode.MarkdownString;
constructor(label: string | vscode.TreeItemLabel, collapsibleState?: vscode.TreeItemCollapsibleState);
constructor(resourceUri: URI, collapsibleState?: vscode.TreeItemCollapsibleState);
@@ -2769,7 +2769,7 @@ export enum ExtensionMode {
//#region Authentication
export class AuthenticationSession implements vscode.AuthenticationSession2 {
export class AuthenticationSession implements vscode.AuthenticationSession {
constructor(public id: string, public accessToken: string, public account: { displayName: string, id: string }, public scopes: string[]) { }
}

View File

@@ -4,13 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IMainContext, IOpenUriOptions } from './extHost.protocol';
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IOpenUriOptions } from './extHost.protocol';
import { WindowState } from 'vscode';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
export class ExtHostWindow implements ExtHostWindowShape {
export class ExtHostWindow implements IExtHostWindow {
private static InitialState: WindowState = {
focused: true
@@ -24,8 +26,8 @@ export class ExtHostWindow implements ExtHostWindowShape {
private _state = ExtHostWindow.InitialState;
get state(): WindowState { return this._state; }
constructor(mainContext: IMainContext) {
this._proxy = mainContext.getProxy(MainContext.MainThreadWindow);
constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadWindow);
this._proxy.$getWindowVisibility().then(isFocused => this.$onDidChangeWindowFocus(isFocused));
}
@@ -67,3 +69,6 @@ export class ExtHostWindow implements ExtHostWindowShape {
return URI.from(result);
}
}
export const IExtHostWindow = createDecorator<IExtHostWindow>('IExtHostWindow');
export interface IExtHostWindow extends ExtHostWindow, ExtHostWindowShape { }

View File

@@ -29,12 +29,14 @@ import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { ExtHostTunnelService } from 'vs/workbench/api/node/extHostTunnelService';
import { IExtHostApiDeprecationService, ExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { IExtHostWindow, ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
// register singleton services
registerSingleton(ILogService, ExtHostLogService);
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
registerSingleton(IExtHostOutputService, ExtHostOutputService2);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostWindow, ExtHostWindow);
registerSingleton(IExtHostDecorations, ExtHostDecorations);
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
registerSingleton(IExtHostCommands, ExtHostCommands);

View File

@@ -121,6 +121,6 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
}
protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService {
return new ExtHostVariableResolverService(folders, undefined, configurationService, process.env as env.IProcessEnvironment);
return new ExtHostVariableResolverService(folders, editorService, configurationService, process.env as env.IProcessEnvironment);
}
}

View File

@@ -59,7 +59,7 @@ export class ExtHostTask extends ExtHostTaskBase {
throw new Error('Task from execution DTO is undefined');
}
const execution = await this.getTaskExecution(executionDTO, task);
this._proxy.$executeTask(executionDTO.task).catch(error => { throw new Error(error); });
this._proxy.$executeTask(executionDTO.task).catch(() => { /* The error here isn't actionable. */ });
return execution;
} else {
const dto = TaskDTO.from(task, extension);
@@ -75,7 +75,7 @@ export class ExtHostTask extends ExtHostTaskBase {
}
// Always get the task execution first to prevent timing issues when retrieving it later
const execution = await this.getTaskExecution(await this._proxy.$getTaskExecution(dto), task);
this._proxy.$executeTask(dto).catch(error => { throw new Error(error); });
this._proxy.$executeTask(dto).catch(() => { /* The error here isn't actionable. */ });
return execution;
}
}

View File

@@ -51,7 +51,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
// fetch JS sources as text and create a new function around it
const source = await response.text();
const initFn = new Function('module', 'exports', 'require', 'window', `${source}\n//# sourceURL=${module.toString(true)}`);
const initFn = new Function('module', 'exports', 'require', `${source}\n//# sourceURL=${module.toString(true)}`);
// define commonjs globals: `module`, `exports`, and `require`
const _exports = {};
@@ -66,7 +66,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
try {
activationTimesBuilder.codeLoadingStart();
initFn(_module, _exports, _require, self);
initFn(_module, _exports, _require);
return <T>(_module.exports !== _exports ? _module.exports : _exports);
} finally {
activationTimesBuilder.codeLoadingStop();