mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-24 17:23:05 -05:00
Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c (#8525)
* Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c * remove files we don't want * fix hygiene * update distro * update distro * fix hygiene * fix strict nulls * distro * distro * fix tests * fix tests * add another edit * fix viewlet icon * fix azure dialog * fix some padding * fix more padding issues
This commit is contained in:
@@ -18,7 +18,7 @@ import { Extensions as PanelExtensions, PanelDescriptor, PanelRegistry } from 'v
|
||||
import { ICommentInfo, ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
|
||||
import { CommentsPanel } from 'vs/workbench/contrib/comments/browser/commentsPanel';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../common/extHost.protocol';
|
||||
import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape, CommentThreadChanges } from '../common/extHost.protocol';
|
||||
import { COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';
|
||||
|
||||
|
||||
@@ -116,17 +116,15 @@ export class MainThreadCommentThread implements modes.CommentThread {
|
||||
this._isDisposed = false;
|
||||
}
|
||||
|
||||
batchUpdate(
|
||||
range: IRange,
|
||||
label: string,
|
||||
contextValue: string | undefined,
|
||||
comments: modes.Comment[],
|
||||
collapsibleState: modes.CommentThreadCollapsibleState) {
|
||||
this._range = range;
|
||||
this._label = label;
|
||||
this._contextValue = contextValue;
|
||||
this._comments = comments;
|
||||
this._collapsibleState = collapsibleState;
|
||||
batchUpdate(changes: CommentThreadChanges) {
|
||||
const modified = (value: keyof CommentThreadChanges): boolean =>
|
||||
Object.prototype.hasOwnProperty.call(changes, value);
|
||||
|
||||
if (modified('range')) { this._range = changes.range!; }
|
||||
if (modified('label')) { this._label = changes.label; }
|
||||
if (modified('contextValue')) { this._contextValue = changes.contextValue; }
|
||||
if (modified('comments')) { this._comments = changes.comments; }
|
||||
if (modified('collapseState')) { this._collapsibleState = changes.collapseState; }
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -228,13 +226,9 @@ export class MainThreadCommentController {
|
||||
updateCommentThread(commentThreadHandle: number,
|
||||
threadId: string,
|
||||
resource: UriComponents,
|
||||
range: IRange,
|
||||
label: string,
|
||||
contextValue: string | undefined,
|
||||
comments: modes.Comment[],
|
||||
collapsibleState: modes.CommentThreadCollapsibleState): void {
|
||||
changes: CommentThreadChanges): void {
|
||||
let thread = this.getKnownThread(commentThreadHandle);
|
||||
thread.batchUpdate(range, label, contextValue, comments, collapsibleState);
|
||||
thread.batchUpdate(changes);
|
||||
|
||||
this._commentService.updateComments(this._uniqueId, {
|
||||
added: [],
|
||||
@@ -430,18 +424,14 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
commentThreadHandle: number,
|
||||
threadId: string,
|
||||
resource: UriComponents,
|
||||
range: IRange,
|
||||
label: string,
|
||||
contextValue: string | undefined,
|
||||
comments: modes.Comment[],
|
||||
collapsibleState: modes.CommentThreadCollapsibleState): void {
|
||||
changes: CommentThreadChanges): void {
|
||||
let provider = this._commentControllers.get(handle);
|
||||
|
||||
if (!provider) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return provider.updateCommentThread(commentThreadHandle, threadId, resource, range, label, contextValue, comments, collapsibleState);
|
||||
return provider.updateCommentThread(commentThreadHandle, threadId, resource, changes);
|
||||
}
|
||||
|
||||
$deleteCommentThread(handle: number, commentThreadHandle: number) {
|
||||
@@ -456,7 +446,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
||||
|
||||
private registerPanel(commentsPanelAlreadyConstructed: boolean) {
|
||||
if (!commentsPanelAlreadyConstructed) {
|
||||
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescriptor(
|
||||
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(PanelDescriptor.create(
|
||||
CommentsPanel,
|
||||
COMMENTS_PANEL_ID,
|
||||
COMMENTS_PANEL_TITLE,
|
||||
|
||||
@@ -33,11 +33,11 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
|
||||
|
||||
private static _convertOpenOptions(options: MainThreadDialogOpenOptions): IOpenDialogOptions {
|
||||
const result: IOpenDialogOptions = {
|
||||
openLabel: options.openLabel,
|
||||
openLabel: options.openLabel || undefined,
|
||||
canSelectFiles: options.canSelectFiles || (!options.canSelectFiles && !options.canSelectFolders),
|
||||
canSelectFolders: options.canSelectFolders,
|
||||
canSelectMany: options.canSelectMany,
|
||||
defaultUri: URI.revive(options.defaultUri)
|
||||
defaultUri: options.defaultUri ? URI.revive(options.defaultUri) : undefined
|
||||
};
|
||||
if (options.filters) {
|
||||
result.filters = [];
|
||||
@@ -48,8 +48,8 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
|
||||
|
||||
private static _convertSaveOptions(options: MainThreadDialogSaveOptions): ISaveDialogOptions {
|
||||
const result: ISaveDialogOptions = {
|
||||
defaultUri: URI.revive(options.defaultUri),
|
||||
saveLabel: options.saveLabel
|
||||
defaultUri: options.defaultUri ? URI.revive(options.defaultUri) : undefined,
|
||||
saveLabel: options.saveLabel || undefined
|
||||
};
|
||||
if (options.filters) {
|
||||
result.filters = [];
|
||||
|
||||
@@ -16,7 +16,7 @@ import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThre
|
||||
import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ITextEditorModel } from 'vs/workbench/common/editor';
|
||||
import { ITextFileService, TextFileModelChangeEvent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { toLocalResource } from 'vs/base/common/resources';
|
||||
|
||||
@@ -70,7 +70,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
private readonly _textModelResolverService: ITextModelService;
|
||||
private readonly _textFileService: ITextFileService;
|
||||
private readonly _fileService: IFileService;
|
||||
private readonly _untitledEditorService: IUntitledEditorService;
|
||||
private readonly _untitledTextEditorService: IUntitledTextEditorService;
|
||||
private readonly _environmentService: IWorkbenchEnvironmentService;
|
||||
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
@@ -87,14 +87,14 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
||||
@IUntitledTextEditorService untitledTextEditorService: IUntitledTextEditorService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
this._modelService = modelService;
|
||||
this._textModelResolverService = textModelResolverService;
|
||||
this._textFileService = textFileService;
|
||||
this._fileService = fileService;
|
||||
this._untitledEditorService = untitledEditorService;
|
||||
this._untitledTextEditorService = untitledTextEditorService;
|
||||
this._environmentService = environmentService;
|
||||
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
|
||||
@@ -227,13 +227,13 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
}
|
||||
|
||||
private _doCreateUntitled(resource?: URI, mode?: string, initialValue?: string): Promise<URI> {
|
||||
return this._untitledEditorService.loadOrCreate({
|
||||
return this._untitledTextEditorService.loadOrCreate({
|
||||
resource,
|
||||
mode,
|
||||
initialValue,
|
||||
useResourcePath: Boolean(resource && resource.path)
|
||||
}).then(model => {
|
||||
const resource = model.getResource();
|
||||
const resource = model.resource;
|
||||
|
||||
if (!this._modelIsSynced.has(resource.toString())) {
|
||||
throw new Error(`expected URI ${resource.toString()} to have come to LIFE`);
|
||||
|
||||
@@ -28,7 +28,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
namespace delta {
|
||||
@@ -327,7 +327,7 @@ export class MainThreadDocumentsAndEditors {
|
||||
@IModeService modeService: IModeService,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
||||
@IUntitledTextEditorService untitledTextEditorService: IUntitledTextEditorService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IBulkEditService bulkEditService: IBulkEditService,
|
||||
@IPanelService panelService: IPanelService,
|
||||
@@ -335,7 +335,7 @@ export class MainThreadDocumentsAndEditors {
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
||||
|
||||
const mainThreadDocuments = this._toDispose.add(new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService, environmentService));
|
||||
const mainThreadDocuments = this._toDispose.add(new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledTextEditorService, environmentService));
|
||||
extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments);
|
||||
|
||||
const mainThreadTextEditors = this._toDispose.add(new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService));
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode } from 'vs/platform/files/common/files';
|
||||
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability } from 'vs/platform/files/common/files';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
@@ -52,10 +52,10 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
$stat(uri: UriComponents): Promise<IStat> {
|
||||
return this._fileService.resolve(URI.revive(uri), { resolveMetadata: true }).then(stat => {
|
||||
return {
|
||||
ctime: 0,
|
||||
ctime: stat.ctime,
|
||||
mtime: stat.mtime,
|
||||
size: stat.size,
|
||||
type: MainThreadFileSystem._getFileType(stat)
|
||||
type: MainThreadFileSystem._asFileType(stat)
|
||||
};
|
||||
}).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
@@ -67,12 +67,22 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
err.name = FileSystemProviderErrorCode.FileNotADirectory;
|
||||
throw err;
|
||||
}
|
||||
return !stat.children ? [] : stat.children.map(child => [child.name, MainThreadFileSystem._getFileType(child)]);
|
||||
return !stat.children ? [] : stat.children.map(child => [child.name, MainThreadFileSystem._asFileType(child)] as [string, FileType]);
|
||||
}).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
private static _getFileType(stat: IFileStat): FileType {
|
||||
return (stat.isDirectory ? FileType.Directory : FileType.File) + (stat.isSymbolicLink ? FileType.SymbolicLink : 0);
|
||||
private static _asFileType(stat: IFileStat): FileType {
|
||||
let res = 0;
|
||||
if (stat.isFile) {
|
||||
res += FileType.File;
|
||||
|
||||
} else if (stat.isDirectory) {
|
||||
res += FileType.Directory;
|
||||
}
|
||||
if (stat.isSymbolicLink) {
|
||||
res += FileType.SymbolicLink;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
$readFile(uri: UriComponents): Promise<VSBuffer> {
|
||||
@@ -80,19 +90,23 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
}
|
||||
|
||||
$writeFile(uri: UriComponents, content: VSBuffer): Promise<void> {
|
||||
return this._fileService.writeFile(URI.revive(uri), content).catch(MainThreadFileSystem._handleError);
|
||||
return this._fileService.writeFile(URI.revive(uri), content)
|
||||
.then(() => undefined).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$rename(source: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> {
|
||||
return this._fileService.move(URI.revive(source), URI.revive(target), opts.overwrite).catch(MainThreadFileSystem._handleError);
|
||||
return this._fileService.move(URI.revive(source), URI.revive(target), opts.overwrite)
|
||||
.then(() => undefined).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$copy(source: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> {
|
||||
return this._fileService.copy(URI.revive(source), URI.revive(target), opts.overwrite).catch(MainThreadFileSystem._handleError);
|
||||
return this._fileService.copy(URI.revive(source), URI.revive(target), opts.overwrite)
|
||||
.then(() => undefined).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$mkdir(uri: UriComponents): Promise<void> {
|
||||
return this._fileService.createFolder(URI.revive(uri)).catch(MainThreadFileSystem._handleError);
|
||||
return this._fileService.createFolder(URI.revive(uri))
|
||||
.then(() => undefined).catch(MainThreadFileSystem._handleError);
|
||||
}
|
||||
|
||||
$delete(uri: UriComponents, opts: FileDeleteOptions): Promise<void> {
|
||||
@@ -121,7 +135,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
class RemoteFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileFolderCopyCapability {
|
||||
|
||||
private readonly _onDidChange = new Emitter<readonly IFileChange[]>();
|
||||
private readonly _registration: IDisposable;
|
||||
|
||||
@@ -3,21 +3,31 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { FileChangeType, IFileService, FileOperation } 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 { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
|
||||
@extHostCustomer
|
||||
export class MainThreadFileSystemEventService {
|
||||
|
||||
private readonly _listener = new Array<IDisposable>();
|
||||
private readonly _listener = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextFileService textfileService: ITextFileService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IProgressService progressService: IProgressService,
|
||||
@IConfigurationService configService: IConfigurationService,
|
||||
@ILogService logService: ILogService,
|
||||
) {
|
||||
|
||||
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemEventService);
|
||||
@@ -28,7 +38,7 @@ export class MainThreadFileSystemEventService {
|
||||
changed: [],
|
||||
deleted: []
|
||||
};
|
||||
fileService.onFileChanges(event => {
|
||||
this._listener.add(fileService.onFileChanges(event => {
|
||||
for (let change of event.changes) {
|
||||
switch (change.type) {
|
||||
case FileChangeType.ADDED:
|
||||
@@ -47,22 +57,64 @@ export class MainThreadFileSystemEventService {
|
||||
events.created.length = 0;
|
||||
events.changed.length = 0;
|
||||
events.deleted.length = 0;
|
||||
}, undefined, this._listener);
|
||||
}));
|
||||
|
||||
// file operation events - (changes the editor makes)
|
||||
fileService.onAfterOperation(e => {
|
||||
if (e.isOperation(FileOperation.MOVE)) {
|
||||
proxy.$onFileRename(e.resource, e.target.resource);
|
||||
|
||||
// BEFORE file operation
|
||||
const messages = new Map<FileOperation, string>();
|
||||
messages.set(FileOperation.CREATE, localize('msg-create', "Running 'File Create' participants..."));
|
||||
messages.set(FileOperation.DELETE, localize('msg-delete', "Running 'File Delete' participants..."));
|
||||
messages.set(FileOperation.MOVE, localize('msg-rename', "Running 'File Rename' participants..."));
|
||||
|
||||
|
||||
this._listener.add(textFileService.onWillRunOperation(e => {
|
||||
|
||||
const timeout = configService.getValue<number>('files.participants.timeout');
|
||||
if (timeout <= 0) {
|
||||
return; // disabled
|
||||
}
|
||||
}, undefined, this._listener);
|
||||
|
||||
textfileService.onWillMove(e => {
|
||||
const promise = proxy.$onWillRename(e.oldResource, e.newResource);
|
||||
e.waitUntil(promise);
|
||||
}, undefined, this._listener);
|
||||
const p = progressService.withProgress({ location: ProgressLocation.Window }, progress => {
|
||||
|
||||
progress.report({ message: messages.get(e.operation) });
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
const cts = new CancellationTokenSource();
|
||||
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
logService.trace('CANCELLED file participants because of timeout', timeout, e.target, e.operation);
|
||||
cts.cancel();
|
||||
reject(new Error('timeout'));
|
||||
}, timeout);
|
||||
|
||||
proxy.$onWillRunFileOperation(e.operation, e.target, e.source, timeout, cts.token)
|
||||
.then(resolve, reject)
|
||||
.finally(() => clearTimeout(timeoutHandle));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
e.waitUntil(p);
|
||||
}));
|
||||
|
||||
// AFTER file operation
|
||||
this._listener.add(textFileService.onDidRunOperation(e => proxy.$onDidRunFileOperation(e.operation, e.target, e.source)));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this._listener);
|
||||
this._listener.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
|
||||
id: 'files',
|
||||
properties: {
|
||||
'files.participants.timeout': {
|
||||
type: 'number',
|
||||
default: 5000,
|
||||
markdownDescription: localize('files.participants.timeout', "Timeout in milliseconds after which file participants for create, rename, and delete are cancelled. Use `0` to disable participants."),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import * as callh from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { decodeSemanticTokensDto } from 'vs/workbench/api/common/shared/semanticTokens';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
|
||||
@@ -324,9 +325,16 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}));
|
||||
}
|
||||
|
||||
// --- semantic tokens
|
||||
|
||||
$registerSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void {
|
||||
this._registrations.set(handle, modes.SemanticTokensProviderRegistry.register(selector, new MainThreadSemanticTokensProvider(this._proxy, handle, legend)));
|
||||
}
|
||||
|
||||
// --- suggest
|
||||
|
||||
private static _inflateSuggestDto(defaultRange: IRange, data: ISuggestDataDto): modes.CompletionItem {
|
||||
private static _inflateSuggestDto(defaultRange: IRange | { insert: IRange, replace: IRange }, data: ISuggestDataDto): modes.CompletionItem {
|
||||
|
||||
return {
|
||||
label: data[ISuggestDataDtoField.label],
|
||||
kind: data[ISuggestDataDtoField.kind],
|
||||
@@ -337,8 +345,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
filterText: data[ISuggestDataDtoField.filterText],
|
||||
preselect: data[ISuggestDataDtoField.preselect],
|
||||
insertText: typeof data.h === 'undefined' ? data[ISuggestDataDtoField.label] : data.h,
|
||||
insertTextRules: data[ISuggestDataDtoField.insertTextRules],
|
||||
range: data[ISuggestDataDtoField.range] || defaultRange,
|
||||
insertTextRules: data[ISuggestDataDtoField.insertTextRules],
|
||||
commitCharacters: data[ISuggestDataDtoField.commitCharacters],
|
||||
additionalTextEdits: data[ISuggestDataDtoField.additionalTextEdits],
|
||||
command: data[ISuggestDataDtoField.command],
|
||||
@@ -371,6 +379,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
if (!result) {
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
let newSuggestion = MainThreadLanguageFeatures._inflateSuggestDto(suggestion.range, result);
|
||||
return mixin(suggestion, newSuggestion, true);
|
||||
});
|
||||
@@ -495,29 +504,37 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
$registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void {
|
||||
this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, {
|
||||
provideOutgoingCalls: async (model, position, token) => {
|
||||
const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, model.uri, position, token);
|
||||
|
||||
prepareCallHierarchy: async (document, position, token) => {
|
||||
const item = await this._proxy.$prepareCallHierarchy(handle, document.uri, position, token);
|
||||
if (!item) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
dispose: () => this._proxy.$releaseCallHierarchy(handle, item._sessionId),
|
||||
root: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item)
|
||||
};
|
||||
},
|
||||
|
||||
provideOutgoingCalls: async (item, token) => {
|
||||
const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, item._sessionId, item._itemId, token);
|
||||
if (!outgoing) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
return outgoing.map(([item, fromRanges]): callh.OutgoingCall => {
|
||||
return {
|
||||
to: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
|
||||
fromRanges
|
||||
};
|
||||
outgoing.forEach(value => {
|
||||
value.to = MainThreadLanguageFeatures._reviveCallHierarchyItemDto(value.to);
|
||||
});
|
||||
return <any>outgoing;
|
||||
},
|
||||
provideIncomingCalls: async (model, position, token) => {
|
||||
const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, model.uri, position, token);
|
||||
provideIncomingCalls: async (item, token) => {
|
||||
const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, item._sessionId, item._itemId, token);
|
||||
if (!incoming) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
return incoming.map(([item, fromRanges]): callh.IncomingCall => {
|
||||
return {
|
||||
from: MainThreadLanguageFeatures._reviveCallHierarchyItemDto(item),
|
||||
fromRanges
|
||||
};
|
||||
incoming.forEach(value => {
|
||||
value.from = MainThreadLanguageFeatures._reviveCallHierarchyItemDto(value.from);
|
||||
});
|
||||
return <any>incoming;
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -585,3 +602,45 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class MainThreadSemanticTokensProvider implements modes.SemanticTokensProvider {
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostLanguageFeaturesShape,
|
||||
private readonly _handle: number,
|
||||
private readonly _legend: modes.SemanticTokensLegend,
|
||||
) {
|
||||
}
|
||||
|
||||
public releaseSemanticTokens(resultId: string | undefined): void {
|
||||
if (resultId) {
|
||||
this._proxy.$releaseSemanticTokens(this._handle, parseInt(resultId, 10));
|
||||
}
|
||||
}
|
||||
|
||||
public getLegend(): modes.SemanticTokensLegend {
|
||||
return this._legend;
|
||||
}
|
||||
|
||||
async provideSemanticTokens(model: ITextModel, lastResultId: string | null, ranges: EditorRange[] | null, token: CancellationToken): Promise<modes.SemanticTokens | modes.SemanticTokensEdits | null> {
|
||||
const nLastResultId = lastResultId ? parseInt(lastResultId, 10) : 0;
|
||||
const encodedDto = await this._proxy.$provideSemanticTokens(this._handle, model.uri, ranges, nLastResultId, token);
|
||||
if (!encodedDto) {
|
||||
return null;
|
||||
}
|
||||
if (token.isCancellationRequested) {
|
||||
return null;
|
||||
}
|
||||
const dto = decodeSemanticTokensDto(encodedDto);
|
||||
if (dto.type === 'full') {
|
||||
return {
|
||||
resultId: String(dto.id),
|
||||
data: dto.data
|
||||
};
|
||||
}
|
||||
return {
|
||||
resultId: String(dto.id),
|
||||
edits: dto.deltas
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
}
|
||||
|
||||
$registerSourceControl(handle: number, id: string, label: string, rootUri: UriComponents | undefined): void {
|
||||
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri && URI.revive(rootUri), this.scmService);
|
||||
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri ? URI.revive(rootUri) : undefined, this.scmService);
|
||||
const repository = this.scmService.registerSCMProvider(provider);
|
||||
this._repositories.set(handle, repository);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { CodeAction } from 'vs/editor/common/modes';
|
||||
import { shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
|
||||
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
|
||||
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
|
||||
import { CodeActionKind } from 'vs/editor/contrib/codeAction/types';
|
||||
import { formatDocumentWithSelectedProvider, FormattingMode } from 'vs/editor/contrib/format/format';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -30,7 +30,8 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; // {{SQL CARBON EDIT}}
|
||||
import { ISaveParticipant, IResolvedTextFileEditorModel, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { SaveReason } from 'vs/workbench/common/editor';
|
||||
import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; // {{SQL CARBON EDIT}}
|
||||
|
||||
@@ -53,7 +54,7 @@ class NotebookUpdateParticipant implements ISaveParticipantParticipant { // {{SQ
|
||||
}
|
||||
|
||||
public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
|
||||
let uri = model.getResource();
|
||||
let uri = model.resource;
|
||||
let notebookEditor = this.notebookService.findNotebookEditor(uri);
|
||||
if (notebookEditor) {
|
||||
notebookEditor.notebookParams.input.updateModel();
|
||||
@@ -76,7 +77,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
|
||||
}
|
||||
|
||||
async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise<void> {
|
||||
if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) {
|
||||
if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) {
|
||||
this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO);
|
||||
}
|
||||
}
|
||||
@@ -138,7 +139,7 @@ export class FinalNewLineParticipant implements ISaveParticipantParticipant {
|
||||
}
|
||||
|
||||
async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise<void> {
|
||||
if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) {
|
||||
if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) {
|
||||
this.doInsertFinalNewLine(model.textEditorModel);
|
||||
}
|
||||
}
|
||||
@@ -172,7 +173,7 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipantParticipant
|
||||
}
|
||||
|
||||
async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise<void> {
|
||||
if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) {
|
||||
if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) {
|
||||
this.doTrimFinalNewLines(model.textEditorModel, env.reason === SaveReason.AUTO);
|
||||
}
|
||||
}
|
||||
@@ -282,7 +283,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
|
||||
|
||||
const model = editorModel.textEditorModel;
|
||||
|
||||
const settingsOverrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() };
|
||||
const settingsOverrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.resource };
|
||||
const setting = this._configurationService.getValue<ICodeActionsOnSaveOptions>('editor.codeActionsOnSave', settingsOverrides);
|
||||
if (!setting) {
|
||||
return undefined;
|
||||
@@ -307,6 +308,10 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const excludedActions = Object.keys(setting)
|
||||
.filter(x => setting[x] === false)
|
||||
.map(x => new CodeActionKind(x));
|
||||
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
|
||||
const timeout = this._configurationService.getValue<number>('editor.codeActionsOnSaveTimeout', settingsOverrides);
|
||||
@@ -317,17 +322,17 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
|
||||
tokenSource.cancel();
|
||||
reject(localize('codeActionsOnSave.didTimeout', "Aborted codeActionsOnSave after {0}ms", timeout));
|
||||
}, timeout)),
|
||||
this.applyOnSaveActions(model, codeActionsOnSave, tokenSource.token)
|
||||
this.applyOnSaveActions(model, codeActionsOnSave, excludedActions, tokenSource.token)
|
||||
]).finally(() => {
|
||||
tokenSource.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
private async applyOnSaveActions(model: ITextModel, codeActionsOnSave: CodeActionKind[], token: CancellationToken): Promise<void> {
|
||||
private async applyOnSaveActions(model: ITextModel, codeActionsOnSave: readonly CodeActionKind[], excludes: readonly CodeActionKind[], token: CancellationToken): Promise<void> {
|
||||
for (const codeActionKind of codeActionsOnSave) {
|
||||
const actionsToRun = await this.getActionsToRun(model, codeActionKind, token);
|
||||
const actionsToRun = await this.getActionsToRun(model, codeActionKind, excludes, token);
|
||||
try {
|
||||
await this.applyCodeActions(actionsToRun.actions);
|
||||
await this.applyCodeActions(actionsToRun.validActions);
|
||||
} catch {
|
||||
// Failure to apply a code action should not block other on save actions
|
||||
} finally {
|
||||
@@ -342,10 +347,10 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
private getActionsToRun(model: ITextModel, codeActionKind: CodeActionKind, token: CancellationToken) {
|
||||
private getActionsToRun(model: ITextModel, codeActionKind: CodeActionKind, excludes: readonly CodeActionKind[], token: CancellationToken) {
|
||||
return getCodeActions(model, model.getFullModelRange(), {
|
||||
type: 'auto',
|
||||
filter: { kind: codeActionKind, includeSourceActions: true },
|
||||
filter: { include: codeActionKind, excludes: excludes, includeSourceActions: true },
|
||||
}, token);
|
||||
}
|
||||
}
|
||||
@@ -368,7 +373,7 @@ class ExtHostSaveParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
setTimeout(() => reject(localize('timeout.onWillSave', "Aborted onWillSaveTextDocument-event after 1750ms")), 1750);
|
||||
this._proxy.$participateInSave(editorModel.getResource(), env.reason).then(values => {
|
||||
this._proxy.$participateInSave(editorModel.resource, env.reason).then(values => {
|
||||
if (!values.every(success => success)) {
|
||||
return Promise.reject(new Error('listener failed'));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { ITerminalInstanceService, ITerminalService, ITerminalInstance } 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';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
|
||||
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
|
||||
@@ -162,15 +163,22 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
|
||||
private _onTerminalDisposed(terminalInstance: ITerminalInstance): void {
|
||||
this._proxy.$acceptTerminalClosed(terminalInstance.id);
|
||||
this._proxy.$acceptTerminalClosed(terminalInstance.id, terminalInstance.exitCode);
|
||||
}
|
||||
|
||||
private _onTerminalOpened(terminalInstance: ITerminalInstance): void {
|
||||
const shellLaunchConfigDto: IShellLaunchConfigDto = {
|
||||
name: terminalInstance.shellLaunchConfig.name,
|
||||
executable: terminalInstance.shellLaunchConfig.executable,
|
||||
args: terminalInstance.shellLaunchConfig.args,
|
||||
cwd: terminalInstance.shellLaunchConfig.cwd,
|
||||
env: terminalInstance.shellLaunchConfig.env
|
||||
};
|
||||
if (terminalInstance.title) {
|
||||
this._proxy.$acceptTerminalOpened(terminalInstance.id, terminalInstance.title);
|
||||
this._proxy.$acceptTerminalOpened(terminalInstance.id, terminalInstance.title, shellLaunchConfigDto);
|
||||
} else {
|
||||
terminalInstance.waitForTitle().then(title => {
|
||||
this._proxy.$acceptTerminalOpened(terminalInstance.id, title);
|
||||
this._proxy.$acceptTerminalOpened(terminalInstance.id, title, shellLaunchConfigDto);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -256,7 +264,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitReady(pid, cwd));
|
||||
}
|
||||
|
||||
public $sendProcessExit(terminalId: number, exitCode: number): void {
|
||||
public $sendProcessExit(terminalId: number, exitCode: number | undefined): void {
|
||||
this._getTerminalProcess(terminalId).then(e => e.emitExit(exitCode));
|
||||
this._terminalProcesses.delete(terminalId);
|
||||
}
|
||||
@@ -327,16 +335,23 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
* listeners are removed.
|
||||
*/
|
||||
class TerminalDataEventTracker extends Disposable {
|
||||
private readonly _bufferer: TerminalDataBufferer;
|
||||
|
||||
constructor(
|
||||
private readonly _callback: (id: number, data: string) => void,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(this._bufferer = new TerminalDataBufferer());
|
||||
|
||||
this._terminalService.terminalInstances.forEach(instance => this._registerInstance(instance));
|
||||
this._register(this._terminalService.onInstanceCreated(instance => this._registerInstance(instance)));
|
||||
this._register(this._terminalService.onInstanceDisposed(instance => this._bufferer.stopBuffering(instance.id)));
|
||||
}
|
||||
|
||||
private _registerInstance(instance: ITerminalInstance): void {
|
||||
this._register(instance.onData(e => this._callback(instance.id, e)));
|
||||
// Buffer data events to reduce the amount of messages going to the extension host
|
||||
this._register(this._bufferer.startBuffering(instance.id, instance.onData, this._callback));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
||||
import { isUndefinedOrNull, isNumber } from 'vs/base/common/types';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTreeViews)
|
||||
export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape {
|
||||
@@ -23,13 +24,16 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
||||
extHostContext: IExtHostContext,
|
||||
@IViewsService private readonly viewsService: IViewsService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
) {
|
||||
super();
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews);
|
||||
}
|
||||
|
||||
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): void {
|
||||
this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options);
|
||||
|
||||
this.extensionService.whenInstalledExtensionsRegistered().then(() => {
|
||||
const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService);
|
||||
this._dataProviders.set(treeViewId, dataProvider);
|
||||
@@ -49,6 +53,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
||||
}
|
||||
|
||||
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void> {
|
||||
this.logService.trace('MainThreadTreeViews#$reveal', treeViewId, item, parentChain, options);
|
||||
|
||||
return this.viewsService.openView(treeViewId, options.focus)
|
||||
.then(() => {
|
||||
const viewer = this.getTreeView(treeViewId);
|
||||
@@ -60,6 +66,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
||||
}
|
||||
|
||||
$refresh(treeViewId: string, itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): Promise<void> {
|
||||
this.logService.trace('MainThreadTreeViews#$refresh', treeViewId, itemsToRefreshByHandle);
|
||||
|
||||
const viewer = this.getTreeView(treeViewId);
|
||||
const dataProvider = this._dataProviders.get(treeViewId);
|
||||
if (viewer && dataProvider) {
|
||||
@@ -70,6 +78,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
||||
}
|
||||
|
||||
$setMessage(treeViewId: string, message: string): void {
|
||||
this.logService.trace('MainThreadTreeViews#$setMessage', treeViewId, message);
|
||||
|
||||
const viewer = this.getTreeView(treeViewId);
|
||||
if (viewer) {
|
||||
viewer.message = message;
|
||||
@@ -77,6 +87,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
|
||||
}
|
||||
|
||||
$setTitle(treeViewId: string, title: string): void {
|
||||
this.logService.trace('MainThreadTreeViews#$setTitle', treeViewId, title);
|
||||
|
||||
const viewer = this.getTreeView(treeViewId);
|
||||
if (viewer) {
|
||||
viewer.title = title;
|
||||
|
||||
@@ -68,7 +68,11 @@ export class MainThreadUrls implements MainThreadUrlsShape {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
async $createAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial<UriComponents> }): Promise<URI> {
|
||||
async $createAppUri(uri: UriComponents): Promise<URI> {
|
||||
return this.urlService.create(uri);
|
||||
}
|
||||
|
||||
async $proposedCreateAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial<UriComponents> }): Promise<URI> {
|
||||
const payload: Partial<UriComponents> = options && options.payload ? options.payload : Object.create(null);
|
||||
|
||||
// we define the authority to be the extension ID to ensure
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
@@ -20,6 +20,7 @@ import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } fr
|
||||
import { IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { CustomFileEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput';
|
||||
import { ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { WebviewExtensionDescription } 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';
|
||||
@@ -98,6 +99,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
constructor(
|
||||
context: extHostProtocol.IExtHostContext,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@ICustomEditorService private readonly _customEditorService: ICustomEditorService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
@@ -168,13 +170,6 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
webview.setName(value);
|
||||
}
|
||||
|
||||
public $setState(handle: extHostProtocol.WebviewPanelHandle, state: modes.WebviewContentState): void {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
if (webview instanceof CustomFileEditorInput) {
|
||||
webview.setState(state);
|
||||
}
|
||||
}
|
||||
|
||||
public $setIconPath(handle: extHostProtocol.WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents; } | undefined): void {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
webview.iconPath = reviveWebviewIcon(value);
|
||||
@@ -268,7 +263,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
canResolve: (webviewInput) => {
|
||||
return webviewInput instanceof CustomFileEditorInput && webviewInput.viewType === viewType;
|
||||
},
|
||||
resolveWebview: async (webviewInput) => {
|
||||
resolveWebview: async (webviewInput: CustomFileEditorInput) => {
|
||||
const handle = webviewInput.id;
|
||||
this._webviewInputs.add(handle, webviewInput);
|
||||
this.hookupWebviewEventDelegate(handle, webviewInput);
|
||||
@@ -276,15 +271,25 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
webviewInput.webview.options = options;
|
||||
webviewInput.webview.extension = extension;
|
||||
|
||||
if (webviewInput instanceof CustomFileEditorInput) {
|
||||
webviewInput.onWillSave(e => {
|
||||
e.waitUntil(this._proxy.$save(handle));
|
||||
});
|
||||
}
|
||||
const model = await this._customEditorService.models.loadOrCreate(webviewInput.getResource(), webviewInput.viewType);
|
||||
|
||||
model.onUndo(edits => { this._proxy.$undoEdits(handle, edits.map(x => x.data)); });
|
||||
model.onApplyEdit(edits => {
|
||||
const editsToApply = edits.filter(x => x.source !== webviewInput).map(x => x.data);
|
||||
if (editsToApply.length) {
|
||||
this._proxy.$applyEdits(handle, editsToApply);
|
||||
}
|
||||
});
|
||||
model.onWillSave(e => { e.waitUntil(this._proxy.$onSave(handle)); });
|
||||
model.onWillSaveAs(e => { e.waitUntil(this._proxy.$onSaveAs(handle, e.resource.toJSON(), e.targetResource.toJSON())); });
|
||||
|
||||
webviewInput.onDisposeWebview(() => {
|
||||
this._customEditorService.models.disposeModel(model);
|
||||
});
|
||||
|
||||
try {
|
||||
await this._proxy.$resolveWebviewEditor(
|
||||
webviewInput.getResource(),
|
||||
{ resource: webviewInput.getResource(), edits: model.currentEdits },
|
||||
handle,
|
||||
viewType,
|
||||
webviewInput.getTitle(),
|
||||
@@ -294,6 +299,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -309,15 +315,35 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
this._editorProviders.delete(viewType);
|
||||
}
|
||||
|
||||
public $onEdit(handle: extHostProtocol.WebviewPanelHandle, editData: any): void {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
if (!(webview instanceof CustomFileEditorInput)) {
|
||||
throw new Error('Webview is not a webview editor');
|
||||
}
|
||||
|
||||
const model = this._customEditorService.models.get(webview.getResource(), webview.viewType);
|
||||
if (!model) {
|
||||
throw new Error('Could not find model for webview editor');
|
||||
}
|
||||
|
||||
model.makeEdit({ source: webview, data: editData });
|
||||
}
|
||||
|
||||
private hookupWebviewEventDelegate(handle: extHostProtocol.WebviewPanelHandle, input: WebviewInput) {
|
||||
input.webview.onDidClickLink((uri: URI) => this.onDidClickLink(handle, uri));
|
||||
input.webview.onMessage((message: any) => this._proxy.$onMessage(handle, message));
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
disposables.add(input.webview.onDidClickLink((uri) => this.onDidClickLink(handle, uri)));
|
||||
disposables.add(input.webview.onMessage((message: any) => { this._proxy.$onMessage(handle, message); }));
|
||||
disposables.add(input.webview.onMissingCsp((extension: ExtensionIdentifier) => this._proxy.$onMissingCsp(handle, extension.value)));
|
||||
|
||||
input.onDispose(() => {
|
||||
disposables.dispose();
|
||||
});
|
||||
input.onDisposeWebview(() => {
|
||||
this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => {
|
||||
this._webviewInputs.delete(handle);
|
||||
});
|
||||
});
|
||||
input.webview.onMissingCsp((extension: ExtensionIdentifier) => this._proxy.$onMissingCsp(handle, extension.value));
|
||||
}
|
||||
|
||||
private updateWebviewViewStates() {
|
||||
@@ -361,9 +387,9 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
}
|
||||
}
|
||||
|
||||
private onDidClickLink(handle: extHostProtocol.WebviewPanelHandle, link: URI): void {
|
||||
private onDidClickLink(handle: extHostProtocol.WebviewPanelHandle, link: string): void {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
if (this.isSupportedLink(webview, link)) {
|
||||
if (this.isSupportedLink(webview, URI.parse(link))) {
|
||||
this._openerService.open(link, { fromUserGesture: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,9 +42,17 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
return Promise.resolve(this.hostService.hasFocus);
|
||||
}
|
||||
|
||||
async $openUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise<boolean> {
|
||||
async $openUri(uriComponents: UriComponents, uriString: string | undefined, options: IOpenUriOptions): Promise<boolean> {
|
||||
const uri = URI.from(uriComponents);
|
||||
return this.openerService.open(uri, { openExternal: true, allowTunneling: options.allowTunneling });
|
||||
let target: URI | string;
|
||||
if (uriString && URI.parse(uriString).toString() === uri.toString()) {
|
||||
// called with string and no transformation happened -> keep string
|
||||
target = uriString;
|
||||
} else {
|
||||
// called with URI or transformed -> use uri
|
||||
target = uri;
|
||||
}
|
||||
return this.openerService.open(target, { openExternal: true, allowTunneling: options.allowTunneling });
|
||||
}
|
||||
|
||||
async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise<UriComponents> {
|
||||
|
||||
@@ -15,11 +15,11 @@ import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'v
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspace } 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 { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing';
|
||||
import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape, IWorkspaceData, ITextSearchComplete } from '../common/extHost.protocol';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { isEqualOrParent } from 'vs/base/common/resources';
|
||||
import { isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
@@ -37,7 +37,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
extHostContext: IExtHostContext,
|
||||
@ISearchService private readonly _searchService: ISearchService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IRequestService private readonly _requestService: IRequestService,
|
||||
@@ -121,7 +121,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
}
|
||||
return {
|
||||
configuration: workspace.configuration || undefined,
|
||||
isUntitled: workspace.configuration ? isEqualOrParent(workspace.configuration, this._environmentService.untitledWorkspacesHome) : false,
|
||||
isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false,
|
||||
folders: workspace.folders,
|
||||
id: workspace.id,
|
||||
name: this._labelService.getWorkspaceLabel(workspace)
|
||||
@@ -155,13 +155,14 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
if (!isPromiseCanceledError(err)) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
return undefined;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
$startTextSearch(pattern: IPatternInfo, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete> {
|
||||
$startTextSearch(pattern: IPatternInfo, _folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
|
||||
const folder = URI.revive(_folder);
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
const folders = workspace.folders.map(folder => folder.uri);
|
||||
const folders = folder ? [folder] : workspace.folders.map(folder => folder.uri);
|
||||
|
||||
const query = this._queryBuilder.text(pattern, folders, options);
|
||||
query._reason = 'startTextSearch';
|
||||
@@ -181,7 +182,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return null;
|
||||
});
|
||||
|
||||
return search;
|
||||
@@ -198,23 +199,21 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
|
||||
return this._searchService.fileSearch(query, token).then(
|
||||
result => {
|
||||
return result.limitHit;
|
||||
return !!result.limitHit;
|
||||
},
|
||||
err => {
|
||||
if (!isPromiseCanceledError(err)) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// --- save & edit resources ---
|
||||
|
||||
$saveAll(includeUntitled?: boolean): Promise<boolean> {
|
||||
return this._textFileService.saveAll(includeUntitled).then(result => {
|
||||
return result.results.every(each => each.success === true);
|
||||
});
|
||||
return this._editorService.saveAll({ includeUntitled });
|
||||
}
|
||||
|
||||
$resolveProxy(url: string): Promise<string | undefined> {
|
||||
|
||||
@@ -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 } from 'vs/workbench/common/views';
|
||||
import { CustomTreeViewPanel, CustomTreeView } from 'vs/workbench/browser/parts/views/customView';
|
||||
import { CustomTreeViewPane, CustomTreeView } from 'vs/workbench/browser/parts/views/customView';
|
||||
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';
|
||||
@@ -37,7 +37,6 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { createCSSRule, asCSSUrl } from 'vs/base/browser/dom';
|
||||
|
||||
export interface IUserFriendlyViewsContainerDescriptor {
|
||||
id: string;
|
||||
@@ -254,10 +253,9 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
|
||||
private registerTestViewContainer(): void {
|
||||
const title = localize('test', "Test");
|
||||
const cssClass = `extensionViewlet-test`;
|
||||
const icon = URI.parse(require.toUrl('./media/test.svg'));
|
||||
|
||||
this.registerCustomViewContainer(TEST_VIEW_CONTAINER_ID, title, icon, TEST_VIEW_CONTAINER_ORDER, cssClass, undefined);
|
||||
this.registerCustomViewContainer(TEST_VIEW_CONTAINER_ID, title, icon, TEST_VIEW_CONTAINER_ORDER, undefined);
|
||||
}
|
||||
|
||||
private isValidViewsContainer(viewsContainersDescriptors: IUserFriendlyViewsContainerDescriptor[], collector: ExtensionMessageCollector): boolean {
|
||||
@@ -290,10 +288,9 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
|
||||
private registerCustomViewContainers(containers: IUserFriendlyViewsContainerDescriptor[], extension: IExtensionDescription, order: number, existingViewContainers: ViewContainer[]): number {
|
||||
containers.forEach(descriptor => {
|
||||
const cssClass = `extensionViewlet-${descriptor.id}`;
|
||||
const icon = resources.joinPath(extension.extensionLocation, descriptor.icon);
|
||||
const id = `workbench.view.extension.${descriptor.id}`;
|
||||
const viewContainer = this.registerCustomViewContainer(id, descriptor.title, icon, order++, cssClass, extension.identifier);
|
||||
const viewContainer = this.registerCustomViewContainer(id, descriptor.title, icon, order++, extension.identifier);
|
||||
|
||||
// Move those views that belongs to this container
|
||||
if (existingViewContainers.length) {
|
||||
@@ -311,7 +308,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
return order;
|
||||
}
|
||||
|
||||
private registerCustomViewContainer(id: string, title: string, icon: URI, order: number, cssClass: string, extensionId: ExtensionIdentifier | undefined): ViewContainer {
|
||||
private registerCustomViewContainer(id: string, title: string, icon: URI, order: number, extensionId: ExtensionIdentifier | undefined): ViewContainer {
|
||||
let viewContainer = this.viewContainersRegistry.get(id);
|
||||
|
||||
if (!viewContainer) {
|
||||
@@ -335,11 +332,11 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
super(id, `${id}.state`, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
|
||||
}
|
||||
}
|
||||
const viewletDescriptor = new ViewletDescriptor(
|
||||
const viewletDescriptor = ViewletDescriptor.create(
|
||||
CustomViewlet,
|
||||
id,
|
||||
title,
|
||||
cssClass,
|
||||
undefined,
|
||||
order,
|
||||
icon
|
||||
);
|
||||
@@ -359,14 +356,10 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
}
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(OpenCustomViewletAction, id, localize('showViewlet', "Show {0}", title)),
|
||||
SyncActionDescriptor.create(OpenCustomViewletAction, id, localize('showViewlet', "Show {0}", title)),
|
||||
`View: Show ${title}`,
|
||||
localize('view', "View")
|
||||
);
|
||||
|
||||
// Generate CSS to show the icon in the activity bar
|
||||
const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${cssClass}`;
|
||||
createCSSRule(iconClass, `-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%; -webkit-mask-size: 24px;`);
|
||||
}
|
||||
|
||||
return viewContainer;
|
||||
@@ -429,7 +422,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
const viewDescriptor = <ICustomViewDescriptor>{
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
ctorDescriptor: { ctor: CustomTreeViewPanel },
|
||||
ctorDescriptor: { ctor: CustomTreeViewPane },
|
||||
when: ContextKeyExpr.deserialize(item.when),
|
||||
canToggleVisibility: true,
|
||||
collapsed: this.showCollapsed(container),
|
||||
|
||||
Reference in New Issue
Block a user