mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-13 03:28:33 -05:00
Merge from vscode 31e03b8ffbb218a87e3941f2b63a249f061fe0e4 (#4986)
This commit is contained in:
@@ -17,6 +17,8 @@ import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocum
|
||||
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 { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { toLocalResource } from 'vs/base/common/resources';
|
||||
|
||||
export class BoundModelReferenceCollection {
|
||||
|
||||
@@ -69,6 +71,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
private readonly _textFileService: ITextFileService;
|
||||
private readonly _fileService: IFileService;
|
||||
private readonly _untitledEditorService: IUntitledEditorService;
|
||||
private readonly _environmentService: IWorkbenchEnvironmentService;
|
||||
|
||||
private _toDispose: IDisposable[];
|
||||
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
|
||||
@@ -85,12 +88,14 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
this._modelService = modelService;
|
||||
this._textModelResolverService = textModelResolverService;
|
||||
this._textFileService = textFileService;
|
||||
this._fileService = fileService;
|
||||
this._untitledEditorService = untitledEditorService;
|
||||
this._environmentService = environmentService;
|
||||
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
|
||||
this._modelIsSynced = {};
|
||||
@@ -214,10 +219,10 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
}
|
||||
|
||||
private _handleUntitledScheme(uri: URI): Promise<boolean> {
|
||||
const asFileUri = uri.with({ scheme: Schemas.file });
|
||||
return this._fileService.resolve(asFileUri).then(stats => {
|
||||
const asLocalUri = toLocalResource(uri, this._environmentService.configuration.remoteAuthority);
|
||||
return this._fileService.resolve(asLocalUri).then(stats => {
|
||||
// don't create a new file ontop of an existing file
|
||||
return Promise.reject(new Error('file already exists on disk'));
|
||||
return Promise.reject(new Error('file already exists'));
|
||||
}, err => {
|
||||
return this._doCreateUntitled(uri).then(resource => !!resource);
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
|
||||
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 { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
namespace delta {
|
||||
|
||||
@@ -330,12 +331,12 @@ export class MainThreadDocumentsAndEditors {
|
||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IBulkEditService bulkEditService: IBulkEditService,
|
||||
@IPanelService panelService: IPanelService
|
||||
|
||||
@IPanelService panelService: IPanelService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
||||
|
||||
const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService);
|
||||
const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService, environmentService);
|
||||
extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments);
|
||||
|
||||
const mainThreadTextEditors = new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService);
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileSer
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
|
||||
import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
|
||||
export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
@@ -105,10 +106,6 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
|
||||
// --- forwarding calls
|
||||
|
||||
private static _asBuffer(data: Uint8Array): Buffer {
|
||||
return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
||||
}
|
||||
|
||||
stat(resource: URI): Promise<IStat> {
|
||||
return this._proxy.$stat(this._handle, resource).then(undefined, err => {
|
||||
throw err;
|
||||
@@ -116,11 +113,11 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
}
|
||||
|
||||
readFile(resource: URI): Promise<Uint8Array> {
|
||||
return this._proxy.$readFile(this._handle, resource);
|
||||
return this._proxy.$readFile(this._handle, resource).then(buffer => buffer.buffer);
|
||||
}
|
||||
|
||||
writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> {
|
||||
return this._proxy.$writeFile(this._handle, resource, RemoteFileSystemProvider._asBuffer(content), opts);
|
||||
return this._proxy.$writeFile(this._handle, resource, VSBuffer.wrap(content), opts);
|
||||
}
|
||||
|
||||
delete(resource: URI, opts: FileDeleteOptions): Promise<void> {
|
||||
@@ -153,12 +150,12 @@ class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
|
||||
read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
||||
return this._proxy.$read(this._handle, fd, pos, length).then(readData => {
|
||||
data.set(readData, offset);
|
||||
data.set(readData.buffer, offset);
|
||||
return readData.byteLength;
|
||||
});
|
||||
}
|
||||
|
||||
write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
||||
return this._proxy.$write(this._handle, fd, pos, Buffer.from(data, offset, length));
|
||||
return this._proxy.$write(this._handle, fd, pos, VSBuffer.wrap(data).slice(offset, offset + length));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +240,7 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) {
|
||||
// Nothing
|
||||
@@ -256,8 +257,9 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
const source = new CancellationTokenSource();
|
||||
const editorOrModel = findEditor(model, this._codeEditorService) || model;
|
||||
const timeout = this._configurationService.getValue<number>('editor.formatOnSaveTimeout', overrides);
|
||||
const request = this._instantiationService.invokeFunction(formatDocumentWithSelectedProvider, model, FormattingMode.Silent, source.token);
|
||||
const request = this._instantiationService.invokeFunction(formatDocumentWithSelectedProvider, editorOrModel, FormattingMode.Silent, source.token);
|
||||
|
||||
setTimeout(() => {
|
||||
reject(localize('timeout.formatOnSave', "Aborted format on save after {0}ms", timeout));
|
||||
|
||||
@@ -3,47 +3,55 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadStatusBar)
|
||||
export class MainThreadStatusBar implements MainThreadStatusBarShape {
|
||||
|
||||
private readonly _entries: { [id: number]: IDisposable };
|
||||
private readonly entries: Map<number, { accessor: IStatusbarEntryAccessor, alignment: MainThreadStatusBarAlignment, priority: number }> = new Map();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IStatusbarService private readonly _statusbarService: IStatusbarService
|
||||
) {
|
||||
this._entries = Object.create(null);
|
||||
}
|
||||
_extHostContext: IExtHostContext,
|
||||
@IStatusbarService private readonly statusbarService: IStatusbarService
|
||||
) { }
|
||||
|
||||
dispose(): void {
|
||||
for (const key in this._entries) {
|
||||
this._entries[key].dispose();
|
||||
}
|
||||
this.entries.forEach(entry => entry.accessor.dispose());
|
||||
this.entries.clear();
|
||||
}
|
||||
|
||||
$setEntry(id: number, extensionId: ExtensionIdentifier, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void {
|
||||
const entry = { text, tooltip, command, color, extensionId };
|
||||
|
||||
// Dispose any old
|
||||
this.$dispose(id);
|
||||
// Reset existing entry if alignment or priority changed
|
||||
let existingEntry = this.entries.get(id);
|
||||
if (existingEntry && (existingEntry.alignment !== alignment || existingEntry.priority !== priority)) {
|
||||
dispose(existingEntry.accessor);
|
||||
this.entries.delete(id);
|
||||
existingEntry = undefined;
|
||||
}
|
||||
|
||||
// Add new
|
||||
const entry = this._statusbarService.addEntry({ text, tooltip, command, color, extensionId }, alignment, priority);
|
||||
this._entries[id] = entry;
|
||||
// Create new entry if not existing
|
||||
if (!existingEntry) {
|
||||
this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, alignment, priority), alignment, priority });
|
||||
}
|
||||
|
||||
// Otherwise update
|
||||
else {
|
||||
existingEntry.accessor.update(entry);
|
||||
}
|
||||
}
|
||||
|
||||
$dispose(id: number) {
|
||||
const disposeable = this._entries[id];
|
||||
if (disposeable) {
|
||||
disposeable.dispose();
|
||||
const entry = this.entries.get(id);
|
||||
if (entry) {
|
||||
dispose(entry.accessor);
|
||||
this.entries.delete(id);
|
||||
}
|
||||
|
||||
delete this._entries[id];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,22 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape } from '../common/extHost.protocol';
|
||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWindow)
|
||||
export class MainThreadWindow implements MainThreadWindowShape {
|
||||
|
||||
private readonly proxy: ExtHostWindowShape;
|
||||
private disposables: IDisposable[] = [];
|
||||
private readonly _tunnels = new Map<number, Promise<RemoteTunnel>>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
@IWindowsService private readonly windowsService: IWindowsService
|
||||
@IWindowsService private readonly windowsService: IWindowsService,
|
||||
@ITunnelService private readonly tunnelService: ITunnelService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostWindow);
|
||||
|
||||
@@ -29,13 +34,54 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
|
||||
for (const tunnel of this._tunnels.values()) {
|
||||
tunnel.then(tunnel => tunnel.dispose());
|
||||
}
|
||||
this._tunnels.clear();
|
||||
}
|
||||
|
||||
$getWindowVisibility(): Promise<boolean> {
|
||||
return this.windowService.isFocused();
|
||||
}
|
||||
|
||||
$openUri(uri: UriComponents): Promise<boolean> {
|
||||
return this.windowsService.openExternal(URI.revive(uri).toString(true));
|
||||
async $openUri(uriComponent: UriComponents): Promise<boolean> {
|
||||
const uri = URI.revive(uriComponent);
|
||||
if (!!this.environmentService.configuration.remoteAuthority) {
|
||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||
const port = this.getLocalhostPort(uri);
|
||||
if (typeof port === 'number') {
|
||||
const tunnel = await this.getOrCreateTunnel(port);
|
||||
if (tunnel) {
|
||||
const tunneledUrl = uri.toString().replace(
|
||||
new RegExp(`^${uri.scheme}://localhost:${port}/`),
|
||||
`${uri.scheme}://localhost:${tunnel.tunnelLocalPort}/`);
|
||||
return this.windowsService.openExternal(tunneledUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.windowsService.openExternal(uri.toString(true));
|
||||
}
|
||||
|
||||
private getLocalhostPort(uri: URI): number | undefined {
|
||||
const match = /^localhost:(\d+)$/.exec(uri.authority);
|
||||
if (match) {
|
||||
return +match[1];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||
const existing = this._tunnels.get(remotePort);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
const tunnel = this.tunnelService.openTunnel(remotePort);
|
||||
if (tunnel) {
|
||||
this._tunnels.set(remotePort, tunnel);
|
||||
}
|
||||
return tunnel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
@@ -46,6 +46,7 @@ import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
|
||||
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
|
||||
@@ -57,7 +58,7 @@ export interface IEnvironment {
|
||||
appLanguage: string;
|
||||
appUriScheme: string;
|
||||
appSettingsHome?: URI;
|
||||
extensionDevelopmentLocationURI?: URI | URI[];
|
||||
extensionDevelopmentLocationURI?: URI[];
|
||||
extensionTestsLocationURI?: URI;
|
||||
globalStorageHome: URI;
|
||||
userHome: URI;
|
||||
@@ -791,8 +792,8 @@ export interface ExtHostWorkspaceShape {
|
||||
export interface ExtHostFileSystemShape {
|
||||
$stat(handle: number, resource: UriComponents): Promise<files.IStat>;
|
||||
$readdir(handle: number, resource: UriComponents): Promise<[string, files.FileType][]>;
|
||||
$readFile(handle: number, resource: UriComponents): Promise<Buffer>;
|
||||
$writeFile(handle: number, resource: UriComponents, content: Buffer, opts: files.FileWriteOptions): Promise<void>;
|
||||
$readFile(handle: number, resource: UriComponents): Promise<VSBuffer>;
|
||||
$writeFile(handle: number, resource: UriComponents, content: VSBuffer, opts: files.FileWriteOptions): Promise<void>;
|
||||
$rename(handle: number, resource: UriComponents, target: UriComponents, opts: files.FileOverwriteOptions): Promise<void>;
|
||||
$copy(handle: number, resource: UriComponents, target: UriComponents, opts: files.FileOverwriteOptions): Promise<void>;
|
||||
$mkdir(handle: number, resource: UriComponents): Promise<void>;
|
||||
@@ -801,8 +802,8 @@ export interface ExtHostFileSystemShape {
|
||||
$unwatch(handle: number, session: number): void;
|
||||
$open(handle: number, resource: UriComponents, opts: files.FileOpenOptions): Promise<number>;
|
||||
$close(handle: number, fd: number): Promise<void>;
|
||||
$read(handle: number, fd: number, pos: number, length: number): Promise<Buffer>;
|
||||
$write(handle: number, fd: number, pos: number, data: Buffer): Promise<number>;
|
||||
$read(handle: number, fd: number, pos: number, length: number): Promise<VSBuffer>;
|
||||
$write(handle: number, fd: number, pos: number, data: VSBuffer): Promise<number>;
|
||||
}
|
||||
|
||||
export interface ExtHostSearchShape {
|
||||
@@ -820,8 +821,8 @@ export interface ExtHostExtensionServiceShape {
|
||||
$deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void>;
|
||||
|
||||
$test_latency(n: number): Promise<number>;
|
||||
$test_up(b: Buffer): Promise<number>;
|
||||
$test_down(size: number): Promise<Buffer>;
|
||||
$test_up(b: VSBuffer): Promise<number>;
|
||||
$test_down(size: number): Promise<VSBuffer>;
|
||||
}
|
||||
|
||||
export interface FileSystemEvents {
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as vscode from 'vscode';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import * as types from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IRawColorInfo, WorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { CustomCodeAction } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand } from './apiCommands';
|
||||
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
import { validateConstraint } from 'vs/base/common/types';
|
||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { cloneAndChange } from 'vs/base/common/objects';
|
||||
import { MainContext, MainThreadCommandsShape, ExtHostCommandsShape, ObjectIdentifier, IMainContext, CommandDto } from '../common/extHost.protocol';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
import { MainContext, MainThreadCommandsShape, ExtHostCommandsShape, ObjectIdentifier, IMainContext, CommandDto } from './extHost.protocol';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import * as vscode from 'vscode';
|
||||
@@ -6,11 +6,11 @@
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import * as types from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape } from '../common/extHost.protocol';
|
||||
import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape } from './extHost.protocol';
|
||||
import { CommandsConverter, ExtHostCommands } from './extHostCommands';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
@@ -7,8 +7,8 @@ import { mixin, deepClone } from 'vs/base/common/objects';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { ExtHostConfigurationShape, MainThreadConfigurationShape, IWorkspaceConfigurationChangeEventData, IConfigurationInitData } from '../common/extHost.protocol';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtHostConfigurationShape, MainThreadConfigurationShape, IWorkspaceConfigurationChangeEventData, IConfigurationInitData } from './extHost.protocol';
|
||||
import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes';
|
||||
import { IConfigurationData, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
|
||||
import { Configuration, ConfigurationChangeEvent, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { MainContext, IMainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData, DecorationRequest, DecorationReply } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { asArray } from 'vs/base/common/arrays';
|
||||
@@ -7,7 +7,7 @@ import { localize } from 'vs/nls';
|
||||
import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as vscode from 'vscode';
|
||||
import { MainContext, MainThreadDiagnosticsShape, ExtHostDiagnosticsShape, IMainContext } from '../common/extHost.protocol';
|
||||
import { MainContext, MainThreadDiagnosticsShape, ExtHostDiagnosticsShape, IMainContext } from './extHost.protocol';
|
||||
import { DiagnosticSeverity } from './extHostTypes';
|
||||
import * as converter from './extHostTypeConverters';
|
||||
import { mergeSort } from 'vs/base/common/arrays';
|
||||
@@ -6,9 +6,9 @@
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
import { MainContext, ExtHostDocumentContentProvidersShape, MainThreadDocumentContentProvidersShape, IMainContext } from '../common/extHost.protocol';
|
||||
import { MainContext, ExtHostDocumentContentProvidersShape, MainThreadDocumentContentProvidersShape, IMainContext } from './extHost.protocol';
|
||||
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
@@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { MirrorTextModel } from 'vs/editor/common/model/mirrorTextModel';
|
||||
import { ensureValidWordDefinition, getWordAtText } from 'vs/editor/common/model/wordHelper';
|
||||
import { MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { EndOfLine, Position, Range } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { EndOfLine, Position, Range } from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
const _modeId2WordDefinition = new Map<string, RegExp>();
|
||||
@@ -8,9 +8,9 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { sequence } from 'vs/base/common/async';
|
||||
import { illegalState } from 'vs/base/common/errors';
|
||||
import { ExtHostDocumentSaveParticipantShape, MainThreadTextEditorsShape, ResourceTextEditDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { TextEdit } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Range, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { TextEdit } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { Range, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import * as vscode from 'vscode';
|
||||
import { LinkedList } from 'vs/base/common/linkedList';
|
||||
@@ -8,9 +8,9 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
|
||||
import { ExtHostDocumentsShape, IMainContext, MainContext, MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentData, setWordDefinitionFor } from 'vs/workbench/api/node/extHostDocumentData';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { ExtHostDocumentData, setWordDefinitionFor } from 'vs/workbench/api/common/extHostDocumentData';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
@@ -8,10 +8,10 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IMainContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData';
|
||||
import { ExtHostTextEditor } from 'vs/workbench/api/node/extHostTextEditor';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
|
||||
import { ExtHostTextEditor } from 'vs/workbench/api/common/extHostTextEditor';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||
|
||||
export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionActivationError, MissingDependencyError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
@@ -4,18 +4,19 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystemShape, IFileChangeDto } from '../common/extHost.protocol';
|
||||
import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystemShape, IFileChangeDto } from './extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { FileChangeType } from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as typeConverter from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import { FileChangeType } from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as typeConverter from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ResourceLabelFormatter } from 'vs/platform/label/common/label';
|
||||
import { State, StateMachine, LinkComputer, Edge } from 'vs/editor/common/modes/linkComputer';
|
||||
import { commonPrefixLength } from 'vs/base/common/strings';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
class FsLinkProvider {
|
||||
|
||||
@@ -229,14 +230,12 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
return Promise.resolve(this.getProvider(handle).readDirectory(URI.revive(resource)));
|
||||
}
|
||||
|
||||
$readFile(handle: number, resource: UriComponents): Promise<Buffer> {
|
||||
return Promise.resolve(this.getProvider(handle).readFile(URI.revive(resource))).then(data => {
|
||||
return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
||||
});
|
||||
$readFile(handle: number, resource: UriComponents): Promise<VSBuffer> {
|
||||
return Promise.resolve(this.getProvider(handle).readFile(URI.revive(resource))).then(data => VSBuffer.wrap(data));
|
||||
}
|
||||
|
||||
$writeFile(handle: number, resource: UriComponents, content: Buffer, opts: files.FileWriteOptions): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).writeFile(URI.revive(resource), content, opts));
|
||||
$writeFile(handle: number, resource: UriComponents, content: VSBuffer, opts: files.FileWriteOptions): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).writeFile(URI.revive(resource), content.buffer, opts));
|
||||
}
|
||||
|
||||
$delete(handle: number, resource: UriComponents, opts: files.FileDeleteOptions): Promise<void> {
|
||||
@@ -288,23 +287,23 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
return Promise.resolve(provider.close(fd));
|
||||
}
|
||||
|
||||
$read(handle: number, fd: number, pos: number, length: number): Promise<Buffer> {
|
||||
$read(handle: number, fd: number, pos: number, length: number): Promise<VSBuffer> {
|
||||
const provider = this.getProvider(handle);
|
||||
if (!provider.read) {
|
||||
throw new Error('FileSystemProvider does not implement "read"');
|
||||
}
|
||||
const data = Buffer.allocUnsafe(length);
|
||||
return Promise.resolve(provider.read(fd, pos, data, 0, length)).then(read => {
|
||||
const data = VSBuffer.alloc(length);
|
||||
return Promise.resolve(provider.read(fd, pos, data.buffer, 0, length)).then(read => {
|
||||
return data.slice(0, read); // don't send zeros
|
||||
});
|
||||
}
|
||||
|
||||
$write(handle: number, fd: number, pos: number, data: Buffer): Promise<number> {
|
||||
$write(handle: number, fd: number, pos: number, data: VSBuffer): Promise<number> {
|
||||
const provider = this.getProvider(handle);
|
||||
if (!provider.write) {
|
||||
throw new Error('FileSystemProvider does not implement "write"');
|
||||
}
|
||||
return Promise.resolve(provider.write(fd, pos, data, 0, data.length));
|
||||
return Promise.resolve(provider.write(fd, pos, data.buffer, 0, data.byteLength));
|
||||
}
|
||||
|
||||
private getProvider(handle: number): vscode.FileSystemProvider {
|
||||
@@ -7,9 +7,9 @@ import { flatten } from 'vs/base/common/arrays';
|
||||
import { AsyncEmitter, Emitter, Event } from 'vs/base/common/event';
|
||||
import { IRelativePattern, parse } from 'vs/base/common/glob';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, MainContext, ResourceFileEditDto, ResourceTextEditDto, MainThreadTextEditorsShape } from '../common/extHost.protocol';
|
||||
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, MainContext, ResourceFileEditDto, ResourceTextEditDto, MainThreadTextEditorsShape } from './extHost.protocol';
|
||||
import * as typeConverter from './extHostTypeConverters';
|
||||
import { Disposable, WorkspaceEdit } from './extHostTypes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtHostHeapServiceShape } from '../common/extHost.protocol';
|
||||
import { ExtHostHeapServiceShape } from './extHost.protocol';
|
||||
|
||||
export class ExtHostHeapService implements ExtHostHeapServiceShape {
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import * as vscode from 'vscode';
|
||||
import * as typeConvert from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol } from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CodeLensDto, MainThreadWebviewsShape, CodeInsetDto, SuggestDataDto, LinksListDto, ChainedCacheId } from '../common/extHost.protocol';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CodeLensDto, MainThreadWebviewsShape, CodeInsetDto, SuggestDataDto, LinksListDto, ChainedCacheId } from './extHost.protocol';
|
||||
import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range as EditorRange } from 'vs/editor/common/core/range';
|
||||
@@ -25,7 +25,7 @@ import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostWebview } from 'vs/workbench/api/node/extHostWebview';
|
||||
import { ExtHostWebview } from 'vs/workbench/api/common/extHostWebview';
|
||||
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
@@ -3,9 +3,9 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MainContext, MainThreadLanguagesShape, IMainContext } from '../common/extHost.protocol';
|
||||
import { MainContext, MainThreadLanguagesShape, IMainContext } from './extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
|
||||
export class ExtHostLanguages {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { ILogService, DelegatedLogService, LogLevel } from 'vs/platform/log/common/log';
|
||||
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { ExtHostLogServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -17,10 +16,10 @@ export class ExtHostLogService extends DelegatedLogService implements ILogServic
|
||||
readonly logFile: URI;
|
||||
|
||||
constructor(
|
||||
logLevel: LogLevel,
|
||||
delegate: ILogService,
|
||||
logsPath: string,
|
||||
) {
|
||||
super(createSpdLogService(ExtensionHostLogFileName, logLevel, logsPath));
|
||||
super(delegate);
|
||||
this._logsPath = logsPath;
|
||||
this.logFile = URI.file(join(logsPath, `${ExtensionHostLogFileName}.log`));
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import * as vscode from 'vscode';
|
||||
import { MainContext, MainThreadMessageServiceShape, MainThreadMessageOptions, IMainContext } from '../common/extHost.protocol';
|
||||
import { MainContext, MainThreadMessageServiceShape, MainThreadMessageOptions, IMainContext } from './extHost.protocol';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
function isMessageItem(item: any): item is vscode.MessageItem {
|
||||
186
src/vs/workbench/api/common/extHostOutput.ts
Normal file
186
src/vs/workbench/api/common/extHostOutput.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MainContext, MainThreadOutputServiceShape, IMainContext, ExtHostOutputServiceShape } from './extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
export abstract class AbstractExtHostOutputChannel extends Disposable implements vscode.OutputChannel {
|
||||
|
||||
readonly _id: Promise<string>;
|
||||
private readonly _name: string;
|
||||
protected readonly _proxy: MainThreadOutputServiceShape;
|
||||
private _disposed: boolean;
|
||||
private _offset: number;
|
||||
|
||||
protected readonly _onDidAppend: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidAppend: Event<void> = this._onDidAppend.event;
|
||||
|
||||
constructor(name: string, log: boolean, file: URI | undefined, proxy: MainThreadOutputServiceShape) {
|
||||
super();
|
||||
|
||||
this._name = name;
|
||||
this._proxy = proxy;
|
||||
this._id = proxy.$register(this.name, log, file);
|
||||
this._offset = 0;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
append(value: string): void {
|
||||
this.validate();
|
||||
this._offset += value ? Buffer.from(value).byteLength : 0;
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this._id.then(id => this._proxy.$update(id));
|
||||
}
|
||||
|
||||
appendLine(value: string): void {
|
||||
this.validate();
|
||||
this.append(value + '\n');
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.validate();
|
||||
const till = this._offset;
|
||||
this._id.then(id => this._proxy.$clear(id, till));
|
||||
}
|
||||
|
||||
show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
|
||||
this.validate();
|
||||
this._id.then(id => this._proxy.$reveal(id, !!(typeof columnOrPreserveFocus === 'boolean' ? columnOrPreserveFocus : preserveFocus)));
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
this.validate();
|
||||
this._id.then(id => this._proxy.$close(id));
|
||||
}
|
||||
|
||||
protected validate(): void {
|
||||
if (this._disposed) {
|
||||
throw new Error('Channel has been closed');
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
if (!this._disposed) {
|
||||
this._id
|
||||
.then(id => this._proxy.$dispose(id))
|
||||
.then(() => this._disposed = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostPushOutputChannel extends AbstractExtHostOutputChannel {
|
||||
|
||||
constructor(name: string, proxy: MainThreadOutputServiceShape) {
|
||||
super(name, false, undefined, proxy);
|
||||
}
|
||||
|
||||
append(value: string): void {
|
||||
super.append(value);
|
||||
this._id.then(id => this._proxy.$append(id, value));
|
||||
this._onDidAppend.fire();
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostLogFileOutputChannel extends AbstractExtHostOutputChannel {
|
||||
|
||||
constructor(name: string, file: URI, proxy: MainThreadOutputServiceShape) {
|
||||
super(name, true, file, proxy);
|
||||
}
|
||||
|
||||
append(value: string): void {
|
||||
throw new Error('Not supported');
|
||||
}
|
||||
}
|
||||
|
||||
export interface IOutputChannelFactory {
|
||||
createOutputChannel(name: string, logsLocation: URI, proxy: MainThreadOutputServiceShape): Promise<AbstractExtHostOutputChannel>;
|
||||
}
|
||||
|
||||
export const PushOutputChannelFactory = new class implements IOutputChannelFactory {
|
||||
async createOutputChannel(name: string, _logsLocation: URI, proxy: MainThreadOutputServiceShape): Promise<AbstractExtHostOutputChannel> {
|
||||
return new ExtHostPushOutputChannel(name, proxy);
|
||||
}
|
||||
};
|
||||
|
||||
export class ExtHostOutputService implements ExtHostOutputServiceShape {
|
||||
|
||||
private readonly _factory: IOutputChannelFactory;
|
||||
private readonly _logsLocation: URI;
|
||||
private readonly _proxy: MainThreadOutputServiceShape;
|
||||
private readonly _channels: Map<string, AbstractExtHostOutputChannel> = new Map<string, AbstractExtHostOutputChannel>();
|
||||
private _visibleChannelDisposable: IDisposable;
|
||||
|
||||
constructor(factory: IOutputChannelFactory, logsLocation: URI, mainContext: IMainContext) {
|
||||
this._factory = factory;
|
||||
this._logsLocation = logsLocation;
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadOutputService);
|
||||
}
|
||||
|
||||
$setVisibleChannel(channelId: string): void {
|
||||
if (this._visibleChannelDisposable) {
|
||||
this._visibleChannelDisposable = dispose(this._visibleChannelDisposable);
|
||||
}
|
||||
if (channelId) {
|
||||
const channel = this._channels.get(channelId);
|
||||
if (channel) {
|
||||
this._visibleChannelDisposable = channel.onDidAppend(() => channel.update());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createOutputChannel(name: string): vscode.OutputChannel {
|
||||
name = name.trim();
|
||||
if (!name) {
|
||||
throw new Error('illegal argument `name`. must not be falsy');
|
||||
} else {
|
||||
const extHostOutputChannel = this._factory.createOutputChannel(name, this._logsLocation, this._proxy);
|
||||
extHostOutputChannel.then(channel => channel._id.then(id => this._channels.set(id, channel)));
|
||||
return {
|
||||
get name(): string {
|
||||
return name;
|
||||
},
|
||||
append(value: string): void {
|
||||
extHostOutputChannel.then(channel => channel.append(value));
|
||||
},
|
||||
appendLine(value: string): void {
|
||||
extHostOutputChannel.then(channel => channel.appendLine(value));
|
||||
},
|
||||
clear(): void {
|
||||
extHostOutputChannel.then(channel => channel.clear());
|
||||
},
|
||||
show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
|
||||
extHostOutputChannel.then(channel => channel.show(columnOrPreserveFocus, preserveFocus));
|
||||
},
|
||||
hide(): void {
|
||||
extHostOutputChannel.then(channel => channel.hide());
|
||||
},
|
||||
dispose(): void {
|
||||
extHostOutputChannel.then(channel => channel.dispose());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
createOutputChannelFromLogFile(name: string, file: URI): vscode.OutputChannel {
|
||||
name = name.trim();
|
||||
if (!name) {
|
||||
throw new Error('illegal argument `name`. must not be falsy');
|
||||
}
|
||||
if (!file) {
|
||||
throw new Error('illegal argument `file`. must not be falsy');
|
||||
}
|
||||
return new ExtHostLogFileOutputChannel(name, file, this._proxy);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ProgressOptions } from 'vscode';
|
||||
import { MainThreadProgressShape, ExtHostProgressShape } from '../common/extHost.protocol';
|
||||
import { MainThreadProgressShape, ExtHostProgressShape } from './extHost.protocol';
|
||||
import { ProgressLocation } from './extHostTypeConverters';
|
||||
import { Progress, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -7,12 +7,12 @@ import { asPromise } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { IExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { InputBox, InputBoxOptions, QuickInput, QuickInputButton, QuickPick, QuickPickItem, QuickPickOptions, WorkspaceFolder, WorkspaceFolderPickOptions } from 'vscode';
|
||||
import { ExtHostQuickOpenShape, IMainContext, MainContext, MainThreadQuickOpenShape, TransferQuickPickItems, TransferQuickInput, TransferQuickInputButton } from '../common/extHost.protocol';
|
||||
import { ExtHostQuickOpenShape, IMainContext, MainContext, MainThreadQuickOpenShape, TransferQuickPickItems, TransferQuickInput, TransferQuickInputButton } from './extHost.protocol';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ThemeIcon, QuickInputButtons } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ThemeIcon, QuickInputButtons } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
@@ -8,8 +8,8 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { debounce } from 'vs/base/common/decorators';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, CommandDto } from '../common/extHost.protocol';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, CommandDto } from './extHost.protocol';
|
||||
import { sortedDiff } from 'vs/base/common/arrays';
|
||||
import { comparePaths } from 'vs/base/common/comparers';
|
||||
import * as vscode from 'vscode';
|
||||
@@ -6,7 +6,7 @@
|
||||
import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable, ThemeColor } from './extHostTypes';
|
||||
import { StatusBarItem, StatusBarAlignment } from 'vscode';
|
||||
import { MainContext, MainThreadStatusBarShape, IMainContext } from '../common/extHost.protocol';
|
||||
import { MainContext, MainThreadStatusBarShape, IMainContext } from './extHost.protocol';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MainContext, MainThreadStorageShape, IMainContext, ExtHostStorageShape } from '../common/extHost.protocol';
|
||||
import { MainContext, MainThreadStorageShape, IMainContext, ExtHostStorageShape } from './extHost.protocol';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export interface IStorageChangeEvent {
|
||||
@@ -10,9 +10,9 @@ import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import { IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData';
|
||||
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { EndOfLine, Position, Range, Selection, SnippetString, TextEditorLineNumbersStyle, TextEditorRevealType } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
|
||||
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { EndOfLine, Position, Range, Selection, SnippetString, TextEditorLineNumbersStyle, TextEditorRevealType } from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class TextEditorDecorationType implements vscode.TextEditorDecorationType {
|
||||
@@ -6,10 +6,10 @@
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/node/extHostTextEditor';
|
||||
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { TextEditorSelectionChangeKind } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/common/extHostTextEditor';
|
||||
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { TextEditorSelectionChangeKind } from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
@@ -9,11 +9,11 @@ import { basename } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from '../common/extHost.protocol';
|
||||
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol';
|
||||
import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel, IRevealOptions } from 'vs/workbench/common/views';
|
||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
import { TreeItemCollapsibleState, ThemeIcon, MarkdownString } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { TreeItemCollapsibleState, ThemeIcon, MarkdownString } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { isUndefinedOrNull, isString } from 'vs/base/common/types';
|
||||
import { equals, coalesce } from 'vs/base/common/arrays';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
@@ -22,7 +22,7 @@ import * as languageSelector from 'vs/editor/common/modes/languageSelector';
|
||||
import { WorkspaceEditDto, ResourceTextEditDto, ResourceFileEditDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { MarkerSeverity, IRelatedInformation, IMarkerData, MarkerTag } from 'vs/platform/markers/common/markers';
|
||||
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { isString, isNumber } from 'vs/base/common/types';
|
||||
import * as marked from 'vs/base/common/marked/marked';
|
||||
import { parse } from 'vs/base/common/marshalling';
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { MainContext, IMainContext, ExtHostUrlsShape, MainThreadUrlsShape } from '../common/extHost.protocol';
|
||||
import { MainContext, IMainContext, ExtHostUrlsShape, MainThreadUrlsShape } from './extHost.protocol';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState, WebviewInsetHandle } from '../common/extHost.protocol';
|
||||
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState, WebviewInsetHandle } from './extHost.protocol';
|
||||
import { Disposable } from './extHostTypes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IMainContext } from '../common/extHost.protocol';
|
||||
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IMainContext } from './extHost.protocol';
|
||||
import { WindowState } from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -38,12 +38,19 @@ export class ExtHostWindow implements ExtHostWindowShape {
|
||||
this._onDidChangeWindowState.fire(this._state);
|
||||
}
|
||||
|
||||
openUri(uri: URI): Promise<boolean> {
|
||||
if (isFalsyOrWhitespace(uri.scheme)) {
|
||||
return Promise.reject('Invalid scheme - cannot be empty');
|
||||
} else if (uri.scheme === Schemas.command) {
|
||||
return Promise.reject(`Invalid scheme '${uri.scheme}'`);
|
||||
openUri(stringOrUri: string | URI): Promise<boolean> {
|
||||
if (typeof stringOrUri === 'string') {
|
||||
try {
|
||||
stringOrUri = URI.parse(stringOrUri);
|
||||
} catch (e) {
|
||||
return Promise.reject(`Invalid uri - '${stringOrUri}'`);
|
||||
}
|
||||
}
|
||||
return this._proxy.$openUri(uri);
|
||||
if (isFalsyOrWhitespace(stringOrUri.scheme)) {
|
||||
return Promise.reject('Invalid scheme - cannot be empty');
|
||||
} else if (stringOrUri.scheme === Schemas.command) {
|
||||
return Promise.reject(`Invalid scheme '${stringOrUri.scheme}'`);
|
||||
}
|
||||
return this._proxy.$openUri(stringOrUri);
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,10 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IRawFileMatch2, resultIsMatch } from 'vs/workbench/services/search/common/search';
|
||||
import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { Range, RelativePattern } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Range, RelativePattern } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostWorkspaceShape, IWorkspaceData, MainThreadMessageServiceShape, MainThreadWorkspaceShape, IMainContext, MainContext, IStaticWorkspaceData } from '../common/extHost.protocol';
|
||||
import { ExtHostWorkspaceShape, IWorkspaceData, MainThreadMessageServiceShape, MainThreadWorkspaceShape, IMainContext, MainContext, IStaticWorkspaceData } from './extHost.protocol';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
|
||||
@@ -55,7 +55,7 @@ import '../browser/mainThreadWorkspace';
|
||||
import '../browser/mainThreadComments';
|
||||
import '../browser/mainThreadTask';
|
||||
import './mainThreadWebview';
|
||||
import 'vs/workbench/api/node/apiCommands';
|
||||
import 'vs/workbench/api/common/apiCommands';
|
||||
|
||||
export class ExtensionPoints implements IWorkbenchContribution {
|
||||
|
||||
|
||||
@@ -16,58 +16,60 @@ import { OverviewRulerLane } from 'vs/editor/common/model';
|
||||
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { score } from 'vs/editor/common/modes/languageSelector';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import { ExtHostContext, IInitData, IMainContext, MainContext, MainThreadKeytarShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostApiCommands } from 'vs/workbench/api/node/extHostApiCommands';
|
||||
import { ExtHostClipboard } from 'vs/workbench/api/node/extHostClipboard';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostComments } from 'vs/workbench/api/node/extHostComments';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { ExtHostContext, IInitData, IMainContext, MainContext, MainThreadKeytarShape, IEnvironment, MainThreadWindowShape, MainThreadTelemetryShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
|
||||
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostComments } from 'vs/workbench/api/common/extHostComments';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
// {{SQL CARBON EDIT}} - Remove ExtHostDebugService
|
||||
// import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
// {{SQL CARBON EDIT}} - Import product
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { ExtHostDecorations } from 'vs/workbench/api/node/extHostDecorations';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
|
||||
import { ExtHostDialogs } from 'vs/workbench/api/node/extHostDialogs';
|
||||
import { ExtHostDocumentContentProvider } from 'vs/workbench/api/node/extHostDocumentContentProviders';
|
||||
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtensionActivatedByAPI } from 'vs/workbench/api/node/extHostExtensionActivator';
|
||||
import { ExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
|
||||
import { ExtHostDialogs } from 'vs/workbench/api/common/extHostDialogs';
|
||||
import { ExtHostDocumentContentProvider } from 'vs/workbench/api/common/extHostDocumentContentProviders';
|
||||
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/common/extHostDocumentSaveParticipant';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ExtensionActivatedByAPI } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { ExtHostFileSystem } from 'vs/workbench/api/node/extHostFileSystem';
|
||||
import { ExtHostFileSystemEventService } from 'vs/workbench/api/node/extHostFileSystemEventService';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
import { ExtHostLanguageFeatures, ISchemeTransformer } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import { ExtHostLanguages } from 'vs/workbench/api/node/extHostLanguages';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
|
||||
import { ExtHostMessageService } from 'vs/workbench/api/node/extHostMessageService';
|
||||
import { ExtHostOutputService } from 'vs/workbench/api/node/extHostOutputService';
|
||||
import { ExtHostProgress } from 'vs/workbench/api/node/extHostProgress';
|
||||
import { ExtHostQuickOpen } from 'vs/workbench/api/node/extHostQuickOpen';
|
||||
import { ExtHostSCM } from 'vs/workbench/api/node/extHostSCM';
|
||||
import { ExtHostFileSystem } from 'vs/workbench/api/common/extHostFileSystem';
|
||||
import { ExtHostFileSystemEventService } from 'vs/workbench/api/common/extHostFileSystemEventService';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService';
|
||||
import { ExtHostLanguageFeatures, ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
|
||||
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
|
||||
import { ExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
|
||||
import { LogOutputChannelFactory } from 'vs/workbench/api/node/extHostOutputService';
|
||||
import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress';
|
||||
import { ExtHostQuickOpen } from 'vs/workbench/api/common/extHostQuickOpen';
|
||||
import { ExtHostSCM } from 'vs/workbench/api/common/extHostSCM';
|
||||
import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch';
|
||||
import { ExtHostStatusBar } from 'vs/workbench/api/node/extHostStatusBar';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
|
||||
import { ExtHostStatusBar } from 'vs/workbench/api/common/extHostStatusBar';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
|
||||
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { ExtHostEditors } from 'vs/workbench/api/node/extHostTextEditors';
|
||||
import { ExtHostTreeViews } from 'vs/workbench/api/node/extHostTreeViews';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ExtHostUrls } from 'vs/workbench/api/node/extHostUrls';
|
||||
import { ExtHostWebviews } from 'vs/workbench/api/node/extHostWebview';
|
||||
import { ExtHostWindow } from 'vs/workbench/api/node/extHostWindow';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
|
||||
import { ExtHostTreeViews } from 'vs/workbench/api/common/extHostTreeViews';
|
||||
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 { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { throwProposedApiError, checkProposedApiEnabled, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { originalFSPath } from 'vs/base/common/resources';
|
||||
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { values } from 'vs/base/common/collections';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
@@ -126,7 +128,7 @@ export function createApiFactory(
|
||||
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, new ExtHostOutputService(initData.logsLocation, rpcProtocol));
|
||||
const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, new ExtHostOutputService(LogOutputChannelFactory, initData.logsLocation, rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
|
||||
if (initData.remoteAuthority) {
|
||||
const cliServer = new CLIServer(extHostCommands);
|
||||
@@ -880,34 +882,59 @@ class Extension<T> implements vscode.Extension<T> {
|
||||
}
|
||||
}
|
||||
|
||||
interface LoadFunction {
|
||||
(request: string, parent: { filename: string; }, isMain: any): any;
|
||||
}
|
||||
|
||||
interface INodeModuleFactory {
|
||||
readonly nodeModuleName: string;
|
||||
load(request: string, parent: { filename: string; }): any;
|
||||
readonly nodeModuleName: string | string[];
|
||||
load(request: string, parent: { filename: string; }, isMain: any, original: LoadFunction): any;
|
||||
alternaiveModuleName?(name: string): string | undefined;
|
||||
}
|
||||
|
||||
export class NodeModuleRequireInterceptor {
|
||||
public static INSTANCE = new NodeModuleRequireInterceptor();
|
||||
|
||||
private readonly _factories: Map<string, INodeModuleFactory>;
|
||||
private readonly _alternatives: ((moduleName: string) => string | undefined)[];
|
||||
|
||||
constructor() {
|
||||
this._factories = new Map<string, INodeModuleFactory>();
|
||||
this._installInterceptor(this._factories);
|
||||
this._alternatives = [];
|
||||
this._installInterceptor(this._factories, this._alternatives);
|
||||
}
|
||||
|
||||
private _installInterceptor(factories: Map<string, INodeModuleFactory>): void {
|
||||
private _installInterceptor(factories: Map<string, INodeModuleFactory>, alternatives: ((moduleName: string) => string | undefined)[]): void {
|
||||
const node_module = <any>require.__$__nodeRequire('module');
|
||||
const original = node_module._load;
|
||||
node_module._load = function load(request: string, parent: { filename: string; }, isMain: any) {
|
||||
for (let alternativeModuleName of alternatives) {
|
||||
let alternative = alternativeModuleName(request);
|
||||
if (alternative) {
|
||||
request = alternative;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!factories.has(request)) {
|
||||
return original.apply(this, arguments);
|
||||
}
|
||||
return factories.get(request)!.load(request, parent);
|
||||
return factories.get(request)!.load(request, parent, isMain, original);
|
||||
};
|
||||
}
|
||||
|
||||
public register(interceptor: INodeModuleFactory): void {
|
||||
this._factories.set(interceptor.nodeModuleName, interceptor);
|
||||
if (Array.isArray(interceptor.nodeModuleName)) {
|
||||
for (let moduleName of interceptor.nodeModuleName) {
|
||||
this._factories.set(moduleName, interceptor);
|
||||
}
|
||||
} else {
|
||||
this._factories.set(interceptor.nodeModuleName, interceptor);
|
||||
}
|
||||
if (typeof interceptor.alternaiveModuleName === 'function') {
|
||||
this._alternatives.push((moduleName) => {
|
||||
return interceptor.alternaiveModuleName!(moduleName);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -957,11 +984,24 @@ interface IKeytarModule {
|
||||
}
|
||||
|
||||
export class KeytarNodeModuleFactory implements INodeModuleFactory {
|
||||
public readonly nodeModuleName = 'keytar';
|
||||
public readonly nodeModuleName: string = 'keytar';
|
||||
|
||||
private alternativeNames: Set<string> | undefined;
|
||||
private _impl: IKeytarModule;
|
||||
|
||||
constructor(mainThreadKeytar: MainThreadKeytarShape) {
|
||||
constructor(mainThreadKeytar: MainThreadKeytarShape, environment: IEnvironment) {
|
||||
if (environment.appRoot) {
|
||||
let appRoot = environment.appRoot.fsPath;
|
||||
if (process.platform === 'win32') {
|
||||
appRoot = appRoot.replace(/\\/g, '/');
|
||||
}
|
||||
if (appRoot[appRoot.length - 1] === '/') {
|
||||
appRoot = appRoot.substr(0, appRoot.length - 1);
|
||||
}
|
||||
this.alternativeNames = new Set();
|
||||
this.alternativeNames.add(`${appRoot}/node_modules.asar/keytar`);
|
||||
this.alternativeNames.add(`${appRoot}/node_modules/keytar`);
|
||||
}
|
||||
this._impl = {
|
||||
getPassword: (service: string, account: string): Promise<string | null> => {
|
||||
return mainThreadKeytar.$getPassword(service, account);
|
||||
@@ -981,4 +1021,100 @@ export class KeytarNodeModuleFactory implements INodeModuleFactory {
|
||||
public load(request: string, parent: { filename: string; }): any {
|
||||
return this._impl;
|
||||
}
|
||||
|
||||
public alternaiveModuleName(name: string): string | undefined {
|
||||
const length = name.length;
|
||||
// We need at least something like: `?/keytar` which requires
|
||||
// more than 7 characters.
|
||||
if (length <= 7 || !this.alternativeNames) {
|
||||
return undefined;
|
||||
}
|
||||
const sep = length - 7;
|
||||
if ((name.charAt(sep) === '/' || name.charAt(sep) === '\\') && endsWith(name, 'keytar')) {
|
||||
name = name.replace(/\\/g, '/');
|
||||
if (this.alternativeNames.has(name)) {
|
||||
return 'keytar';
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
interface OpenOptions {
|
||||
wait: boolean;
|
||||
app: string | string[];
|
||||
}
|
||||
|
||||
interface IOriginalOpen {
|
||||
(target: string, options?: OpenOptions): Thenable<any>;
|
||||
}
|
||||
|
||||
interface IOpenModule {
|
||||
(target: string, options?: OpenOptions): Thenable<void>;
|
||||
}
|
||||
|
||||
export class OpenNodeModuleFactory implements INodeModuleFactory {
|
||||
|
||||
public readonly nodeModuleName: string[] = ['open', 'opn'];
|
||||
|
||||
private _extensionId: string | undefined;
|
||||
private _original: IOriginalOpen;
|
||||
private _impl: IOpenModule;
|
||||
|
||||
constructor(mainThreadWindow: MainThreadWindowShape, private _mainThreadTelemerty: MainThreadTelemetryShape, private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>) {
|
||||
this._impl = (target, options) => {
|
||||
const uri: URI = URI.parse(target);
|
||||
// If we have options use the original method.
|
||||
if (options) {
|
||||
return this.callOriginal(target, options);
|
||||
}
|
||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||
return mainThreadWindow.$openUri(uri);
|
||||
} else if (uri.scheme === 'mailto') {
|
||||
return mainThreadWindow.$openUri(uri);
|
||||
}
|
||||
return this.callOriginal(target, options);
|
||||
};
|
||||
}
|
||||
|
||||
public load(request: string, parent: { filename: string; }, isMain: any, original: LoadFunction): any {
|
||||
// get extension id from filename and api for extension
|
||||
const extension = this._extensionPaths.findSubstr(URI.file(parent.filename).fsPath);
|
||||
if (extension) {
|
||||
this._extensionId = extension.identifier.value;
|
||||
this.sendShimmingTelemetry();
|
||||
}
|
||||
|
||||
this._original = original(request, parent, isMain);
|
||||
return this._impl;
|
||||
}
|
||||
|
||||
private callOriginal(target: string, options: OpenOptions | undefined): Thenable<any> {
|
||||
this.sendNoForwardTelemetry();
|
||||
return this._original(target, options);
|
||||
}
|
||||
|
||||
private sendShimmingTelemetry(): void {
|
||||
if (!this._extensionId) {
|
||||
return;
|
||||
}
|
||||
/* __GDPR__
|
||||
"shimming.open" : {
|
||||
"extension": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this._mainThreadTelemerty.$publicLog('shimming.open', { extension: this._extensionId });
|
||||
}
|
||||
|
||||
private sendNoForwardTelemetry(): void {
|
||||
if (!this._extensionId) {
|
||||
return;
|
||||
}
|
||||
/* __GDPR__
|
||||
"shimming.open.call.noForward" : {
|
||||
"extension": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this._mainThreadTelemerty.$publicLog('shimming.open.call.noForward', { extension: this._extensionId });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { generateRandomPipeName } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import * as http from 'http';
|
||||
import * as fs from 'fs';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IURIToOpen, IOpenSettings } from 'vs/platform/windows/common/windows';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
|
||||
|
||||
@@ -16,24 +16,24 @@ import {
|
||||
IMainContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto
|
||||
} from 'vs/workbench/api/common/extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint, DebugAdapterServer, DebugAdapterExecutable } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint, DebugAdapterServer, DebugAdapterExecutable } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ExecutableDebugAdapter, SocketDebugAdapter } from 'vs/workbench/contrib/debug/node/debugAdapter';
|
||||
import { AbstractDebugAdapter } from 'vs/workbench/contrib/debug/common/abstractDebugAdapter';
|
||||
import { IExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { getTerminalLauncher, hasChildProcesses, prepareCommand } from 'vs/workbench/contrib/debug/node/terminals';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from './extHostConfiguration';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from '../common/extHostConfiguration';
|
||||
import { convertToVSCPaths, convertToDAPaths, isDebuggerMainContribution } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
|
||||
@@ -16,15 +16,15 @@ import * as pfs from 'vs/base/node/pfs';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
// {{SQL CARBON EDIT}} - Remove createApiFactory initializeExtensionApi, and IExtensionApiFactory imports
|
||||
//import { createApiFactory, IExtensionApiFactory, NodeModuleRequireInterceptor, VSCodeNodeModuleFactory } from 'vs/workbench/api/node/extHost.api.impl';
|
||||
import { NodeModuleRequireInterceptor, VSCodeNodeModuleFactory, KeytarNodeModuleFactory } from 'vs/workbench/api/node/extHost.api.impl';
|
||||
import { NodeModuleRequireInterceptor, KeytarNodeModuleFactory, OpenNodeModuleFactory } from 'vs/workbench/api/node/extHost.api.impl';
|
||||
import { ExtHostExtensionServiceShape, IEnvironment, IInitData, IMainContext, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IStaticWorkspaceData } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionMemento, IExtensionModule, HostExtension } from 'vs/workbench/api/node/extHostExtensionActivator';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionMemento, IExtensionModule, HostExtension } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { connectProxyResolver } from 'vs/workbench/services/extensions/node/proxyResolver';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
@@ -35,6 +35,7 @@ import { IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { realpath } from 'vs/base/node/extpath';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
class ExtensionMemento implements IExtensionMemento {
|
||||
|
||||
@@ -165,6 +166,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
private readonly _extHostContext: IMainContext;
|
||||
private readonly _extHostWorkspace: ExtHostWorkspace;
|
||||
private readonly _extHostConfiguration: ExtHostConfiguration;
|
||||
private readonly _environment: IEnvironment;
|
||||
private readonly _extHostLogService: ExtHostLogService;
|
||||
|
||||
private readonly _mainThreadWorkspaceProxy: MainThreadWorkspaceShape;
|
||||
@@ -190,6 +192,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
extHostContext: IMainContext,
|
||||
extHostWorkspace: ExtHostWorkspace,
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
environment: IEnvironment,
|
||||
extHostLogService: ExtHostLogService
|
||||
) {
|
||||
this._nativeExit = nativeExit;
|
||||
@@ -197,6 +200,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
this._extHostContext = extHostContext;
|
||||
this._extHostWorkspace = extHostWorkspace;
|
||||
this._extHostConfiguration = extHostConfiguration;
|
||||
this._environment = environment;
|
||||
this._extHostLogService = extHostLogService;
|
||||
|
||||
this._mainThreadWorkspaceProxy = this._extHostContext.getProxy(MainContext.MainThreadWorkspace);
|
||||
@@ -246,12 +250,18 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
private async _initialize(): Promise<void> {
|
||||
try {
|
||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||
|
||||
const extensionPaths = await this.getExtensionPathIndex();
|
||||
// {{SQL CARBON EDIT}} - disable VSCodeNodeModuleFactory and use older initializeExtensionApi
|
||||
// const extensionPaths = await this.getExtensionPathIndex();
|
||||
// NodeModuleRequireInterceptor.INSTANCE.register(new VSCodeNodeModuleFactory(this._extensionApiFactory, extensionPaths, this._registry, configProvider));
|
||||
await initializeExtensionApi(this, this._extensionApiFactory, this._registry, configProvider);
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new KeytarNodeModuleFactory(this._extHostContext.getProxy(MainContext.MainThreadKeytar)));
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new KeytarNodeModuleFactory(this._extHostContext.getProxy(MainContext.MainThreadKeytar), this._environment));
|
||||
if (this._initData.remoteAuthority) {
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new OpenNodeModuleFactory(
|
||||
this._extHostContext.getProxy(MainContext.MainThreadWindow),
|
||||
this._extHostContext.getProxy(MainContext.MainThreadTelemetry),
|
||||
extensionPaths
|
||||
));
|
||||
}
|
||||
|
||||
// Do this when extension service exists, but extensions are not being activated yet.
|
||||
await connectProxyResolver(this._extHostWorkspace, configProvider, this, this._extHostLogService, this._mainThreadTelemetryProxy);
|
||||
@@ -608,7 +618,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
}
|
||||
|
||||
private _doHandleExtensionTests(): Promise<void> {
|
||||
const { extensionDevelopmentLocationURI, extensionTestsLocationURI } = this._initData.environment;
|
||||
const { extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, extensionTestsLocationURI } = this._initData.environment;
|
||||
if (!(extensionDevelopmentLocationURI && extensionTestsLocationURI && extensionTestsLocationURI.scheme === Schemas.file)) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
@@ -759,13 +769,12 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
return n;
|
||||
}
|
||||
|
||||
public async $test_up(b: Buffer): Promise<number> {
|
||||
return b.length;
|
||||
public async $test_up(b: VSBuffer): Promise<number> {
|
||||
return b.byteLength;
|
||||
}
|
||||
|
||||
public async $test_down(size: number): Promise<Buffer> {
|
||||
const b = Buffer.alloc(size, Math.random() % 256);
|
||||
return b;
|
||||
public async $test_down(size: number): Promise<VSBuffer> {
|
||||
return VSBuffer.wrap(Buffer.alloc(size, Math.random() % 256));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,101 +3,16 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MainContext, MainThreadOutputServiceShape, IMainContext, ExtHostOutputServiceShape } from '../common/extHost.protocol';
|
||||
import { MainThreadOutputServiceShape } from '../common/extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { OutputAppender } from 'vs/workbench/services/output/node/outputAppender';
|
||||
import { toLocalISOString } from 'vs/base/common/date';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { dirExists, mkdirp } from 'vs/base/node/pfs';
|
||||
import { AbstractExtHostOutputChannel, IOutputChannelFactory, ExtHostPushOutputChannel } from 'vs/workbench/api/common/extHostOutput';
|
||||
|
||||
abstract class AbstractExtHostOutputChannel extends Disposable implements vscode.OutputChannel {
|
||||
|
||||
readonly _id: Promise<string>;
|
||||
private readonly _name: string;
|
||||
protected readonly _proxy: MainThreadOutputServiceShape;
|
||||
private _disposed: boolean;
|
||||
private _offset: number;
|
||||
|
||||
protected readonly _onDidAppend: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidAppend: Event<void> = this._onDidAppend.event;
|
||||
|
||||
constructor(name: string, log: boolean, file: URI | undefined, proxy: MainThreadOutputServiceShape) {
|
||||
super();
|
||||
|
||||
this._name = name;
|
||||
this._proxy = proxy;
|
||||
this._id = proxy.$register(this.name, log, file);
|
||||
this._offset = 0;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
append(value: string): void {
|
||||
this.validate();
|
||||
this._offset += value ? Buffer.from(value).byteLength : 0;
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this._id.then(id => this._proxy.$update(id));
|
||||
}
|
||||
|
||||
appendLine(value: string): void {
|
||||
this.validate();
|
||||
this.append(value + '\n');
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.validate();
|
||||
const till = this._offset;
|
||||
this._id.then(id => this._proxy.$clear(id, till));
|
||||
}
|
||||
|
||||
show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
|
||||
this.validate();
|
||||
this._id.then(id => this._proxy.$reveal(id, !!(typeof columnOrPreserveFocus === 'boolean' ? columnOrPreserveFocus : preserveFocus)));
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
this.validate();
|
||||
this._id.then(id => this._proxy.$close(id));
|
||||
}
|
||||
|
||||
protected validate(): void {
|
||||
if (this._disposed) {
|
||||
throw new Error('Channel has been closed');
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
if (!this._disposed) {
|
||||
this._id
|
||||
.then(id => this._proxy.$dispose(id))
|
||||
.then(() => this._disposed = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostPushOutputChannel extends AbstractExtHostOutputChannel {
|
||||
|
||||
constructor(name: string, proxy: MainThreadOutputServiceShape) {
|
||||
super(name, false, undefined, proxy);
|
||||
}
|
||||
|
||||
append(value: string): void {
|
||||
super.append(value);
|
||||
this._id.then(id => this._proxy.$append(id, value));
|
||||
this._onDidAppend.fire();
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
|
||||
export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
|
||||
|
||||
private _appender: OutputAppender;
|
||||
|
||||
@@ -128,95 +43,23 @@ class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostLogFileOutputChannel extends AbstractExtHostOutputChannel {
|
||||
export const LogOutputChannelFactory = new class implements IOutputChannelFactory {
|
||||
|
||||
constructor(name: string, file: URI, proxy: MainThreadOutputServiceShape) {
|
||||
super(name, true, file, proxy);
|
||||
}
|
||||
_namePool = 1;
|
||||
|
||||
append(value: string): void {
|
||||
throw new Error('Not supported');
|
||||
}
|
||||
}
|
||||
|
||||
let namePool = 1;
|
||||
async function createExtHostOutputChannel(name: string, outputDirPromise: Promise<string>, proxy: MainThreadOutputServiceShape): Promise<AbstractExtHostOutputChannel> {
|
||||
try {
|
||||
const outputDir = await outputDirPromise;
|
||||
const fileName = `${namePool++}-${name}`;
|
||||
const file = URI.file(join(outputDir, `${fileName}.log`));
|
||||
const appender = new OutputAppender(fileName, file.fsPath);
|
||||
return new ExtHostOutputChannelBackedByFile(name, appender, proxy);
|
||||
} catch (error) {
|
||||
// Do not crash if logger cannot be created
|
||||
console.log(error);
|
||||
return new ExtHostPushOutputChannel(name, proxy);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostOutputService implements ExtHostOutputServiceShape {
|
||||
|
||||
private readonly _outputDir: Promise<string>;
|
||||
private _proxy: MainThreadOutputServiceShape;
|
||||
private _channels: Map<string, AbstractExtHostOutputChannel> = new Map<string, AbstractExtHostOutputChannel>();
|
||||
private _visibleChannelDisposable: IDisposable;
|
||||
|
||||
constructor(logsLocation: URI, mainContext: IMainContext) {
|
||||
const outputDirPath = join(logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
|
||||
this._outputDir = dirExists(outputDirPath).then(exists => exists ? exists : mkdirp(outputDirPath).then(() => true)).then(() => outputDirPath);
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadOutputService);
|
||||
}
|
||||
|
||||
$setVisibleChannel(channelId: string): void {
|
||||
if (this._visibleChannelDisposable) {
|
||||
this._visibleChannelDisposable = dispose(this._visibleChannelDisposable);
|
||||
}
|
||||
if (channelId) {
|
||||
const channel = this._channels.get(channelId);
|
||||
if (channel) {
|
||||
this._visibleChannelDisposable = channel.onDidAppend(() => channel.update());
|
||||
}
|
||||
async createOutputChannel(name: string, logsLocation: URI, proxy: MainThreadOutputServiceShape): Promise<AbstractExtHostOutputChannel> {
|
||||
try {
|
||||
const outputDirPath = join(logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
|
||||
const outputDir = await dirExists(outputDirPath).then(exists => exists ? exists : mkdirp(outputDirPath).then(() => true)).then(() => outputDirPath);
|
||||
const fileName = `${this._namePool++}-${name}`;
|
||||
const file = URI.file(join(outputDir, `${fileName}.log`));
|
||||
const appender = new OutputAppender(fileName, file.fsPath);
|
||||
return new ExtHostOutputChannelBackedByFile(name, appender, proxy);
|
||||
} catch (error) {
|
||||
// Do not crash if logger cannot be created
|
||||
console.log(error);
|
||||
return new ExtHostPushOutputChannel(name, proxy);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
createOutputChannel(name: string): vscode.OutputChannel {
|
||||
name = name.trim();
|
||||
if (!name) {
|
||||
throw new Error('illegal argument `name`. must not be falsy');
|
||||
} else {
|
||||
const extHostOutputChannel = createExtHostOutputChannel(name, this._outputDir, this._proxy);
|
||||
extHostOutputChannel.then(channel => channel._id.then(id => this._channels.set(id, channel)));
|
||||
return <vscode.OutputChannel>{
|
||||
append(value: string): void {
|
||||
extHostOutputChannel.then(channel => channel.append(value));
|
||||
},
|
||||
appendLine(value: string): void {
|
||||
extHostOutputChannel.then(channel => channel.appendLine(value));
|
||||
},
|
||||
clear(): void {
|
||||
extHostOutputChannel.then(channel => channel.clear());
|
||||
},
|
||||
show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
|
||||
extHostOutputChannel.then(channel => channel.show(columnOrPreserveFocus, preserveFocus));
|
||||
},
|
||||
hide(): void {
|
||||
extHostOutputChannel.then(channel => channel.hide());
|
||||
},
|
||||
dispose(): void {
|
||||
extHostOutputChannel.then(channel => channel.dispose());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
createOutputChannelFromLogFile(name: string, file: URI): vscode.OutputChannel {
|
||||
name = name.trim();
|
||||
if (!name) {
|
||||
throw new Error('illegal argument `name`. must not be falsy');
|
||||
}
|
||||
if (!file) {
|
||||
throw new Error('illegal argument `file`. must not be falsy');
|
||||
}
|
||||
return new ExtHostLogFileOutputChannel(name, file, this._proxy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ import { win32 } from 'vs/base/node/processes';
|
||||
|
||||
import { MainContext, MainThreadTaskShape, ExtHostTaskShape, IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
|
||||
import * as types from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ExtHostWorkspace, IExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ExtHostWorkspace, IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import * as vscode from 'vscode';
|
||||
import {
|
||||
TaskDefinitionDTO, TaskExecutionDTO, TaskPresentationOptionsDTO,
|
||||
@@ -26,8 +26,8 @@ import {
|
||||
} from '../common/shared/tasks';
|
||||
// {{SQL CARBON EDIT}}
|
||||
// import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform';
|
||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
||||
|
||||
@@ -16,6 +16,7 @@ import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDE
|
||||
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
export class OpenFileAction extends Action {
|
||||
|
||||
@@ -289,14 +290,15 @@ export class DuplicateWorkspaceInNewWindowAction extends Action {
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||
@IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
@IWorkspacesService private readonly workspacesService: IWorkspacesService
|
||||
@IWorkspacesService private readonly workspacesService: IWorkspacesService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
const folders = this.workspaceContextService.getWorkspace().folders;
|
||||
const remoteAuthority = this.windowService.getConfiguration().remoteAuthority;
|
||||
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
||||
|
||||
return this.workspacesService.createUntitledWorkspace(folders, remoteAuthority).then(newWorkspace => {
|
||||
return this.workspaceEditingService.copyWorkspaceSettings(newWorkspace).then(() => {
|
||||
|
||||
@@ -44,6 +44,12 @@ export abstract class Composite extends Component implements IComposite {
|
||||
return this._onDidFocus.event;
|
||||
}
|
||||
|
||||
protected fireOnDidFocus(): void {
|
||||
if (this._onDidFocus) {
|
||||
this._onDidFocus.fire();
|
||||
}
|
||||
}
|
||||
|
||||
private _onDidBlur: Emitter<void>;
|
||||
get onDidBlur(): Event<void> {
|
||||
if (!this._onDidBlur) {
|
||||
|
||||
@@ -7,13 +7,13 @@ import { Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { IWindowService, IWindowsConfiguration } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowsConfiguration } from 'vs/platform/windows/common/windows';
|
||||
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext } from 'vs/workbench/common/editor';
|
||||
import { IsMacContext, IsLinuxContext, IsWindowsContext, HasMacNativeTabsContext, IsDevelopmentContext, SupportsWorkspacesContext, SupportsOpenFileFolderContext, WorkbenchStateContext, WorkspaceFolderCountContext, IsRemoteContext } from 'vs/workbench/common/contextkeys';
|
||||
import { IsMacContext, IsLinuxContext, IsWindowsContext, HasMacNativeTabsContext, IsDevelopmentContext, SupportsWorkspacesContext, WorkbenchStateContext, WorkspaceFolderCountContext, RemoteAuthorityContext } from 'vs/workbench/common/contextkeys';
|
||||
import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { SideBarVisibleContext } from 'vs/workbench/common/viewlet';
|
||||
@@ -43,8 +43,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@IWindowService private windowService: IWindowService,
|
||||
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService,
|
||||
@IEditorService private editorService: IEditorService,
|
||||
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
|
||||
@IWorkbenchLayoutService private layoutService: IWorkbenchLayoutService,
|
||||
@@ -88,7 +87,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
IsLinuxContext.bindTo(this.contextKeyService);
|
||||
IsWindowsContext.bindTo(this.contextKeyService);
|
||||
|
||||
IsRemoteContext.bindTo(this.contextKeyService).set(!!this.windowService.getConfiguration().remoteAuthority);
|
||||
RemoteAuthorityContext.bindTo(this.contextKeyService).set(this.environmentService.configuration.remoteAuthority || '');
|
||||
|
||||
// macOS Native Tabs
|
||||
const windowConfig = this.configurationService.getValue<IWindowsConfiguration>();
|
||||
@@ -99,7 +98,6 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
|
||||
// File Pickers
|
||||
SupportsWorkspacesContext.bindTo(this.contextKeyService);
|
||||
SupportsOpenFileFolderContext.bindTo(this.contextKeyService).set(!!this.windowService.getConfiguration().remoteAuthority);
|
||||
|
||||
// Editors
|
||||
this.activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService);
|
||||
|
||||
@@ -16,7 +16,7 @@ import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IDecorationsService, IResourceDecorationChangeEvent, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { FileKind, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files';
|
||||
import { FileKind, FILES_ASSOCIATIONS_CONFIG, IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
@@ -93,7 +93,8 @@ export class ResourceLabels extends Disposable {
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IModelService private readonly modelService: IModelService,
|
||||
@IDecorationsService private readonly decorationsService: IDecorationsService,
|
||||
@IThemeService private readonly themeService: IThemeService
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -116,7 +117,7 @@ export class ResourceLabels extends Disposable {
|
||||
return; // we need the resource to compare
|
||||
}
|
||||
|
||||
if (e.model.uri.scheme === Schemas.file && e.oldModeId === PLAINTEXT_MODE_ID) { // todo@remote does this apply?
|
||||
if (this.fileService.canHandleResource(e.model.uri) && e.oldModeId === PLAINTEXT_MODE_ID) {
|
||||
return; // ignore transitions in files from no mode to specific mode because this happens each time a model is created
|
||||
}
|
||||
|
||||
@@ -202,9 +203,9 @@ export class ResourceLabel extends ResourceLabels {
|
||||
@IModelService modelService: IModelService,
|
||||
@IDecorationsService decorationsService: IDecorationsService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@ILabelService labelService: ILabelService
|
||||
@IFileService fileService: IFileService
|
||||
) {
|
||||
super(DEFAULT_LABELS_CONTAINER, instantiationService, extensionService, configurationService, modelService, decorationsService, themeService);
|
||||
super(DEFAULT_LABELS_CONTAINER, instantiationService, extensionService, configurationService, modelService, decorationsService, themeService, fileService);
|
||||
|
||||
this._label = this._register(this.create(container, options));
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import { ITitleService } from 'vs/workbench/services/title/common/titleService';
|
||||
import { IInstantiationService, ServicesAccessor, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { LifecyclePhase, StartupKind, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IWindowService, IPath, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid';
|
||||
@@ -89,7 +89,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
private editorPartView: View;
|
||||
private statusBarPartView: View;
|
||||
|
||||
private environmentService: IEnvironmentService;
|
||||
private environmentService: IWorkbenchEnvironmentService;
|
||||
private configurationService: IConfigurationService;
|
||||
private lifecycleService: ILifecycleService;
|
||||
private storageService: IStorageService;
|
||||
@@ -161,12 +161,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
protected initLayout(accessor: ServicesAccessor): void {
|
||||
|
||||
// Services
|
||||
this.environmentService = accessor.get(IEnvironmentService);
|
||||
this.environmentService = accessor.get(IWorkbenchEnvironmentService);
|
||||
this.configurationService = accessor.get(IConfigurationService);
|
||||
this.lifecycleService = accessor.get(ILifecycleService);
|
||||
this.windowService = accessor.get(IWindowService);
|
||||
this.contextService = accessor.get(IWorkspaceContextService);
|
||||
this.storageService = accessor.get(IStorageService);
|
||||
this.backupFileService = accessor.get(IBackupFileService);
|
||||
|
||||
// Parts
|
||||
this.editorService = accessor.get(IEditorService);
|
||||
@@ -389,7 +390,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
}
|
||||
|
||||
private resolveEditorsToOpen(): Promise<IResourceEditor[]> | IResourceEditor[] {
|
||||
const configuration = this.windowService.getConfiguration();
|
||||
const configuration = this.environmentService.configuration;
|
||||
const hasInitialFilesToOpen = this.hasInitialFilesToOpen();
|
||||
|
||||
// Only restore editors if we are not instructed to open files initially
|
||||
@@ -418,8 +419,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
|
||||
// Empty workbench
|
||||
else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.configurationService.inspect('workbench.startupEditor').value === 'newUntitledFile') {
|
||||
const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0;
|
||||
if (!isEmpty) {
|
||||
if (this.editorGroupService.willRestoreEditors) {
|
||||
return []; // do not open any empty untitled file if we restored editors from previous session
|
||||
}
|
||||
|
||||
@@ -436,7 +436,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
}
|
||||
|
||||
private hasInitialFilesToOpen(): boolean {
|
||||
const configuration = this.windowService.getConfiguration();
|
||||
const configuration = this.environmentService.configuration;
|
||||
|
||||
return !!(
|
||||
(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
|
||||
|
||||
@@ -8,8 +8,18 @@ import { domContentLoaded, addDisposableListener, EventType } from 'vs/base/brow
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { SimpleLogService } from 'vs/workbench/browser/nodeless.simpleservices';
|
||||
import { SimpleLogService, SimpleProductService, SimpleWorkbenchEnvironmentService } from 'vs/workbench/browser/nodeless.simpleservices';
|
||||
import { Workbench } from 'vs/workbench/browser/workbench';
|
||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { RemoteAgentService } from 'vs/workbench/services/remote/browser/remoteAgentServiceImpl';
|
||||
import { RemoteAuthorityResolverService } from 'vs/platform/remote/browser/remoteAuthorityResolverService';
|
||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileService3 } from 'vs/workbench/services/files2/browser/fileService2';
|
||||
|
||||
class CodeRendererMain extends Disposable {
|
||||
|
||||
@@ -42,14 +52,41 @@ class CodeRendererMain extends Disposable {
|
||||
private initServices(): { serviceCollection: ServiceCollection, logService: ILogService } {
|
||||
const serviceCollection = new ServiceCollection();
|
||||
|
||||
const logService = new SimpleLogService();
|
||||
serviceCollection.set(ILogService, logService);
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// NOTE: DO NOT ADD ANY OTHER SERVICE INTO THE COLLECTION HERE.
|
||||
// CONTRIBUTE IT VIA WORKBENCH.MAIN.TS AND registerSingleton().
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
// Log
|
||||
const logService = new SimpleLogService();
|
||||
serviceCollection.set(ILogService, logService);
|
||||
|
||||
// Environment
|
||||
const environmentService = new SimpleWorkbenchEnvironmentService();
|
||||
serviceCollection.set(IWorkbenchEnvironmentService, environmentService);
|
||||
|
||||
// Product
|
||||
const productService = new SimpleProductService();
|
||||
serviceCollection.set(IProductService, productService);
|
||||
|
||||
// Remote
|
||||
const remoteAuthorityResolverService = new RemoteAuthorityResolverService();
|
||||
serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService);
|
||||
|
||||
const remoteAgentService = this._register(new RemoteAgentService(environmentService, productService, remoteAuthorityResolverService));
|
||||
serviceCollection.set(IRemoteAgentService, remoteAgentService);
|
||||
|
||||
// Files
|
||||
const fileService = this._register(new FileService3(logService));
|
||||
serviceCollection.set(IFileService, fileService);
|
||||
|
||||
const connection = remoteAgentService.getConnection();
|
||||
if (connection) {
|
||||
const channel = connection.getChannel<IChannel>(REMOTE_FILE_SYSTEM_CHANNEL_NAME);
|
||||
const remoteFileSystemProvider = this._register(new RemoteExtensionsFileSystemProvider(channel, remoteAgentService.getEnvironment()));
|
||||
fileService.registerProvider('vscode-remote', remoteFileSystemProvider);
|
||||
}
|
||||
|
||||
return { serviceCollection, logService };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { ITextSnapshot, IFileStat, IContent, IFileService, IResourceEncodings, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IStreamContent, IUpdateContentOptions, snapshotToString, ICreateFileOptions, IResourceEncoding, IFileStatWithMetadata, FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
|
||||
import { ITextSnapshot } from 'vs/platform/files/common/files';
|
||||
import { ITextBufferFactory } from 'vs/editor/common/model';
|
||||
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
||||
import { keys, ResourceMap } from 'vs/base/common/map';
|
||||
@@ -17,7 +17,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
|
||||
import { SimpleConfigurationService as StandaloneEditorConfigurationService, StandaloneKeybindingService, SimpleResourcePropertiesService } from 'vs/editor/standalone/browser/simpleServices';
|
||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IEnvironmentService, IExtensionHostDebugParams, IDebugParams } from 'vs/platform/environment/common/environment';
|
||||
import { IExtensionHostDebugParams, IDebugParams } from 'vs/platform/environment/common/environment';
|
||||
import { IExtensionGalleryService, IQueryOptions, IGalleryExtension, InstallOperation, StatisticType, ITranslation, IGalleryExtensionVersion, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation, IExtensionEnablementService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IPager } from 'vs/base/common/paging';
|
||||
import { IExtensionManifest, ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -32,9 +32,7 @@ import { ILogService, LogLevel, ConsoleLogService } from 'vs/platform/log/common
|
||||
import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IRemoteAuthorityResolverService, ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { joinPath, isEqualOrParent, isEqual, dirname } from 'vs/base/common/resources';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { isEqualOrParent, isEqual } from 'vs/base/common/resources';
|
||||
import { ISearchService, ITextQueryProps, ISearchProgressItem, ISearchComplete, IFileQueryProps, SearchProviderType, ISearchResultProvider, ITextQuery, IFileMatch, QueryType, FileMatch, pathIncludedInQuery } from 'vs/workbench/services/search/common/search';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -48,7 +46,7 @@ import { ITextMateService, IGrammar as ITextMategrammar } from 'vs/workbench/ser
|
||||
import { LanguageId, TokenizationRegistry } from 'vs/editor/common/modes';
|
||||
import { IUpdateService, State } from 'vs/platform/update/common/update';
|
||||
import { IWindowConfiguration, IPath, IPathsToWaitFor, IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IURIToOpen, IMessageBoxResult, IWindowsService, IOpenSettings } from 'vs/platform/windows/common/windows';
|
||||
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceFolderCreationData, isSingleFolderWorkspaceIdentifier, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { ExportData } from 'vs/base/common/performance';
|
||||
import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history';
|
||||
@@ -59,10 +57,14 @@ import { ITextResourcePropertiesService } from 'vs/editor/common/services/resour
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Color, RGBA } from 'vs/base/common/color';
|
||||
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||
import { IRemoteAgentService, IRemoteAgentConnection } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
export const workspaceResource = URI.file(isWindows ? 'C:\\simpleWorkspace' : '/simpleWorkspace');
|
||||
export const workspaceResource = URI.from({
|
||||
scheme: 'vscode-remote',
|
||||
authority: document.location.host,
|
||||
path: (<any>self).USER_HOME_DIR || '/'
|
||||
});
|
||||
|
||||
//#region Backup File
|
||||
|
||||
@@ -225,7 +227,8 @@ registerSingleton(IDownloadService, SimpleDownloadService, true);
|
||||
|
||||
//#region Environment
|
||||
|
||||
export class SimpleEnvironmentService implements IEnvironmentService {
|
||||
export class SimpleWorkbenchEnvironmentService implements IWorkbenchEnvironmentService {
|
||||
configuration: IWindowConfiguration = new SimpleWindowConfiguration();
|
||||
untitledWorkspacesHome: URI;
|
||||
extensionTestsLocationURI?: URI;
|
||||
_serviceBrand: any;
|
||||
@@ -240,6 +243,8 @@ export class SimpleEnvironmentService implements IEnvironmentService {
|
||||
appSettingsHome: string = '/nodeless/settings';
|
||||
appSettingsPath: string = '/nodeless/settings/settings.json';
|
||||
appKeybindingsPath: string = '/nodeless/settings/keybindings.json';
|
||||
machineSettingsHome: string;
|
||||
machineSettingsPath: string;
|
||||
settingsSearchBuildId?: number;
|
||||
settingsSearchUrl?: string;
|
||||
globalStorageHome: string;
|
||||
@@ -251,7 +256,7 @@ export class SimpleEnvironmentService implements IEnvironmentService {
|
||||
disableExtensions: boolean | string[];
|
||||
builtinExtensionsPath: string;
|
||||
extensionsPath: string;
|
||||
extensionDevelopmentLocationURI?: URI | URI[];
|
||||
extensionDevelopmentLocationURI?: URI[];
|
||||
extensionTestsPath?: string;
|
||||
debugExtensionHost: IExtensionHostDebugParams;
|
||||
debugSearch: IDebugParams;
|
||||
@@ -275,7 +280,6 @@ export class SimpleEnvironmentService implements IEnvironmentService {
|
||||
driverVerbose: boolean;
|
||||
}
|
||||
|
||||
registerSingleton(IEnvironmentService, SimpleEnvironmentService);
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -667,425 +671,6 @@ export class SimpleProductService implements IProductService {
|
||||
enableTelemetry: boolean = false;
|
||||
}
|
||||
|
||||
registerSingleton(IProductService, SimpleProductService, true);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Remote Agent
|
||||
|
||||
export class SimpleRemoteAgentService implements IRemoteAgentService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
getConnection(): IRemoteAgentConnection | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
getEnvironment(): Promise<IRemoteAgentEnvironment | null> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IRemoteAgentService, SimpleRemoteAgentService);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Remote Authority Resolver
|
||||
|
||||
export class SimpleRemoteAuthorityResolverService implements IRemoteAuthorityResolverService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
resolveAuthority(authority: string): Promise<ResolvedAuthority> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
clearResolvedAuthority(authority: string): void { }
|
||||
|
||||
setResolvedAuthority(resolvedAuthority: ResolvedAuthority): void { }
|
||||
|
||||
setResolvedAuthorityError(authority: string, err: any): void { }
|
||||
}
|
||||
|
||||
registerSingleton(IRemoteAuthorityResolverService, SimpleRemoteAuthorityResolverService, true);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region File Servie
|
||||
|
||||
const fileMap: ResourceMap<IFileStat> = new ResourceMap();
|
||||
const contentMap: ResourceMap<IContent> = new ResourceMap();
|
||||
initFakeFileSystem();
|
||||
|
||||
export class SimpleRemoteFileService implements IFileService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
encoding: IResourceEncodings;
|
||||
|
||||
readonly onFileChanges = Event.None;
|
||||
readonly onAfterOperation = Event.None;
|
||||
readonly onDidChangeFileSystemProviderRegistrations = Event.None;
|
||||
readonly onWillActivateFileSystemProvider = Event.None;
|
||||
readonly onError = Event.None;
|
||||
|
||||
resolve(resource: URI, options?: IResolveFileOptions): Promise<IFileStatWithMetadata> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(fileMap.get(resource));
|
||||
}
|
||||
|
||||
resolveAll(toResolve: { resource: URI, options?: IResolveFileOptions }[]): Promise<IResolveFileResult[]> {
|
||||
return Promise.all(toResolve.map(resourceAndOption => this.resolve(resourceAndOption.resource, resourceAndOption.options))).then(stats => stats.map(stat => ({ stat, success: true })));
|
||||
}
|
||||
|
||||
exists(resource: URI): Promise<boolean> {
|
||||
return Promise.resolve(fileMap.has(resource));
|
||||
}
|
||||
|
||||
resolveContent(resource: URI, _options?: IResolveContentOptions): Promise<IContent> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(contentMap.get(resource));
|
||||
}
|
||||
|
||||
resolveStreamContent(resource: URI, _options?: IResolveContentOptions): Promise<IStreamContent> {
|
||||
return Promise.resolve(contentMap.get(resource)).then(content => {
|
||||
return {
|
||||
// @ts-ignore
|
||||
resource: content.resource,
|
||||
value: {
|
||||
on: (event: string, callback: Function): void => {
|
||||
if (event === 'data') {
|
||||
// @ts-ignore
|
||||
callback(content.value);
|
||||
}
|
||||
|
||||
if (event === 'end') {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
},
|
||||
// @ts-ignore
|
||||
etag: content.etag,
|
||||
// @ts-ignore
|
||||
encoding: content.encoding,
|
||||
// @ts-ignore
|
||||
mtime: content.mtime,
|
||||
// @ts-ignore
|
||||
name: content.name,
|
||||
// @ts-ignore
|
||||
size: content.size
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
updateContent(resource: URI, value: string | ITextSnapshot, _options?: IUpdateContentOptions): Promise<IFileStatWithMetadata> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(fileMap.get(resource)).then(file => {
|
||||
const content = contentMap.get(resource);
|
||||
|
||||
if (typeof value === 'string') {
|
||||
// @ts-ignore
|
||||
content.value = value;
|
||||
} else {
|
||||
// @ts-ignore
|
||||
content.value = snapshotToString(value);
|
||||
}
|
||||
|
||||
return file;
|
||||
});
|
||||
}
|
||||
|
||||
move(_source: URI, _target: URI, _overwrite?: boolean): Promise<IFileStatWithMetadata> { return Promise.resolve(null!); }
|
||||
|
||||
copy(_source: URI, _target: URI, _overwrite?: boolean): Promise<any> {
|
||||
const parent = fileMap.get(dirname(_target));
|
||||
if (!parent) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
return this.resolveContent(_source).then(content => {
|
||||
return Promise.resolve(createFile(parent, basename(_target.path), content.value));
|
||||
});
|
||||
}
|
||||
|
||||
createFile(_resource: URI, _content?: string, _options?: ICreateFileOptions): Promise<IFileStatWithMetadata> {
|
||||
const parent = fileMap.get(dirname(_resource));
|
||||
if (!parent) {
|
||||
return Promise.reject(new Error(`Unable to create file in ${dirname(_resource).path}`));
|
||||
}
|
||||
|
||||
return Promise.resolve(createFile(parent, basename(_resource.path)));
|
||||
}
|
||||
|
||||
createFolder(_resource: URI): Promise<IFileStatWithMetadata> {
|
||||
const parent = fileMap.get(dirname(_resource));
|
||||
if (!parent) {
|
||||
return Promise.reject(new Error(`Unable to create folder in ${dirname(_resource).path}`));
|
||||
}
|
||||
|
||||
return Promise.resolve(createFolder(parent, basename(_resource.path)));
|
||||
}
|
||||
|
||||
registerProvider() { return { dispose() { } }; }
|
||||
|
||||
activateProvider(_scheme: string): Promise<void> { return Promise.resolve(undefined); }
|
||||
|
||||
canHandleResource(resource: URI): boolean { return resource.scheme === 'file'; }
|
||||
|
||||
hasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean { return false; }
|
||||
|
||||
del(_resource: URI, _options?: { useTrash?: boolean, recursive?: boolean }): Promise<void> { return Promise.resolve(); }
|
||||
|
||||
watch(_resource: URI): IDisposable { return Disposable.None; }
|
||||
|
||||
getWriteEncoding(_resource: URI): IResourceEncoding { return { encoding: 'utf8', hasBOM: false }; }
|
||||
|
||||
dispose(): void { }
|
||||
}
|
||||
|
||||
function createFile(parent: IFileStat, name: string, content: string = ''): IFileStatWithMetadata {
|
||||
const file: IFileStatWithMetadata = {
|
||||
resource: joinPath(parent.resource, name),
|
||||
etag: Date.now().toString(),
|
||||
mtime: Date.now(),
|
||||
isDirectory: false,
|
||||
name,
|
||||
size: -1
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
parent.children.push(file);
|
||||
|
||||
fileMap.set(file.resource, file);
|
||||
|
||||
contentMap.set(file.resource, {
|
||||
resource: joinPath(parent.resource, name),
|
||||
etag: Date.now().toString(),
|
||||
mtime: Date.now(),
|
||||
value: content,
|
||||
encoding: 'utf8',
|
||||
name
|
||||
} as IContent);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
function createFolder(parent: IFileStat, name: string): IFileStatWithMetadata {
|
||||
const folder: IFileStatWithMetadata = {
|
||||
resource: joinPath(parent.resource, name),
|
||||
etag: Date.now().toString(),
|
||||
mtime: Date.now(),
|
||||
isDirectory: true,
|
||||
name,
|
||||
size: 0,
|
||||
children: []
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
parent.children.push(folder);
|
||||
|
||||
fileMap.set(folder.resource, folder);
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
function initFakeFileSystem(): void {
|
||||
|
||||
const root: IFileStat = {
|
||||
resource: workspaceResource,
|
||||
etag: Date.now().toString(),
|
||||
mtime: Date.now(),
|
||||
isDirectory: true,
|
||||
name: basename(workspaceResource.fsPath),
|
||||
children: [],
|
||||
size: 0
|
||||
};
|
||||
|
||||
fileMap.set(root.resource, root);
|
||||
|
||||
createFile(root, '.gitignore', `out
|
||||
node_modules
|
||||
.vscode-test/
|
||||
*.vsix
|
||||
`);
|
||||
createFile(root, '.vscodeignore', `.vscode/**
|
||||
.vscode-test/**
|
||||
out/test/**
|
||||
src/**
|
||||
.gitignore
|
||||
vsc-extension-quickstart.md
|
||||
**/tsconfig.json
|
||||
**/tslint.json
|
||||
**/*.map
|
||||
**/*.ts`);
|
||||
createFile(root, 'CHANGELOG.md', `# Change Log
|
||||
All notable changes to the "test-ts" extension will be documented in this file.
|
||||
|
||||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
||||
|
||||
## [Unreleased]
|
||||
- Initial release`);
|
||||
createFile(root, 'package.json', `{
|
||||
"name": "test-ts",
|
||||
"displayName": "test-ts",
|
||||
"description": "",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"vscode": "^1.31.0"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onCommand:extension.helloWorld"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "extension.helloWorld",
|
||||
"title": "Hello World"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "tsc -p ./",
|
||||
"watch": "tsc -watch -p ./",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install",
|
||||
"test": "npm run compile && node ./node_modules/vscode/bin/test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^3.3.1",
|
||||
"vscode": "^1.1.28",
|
||||
"tslint": "^5.12.1",
|
||||
"@types/node": "^8.10.25",
|
||||
"@types/mocha": "^2.2.42"
|
||||
}
|
||||
}
|
||||
`);
|
||||
createFile(root, 'tsconfig.json', `{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"rootDir": "src",
|
||||
"strict": true /* enable all strict type-checking options */
|
||||
/* Additional Checks */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test"
|
||||
]
|
||||
}
|
||||
`);
|
||||
createFile(root, 'tslint.json', `{
|
||||
"rules": {
|
||||
"no-string-throw": true,
|
||||
"no-unused-expression": true,
|
||||
"no-duplicate-variable": true,
|
||||
"curly": true,
|
||||
"class-name": true,
|
||||
"semicolon": [
|
||||
true,
|
||||
"always"
|
||||
],
|
||||
"triple-equals": true
|
||||
},
|
||||
"defaultSeverity": "warning"
|
||||
}
|
||||
`);
|
||||
|
||||
const src = createFolder(root, 'src');
|
||||
createFile(src, 'extension.ts', `// The module 'vscode' contains the VS Code extensibility API
|
||||
// Import the module and reference it with the alias vscode in your code below
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
// this method is called when your extension is activated
|
||||
// your extension is activated the very first time the command is executed
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// Use the console to output diagnostic information (console.log) and errors (console.error)
|
||||
// This line of code will only be executed once when your extension is activated
|
||||
console.log('Congratulations, your extension "test-ts" is now active!');
|
||||
|
||||
// The command has been defined in the package.json file
|
||||
// Now provide the implementation of the command with registerCommand
|
||||
// The commandId parameter must match the command field in package.json
|
||||
let disposable = vscode.commands.registerCommand('extension.helloWorld', () => {
|
||||
// The code you place here will be executed every time your command is executed
|
||||
|
||||
// Display a message box to the user
|
||||
vscode.window.showInformationMessage('Hello World!');
|
||||
});
|
||||
|
||||
context.subscriptions.push(disposable);
|
||||
}
|
||||
|
||||
// this method is called when your extension is deactivated
|
||||
export function deactivate() {}
|
||||
`);
|
||||
|
||||
const test = createFolder(src, 'test');
|
||||
|
||||
createFile(test, 'extension.test.ts', `//
|
||||
// Note: This example test is leveraging the Mocha test framework.
|
||||
// Please refer to their documentation on https://mochajs.org/ for help.
|
||||
//
|
||||
|
||||
// The module 'assert' provides assertion methods from node
|
||||
import * as assert from 'assert';
|
||||
|
||||
// You can import and use all API from the 'vscode' module
|
||||
// as well as import your extension to test it
|
||||
// import * as vscode from 'vscode';
|
||||
// import * as myExtension from '../extension';
|
||||
|
||||
// Defines a Mocha test suite to group tests of similar kind together
|
||||
suite("Extension Tests", function () {
|
||||
|
||||
// Defines a Mocha unit test
|
||||
test("Something 1", function() {
|
||||
assert.equal(-1, [1, 2, 3].indexOf(5));
|
||||
assert.equal(-1, [1, 2, 3].indexOf(0));
|
||||
});
|
||||
});`);
|
||||
|
||||
createFile(test, 'index.ts', `//
|
||||
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
|
||||
//
|
||||
// This file is providing the test runner to use when running extension tests.
|
||||
// By default the test runner in use is Mocha based.
|
||||
//
|
||||
// You can provide your own test runner if you want to override it by exporting
|
||||
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
|
||||
// host can call to run the tests. The test runner is expected to use console.log
|
||||
// to report the results back to the caller. When the tests are finished, return
|
||||
// a possible error to the callback or null if none.
|
||||
|
||||
import * as testRunner from 'vscode/lib/testrunner';
|
||||
|
||||
// You can directly control Mocha options by configuring the test runner below
|
||||
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options
|
||||
// for more info
|
||||
testRunner.configure({
|
||||
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
|
||||
useColors: true // colored output from test results
|
||||
});
|
||||
|
||||
module.exports = testRunner;`);
|
||||
}
|
||||
|
||||
registerSingleton(IFileService, SimpleRemoteFileService);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Request
|
||||
@@ -1382,7 +967,7 @@ export class SimpleWindowService implements IWindowService {
|
||||
|
||||
hasFocus = true;
|
||||
|
||||
private configuration: IWindowConfiguration = new SimpleWindowConfiguration();
|
||||
readonly windowId = 0;
|
||||
|
||||
isFocused(): Promise<boolean> {
|
||||
return Promise.resolve(false);
|
||||
@@ -1392,14 +977,6 @@ export class SimpleWindowService implements IWindowService {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
getConfiguration(): IWindowConfiguration {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
getCurrentWindowId(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -1788,7 +1365,7 @@ export class SimpleWorkspaceService implements IWorkspaceContextService {
|
||||
constructor() {
|
||||
this.workspace = new Workspace(
|
||||
workspaceResource.toString(),
|
||||
toWorkspaceFolders([{ path: workspaceResource.fsPath }])
|
||||
toWorkspaceFolders([{ uri: workspaceResource.toString() }])
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1861,3 +1438,16 @@ export class SimpleWorkspacesService implements IWorkspacesService {
|
||||
registerSingleton(IWorkspacesService, SimpleWorkspacesService);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region remote
|
||||
|
||||
class SimpleTunnelService implements ITunnelService {
|
||||
_serviceBrand: any;
|
||||
openTunnel(remotePort: number) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(ITunnelService, SimpleTunnelService);
|
||||
|
||||
//#endregion
|
||||
@@ -51,6 +51,8 @@ import { Schemas } from 'vs/base/common/network';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { OpenWorkspaceButtonContribution } from 'vs/workbench/browser/parts/editor/editorWidgets';
|
||||
import { ZoomStatusbarItem } from 'vs/workbench/browser/parts/editor/resourceViewer';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { toLocalResource } from 'vs/base/common/resources';
|
||||
|
||||
// Register String Editor
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
@@ -111,7 +113,8 @@ interface ISerializedUntitledEditorInput {
|
||||
class UntitledEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
constructor(
|
||||
@ITextFileService private readonly textFileService: ITextFileService
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
) { }
|
||||
|
||||
serialize(editorInput: EditorInput): string | undefined {
|
||||
@@ -128,7 +131,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
let resource = untitledEditorInput.getResource();
|
||||
if (untitledEditorInput.hasAssociatedFilePath) {
|
||||
resource = resource.with({ scheme: Schemas.file }); // untitled with associated file path use the file schema
|
||||
resource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority); // untitled with associated file path use the local schema
|
||||
}
|
||||
|
||||
const serialized: ISerializedUntitledEditorInput = {
|
||||
@@ -145,7 +148,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
|
||||
return instantiationService.invokeFunction<UntitledEditorInput>(accessor => {
|
||||
const deserialized: ISerializedUntitledEditorInput = JSON.parse(serializedEditorInput);
|
||||
const resource = !!deserialized.resourceJSON ? URI.revive(deserialized.resourceJSON) : URI.parse(deserialized.resource);
|
||||
const filePath = resource.scheme === Schemas.file ? resource.fsPath : undefined;
|
||||
const filePath = resource.scheme === Schemas.untitled ? undefined : resource.scheme === Schemas.file ? resource.fsPath : resource.path;
|
||||
const language = deserialized.modeId;
|
||||
const encoding = deserialized.encoding;
|
||||
|
||||
|
||||
@@ -231,6 +231,10 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
return this._whenRestored;
|
||||
}
|
||||
|
||||
get willRestoreEditors(): boolean {
|
||||
return !!this.workspaceMemento[EditorPart.EDITOR_PART_UI_STATE_STORAGE_KEY];
|
||||
}
|
||||
|
||||
getGroups(order = GroupsOrder.CREATION_TIME): IEditorGroupView[] {
|
||||
switch (order) {
|
||||
case GroupsOrder.CREATION_TIME:
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, INotificationViewItem } from 'vs/workbench/common/notifications';
|
||||
import { IStatusbarService, StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { HIDE_NOTIFICATIONS_CENTER, SHOW_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export class NotificationsStatus extends Disposable {
|
||||
private statusItem: IDisposable;
|
||||
private statusItem: IStatusbarEntryAccessor;
|
||||
private isNotificationsCenterVisible: boolean;
|
||||
private _counter: Set<INotificationViewItem>;
|
||||
|
||||
@@ -64,19 +64,18 @@ export class NotificationsStatus extends Disposable {
|
||||
}
|
||||
|
||||
private updateNotificationsStatusItem(): void {
|
||||
|
||||
// Dispose old first
|
||||
if (this.statusItem) {
|
||||
this.statusItem.dispose();
|
||||
}
|
||||
|
||||
// Create new
|
||||
this.statusItem = this.statusbarService.addEntry({
|
||||
const statusProperties: IStatusbarEntry = {
|
||||
text: this.count === 0 ? '$(bell)' : `$(bell) ${this.count}`,
|
||||
command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER,
|
||||
tooltip: this.getTooltip(),
|
||||
showBeak: this.isNotificationsCenterVisible
|
||||
}, StatusbarAlignment.RIGHT, -1000 /* towards the far end of the right hand side */);
|
||||
};
|
||||
|
||||
if (!this.statusItem) {
|
||||
this.statusItem = this.statusbarService.addEntry(statusProperties, StatusbarAlignment.RIGHT, -1000 /* towards the far end of the right hand side */);
|
||||
} else {
|
||||
this.statusItem.update(statusProperties);
|
||||
}
|
||||
}
|
||||
|
||||
private getTooltip(): string {
|
||||
@@ -98,12 +97,4 @@ export class NotificationsStatus extends Disposable {
|
||||
|
||||
return localize('notifications', "{0} New Notifications", this.count);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose();
|
||||
|
||||
if (this.statusItem) {
|
||||
this.statusItem.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,16 +49,27 @@
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.left {
|
||||
padding-left: 7px;
|
||||
}
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.left:first-child,
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.has-background-color.left {
|
||||
padding-right: 7px; /* expand padding if background color is configured for the status bar entry to make it look centered properly */
|
||||
}
|
||||
|
||||
/* adding padding to the most right status bar item */
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.right:first-child {
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
/* tweak appearance for items with background to improve hover feedback */
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.left:first-child,
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.has-background-color.left,
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.right:first-child {
|
||||
padding-left: 7px; /* expand padding if background color is configured for the status bar entry to make it look centered properly */
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.left > :first-child,
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.right > :first-child
|
||||
{
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.statusbar > .statusbar-item a {
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
import 'vs/css!./media/statusbarpart';
|
||||
import * as nls from 'vs/nls';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { dispose, IDisposable, toDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { dispose, IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { IStatusbarRegistry, Extensions, IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||
import { IStatusbarRegistry, Extensions } from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector, ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
@@ -24,11 +24,14 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
|
||||
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { isThemeColor } from 'vs/editor/common/editorCommon';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { addClass, EventHelper, createStyleSheet, addDisposableListener } from 'vs/base/browser/dom';
|
||||
import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, clearNode, removeClass } from 'vs/base/browser/dom';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
|
||||
interface PendingEntry { entry: IStatusbarEntry; alignment: StatusbarAlignment; priority: number; accessor?: IStatusbarEntryAccessor; }
|
||||
|
||||
export class StatusbarPart extends Part implements IStatusbarService {
|
||||
|
||||
@@ -46,10 +49,10 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
|
||||
//#endregion
|
||||
|
||||
private statusMsgDispose: IDisposable;
|
||||
private statusMessageDispose: IDisposable;
|
||||
private styleElement: HTMLStyleElement;
|
||||
|
||||
private pendingEntries: { entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number, disposable: IDisposable }[] = [];
|
||||
private pendingEntries: PendingEntry[] = [];
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@@ -67,24 +70,38 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles()));
|
||||
}
|
||||
|
||||
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IDisposable {
|
||||
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IStatusbarEntryAccessor {
|
||||
|
||||
// As long as we have not been created into a container yet, record all entries
|
||||
// that are pending so that they can get created at a later point
|
||||
if (!this.element) {
|
||||
const pendingEntry = { entry, alignment, priority, disposable: Disposable.None };
|
||||
const pendingEntry: PendingEntry = {
|
||||
entry, alignment, priority
|
||||
};
|
||||
this.pendingEntries.push(pendingEntry);
|
||||
|
||||
return toDisposable(() => {
|
||||
this.pendingEntries = this.pendingEntries.filter(e => e !== pendingEntry);
|
||||
pendingEntry.disposable.dispose();
|
||||
});
|
||||
const accessor: IStatusbarEntryAccessor = {
|
||||
update: (entry: IStatusbarEntry) => {
|
||||
if (pendingEntry.accessor) {
|
||||
pendingEntry.accessor.update(entry);
|
||||
} else {
|
||||
pendingEntry.entry = entry;
|
||||
}
|
||||
},
|
||||
dispose: () => {
|
||||
if (pendingEntry.accessor) {
|
||||
pendingEntry.accessor.dispose();
|
||||
} else {
|
||||
this.pendingEntries = this.pendingEntries.filter(entry => entry !== pendingEntry);
|
||||
}
|
||||
}
|
||||
};
|
||||
return accessor;
|
||||
}
|
||||
|
||||
// Render entry in status bar
|
||||
const el = this.doCreateStatusItem(alignment, priority, entry.showBeak ? 'has-beak' : undefined);
|
||||
const item = this.instantiationService.createInstance(StatusBarEntryItem, entry);
|
||||
const toDispose = item.render(el);
|
||||
const el = this.doCreateStatusItem(alignment, priority, ...coalesce(['statusbar-entry', entry.showBeak ? 'has-beak' : undefined]));
|
||||
const item = this.instantiationService.createInstance(StatusBarEntryItem, el, entry);
|
||||
|
||||
// Insert according to priority
|
||||
const container = this.element;
|
||||
@@ -106,13 +123,24 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
container.appendChild(el);
|
||||
}
|
||||
|
||||
return toDisposable(() => {
|
||||
el.remove();
|
||||
return {
|
||||
update: entry => {
|
||||
|
||||
if (toDispose) {
|
||||
toDispose.dispose();
|
||||
// Update beak
|
||||
if (entry.showBeak) {
|
||||
addClass(el, 'has-beak');
|
||||
} else {
|
||||
removeClass(el, 'has-beak');
|
||||
}
|
||||
|
||||
// Update entry
|
||||
item.update(entry);
|
||||
},
|
||||
dispose: () => {
|
||||
el.remove();
|
||||
dispose(item);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
private getEntries(alignment: StatusbarAlignment): HTMLElement[] {
|
||||
@@ -164,7 +192,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
while (this.pendingEntries.length) {
|
||||
const entry = this.pendingEntries.shift();
|
||||
if (entry) {
|
||||
entry.disposable = this.addEntry(entry.entry, entry.alignment, entry.priority);
|
||||
entry.accessor = this.addEntry(entry.entry, entry.alignment, entry.priority);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,11 +223,11 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
this.styleElement.innerHTML = `.monaco-workbench .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`;
|
||||
}
|
||||
|
||||
private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0, extraClass?: string): HTMLElement {
|
||||
private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0, ...extraClasses: string[]): HTMLElement {
|
||||
const el = document.createElement('div');
|
||||
addClass(el, 'statusbar-item');
|
||||
if (extraClass) {
|
||||
addClass(el, extraClass);
|
||||
if (extraClasses) {
|
||||
addClasses(el, ...extraClasses);
|
||||
}
|
||||
|
||||
if (alignment === StatusbarAlignment.RIGHT) {
|
||||
@@ -215,20 +243,20 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
}
|
||||
|
||||
setStatusMessage(message: string, autoDisposeAfter: number = -1, delayBy: number = 0): IDisposable {
|
||||
if (this.statusMsgDispose) {
|
||||
this.statusMsgDispose.dispose(); // dismiss any previous
|
||||
}
|
||||
|
||||
// Dismiss any previous
|
||||
dispose(this.statusMessageDispose);
|
||||
|
||||
// Create new
|
||||
let statusDispose: IDisposable;
|
||||
let statusMessageEntry: IStatusbarEntryAccessor;
|
||||
let showHandle: any = setTimeout(() => {
|
||||
statusDispose = this.addEntry({ text: message }, StatusbarAlignment.LEFT, -Number.MAX_VALUE /* far right on left hand side */);
|
||||
statusMessageEntry = this.addEntry({ text: message }, StatusbarAlignment.LEFT, -Number.MAX_VALUE /* far right on left hand side */);
|
||||
showHandle = null;
|
||||
}, delayBy);
|
||||
let hideHandle: any;
|
||||
|
||||
// Dispose function takes care of timeouts and actual entry
|
||||
const dispose = {
|
||||
const statusMessageDispose = {
|
||||
dispose: () => {
|
||||
if (showHandle) {
|
||||
clearTimeout(showHandle);
|
||||
@@ -238,18 +266,18 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
clearTimeout(hideHandle);
|
||||
}
|
||||
|
||||
if (statusDispose) {
|
||||
statusDispose.dispose();
|
||||
if (statusMessageEntry) {
|
||||
statusMessageEntry.dispose();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.statusMsgDispose = dispose;
|
||||
this.statusMessageDispose = statusMessageDispose;
|
||||
|
||||
if (typeof autoDisposeAfter === 'number' && autoDisposeAfter > 0) {
|
||||
hideHandle = setTimeout(() => dispose.dispose(), autoDisposeAfter);
|
||||
hideHandle = setTimeout(() => statusMessageDispose.dispose(), autoDisposeAfter);
|
||||
}
|
||||
|
||||
return dispose;
|
||||
return statusMessageDispose;
|
||||
}
|
||||
|
||||
layout(width: number, height: number): void {
|
||||
@@ -264,10 +292,12 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
}
|
||||
|
||||
let manageExtensionAction: ManageExtensionAction;
|
||||
class StatusBarEntryItem implements IStatusbarItem {
|
||||
class StatusBarEntryItem extends Disposable {
|
||||
private entryDisposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
private entry: IStatusbarEntry,
|
||||
private container: HTMLElement,
|
||||
entry: IStatusbarEntry,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@@ -276,78 +306,80 @@ class StatusBarEntryItem implements IStatusbarItem {
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IThemeService private readonly themeService: IThemeService
|
||||
) {
|
||||
this.entry = entry;
|
||||
super();
|
||||
|
||||
if (!manageExtensionAction) {
|
||||
manageExtensionAction = this.instantiationService.createInstance(ManageExtensionAction);
|
||||
}
|
||||
|
||||
this.render(entry);
|
||||
}
|
||||
|
||||
render(el: HTMLElement): IDisposable {
|
||||
let toDispose: IDisposable[] = [];
|
||||
addClass(el, 'statusbar-entry');
|
||||
update(entry: IStatusbarEntry): void {
|
||||
clearNode(this.container);
|
||||
this.entryDisposables = dispose(this.entryDisposables);
|
||||
|
||||
this.render(entry);
|
||||
}
|
||||
|
||||
private render(entry: IStatusbarEntry): void {
|
||||
|
||||
// Text Container
|
||||
let textContainer: HTMLElement;
|
||||
if (this.entry.command) {
|
||||
if (entry.command) {
|
||||
textContainer = document.createElement('a');
|
||||
|
||||
toDispose.push(addDisposableListener(textContainer, 'click', () => this.executeCommand(this.entry.command!, this.entry.arguments)));
|
||||
this.entryDisposables.push((addDisposableListener(textContainer, 'click', () => this.executeCommand(entry.command!, entry.arguments))));
|
||||
} else {
|
||||
textContainer = document.createElement('span');
|
||||
}
|
||||
|
||||
// Label
|
||||
new OcticonLabel(textContainer).text = this.entry.text;
|
||||
new OcticonLabel(textContainer).text = entry.text;
|
||||
|
||||
// Tooltip
|
||||
if (this.entry.tooltip) {
|
||||
textContainer.title = this.entry.tooltip;
|
||||
if (entry.tooltip) {
|
||||
textContainer.title = entry.tooltip;
|
||||
}
|
||||
|
||||
// Color (only applies to text container)
|
||||
toDispose.push(this.applyColor(textContainer, this.entry.color));
|
||||
this.applyColor(textContainer, entry.color);
|
||||
|
||||
// Background Color (applies to parent element to fully fill container)
|
||||
if (this.entry.backgroundColor) {
|
||||
toDispose.push(this.applyColor(el, this.entry.backgroundColor, true));
|
||||
addClass(el, 'has-background-color');
|
||||
if (entry.backgroundColor) {
|
||||
this.applyColor(this.container, entry.backgroundColor, true);
|
||||
addClass(this.container, 'has-background-color');
|
||||
}
|
||||
|
||||
// Context Menu
|
||||
if (this.entry.extensionId) {
|
||||
toDispose.push(addDisposableListener(textContainer, 'contextmenu', e => {
|
||||
if (entry.extensionId) {
|
||||
this.entryDisposables.push((addDisposableListener(textContainer, 'contextmenu', e => {
|
||||
EventHelper.stop(e, true);
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => el,
|
||||
getActionsContext: () => this.entry.extensionId!.value,
|
||||
getAnchor: () => this.container,
|
||||
getActionsContext: () => entry.extensionId!.value,
|
||||
getActions: () => [manageExtensionAction]
|
||||
});
|
||||
}));
|
||||
})));
|
||||
}
|
||||
|
||||
el.appendChild(textContainer);
|
||||
|
||||
return toDisposable(() => toDispose = dispose(toDispose));
|
||||
this.container.appendChild(textContainer);
|
||||
}
|
||||
|
||||
private applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): IDisposable {
|
||||
const disposable: IDisposable[] = [];
|
||||
|
||||
private applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): void {
|
||||
if (color) {
|
||||
if (isThemeColor(color)) {
|
||||
const colorId = color.id;
|
||||
color = (this.themeService.getTheme().getColor(colorId) || Color.transparent).toString();
|
||||
disposable.push(this.themeService.onThemeChange(theme => {
|
||||
this.entryDisposables.push(((this.themeService.onThemeChange(theme => {
|
||||
const colorValue = (theme.getColor(colorId) || Color.transparent).toString();
|
||||
isBackground ? container.style.backgroundColor = colorValue : container.style.color = colorValue;
|
||||
}));
|
||||
}))));
|
||||
}
|
||||
|
||||
isBackground ? container.style.backgroundColor = color : container.style.color = color;
|
||||
}
|
||||
|
||||
return combinedDisposable(disposable);
|
||||
}
|
||||
|
||||
private executeCommand(id: string, args?: unknown[]) {
|
||||
@@ -368,6 +400,12 @@ class StatusBarEntryItem implements IStatusbarItem {
|
||||
this.telemetryService.publicLog('workbenchActionExecuted', { id, from: 'status bar' });
|
||||
this.commandService.executeCommand(id, ...args).then(undefined, err => this.notificationService.error(toErrorMessage(err)));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.entryDisposables = dispose(this.entryDisposables);
|
||||
}
|
||||
}
|
||||
|
||||
class ManageExtensionAction extends Action {
|
||||
|
||||
@@ -312,7 +312,7 @@ export class MenubarControl extends Disposable {
|
||||
// Send menus to main process to be rendered by Electron
|
||||
const menubarData = { menus: {}, keybindings: {} };
|
||||
if (this.getMenubarMenus(menubarData)) {
|
||||
this.menubarService.updateMenubar(this.windowService.getCurrentWindowId(), menubarData);
|
||||
this.menubarService.updateMenubar(this.windowService.windowId, menubarData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -440,7 +440,7 @@ export class MenubarControl extends Disposable {
|
||||
return null;
|
||||
|
||||
case StateType.Idle:
|
||||
const windowId = this.windowService.getCurrentWindowId();
|
||||
const windowId = this.windowService.windowId;
|
||||
return new Action('update.check', nls.localize({ key: 'checkForUpdates', comment: ['&& denotes a mnemonic'] }, "Check for &&Updates..."), undefined, true, () =>
|
||||
this.updateService.checkForUpdates({ windowId }));
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import * as nls from 'vs/nls';
|
||||
import { EditorInput, toResource, Verbosity, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { TITLE_BAR_ACTIVE_BACKGROUND, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_BACKGROUND, TITLE_BAR_BORDER } from 'vs/workbench/common/theme';
|
||||
@@ -85,7 +85,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IWindowsService private readonly windowsService: IWindowsService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@@ -412,7 +412,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
// Resizer
|
||||
this.resizer = append(this.element, $('div.resizer'));
|
||||
|
||||
const isMaximized = this.windowService.getConfiguration().maximized ? true : false;
|
||||
const isMaximized = this.environmentService.configuration.maximized ? true : false;
|
||||
this.onDidChangeMaximized(isMaximized);
|
||||
this.windowService.onDidChangeMaximize(this.onDidChangeMaximized, this);
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ export abstract class ViewletPanel extends Panel implements IView {
|
||||
protected actionRunner?: IActionRunner;
|
||||
protected toolbar: ToolBar;
|
||||
private headerContainer: HTMLElement;
|
||||
private titleContainer: HTMLElement;
|
||||
|
||||
constructor(
|
||||
options: IViewletPanelOptions,
|
||||
@@ -141,7 +142,12 @@ export abstract class ViewletPanel extends Panel implements IView {
|
||||
}
|
||||
|
||||
protected renderHeaderTitle(container: HTMLElement, title: string): void {
|
||||
append(container, $('h3.title', undefined, title));
|
||||
this.titleContainer = append(container, $('h3.title', undefined, title));
|
||||
}
|
||||
|
||||
protected updateTitle(title: string): void {
|
||||
this.titleContainer.textContent = title;
|
||||
this._onDidChangeTitleArea.fire();
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
|
||||
@@ -200,7 +200,11 @@ export class Workbench extends Layout {
|
||||
// TODO@Ben legacy file service
|
||||
const fileService = accessor.get(IFileService) as any;
|
||||
if (typeof fileService.setLegacyService === 'function') {
|
||||
fileService.setLegacyService(accessor.get(ILegacyFileService));
|
||||
try {
|
||||
fileService.setLegacyService(accessor.get(ILegacyFileService));
|
||||
} catch (error) {
|
||||
//ignore, legacy file service might not be registered
|
||||
}
|
||||
}
|
||||
|
||||
// TODO@Sandeep debt around cyclic dependencies
|
||||
@@ -391,7 +395,7 @@ export class Workbench extends Layout {
|
||||
|
||||
// Restore Zen Mode
|
||||
if (this.state.zenMode.restore) {
|
||||
this.toggleZenMode(true, true);
|
||||
this.toggleZenMode(false, true);
|
||||
}
|
||||
|
||||
// Restore Editor Center Mode
|
||||
|
||||
@@ -9,12 +9,12 @@ import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform';
|
||||
export const IsMacContext = new RawContextKey<boolean>('isMac', isMacintosh);
|
||||
export const IsLinuxContext = new RawContextKey<boolean>('isLinux', isLinux);
|
||||
export const IsWindowsContext = new RawContextKey<boolean>('isWindows', isWindows);
|
||||
export const IsRemoteContext = new RawContextKey<boolean>('isRemote', false);
|
||||
|
||||
export const RemoteAuthorityContext = new RawContextKey<string>('remoteAuthority', '');
|
||||
|
||||
export const HasMacNativeTabsContext = new RawContextKey<boolean>('hasMacNativeTabs', false);
|
||||
|
||||
export const SupportsWorkspacesContext = new RawContextKey<boolean>('supportsWorkspaces', true);
|
||||
export const SupportsOpenFileFolderContext = new RawContextKey<boolean>('supportsOpenFileFolder', isMacintosh);
|
||||
|
||||
export const IsDevelopmentContext = new RawContextKey<boolean>('isDevelopment', false);
|
||||
|
||||
|
||||
@@ -235,9 +235,9 @@ export class FocusSessionActionItem extends SelectActionItem {
|
||||
}
|
||||
|
||||
protected getSessions(): ReadonlyArray<IDebugSession> {
|
||||
const hideSubSessions = this.configurationService.getValue<IDebugConfiguration>('debug').hideSubSessions;
|
||||
const showSubSessions = this.configurationService.getValue<IDebugConfiguration>('debug').showSubSessionsInToolBar;
|
||||
const sessions = this.debugService.getModel().getSessions();
|
||||
|
||||
return hideSubSessions ? sessions.filter(s => !s.parentSession) : sessions;
|
||||
return showSubSessions ? sessions : sessions.filter(s => !s.parentSession);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,9 +185,9 @@ export function registerCommands(): void {
|
||||
if (!session || !session.getId) {
|
||||
session = debugService.getViewModel().focusedSession;
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
const hideSubSessions = configurationService.getValue<IDebugConfiguration>('debug').hideSubSessions;
|
||||
const showSubSessions = configurationService.getValue<IDebugConfiguration>('debug').showSubSessionsInToolBar;
|
||||
// Stop should be sent to the root parent session
|
||||
while (hideSubSessions && session && session.parentSession) {
|
||||
while (!showSubSessions && session && session.parentSession) {
|
||||
session = session.parentSession;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +150,9 @@ export interface IDebugSession extends ITreeElement {
|
||||
readonly state: State;
|
||||
readonly root: IWorkspaceFolder;
|
||||
readonly parentSession: IDebugSession | undefined;
|
||||
readonly subId: string | undefined;
|
||||
|
||||
setSubId(subId: string | undefined): void;
|
||||
|
||||
getLabel(): string;
|
||||
|
||||
@@ -424,7 +427,7 @@ export interface IDebugConfiguration {
|
||||
internalConsoleOptions: 'neverOpen' | 'openOnSessionStart' | 'openOnFirstSessionStart';
|
||||
extensionHostDebugAdapter: boolean;
|
||||
enableAllHovers: boolean;
|
||||
hideSubSessions: boolean;
|
||||
showSubSessionsInToolBar: boolean;
|
||||
console: {
|
||||
fontSize: number;
|
||||
fontFamily: string;
|
||||
|
||||
@@ -229,6 +229,11 @@ configurationRegistry.registerConfiguration({
|
||||
description: nls.localize({ comment: ['This is the description for a setting'], key: 'enableAllHovers' }, "Controls whether the non-debug hovers should be enabled while debugging. When enabled the hover providers will be called to provide a hover. Regular hovers will not be shown even if this setting is enabled."),
|
||||
default: false
|
||||
},
|
||||
'debug.showSubSessionsInToolBar': {
|
||||
type: 'boolean',
|
||||
description: nls.localize({ comment: ['This is the description for a setting'], key: 'showSubSessionsInToolBar' }, "Controls whether the debug sub-sessions are shown in the debug tool bar. When this setting is false the stop command on a sub-session will also stop the parent session."),
|
||||
default: false
|
||||
},
|
||||
'debug.console.fontSize': {
|
||||
type: 'number',
|
||||
description: nls.localize('debug.console.fontSize', "Controls the font size in pixels in the debug console."),
|
||||
|
||||
@@ -34,6 +34,7 @@ import { launchSchema, debuggersExtPoint, breakpointsExtPoint } from 'vs/workben
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
|
||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||
jsonRegistry.registerSchema(launchSchemaId, launchSchema);
|
||||
@@ -535,6 +536,7 @@ class Launch extends AbstractLaunch implements ILaunch {
|
||||
private configurationManager: ConfigurationManager,
|
||||
public workspace: IWorkspaceFolder,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
@@ -574,7 +576,7 @@ class Launch extends AbstractLaunch implements ILaunch {
|
||||
}
|
||||
|
||||
created = true; // pin only if config file is created #8727
|
||||
return this.fileService.updateContent(resource, content).then(() => {
|
||||
return this.textFileService.write(resource, content).then(() => {
|
||||
// convert string into IContent; see #32135
|
||||
return content;
|
||||
});
|
||||
|
||||
@@ -135,27 +135,28 @@ export class DebugService implements IDebugService {
|
||||
this.toDispose.push(this.storageService.onWillSaveState(this.saveState, this));
|
||||
this.lifecycleService.onShutdown(this.dispose, this);
|
||||
|
||||
this.toDispose.push(this.extensionHostDebugService.onAttachSession(data => {
|
||||
const session = this.model.getSession(data.id, true);
|
||||
this.toDispose.push(this.extensionHostDebugService.onAttachSession(event => {
|
||||
const session = this.model.getSession(event.sessionId, true);
|
||||
if (session) {
|
||||
// EH was started in debug mode -> attach to it
|
||||
session.configuration.request = 'attach';
|
||||
session.configuration.port = data.port;
|
||||
session.configuration.port = event.port;
|
||||
session.setSubId(event.subId);
|
||||
this.launchOrAttachToSession(session).then(undefined, errors.onUnexpectedError);
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.extensionHostDebugService.onTerminateSession(sessionId => {
|
||||
const session = this.model.getSession(sessionId);
|
||||
if (session) {
|
||||
this.toDispose.push(this.extensionHostDebugService.onTerminateSession(event => {
|
||||
const session = this.model.getSession(event.sessionId);
|
||||
if (session && session.subId === event.subId) {
|
||||
session.disconnect().then(undefined, errors.onUnexpectedError);
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.extensionHostDebugService.onLogToSession(data => {
|
||||
const session = this.model.getSession(data.id, true);
|
||||
this.toDispose.push(this.extensionHostDebugService.onLogToSession(event => {
|
||||
const session = this.model.getSession(event.sessionId, true);
|
||||
if (session) {
|
||||
// extension logged output -> show it in REPL
|
||||
const sev = data.log.severity === 'warn' ? severity.Warning : data.log.severity === 'error' ? severity.Error : severity.Info;
|
||||
const { args, stack } = parse(data.log);
|
||||
const sev = event.log.severity === 'warn' ? severity.Warning : event.log.severity === 'error' ? severity.Error : severity.Info;
|
||||
const { args, stack } = parse(event.log);
|
||||
const frame = !!stack ? getFirstFrame(stack) : undefined;
|
||||
session.logToRepl(sev, args, frame);
|
||||
}
|
||||
@@ -439,9 +440,9 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
|
||||
this.viewModel.firstSessionStart = false;
|
||||
const hideSubSessions = this.configurationService.getValue<IDebugConfiguration>('debug').hideSubSessions;
|
||||
const showSubSessions = this.configurationService.getValue<IDebugConfiguration>('debug').showSubSessionsInToolBar;
|
||||
const sessions = this.model.getSessions();
|
||||
const shownSessions = hideSubSessions ? sessions.filter(s => !s.parentSession) : sessions;
|
||||
const shownSessions = showSubSessions ? sessions : sessions.filter(s => !s.parentSession);
|
||||
if (shownSessions.length > 1) {
|
||||
this.viewModel.setMultiSessionView(true);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,9 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
export class DebugSession implements IDebugSession {
|
||||
|
||||
private id: string;
|
||||
private _subId: string | undefined;
|
||||
private raw: RawDebugSession | undefined;
|
||||
private initialized = false;
|
||||
|
||||
@@ -76,6 +78,14 @@ export class DebugSession implements IDebugSession {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
setSubId(subId: string | undefined) {
|
||||
this._subId = subId;
|
||||
}
|
||||
|
||||
get subId(): string | undefined {
|
||||
return this._subId;
|
||||
}
|
||||
|
||||
get configuration(): IConfig {
|
||||
return this._configuration.resolved;
|
||||
}
|
||||
|
||||
@@ -124,6 +124,12 @@ export class MockDebugService implements IDebugService {
|
||||
|
||||
export class MockSession implements IDebugSession {
|
||||
|
||||
subId: string | undefined;
|
||||
|
||||
setSubId(subId: string | undefined): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
get parentSession(): IDebugSession | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as assert from 'assert';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { INotificationService, IPromptChoice, Severity, IPromptOptions } from 'vs/platform/notification/common/notification';
|
||||
import { INotificationService, IPromptChoice, IPromptOptions, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -37,7 +37,6 @@ suite('Experimental Prompts', () => {
|
||||
commands: [
|
||||
{
|
||||
text: 'Yes',
|
||||
externalLink: 'https://code.visualstudio.com'
|
||||
},
|
||||
{
|
||||
text: 'No'
|
||||
@@ -83,30 +82,30 @@ suite('Experimental Prompts', () => {
|
||||
});
|
||||
|
||||
|
||||
// test('Show experimental prompt if experiment should be run. Choosing option with link should mark experiment as complete', () => {
|
||||
test('Show experimental prompt if experiment should be run. Choosing option with link should mark experiment as complete', () => {
|
||||
|
||||
// storageData = {
|
||||
// enabled: true,
|
||||
// state: ExperimentState.Run
|
||||
// };
|
||||
storageData = {
|
||||
enabled: true,
|
||||
state: ExperimentState.Run
|
||||
};
|
||||
|
||||
// instantiationService.stub(INotificationService, {
|
||||
// prompt: (a: Severity, b: string, c: IPromptChoice[], options: IPromptOptions) => {
|
||||
// assert.equal(b, promptText);
|
||||
// assert.equal(c.length, 2);
|
||||
// c[0].run();
|
||||
// return undefined!;
|
||||
// }
|
||||
// });
|
||||
instantiationService.stub(INotificationService, {
|
||||
prompt: (a: Severity, b: string, c: IPromptChoice[], options: IPromptOptions) => {
|
||||
assert.equal(b, promptText);
|
||||
assert.equal(c.length, 2);
|
||||
c[0].run();
|
||||
return undefined!;
|
||||
}
|
||||
});
|
||||
|
||||
// experimentalPrompt = instantiationService.createInstance(ExperimentalPrompts);
|
||||
// onExperimentEnabledEvent.fire(experiment);
|
||||
experimentalPrompt = instantiationService.createInstance(ExperimentalPrompts);
|
||||
onExperimentEnabledEvent.fire(experiment);
|
||||
|
||||
// return Promise.resolve(null).then(result => {
|
||||
// assert.equal(storageData['state'], ExperimentState.Complete);
|
||||
// });
|
||||
return Promise.resolve(null).then(result => {
|
||||
assert.equal(storageData['state'], ExperimentState.Complete);
|
||||
});
|
||||
|
||||
// });
|
||||
});
|
||||
|
||||
test('Show experimental prompt if experiment should be run. Choosing negative option should mark experiment as complete', () => {
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { IViewlet } from 'vs/workbench/common/viewlet';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IPager } from 'vs/base/common/paging';
|
||||
import { IQueryOptions, EnablementState, ILocalExtension, IGalleryExtension, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IQueryOptions, EnablementState, ILocalExtension, IGalleryExtension, IExtensionIdentifier, IExtensionManagementServer } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IViewContainersRegistry, ViewContainer, Extensions as ViewContainerExtensions } from 'vs/workbench/common/views';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
@@ -32,40 +32,41 @@ export const enum ExtensionState {
|
||||
}
|
||||
|
||||
export interface IExtension {
|
||||
type?: ExtensionType;
|
||||
state: ExtensionState;
|
||||
name: string;
|
||||
displayName: string;
|
||||
identifier: IExtensionIdentifier;
|
||||
publisher: string;
|
||||
publisherDisplayName: string;
|
||||
version: string;
|
||||
latestVersion: string;
|
||||
description: string;
|
||||
url?: string;
|
||||
readonly type?: ExtensionType;
|
||||
readonly state: ExtensionState;
|
||||
readonly name: string;
|
||||
readonly displayName: string;
|
||||
readonly identifier: IExtensionIdentifier;
|
||||
readonly publisher: string;
|
||||
readonly publisherDisplayName: string;
|
||||
readonly version: string;
|
||||
readonly latestVersion: string;
|
||||
readonly description: string;
|
||||
readonly url?: string;
|
||||
// {{SQL CARBON EDIT}}
|
||||
downloadPage: string;
|
||||
repository?: string;
|
||||
iconUrl: string;
|
||||
iconUrlFallback: string;
|
||||
licenseUrl?: string;
|
||||
installCount?: number;
|
||||
rating?: number;
|
||||
ratingCount?: number;
|
||||
outdated: boolean;
|
||||
enablementState: EnablementState;
|
||||
dependencies: string[];
|
||||
extensionPack: string[];
|
||||
telemetryData: any;
|
||||
preview: boolean;
|
||||
readonly downloadPage?: string;
|
||||
readonly repository?: string;
|
||||
readonly iconUrl: string;
|
||||
readonly iconUrlFallback: string;
|
||||
readonly licenseUrl?: string;
|
||||
readonly installCount?: number;
|
||||
readonly rating?: number;
|
||||
readonly ratingCount?: number;
|
||||
readonly outdated: boolean;
|
||||
readonly enablementState: EnablementState;
|
||||
readonly dependencies: string[];
|
||||
readonly extensionPack: string[];
|
||||
readonly telemetryData: any;
|
||||
readonly preview: boolean;
|
||||
getManifest(token: CancellationToken): Promise<IExtensionManifest | null>;
|
||||
getReadme(token: CancellationToken): Promise<string>;
|
||||
hasReadme(): boolean;
|
||||
getChangelog(token: CancellationToken): Promise<string>;
|
||||
hasChangelog(): boolean;
|
||||
local?: ILocalExtension;
|
||||
readonly server?: IExtensionManagementServer;
|
||||
readonly local?: ILocalExtension;
|
||||
gallery?: IGalleryExtension;
|
||||
isMalicious: boolean;
|
||||
readonly isMalicious: boolean;
|
||||
}
|
||||
|
||||
export interface IExtensionDependencies {
|
||||
@@ -84,7 +85,8 @@ export interface IExtensionsWorkbenchService {
|
||||
_serviceBrand: any;
|
||||
onChange: Event<IExtension | undefined>;
|
||||
local: IExtension[];
|
||||
queryLocal(): Promise<IExtension[]>;
|
||||
outdated: IExtension[];
|
||||
queryLocal(server?: IExtensionManagementServer): Promise<IExtension[]>;
|
||||
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;
|
||||
queryGallery(options: IQueryOptions, token: CancellationToken): Promise<IPager<IExtension>>;
|
||||
canInstall(extension: IExtension): boolean;
|
||||
@@ -128,6 +130,7 @@ export enum ExtensionsPolicy {
|
||||
|
||||
export interface IExtensionContainer {
|
||||
extension: IExtension | null;
|
||||
updateWhenCounterExtensionChanges?: boolean;
|
||||
update(): void;
|
||||
}
|
||||
|
||||
@@ -149,7 +152,11 @@ export class ExtensionContainers extends Disposable {
|
||||
for (const container of this.containers) {
|
||||
if (extension && container.extension) {
|
||||
if (areSameExtensions(container.extension.identifier, extension.identifier)) {
|
||||
container.extension = extension;
|
||||
if (!container.extension.server || container.extension.server === extension.server) {
|
||||
container.extension = extension;
|
||||
} else if (container.updateWhenCounterExtensionChanges) {
|
||||
container.update();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
container.update();
|
||||
|
||||
@@ -28,7 +28,7 @@ import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension
|
||||
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, SystemDisabledLabelAction, SystemDisabledWarningAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
@@ -215,6 +215,8 @@ export class ExtensionEditor extends BaseEditor {
|
||||
|
||||
createEditor(parent: HTMLElement): void {
|
||||
const root = append(parent, $('.extension-editor'));
|
||||
root.tabIndex = 0; // this is required for the focus tracker on the editor
|
||||
root.style.outline = 'none';
|
||||
this.header = append(root, $('.header'));
|
||||
|
||||
this.iconContainer = append(this.header, $('.icon-container'));
|
||||
@@ -380,6 +382,8 @@ export class ExtensionEditor extends BaseEditor {
|
||||
// this.instantiationService.createInstance(RatingsWidget, this.rating, false)
|
||||
];
|
||||
const reloadAction = this.instantiationService.createInstance(ReloadAction);
|
||||
const combinedInstallAction = this.instantiationService.createInstance(CombinedInstallAction);
|
||||
const systemDisabledWarningAction = this.instantiationService.createInstance(SystemDisabledWarningAction);
|
||||
const actions = [
|
||||
reloadAction,
|
||||
this.instantiationService.createInstance(StatusLabelAction),
|
||||
@@ -388,7 +392,10 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.instantiationService.createInstance(SetFileIconThemeAction, fileIconThemes),
|
||||
this.instantiationService.createInstance(EnableDropDownAction),
|
||||
this.instantiationService.createInstance(DisableDropDownAction, runningExtensions),
|
||||
this.instantiationService.createInstance(CombinedInstallAction),
|
||||
this.instantiationService.createInstance(RemoteInstallAction),
|
||||
combinedInstallAction,
|
||||
systemDisabledWarningAction,
|
||||
this.instantiationService.createInstance(SystemDisabledLabelAction, systemDisabledWarningAction),
|
||||
this.instantiationService.createInstance(MaliciousStatusLabelAction, true),
|
||||
];
|
||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
|
||||
@@ -410,6 +417,9 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.extensionManifest.get()
|
||||
.promise
|
||||
.then(manifest => {
|
||||
if (manifest) {
|
||||
combinedInstallAction.manifest = manifest;
|
||||
}
|
||||
if (extension.extensionPack.length) {
|
||||
this.navbar.push(NavbarSection.ExtensionPack, localize('extensionPack', "Extension Pack"), localize('extensionsPack', "Set of extensions that can be installed together"));
|
||||
}
|
||||
@@ -543,19 +553,20 @@ export class ExtensionEditor extends BaseEditor {
|
||||
.then(renderBody)
|
||||
.then(removeEmbeddedSVGs)
|
||||
.then(body => {
|
||||
const wbeviewElement = this.instantiationService.createInstance(WebviewElement,
|
||||
const webviewElement = this.instantiationService.createInstance(WebviewElement,
|
||||
{
|
||||
enableFindWidget: true,
|
||||
},
|
||||
{
|
||||
svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders
|
||||
});
|
||||
wbeviewElement.mountTo(this.content);
|
||||
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, wbeviewElement);
|
||||
webviewElement.mountTo(this.content);
|
||||
this.contentDisposables.push(webviewElement.onDidFocus(() => this.fireOnDidFocus()));
|
||||
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, webviewElement);
|
||||
this.contentDisposables.push(toDisposable(removeLayoutParticipant));
|
||||
wbeviewElement.contents = body;
|
||||
webviewElement.contents = body;
|
||||
|
||||
wbeviewElement.onDidClickLink(link => {
|
||||
this.contentDisposables.push(webviewElement.onDidClickLink(link => {
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
@@ -563,9 +574,9 @@ export class ExtensionEditor extends BaseEditor {
|
||||
if (['http', 'https', 'mailto'].indexOf(link.scheme) >= 0 || (link.scheme === 'command' && link.path === ShowCurrentReleaseNotesAction.ID)) {
|
||||
this.openerService.open(link);
|
||||
}
|
||||
}, null, this.contentDisposables);
|
||||
this.contentDisposables.push(wbeviewElement);
|
||||
return wbeviewElement;
|
||||
}, null, this.contentDisposables));
|
||||
this.contentDisposables.push(webviewElement);
|
||||
return webviewElement;
|
||||
})
|
||||
.then(undefined, () => {
|
||||
const p = append(this.content, $('p.nocontent'));
|
||||
|
||||
@@ -16,9 +16,9 @@ import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG, ExtensionsPolicy, ExtensionsPolicyKey } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
|
||||
import { IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionRecommendation, IGalleryExtension, IExtensionsConfigContent, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionRecommendation, IGalleryExtension, IExtensionsConfigContent, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionType, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
@@ -56,6 +56,11 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING, IFileIconTheme, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
@@ -145,16 +150,29 @@ export class InstallAction extends ExtensionAction {
|
||||
private static readonly Class = 'extension-action prominent install';
|
||||
private static readonly InstallingClass = 'extension-action install installing';
|
||||
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
private _manifest: IExtensionManifest | null;
|
||||
set manifest(manifest: IExtensionManifest) {
|
||||
this._manifest = manifest;
|
||||
this.updateLabel();
|
||||
}
|
||||
|
||||
constructor(
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IExtensionService private readonly runtimeExtensionService: IExtensionService,
|
||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService
|
||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
|
||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
) {
|
||||
super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false);
|
||||
this.update();
|
||||
this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables);
|
||||
}
|
||||
|
||||
update(): void {
|
||||
@@ -166,15 +184,28 @@ export class InstallAction extends ExtensionAction {
|
||||
}
|
||||
|
||||
this.enabled = this.extensionsWorkbenchService.canInstall(this.extension) && this.extension.state === ExtensionState.Uninstalled;
|
||||
this.class = this.extension.state === ExtensionState.Installing ? InstallAction.InstallingClass : InstallAction.Class;
|
||||
this.updateLabel();
|
||||
}
|
||||
|
||||
private updateLabel(): void {
|
||||
if (this.extension.state === ExtensionState.Installing) {
|
||||
this.label = InstallAction.INSTALLING_LABEL;
|
||||
this.class = InstallAction.InstallingClass;
|
||||
this.tooltip = InstallAction.INSTALLING_LABEL;
|
||||
} else {
|
||||
this.label = InstallAction.INSTALL_LABEL;
|
||||
this.class = InstallAction.Class;
|
||||
this.tooltip = InstallAction.INSTALL_LABEL;
|
||||
if (this._manifest && this.workbenchEnvironmentService.configuration.remoteAuthority) {
|
||||
if (isUIExtension(this._manifest, this.configurationService)) {
|
||||
this.label = `${InstallAction.INSTALL_LABEL} (${this.extensionManagementServerService.localExtensionManagementServer.label})`;
|
||||
this.tooltip = `${InstallAction.INSTALL_LABEL} (${this.extensionManagementServerService.localExtensionManagementServer.label})`;
|
||||
} else {
|
||||
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
||||
this.label = `${InstallAction.INSTALL_LABEL} (${host})`;
|
||||
this.tooltip = `${InstallAction.INSTALL_LABEL} (${host})`;
|
||||
}
|
||||
} else {
|
||||
this.label = InstallAction.INSTALL_LABEL;
|
||||
this.tooltip = InstallAction.INSTALL_LABEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +216,8 @@ export class InstallAction extends ExtensionAction {
|
||||
|
||||
const extension = await this.install(this.extension);
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName));
|
||||
|
||||
// Add extension object check since ADS third party extensions will be directed to a download page
|
||||
// and the extension object will be undefined.
|
||||
if (extension && extension.local) {
|
||||
@@ -246,6 +278,93 @@ export class InstallAction extends ExtensionAction {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoteInstallAction extends ExtensionAction {
|
||||
|
||||
private static INSTALL_LABEL = localize('install', "Install");
|
||||
private static INSTALLING_LABEL = localize('installing', "Installing");
|
||||
|
||||
private static readonly Class = 'extension-action prominent install';
|
||||
private static readonly InstallingClass = 'extension-action install installing';
|
||||
|
||||
updateWhenCounterExtensionChanges: boolean = true;
|
||||
private disposables: IDisposable[] = [];
|
||||
private installing: boolean = false;
|
||||
|
||||
constructor(
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
) {
|
||||
super(`extensions.remoteinstall`, RemoteInstallAction.INSTALL_LABEL, RemoteInstallAction.Class, false);
|
||||
this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables);
|
||||
this.updateLabel();
|
||||
this.update();
|
||||
}
|
||||
|
||||
private updateLabel(): void {
|
||||
if (this.installing) {
|
||||
this.label = RemoteInstallAction.INSTALLING_LABEL;
|
||||
return;
|
||||
}
|
||||
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
||||
if (remoteAuthority) {
|
||||
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
||||
this.label = `${RemoteInstallAction.INSTALL_LABEL} (${host})`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.class = RemoteInstallAction.Class;
|
||||
if (this.installing) {
|
||||
this.enabled = true;
|
||||
this.class = RemoteInstallAction.InstallingClass;
|
||||
this.updateLabel();
|
||||
return;
|
||||
}
|
||||
if (this.environmentService.configuration.remoteAuthority
|
||||
// Installed User Extension
|
||||
&& this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed
|
||||
// Local Workspace Extension
|
||||
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
|
||||
// Extension does not exist in remote
|
||||
&& !this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
|
||||
&& this.extensionsWorkbenchService.canInstall(this.extension)
|
||||
) {
|
||||
this.enabled = true;
|
||||
this.updateLabel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer && !this.installing) {
|
||||
this.installing = true;
|
||||
this.update();
|
||||
this.extensionsWorkbenchService.open(this.extension);
|
||||
alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName));
|
||||
if (this.extension.gallery) {
|
||||
await this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(this.extension.gallery);
|
||||
this.installing = false;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class UninstallAction extends ExtensionAction {
|
||||
@@ -281,19 +400,12 @@ export class UninstallAction extends ExtensionAction {
|
||||
this.label = UninstallAction.UninstallLabel;
|
||||
this.class = UninstallAction.UninstallClass;
|
||||
|
||||
const installedExtensions = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier));
|
||||
|
||||
if (!installedExtensions.length) {
|
||||
this.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (state !== ExtensionState.Installed) {
|
||||
this.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (installedExtensions[0].type !== ExtensionType.User) {
|
||||
if (this.extension.type !== ExtensionType.User) {
|
||||
this.enabled = false;
|
||||
return;
|
||||
}
|
||||
@@ -330,6 +442,8 @@ export class CombinedInstallAction extends ExtensionAction {
|
||||
this.update();
|
||||
}
|
||||
|
||||
set manifest(manifiest: IExtensionManifest) { this.installAction.manifest = manifiest; this.update(); }
|
||||
|
||||
update(): void {
|
||||
this.installAction.extension = this.extension;
|
||||
this.uninstallAction.extension = this.extension;
|
||||
@@ -901,36 +1015,32 @@ export class CheckForUpdatesAction extends Action {
|
||||
}
|
||||
|
||||
private checkUpdatesAndNotify(): void {
|
||||
this.extensionsWorkbenchService.queryLocal().then(
|
||||
extensions => {
|
||||
const outdatedExtensions = extensions.filter(ext => ext.outdated === true);
|
||||
if (!outdatedExtensions.length) {
|
||||
this.notificationService.info(localize('noUpdatesAvailable', "All Extensions are up to date."));
|
||||
return;
|
||||
}
|
||||
const outdated = this.extensionsWorkbenchService.outdated;
|
||||
if (!outdated.length) {
|
||||
this.notificationService.info(localize('noUpdatesAvailable', "All Extensions are up to date."));
|
||||
return;
|
||||
}
|
||||
|
||||
let msgAvailableExtensions = outdatedExtensions.length === 1 ? localize('singleUpdateAvailable', "An extension update is available.") : localize('updatesAvailable', "{0} extension updates are available.", outdatedExtensions.length);
|
||||
let msgAvailableExtensions = outdated.length === 1 ? localize('singleUpdateAvailable', "An extension update is available.") : localize('updatesAvailable', "{0} extension updates are available.", outdated.length);
|
||||
|
||||
const disabledExtensionsCount = outdatedExtensions.filter(ext => ext.enablementState === EnablementState.Disabled || ext.enablementState === EnablementState.WorkspaceDisabled).length;
|
||||
if (disabledExtensionsCount) {
|
||||
if (outdatedExtensions.length === 1) {
|
||||
msgAvailableExtensions = localize('singleDisabledUpdateAvailable', "An update to an extension which is disabled is available.");
|
||||
} else if (disabledExtensionsCount === 1) {
|
||||
msgAvailableExtensions = localize('updatesAvailableOneDisabled', "{0} extension updates are available. One of them is for a disabled extension.", outdatedExtensions.length);
|
||||
} else if (disabledExtensionsCount === outdatedExtensions.length) {
|
||||
msgAvailableExtensions = localize('updatesAvailableAllDisabled', "{0} extension updates are available. All of them are for disabled extensions.", outdatedExtensions.length);
|
||||
} else {
|
||||
msgAvailableExtensions = localize('updatesAvailableIncludingDisabled', "{0} extension updates are available. {1} of them are for disabled extensions.", outdatedExtensions.length, disabledExtensionsCount);
|
||||
}
|
||||
}
|
||||
|
||||
this.viewletService.openViewlet(VIEWLET_ID, true)
|
||||
.then(viewlet => viewlet as IExtensionsViewlet)
|
||||
.then(viewlet => viewlet.search(''));
|
||||
|
||||
this.notificationService.info(msgAvailableExtensions);
|
||||
const disabledExtensionsCount = outdated.filter(ext => ext.enablementState === EnablementState.Disabled || ext.enablementState === EnablementState.WorkspaceDisabled).length;
|
||||
if (disabledExtensionsCount) {
|
||||
if (outdated.length === 1) {
|
||||
msgAvailableExtensions = localize('singleDisabledUpdateAvailable', "An update to an extension which is disabled is available.");
|
||||
} else if (disabledExtensionsCount === 1) {
|
||||
msgAvailableExtensions = localize('updatesAvailableOneDisabled', "{0} extension updates are available. One of them is for a disabled extension.", outdated.length);
|
||||
} else if (disabledExtensionsCount === outdated.length) {
|
||||
msgAvailableExtensions = localize('updatesAvailableAllDisabled', "{0} extension updates are available. All of them are for disabled extensions.", outdated.length);
|
||||
} else {
|
||||
msgAvailableExtensions = localize('updatesAvailableIncludingDisabled', "{0} extension updates are available. {1} of them are for disabled extensions.", outdated.length, disabledExtensionsCount);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this.viewletService.openViewlet(VIEWLET_ID, true)
|
||||
.then(viewlet => viewlet as IExtensionsViewlet)
|
||||
.then(viewlet => viewlet.search(''));
|
||||
|
||||
this.notificationService.info(msgAvailableExtensions);
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
@@ -1009,16 +1119,12 @@ export class UpdateAllAction extends Action {
|
||||
this.update();
|
||||
}
|
||||
|
||||
private get outdated(): IExtension[] {
|
||||
return this.extensionsWorkbenchService.local.filter(e => e.outdated && e.state !== ExtensionState.Installing);
|
||||
}
|
||||
|
||||
private update(): void {
|
||||
this.enabled = this.outdated.length > 0;
|
||||
this.enabled = this.extensionsWorkbenchService.outdated.length > 0;
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
return Promise.all(this.outdated.map(e => this.install(e)));
|
||||
return Promise.all(this.extensionsWorkbenchService.outdated.map(e => this.install(e)));
|
||||
}
|
||||
|
||||
private install(extension: IExtension): Promise<any> {
|
||||
@@ -1044,16 +1150,18 @@ export class ReloadAction extends ExtensionAction {
|
||||
private static readonly EnabledClass = 'extension-action reload';
|
||||
private static readonly DisabledClass = `${ReloadAction.EnabledClass} disabled`;
|
||||
|
||||
updateWhenCounterExtensionChanges: boolean = true;
|
||||
private disposables: IDisposable[] = [];
|
||||
private _runningExtensions: IExtensionDescription[] = [];
|
||||
private get runningExtensions(): IExtensionDescription[] { return this._runningExtensions; }
|
||||
private set runningExtensions(runningExtensions: IExtensionDescription[]) { this._runningExtensions = runningExtensions; this.update(); }
|
||||
private _runningExtensions: IExtensionDescription[] | null = null;
|
||||
|
||||
constructor(
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
|
||||
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
|
||||
@@ -1061,81 +1169,90 @@ export class ReloadAction extends ExtensionAction {
|
||||
}
|
||||
|
||||
private updateRunningExtensions(): void {
|
||||
this.extensionService.getExtensions().then(runningExtensions => this.runningExtensions = runningExtensions);
|
||||
this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.tooltip = '';
|
||||
if (!this.extension) {
|
||||
if (!this.extension || !this._runningExtensions) {
|
||||
return;
|
||||
}
|
||||
const state = this.extension.state;
|
||||
if (state === ExtensionState.Installing || state === ExtensionState.Uninstalling) {
|
||||
return;
|
||||
}
|
||||
const installed = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
|
||||
const local = this.extension.local || (installed && installed.local);
|
||||
if (local && local.manifest && local.manifest.contributes && local.manifest.contributes.localizations && local.manifest.contributes.localizations.length > 0) {
|
||||
if (this.extension.local && this.extension.local.manifest && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.localizations && this.extension.local.manifest.contributes.localizations.length > 0) {
|
||||
return;
|
||||
}
|
||||
this.computeReloadState(installed);
|
||||
this.computeReloadState();
|
||||
this.class = this.enabled ? ReloadAction.EnabledClass : ReloadAction.DisabledClass;
|
||||
}
|
||||
|
||||
private computeReloadState(installed: IExtension): void {
|
||||
private computeReloadState(): void {
|
||||
if (!this._runningExtensions) {
|
||||
return;
|
||||
}
|
||||
const isUninstalled = this.extension.state === ExtensionState.Uninstalled;
|
||||
const isDisabled = this.extension.local ? !this.extensionEnablementService.isEnabled(this.extension.local) : false;
|
||||
const isEnabled = this.extension.local ? this.extensionEnablementService.isEnabled(this.extension.local) : false;
|
||||
const runningExtension = this.runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
|
||||
const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
|
||||
|
||||
if (installed && installed.local) {
|
||||
if (isUninstalled) {
|
||||
if (runningExtension) {
|
||||
const isDifferentVersionRunning = this.extension.version !== runningExtension.version;
|
||||
if (isDifferentVersionRunning && !isDisabled) {
|
||||
if (!(this.extension.local && this.extensionService.canAddExtension(toExtensionDescription(this.extension.local)))) {
|
||||
// Requires reload to run the updated extension
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postUpdateTooltip', "Please reload Azure Data Studio to complete the updating of this extension.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isDisabled) {
|
||||
// Requires reload to disable the extension
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postDisableTooltip', "Please reload Azure Data Studio to complete the disabling of this extension.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!isDisabled && !(this.extension.local && this.extensionService.canAddExtension(toExtensionDescription(this.extension.local)))) {
|
||||
this.enabled = true;
|
||||
if (isEnabled) {
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to complete the enabling of this extension.");
|
||||
} else {
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postInstallTooltip', "Please reload Azure Data Studio to complete the installation of this extension.");
|
||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName));
|
||||
}
|
||||
}
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postUninstallTooltip', "Please reload Azure Data Studio to complete the uninstallation of this extension.");
|
||||
alert(localize('uninstallExtensionComplete', "Please reload Azure Data Studio to complete the uninstallation of the extension {0}.", this.extension.displayName));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUninstalled && runningExtension) {
|
||||
// Requires reload to deactivate the extension
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postUninstallTooltip', "Please reload Azure Data Studio to complete the uninstallation of this extension.");
|
||||
alert(localize('uninstallExtensionComplete', "Please reload Azure Data Studio to complete the uninstallation of the extension {0}.", this.extension.displayName));
|
||||
return;
|
||||
if (this.extension.local) {
|
||||
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
||||
if (runningExtension) {
|
||||
// Extension is running
|
||||
const isSameExtensionRunning = this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation);
|
||||
const isSameVersionRunning = isSameExtensionRunning && this.extension.version === runningExtension.version;
|
||||
if (isEnabled) {
|
||||
if (!isSameVersionRunning && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postUpdateTooltip', "Please reload Azure Data Studio to enable the updated extension.");
|
||||
}
|
||||
} else {
|
||||
if (isSameExtensionRunning) {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postDisableTooltip', "Please reload Azure Data Studio to disable this extension.");
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// Extension is not running
|
||||
if (isEnabled && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");
|
||||
return;
|
||||
}
|
||||
if (this.workbenchEnvironmentService.configuration.remoteAuthority
|
||||
// Local Workspace Extension
|
||||
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
|
||||
) {
|
||||
const remoteExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0];
|
||||
// Extension exist in remote and enabled
|
||||
if (remoteExtension && remoteExtension.local && this.extensionEnablementService.isEnabled(remoteExtension.local)) {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");
|
||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1394,10 +1511,11 @@ export class ClearExtensionsInputAction extends Action {
|
||||
id: string,
|
||||
label: string,
|
||||
onSearchChange: Event<string>,
|
||||
value: string,
|
||||
@IViewletService private readonly viewletService: IViewletService
|
||||
) {
|
||||
super(id, label, 'clear-extensions', true);
|
||||
this.enabled = false;
|
||||
this.onSearchChange(value);
|
||||
onSearchChange(this.onSearchChange, this, this.disposables);
|
||||
}
|
||||
|
||||
@@ -1893,6 +2011,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
||||
label: string,
|
||||
@IWorkspaceContextService protected contextService: IWorkspaceContextService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@IEditorService protected editorService: IEditorService,
|
||||
@IJSONEditingService private readonly jsonEditingService: IJSONEditingService,
|
||||
@ITextModelService private readonly textModelResolverService: ITextModelService
|
||||
@@ -2041,7 +2160,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
||||
return Promise.resolve(this.fileService.resolveContent(extensionsFileResource)).then(content => {
|
||||
return { created: false, extensionsFileResource, content: content.value };
|
||||
}, err => {
|
||||
return this.fileService.updateContent(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => {
|
||||
return this.textFileService.write(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => {
|
||||
return { created: true, extensionsFileResource, content: ExtensionsConfigurationInitialContent };
|
||||
});
|
||||
});
|
||||
@@ -2059,12 +2178,13 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi
|
||||
id: string,
|
||||
label: string,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IJSONEditingService jsonEditingService: IJSONEditingService,
|
||||
@ITextModelService textModelResolverService: ITextModelService
|
||||
) {
|
||||
super(id, label, contextService, fileService, editorService, jsonEditingService, textModelResolverService);
|
||||
super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
|
||||
this.contextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables);
|
||||
this.update();
|
||||
}
|
||||
@@ -2100,13 +2220,14 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac
|
||||
id: string,
|
||||
label: string,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IJSONEditingService jsonEditingService: IJSONEditingService,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(id, label, contextService, fileService, editorService, jsonEditingService, textModelResolverService);
|
||||
super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
|
||||
this.contextService.onDidChangeWorkspaceFolders(() => this.update(), this, this.disposables);
|
||||
this.update();
|
||||
}
|
||||
@@ -2145,6 +2266,7 @@ export class AddToWorkspaceFolderRecommendationsAction extends AbstractConfigure
|
||||
id: string,
|
||||
label: string,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IJSONEditingService jsonEditingService: IJSONEditingService,
|
||||
@@ -2152,7 +2274,7 @@ export class AddToWorkspaceFolderRecommendationsAction extends AbstractConfigure
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) {
|
||||
super(id, label, contextService, fileService, editorService, jsonEditingService, textModelResolverService);
|
||||
super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
|
||||
}
|
||||
|
||||
run(shouldRecommend: boolean): Promise<void> {
|
||||
@@ -2228,13 +2350,14 @@ export class AddToWorkspaceRecommendationsAction extends AbstractConfigureRecomm
|
||||
id: string,
|
||||
label: string,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IJSONEditingService jsonEditingService: IJSONEditingService,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) {
|
||||
super(id, label, contextService, fileService, editorService, jsonEditingService, textModelResolverService);
|
||||
super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
|
||||
}
|
||||
|
||||
run(shouldRecommend: boolean): Promise<void> {
|
||||
@@ -2410,6 +2533,103 @@ export class MaliciousStatusLabelAction extends ExtensionAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class SystemDisabledLabelAction extends ExtensionAction {
|
||||
|
||||
private static readonly Class = 'disable-status';
|
||||
|
||||
updateWhenCounterExtensionChanges: boolean = true;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly warningAction: SystemDisabledWarningAction,
|
||||
) {
|
||||
super('extensions.systemDisabledLabel', warningAction.tooltip, `${SystemDisabledLabelAction.Class} hide`, false);
|
||||
warningAction.onDidChange(() => this.update(), this, this.disposables);
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enabled = this.warningAction.enabled;
|
||||
if (this.enabled) {
|
||||
this.class = SystemDisabledLabelAction.Class;
|
||||
this.label = this.warningAction.tooltip;
|
||||
} else {
|
||||
this.class = `${SystemDisabledLabelAction.Class} hide`;
|
||||
this.label = '';
|
||||
}
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this.disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class SystemDisabledWarningAction extends ExtensionAction {
|
||||
|
||||
private static readonly Class = 'disable-warning';
|
||||
|
||||
updateWhenCounterExtensionChanges: boolean = true;
|
||||
private disposables: IDisposable[] = [];
|
||||
private _runningExtensions: IExtensionDescription[] | null = null;
|
||||
|
||||
constructor(
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
) {
|
||||
super('extensions.install', '', `${SystemDisabledWarningAction.Class} hide`, false);
|
||||
this.labelService.onDidChangeFormatters(() => this.update(), this, this.disposables);
|
||||
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
|
||||
this.updateRunningExtensions();
|
||||
this.update();
|
||||
}
|
||||
|
||||
private updateRunningExtensions(): void {
|
||||
this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.class = `${SystemDisabledWarningAction.Class} hide`;
|
||||
this.tooltip = '';
|
||||
if (this.extension && this.extension.local && this._runningExtensions) {
|
||||
if (
|
||||
// Remote Window
|
||||
this.workbenchEnvironmentService.configuration.remoteAuthority
|
||||
// Local Workspace Extension
|
||||
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
|
||||
// Extension does not exist in remote
|
||||
&& !this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
|
||||
) {
|
||||
this.enabled = true;
|
||||
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
||||
this.tooltip = localize('disabled workspace Extension', "This extension is disabled because it cannot run in a window connected to the remote server.", host, host);
|
||||
if (this.extensionsWorkbenchService.canInstall(this.extension)) {
|
||||
this.tooltip = `${this.tooltip} ${localize('Install in remote server', "Install it in '{0}' server to enable.", host)}`;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this.disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class DisableAllAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.disableAll';
|
||||
|
||||
@@ -12,8 +12,8 @@ import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IExtension, IExtensionsWorkbenchService, ExtensionContainers } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem, StatusLabelAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -54,9 +54,9 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
private extensionViewState: IExtensionsViewState,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
) { }
|
||||
|
||||
get templateId() { return 'extension'; }
|
||||
@@ -100,7 +100,9 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
this.instantiationService.createInstance(UpdateAction),
|
||||
this.instantiationService.createInstance(ReloadAction),
|
||||
this.instantiationService.createInstance(InstallAction),
|
||||
this.instantiationService.createInstance(RemoteInstallAction),
|
||||
this.instantiationService.createInstance(MaliciousStatusLabelAction, false),
|
||||
this.instantiationService.createInstance(SystemDisabledWarningAction),
|
||||
this.instantiationService.createInstance(ManageExtensionAction)
|
||||
];
|
||||
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets]);
|
||||
@@ -136,23 +138,18 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
||||
renderElement(extension: IExtension, index: number, data: ITemplateData): void {
|
||||
removeClass(data.element, 'loading');
|
||||
|
||||
if (extension.state !== ExtensionState.Uninstalled && !extension.server) {
|
||||
// Get the extension if it is installed and has no server information
|
||||
extension = this.extensionsWorkbenchService.local.filter(e => e.server === extension.server && areSameExtensions(e.identifier, extension.identifier))[0] || extension;
|
||||
}
|
||||
|
||||
data.extensionDisposables = dispose(data.extensionDisposables);
|
||||
|
||||
const updateEnablement = async () => {
|
||||
const runningExtensions = await this.extensionService.getExtensions();
|
||||
const installed = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, extension.identifier))[0];
|
||||
if (installed && installed.local) {
|
||||
const installedExtensionServer = this.extensionManagementServerService.getExtensionManagementServer(installed.local.location);
|
||||
const isSameExtensionRunning = runningExtensions.some(e => {
|
||||
if (!areSameExtensions({ id: e.identifier.value }, extension.identifier)) {
|
||||
return false;
|
||||
}
|
||||
const runningExtensionServer = this.extensionManagementServerService.getExtensionManagementServer(e.extensionLocation);
|
||||
if (!installedExtensionServer || !runningExtensionServer) {
|
||||
return false;
|
||||
}
|
||||
return installedExtensionServer.authority === runningExtensionServer.authority;
|
||||
});
|
||||
if (extension.local) {
|
||||
const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, extension.identifier))[0];
|
||||
const isSameExtensionRunning = runningExtension && extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation);
|
||||
toggleClass(data.root, 'disabled', !isSameExtensionRunning);
|
||||
} else {
|
||||
removeClass(data.root, 'disabled');
|
||||
|
||||
@@ -24,9 +24,9 @@ import {
|
||||
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction
|
||||
} from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { IExtensionManagementService, IExtensionManagementServerService, IExtensionManagementServer, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionManagementService, IExtensionManagementServerService, IExtensionManagementServer, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, GroupByServerExtensionsView, DefaultRecommendedExtensionsView } from './extensionsViews';
|
||||
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from './extensionsViews';
|
||||
import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
|
||||
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
@@ -35,7 +35,6 @@ import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/servi
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IViewsRegistry, IViewDescriptor, Extensions } from 'vs/workbench/common/views';
|
||||
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -54,6 +53,8 @@ import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { RemoteAuthorityContext as RemoteAuthorityContext } from 'vs/workbench/common/contextkeys';
|
||||
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
|
||||
interface SearchInputEvent extends Event {
|
||||
target: HTMLInputElement;
|
||||
@@ -61,12 +62,13 @@ interface SearchInputEvent extends Event {
|
||||
}
|
||||
|
||||
const NonEmptyWorkspaceContext = new RawContextKey<boolean>('nonEmptyWorkspace', false);
|
||||
const SearchExtensionsContext = new RawContextKey<boolean>('searchExtensions', false);
|
||||
const DefaultViewsContext = new RawContextKey<boolean>('defaultExtensionViews', true);
|
||||
const SearchMarketplaceExtensionsContext = new RawContextKey<boolean>('searchMarketplaceExtensions', false);
|
||||
const SearchServerExtensionsContext = new RawContextKey<boolean>('searchServerExtensions', false);
|
||||
const HasInstalledExtensionsContext = new RawContextKey<boolean>('hasInstalledExtensions', true);
|
||||
const SearchBuiltInExtensionsContext = new RawContextKey<boolean>('searchBuiltInExtensions', false);
|
||||
const RecommendedExtensionsContext = new RawContextKey<boolean>('recommendedExtensions', false);
|
||||
const DefaultRecommendedExtensionsContext = new RawContextKey<boolean>('defaultRecommendedExtensions', false);
|
||||
const GroupByServersContext = new RawContextKey<boolean>('groupByServersContext', false);
|
||||
const viewIdNameMappings: { [id: string]: string } = {
|
||||
'extensions.listView': localize('marketPlace', "Marketplace"),
|
||||
'extensions.enabledExtensionList': localize('enabledExtensions', "Enabled"),
|
||||
@@ -92,10 +94,10 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
private registerViews(): void {
|
||||
let viewDescriptors: IViewDescriptor[] = [];
|
||||
viewDescriptors.push(this.createMarketPlaceExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createEnabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDisabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDefaultEnabledExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createDefaultDisabledExtensionsListViewDescriptor());
|
||||
// {{SQL CARBON EDIT}}
|
||||
// viewDescriptors.push(this.createPopularExtensionsListViewDescriptor());
|
||||
// viewDescriptors.push(this.createDefaultPopularExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInBasicsExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createBuiltInThemesExtensionsListViewDescriptor());
|
||||
@@ -103,8 +105,8 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
viewDescriptors.push(this.createOtherRecommendedExtensionsListViewDescriptor());
|
||||
viewDescriptors.push(this.createWorkspaceRecommendedExtensionsListViewDescriptor());
|
||||
|
||||
viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.localExtensionManagementServer));
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.localExtensionManagementServer));
|
||||
viewDescriptors.push(...this.createExtensionsViewDescriptorsForServer(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||
}
|
||||
|
||||
@@ -118,20 +120,20 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: ExtensionsListView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchExtensions'), ContextKeyExpr.not('searchInstalledExtensions'), ContextKeyExpr.not('searchBuiltInExtensions'), ContextKeyExpr.not('recommendedExtensions'), ContextKeyExpr.not('groupByServersContext')),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchMarketplaceExtensions')),
|
||||
weight: 100
|
||||
};
|
||||
}
|
||||
|
||||
// Separate view for enabled extensions required as we need to show enabled, disabled and recommended sections
|
||||
// in the default view when there is no search text, but user has installed extensions.
|
||||
private createEnabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
private createDefaultEnabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.enabledExtensionList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: EnabledExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.not('searchExtensions'), ContextKeyExpr.has('hasInstalledExtensions')),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')),
|
||||
weight: 40,
|
||||
canToggleVisibility: true,
|
||||
order: 1
|
||||
@@ -140,13 +142,13 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
|
||||
// Separate view for disabled extensions required as we need to show enabled, disabled and recommended sections
|
||||
// in the default view when there is no search text, but user has installed extensions.
|
||||
private createDisabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
private createDefaultDisabledExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.disabledExtensionList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: DisabledExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.not('searchExtensions'), ContextKeyExpr.has('hasInstalledExtensions')),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')),
|
||||
weight: 10,
|
||||
canToggleVisibility: true,
|
||||
order: 3,
|
||||
@@ -154,28 +156,36 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
};
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
// // Separate view for popular extensions required as we need to show popular and recommended sections
|
||||
// // in the default view when there is no search text, and user has no installed extensions.
|
||||
// private createPopularExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
// const id = 'extensions.popularExtensionsList';
|
||||
// return {
|
||||
// id,
|
||||
// name: viewIdNameMappings[id],
|
||||
// ctorDescriptor: { ctor: ExtensionsListView },
|
||||
// when: ContextKeyExpr.and(ContextKeyExpr.not('searchExtensions'), ContextKeyExpr.not('hasInstalledExtensions')),
|
||||
// weight: 60,
|
||||
// order: 1
|
||||
// };
|
||||
// }
|
||||
/* // {{SQL CARBON EDIT}}
|
||||
// Separate view for popular extensions required as we need to show popular and recommended sections
|
||||
// in the default view when there is no search text, and user has no installed extensions.
|
||||
private createDefaultPopularExtensionsListViewDescriptor(): IViewDescriptor {
|
||||
const id = 'extensions.popularExtensionsList';
|
||||
return {
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: ExtensionsListView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.not('hasInstalledExtensions')),
|
||||
weight: 60,
|
||||
order: 1
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
private createExtensionsViewDescriptorsForServer(server: IExtensionManagementServer): IViewDescriptor[] {
|
||||
return [{
|
||||
id: `server.extensionsList.${server.authority}`,
|
||||
id: `extensions.${server.authority}.installed`,
|
||||
name: server.label,
|
||||
ctorDescriptor: { ctor: GroupByServerExtensionsView },
|
||||
when: ContextKeyExpr.has('groupByServersContext'),
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('searchServerExtensions')),
|
||||
weight: 100
|
||||
}, {
|
||||
id: `extensions.${server.authority}.default`,
|
||||
name: server.label,
|
||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.notEqualsTo('')),
|
||||
weight: 40,
|
||||
order: 1
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -188,7 +198,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
||||
id,
|
||||
name: viewIdNameMappings[id],
|
||||
ctorDescriptor: { ctor: DefaultRecommendedExtensionsView },
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.not('searchExtensions'), ContextKeyExpr.has('defaultRecommendedExtensions')),
|
||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('defaultRecommendedExtensions')),
|
||||
weight: 40,
|
||||
order: 2,
|
||||
canToggleVisibility: true
|
||||
@@ -266,10 +276,11 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
|
||||
private onSearchChange: EventOf<string>;
|
||||
private nonEmptyWorkspaceContextKey: IContextKey<boolean>;
|
||||
private searchExtensionsContextKey: IContextKey<boolean>;
|
||||
private defaultViewsContextKey: IContextKey<boolean>;
|
||||
private searchMarketplaceExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchServerExtensionsContextKey: IContextKey<boolean>;
|
||||
private hasInstalledExtensionsContextKey: IContextKey<boolean>;
|
||||
private searchBuiltInExtensionsContextKey: IContextKey<boolean>;
|
||||
private groupByServersContextKey: IContextKey<boolean>;
|
||||
private recommendedExtensionsContextKey: IContextKey<boolean>;
|
||||
private defaultRecommendedExtensionsContextKey: IContextKey<boolean>;
|
||||
|
||||
@@ -304,11 +315,12 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
|
||||
this.searchDelayer = new Delayer(500);
|
||||
this.nonEmptyWorkspaceContextKey = NonEmptyWorkspaceContext.bindTo(contextKeyService);
|
||||
this.searchExtensionsContextKey = SearchExtensionsContext.bindTo(contextKeyService);
|
||||
this.defaultViewsContextKey = DefaultViewsContext.bindTo(contextKeyService);
|
||||
this.searchMarketplaceExtensionsContextKey = SearchMarketplaceExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchServerExtensionsContextKey = SearchServerExtensionsContext.bindTo(contextKeyService);
|
||||
this.hasInstalledExtensionsContextKey = HasInstalledExtensionsContext.bindTo(contextKeyService);
|
||||
this.searchBuiltInExtensionsContextKey = SearchBuiltInExtensionsContext.bindTo(contextKeyService);
|
||||
this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService);
|
||||
this.groupByServersContextKey = GroupByServersContext.bindTo(contextKeyService);
|
||||
this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService);
|
||||
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
|
||||
this.disposables.push(this.viewletService.onDidViewletOpen(this.onViewletOpen, this, this.disposables));
|
||||
@@ -393,7 +405,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
getActions(): IAction[] {
|
||||
if (!this.primaryActions) {
|
||||
this.primaryActions = [
|
||||
this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange)
|
||||
this.instantiationService.createInstance(ClearExtensionsInputAction, ClearExtensionsInputAction.ID, ClearExtensionsInputAction.LABEL, this.onSearchChange, this.searchBox.getValue())
|
||||
];
|
||||
}
|
||||
return this.primaryActions;
|
||||
@@ -455,19 +467,20 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
||||
|
||||
private doSearch(): Promise<void> {
|
||||
const value = this.normalizedQuery();
|
||||
this.searchExtensionsContextKey.set(!!value);
|
||||
this.searchBuiltInExtensionsContextKey.set(ExtensionsListView.isBuiltInExtensionsQuery(value));
|
||||
this.groupByServersContextKey.set(ExtensionsListView.isGroupByServersExtensionsQuery(value));
|
||||
this.recommendedExtensionsContextKey.set(ExtensionsListView.isRecommendedExtensionsQuery(value));
|
||||
this.defaultViewsContextKey.set(!value);
|
||||
const isServerExtensionsQuery = ExtensionsListView.isServerExtensionsQuery(value);
|
||||
const isBuiltInExtensionsQuery = ExtensionsListView.isBuiltInExtensionsQuery(value);
|
||||
const isRecommendedExtensionsQuery = ExtensionsListView.isRecommendedExtensionsQuery(value);
|
||||
this.searchServerExtensionsContextKey.set(isServerExtensionsQuery);
|
||||
this.searchBuiltInExtensionsContextKey.set(isBuiltInExtensionsQuery);
|
||||
this.recommendedExtensionsContextKey.set(isRecommendedExtensionsQuery);
|
||||
this.searchMarketplaceExtensionsContextKey.set(!!value && !isServerExtensionsQuery && !isBuiltInExtensionsQuery && !isRecommendedExtensionsQuery);
|
||||
this.nonEmptyWorkspaceContextKey.set(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY);
|
||||
|
||||
if (value) {
|
||||
return this.progress(Promise.all(this.panels.map(view =>
|
||||
(<ExtensionsListView>view).show(this.normalizedQuery())
|
||||
.then(model => this.alertSearchResult(model.length, view.id))
|
||||
))).then(() => undefined);
|
||||
}
|
||||
return Promise.resolve();
|
||||
return this.progress(Promise.all(this.panels.map(view =>
|
||||
(<ExtensionsListView>view).show(this.normalizedQuery())
|
||||
.then(model => this.alertSearchResult(model.length, view.id))
|
||||
))).then(() => undefined);
|
||||
}
|
||||
|
||||
protected onDidAddViews(added: IAddedViewDescriptorRef[]): ViewletPanel[] {
|
||||
@@ -565,7 +578,8 @@ export class StatusUpdater implements IWorkbenchContribution {
|
||||
|
||||
constructor(
|
||||
@IActivityService private readonly activityService: IActivityService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
|
||||
) {
|
||||
extensionsWorkbenchService.onChange(this.onServiceChange, this, this.disposables);
|
||||
}
|
||||
@@ -579,7 +593,7 @@ export class StatusUpdater implements IWorkbenchContribution {
|
||||
return;
|
||||
}
|
||||
|
||||
const outdated = this.extensionsWorkbenchService.local.reduce((r, e) => r + (e.outdated && e.enablementState !== EnablementState.Disabled && e.enablementState !== EnablementState.WorkspaceDisabled ? 1 : 0), 0);
|
||||
const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) ? 1 : 0), 0);
|
||||
if (outdated > 0) {
|
||||
const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n));
|
||||
this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge');
|
||||
|
||||
@@ -9,7 +9,7 @@ import { assign } from 'vs/base/common/objects';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { PagedModel, IPagedModel, IPager, DelayedPagedModel } from 'vs/base/common/paging';
|
||||
import { SortBy, SortOrder, IQueryOptions, IExtensionTipsService, IExtensionRecommendation } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { SortBy, SortOrder, IQueryOptions, IExtensionTipsService, IExtensionRecommendation, IExtensionManagementServer } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -45,6 +45,9 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
class ExtensionsViewState extends Disposable implements IExtensionsViewState {
|
||||
|
||||
@@ -63,8 +66,13 @@ class ExtensionsViewState extends Disposable implements IExtensionsViewState {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ExtensionsListViewOptions extends IViewletViewOptions {
|
||||
server?: IExtensionManagementServer;
|
||||
}
|
||||
|
||||
export class ExtensionsListView extends ViewletPanel {
|
||||
|
||||
private readonly server: IExtensionManagementServer | undefined;
|
||||
private messageBox: HTMLElement;
|
||||
private extensionsList: HTMLElement;
|
||||
private badge: CountBadge;
|
||||
@@ -73,7 +81,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
private queryRequest: { query: string, request: CancelablePromise<IPagedModel<IExtension>> } | null;
|
||||
|
||||
constructor(
|
||||
private options: IViewletViewOptions,
|
||||
options: ExtensionsListViewOptions,
|
||||
@INotificationService protected notificationService: INotificationService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@@ -91,6 +99,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService
|
||||
) {
|
||||
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService);
|
||||
this.server = options.server;
|
||||
}
|
||||
|
||||
protected renderHeader(container: HTMLElement): void {
|
||||
@@ -98,7 +107,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
|
||||
renderHeaderTitle(container: HTMLElement): void {
|
||||
super.renderHeaderTitle(container, this.options.title);
|
||||
super.renderHeaderTitle(container, this.title);
|
||||
|
||||
this.badgeContainer = append(container, $('.count-badge-wrapper'));
|
||||
this.badge = new CountBadge(this.badgeContainer);
|
||||
@@ -233,7 +242,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
|
||||
private async queryByIds(ids: string[], options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const idsSet: Set<string> = ids.reduce((result, id) => { result.add(id.toLowerCase()); return result; }, new Set<string>());
|
||||
const result = (await this.extensionsWorkbenchService.queryLocal())
|
||||
const result = (await this.extensionsWorkbenchService.queryLocal(this.server))
|
||||
.filter(e => idsSet.has(e.identifier.id.toLowerCase()));
|
||||
|
||||
if (result.length) {
|
||||
@@ -261,7 +270,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
|
||||
value = value.replace(/@builtin/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
||||
let result = await this.extensionsWorkbenchService.queryLocal();
|
||||
let result = await this.extensionsWorkbenchService.queryLocal(this.server);
|
||||
|
||||
result = result
|
||||
.filter(e => e.type === ExtensionType.System && (e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1));
|
||||
@@ -313,7 +322,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
// Show installed extensions
|
||||
value = value.replace(/@installed/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
||||
|
||||
let result = await this.extensionsWorkbenchService.queryLocal();
|
||||
let result = await this.extensionsWorkbenchService.queryLocal(this.server);
|
||||
|
||||
result = result
|
||||
.filter(e => e.type === ExtensionType.User
|
||||
@@ -327,7 +336,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
if (/@outdated/i.test(value)) {
|
||||
value = value.replace(/@outdated/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
||||
|
||||
const local = await this.extensionsWorkbenchService.queryLocal();
|
||||
const local = await this.extensionsWorkbenchService.queryLocal(this.server);
|
||||
const result = local
|
||||
.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName))
|
||||
.filter(extension => extension.outdated
|
||||
@@ -340,7 +349,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
if (/@disabled/i.test(value)) {
|
||||
value = value.replace(/@disabled/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase();
|
||||
|
||||
const local = await this.extensionsWorkbenchService.queryLocal();
|
||||
const local = await this.extensionsWorkbenchService.queryLocal(this.server);
|
||||
const runningExtensions = await this.extensionService.getExtensions();
|
||||
|
||||
const result = local
|
||||
@@ -355,7 +364,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
if (/@enabled/i.test(value)) {
|
||||
value = value ? value.replace(/@enabled/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase() : '';
|
||||
|
||||
const local = (await this.extensionsWorkbenchService.queryLocal()).filter(e => e.type === ExtensionType.User);
|
||||
const local = (await this.extensionsWorkbenchService.queryLocal(this.server)).filter(e => e.type === ExtensionType.User);
|
||||
const runningExtensions = await this.extensionService.getExtensions();
|
||||
|
||||
const result = local
|
||||
@@ -485,7 +494,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
private getAllRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const value = query.value.replace(/@recommended:all/g, '').replace(/@recommended/g, '').trim().toLowerCase();
|
||||
|
||||
return this.extensionsWorkbenchService.queryLocal()
|
||||
return this.extensionsWorkbenchService.queryLocal(this.server)
|
||||
.then(result => result.filter(e => e.type === ExtensionType.User))
|
||||
.then(local => {
|
||||
const fileBasedRecommendations = this.tipsService.getFileBasedRecommendations();
|
||||
@@ -540,7 +549,7 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
private getRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
|
||||
const value = query.value.replace(/@recommended/g, '').trim().toLowerCase();
|
||||
|
||||
return this.extensionsWorkbenchService.queryLocal()
|
||||
return this.extensionsWorkbenchService.queryLocal(this.server)
|
||||
.then(result => result.filter(e => e.type === ExtensionType.User))
|
||||
.then(local => {
|
||||
let fileBasedRecommendations = this.tipsService.getFileBasedRecommendations();
|
||||
@@ -780,8 +789,8 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
return /@installed|@outdated|@enabled|@disabled/i.test(query);
|
||||
}
|
||||
|
||||
static isGroupByServersExtensionsQuery(query: string): boolean {
|
||||
return !!Query.parse(query).groupBy;
|
||||
static isServerExtensionsQuery(query: string): boolean {
|
||||
return /@installed|@outdated/i.test(query);
|
||||
}
|
||||
|
||||
static isRecommendedExtensionsQuery(query: string): boolean {
|
||||
@@ -818,10 +827,40 @@ export class ExtensionsListView extends ViewletPanel {
|
||||
}
|
||||
}
|
||||
|
||||
export class GroupByServerExtensionsView extends ExtensionsListView {
|
||||
function getServerLabel(server: IExtensionManagementServer, labelService: ILabelService, workbenchEnvironmentService: IWorkbenchEnvironmentService): string {
|
||||
return workbenchEnvironmentService.configuration.remoteAuthority === server.authority ? labelService.getHostLabel(REMOTE_HOST_SCHEME, server.authority) || server.label : server.label;
|
||||
}
|
||||
|
||||
export class ServerExtensionsView extends ExtensionsListView {
|
||||
|
||||
constructor(
|
||||
server: IExtensionManagementServer,
|
||||
options: ExtensionsListViewOptions,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IExtensionTipsService tipsService: IExtensionTipsService,
|
||||
@IModeService modeService: IModeService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IExperimentService experimentService: IExperimentService,
|
||||
@IWorkbenchThemeService workbenchThemeService: IWorkbenchThemeService,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@ILabelService labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
options.title = getServerLabel(server, labelService, workbenchEnvironmentService);
|
||||
options.server = server;
|
||||
super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, modeService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService);
|
||||
this.disposables.push(labelService.onDidChangeFormatters(() => this.updateTitle(getServerLabel(server, labelService, workbenchEnvironmentService))));
|
||||
}
|
||||
|
||||
async show(query: string): Promise<IPagedModel<IExtension>> {
|
||||
query = query.replace(/@group:server/g, '').trim();
|
||||
query = query ? query : '@installed';
|
||||
if (!ExtensionsListView.isInstalledExtensionsQuery(query) && !ExtensionsListView.isBuiltInExtensionsQuery(query)) {
|
||||
query = query += ' @installed';
|
||||
|
||||
@@ -16,7 +16,7 @@ import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
|
||||
private _extension: IExtension;
|
||||
@@ -205,7 +205,7 @@ export class RemoteBadgeWidget extends ExtensionWidget {
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||
@IWindowService private readonly windowService: IWindowService
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
super();
|
||||
this.render();
|
||||
@@ -222,11 +222,10 @@ export class RemoteBadgeWidget extends ExtensionWidget {
|
||||
|
||||
render(): void {
|
||||
this.clear();
|
||||
if (!this.extension || !this.extension.local) {
|
||||
if (!this.extension || !this.extension.local || !this.extension.server) {
|
||||
return;
|
||||
}
|
||||
const server = this.extensionManagementServerService.getExtensionManagementServer(this.extension.local.location);
|
||||
if (server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.element = append(this.parent, $('div.extension-remote-badge'));
|
||||
append(this.element, $('span.octicon.octicon-file-symlink-directory'));
|
||||
|
||||
@@ -245,7 +244,7 @@ export class RemoteBadgeWidget extends ExtensionWidget {
|
||||
|
||||
const updateTitle = () => {
|
||||
if (this.element) {
|
||||
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.windowService.getConfiguration().remoteAuthority));
|
||||
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority));
|
||||
}
|
||||
};
|
||||
this.labelService.onDidChangeFormatters(() => updateTitle(), this, this.disposables);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
.monaco-action-bar .action-item.disabled .action-label.extension-action.extension-editor-dropdown-action,
|
||||
.monaco-action-bar .action-item.disabled .action-label.extension-action.reload,
|
||||
.monaco-action-bar .action-item.disabled .action-label.disable-status.hide,
|
||||
.monaco-action-bar .action-item.disabled .action-label.disable-warning.hide,
|
||||
.monaco-action-bar .action-item.disabled .action-label.extension-status-label.hide,
|
||||
.monaco-action-bar .action-item.disabled .action-label.malicious-status.not-malicious {
|
||||
display: none;
|
||||
@@ -61,6 +62,29 @@
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .actions > .monaco-action-bar > .actions-container > .action-item > .action-label.disable-status {
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.extension-editor > .header > .details > .actions > .monaco-action-bar > .actions-container > .action-item > .action-label.disable-warning,
|
||||
.extensions-viewlet>.extensions .extension>.details>.footer>.monaco-action-bar .action-item .action-label.disable-warning {
|
||||
cursor: default;
|
||||
margin: 0.1em;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .action-label.disable-warning.icon {
|
||||
opacity: 1;
|
||||
height: 18px;
|
||||
width: 10px;
|
||||
background: url('status-warning.svg') center center no-repeat;
|
||||
margin-top: 0.15em
|
||||
}
|
||||
|
||||
.vs-dark .monaco-action-bar .action-item .action-label.disable-warning.icon {
|
||||
background: url('status-warning-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.extension-status-label,
|
||||
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.disable-status,
|
||||
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.malicious-status {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" height="16" width="16"><path fill="#1E1E1E" d="M7.5 2L2 12l2 2h9l2-2L9.5 2z"/><path d="M9 3H8l-4.5 9 1 1h8l1-1L9 3zm0 9H8v-1h1v1zm0-2H8V6h1v4z" fill="#fc0"/><path d="M9 10H8V6h1v4zm0 1H8v1h1v-1z"/></svg>
|
||||
|
After Width: | Height: | Size: 263 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path fill="#F6F6F6" d="M7.5 2L2 12l2 2h9l2-2L9.5 2z"/><path d="M9 3H8l-4.5 9 1 1h8l1-1L9 3zm0 9H8v-1h1v1zm0-2H8V6h1v4z" fill="#fc0"/><path d="M9 10H8V6h1v4zm0 1H8v1h1v-1z"/></svg>
|
||||
|
After Width: | Height: | Size: 297 B |
@@ -43,6 +43,7 @@ import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
|
||||
import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { SlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
export const IExtensionHostProfileService = createDecorator<IExtensionHostProfileService>('extensionHostProfileService');
|
||||
export const CONTEXT_PROFILE_SESSION_STATE = new RawContextKey<string>('profileSessionState', 'none');
|
||||
@@ -119,7 +120,7 @@ export class RuntimeExtensionsEditor extends BaseEditor {
|
||||
@IExtensionHostProfileService private readonly _extensionHostProfileService: IExtensionHostProfileService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@IWindowService private readonly _windowService: IWindowService
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
super(RuntimeExtensionsEditor.ID, telemetryService, themeService, storageService);
|
||||
|
||||
@@ -381,7 +382,7 @@ export class RuntimeExtensionsEditor extends BaseEditor {
|
||||
el.innerHTML = renderOcticons(`$(rss) ${element.description.extensionLocation.authority}`);
|
||||
data.msgContainer.appendChild(el);
|
||||
|
||||
const hostLabel = this._labelService.getHostLabel(REMOTE_HOST_SCHEME, this._windowService.getConfiguration().remoteAuthority);
|
||||
const hostLabel = this._labelService.getHostLabel(REMOTE_HOST_SCHEME, this._environmentService.configuration.remoteAuthority);
|
||||
if (hostLabel) {
|
||||
el.innerHTML = renderOcticons(`$(rss) ${hostLabel}`);
|
||||
}
|
||||
|
||||
@@ -9,15 +9,15 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { index, distinct } from 'vs/base/common/arrays';
|
||||
import { ThrottledDelayer } from 'vs/base/common/async';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
// {{SQL CARBON EDIT}}
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions,
|
||||
InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, IExtensionManagementServerService, INSTALL_ERROR_INCOMPATIBLE
|
||||
InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, INSTALL_ERROR_INCOMPATIBLE
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
@@ -37,7 +37,6 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, IExtension as IPlatformExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
|
||||
@@ -55,6 +54,7 @@ class Extension implements IExtension {
|
||||
constructor(
|
||||
private galleryService: IExtensionGalleryService,
|
||||
private stateProvider: IExtensionStateProvider<ExtensionState>,
|
||||
public readonly server: IExtensionManagementServer | undefined,
|
||||
public local: ILocalExtension | undefined,
|
||||
public gallery: IGalleryExtension | undefined,
|
||||
private telemetryService: ITelemetryService,
|
||||
@@ -370,14 +370,179 @@ class ExtensionDependencies implements IExtensionDependencies {
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService, IURLHandler {
|
||||
class Extensions extends Disposable {
|
||||
|
||||
private static readonly SyncPeriod = 1000 * 60 * 60 * 12; // 12 hours
|
||||
_serviceBrand: any;
|
||||
private stateProvider: IExtensionStateProvider<ExtensionState>;
|
||||
private readonly _onChange: Emitter<Extension | undefined> = new Emitter<Extension | undefined>();
|
||||
get onChange(): Event<Extension | undefined> { return this._onChange.event; }
|
||||
|
||||
private readonly stateProvider: IExtensionStateProvider<ExtensionState>;
|
||||
private installing: Extension[] = [];
|
||||
private uninstalling: Extension[] = [];
|
||||
private installed: Extension[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly server: IExtensionManagementServer,
|
||||
@IExtensionGalleryService private readonly galleryService: IExtensionGalleryService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
|
||||
) {
|
||||
super();
|
||||
this.stateProvider = ext => this.getExtensionState(ext);
|
||||
this._register(server.extensionManagementService.onInstallExtension(e => this.onInstallExtension(e)));
|
||||
this._register(server.extensionManagementService.onDidInstallExtension(e => this.onDidInstallExtension(e)));
|
||||
this._register(server.extensionManagementService.onUninstallExtension(e => this.onUninstallExtension(e)));
|
||||
this._register(server.extensionManagementService.onDidUninstallExtension(e => this.onDidUninstallExtension(e)));
|
||||
this._register(extensionEnablementService.onEnablementChanged(e => this.onEnablementChanged(e)));
|
||||
}
|
||||
|
||||
get local(): IExtension[] {
|
||||
const installing = this.installing
|
||||
.filter(e => !this.installed.some(installed => areSameExtensions(installed.identifier, e.identifier)))
|
||||
.map(e => e);
|
||||
|
||||
return [...this.installed, ...installing];
|
||||
}
|
||||
|
||||
async queryInstalled(): Promise<IExtension[]> {
|
||||
const installed = await this.server.extensionManagementService.getInstalled();
|
||||
const byId = index(this.installed, e => e.identifier.id);
|
||||
this.installed = installed.map(local => {
|
||||
const extension = byId[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, this.server, local, undefined, this.telemetryService, this.logService, this.fileService);
|
||||
extension.local = local;
|
||||
extension.enablementState = this.extensionEnablementService.getEnablementState(local);
|
||||
return extension;
|
||||
});
|
||||
this._onChange.fire(undefined);
|
||||
return this.local;
|
||||
}
|
||||
|
||||
async syncLocalWithGalleryExtension(gallery: IGalleryExtension, maliciousExtensionSet: Set<string>): Promise<boolean> {
|
||||
const extension = this.getInstalledExtensionMatchingGallery(gallery);
|
||||
if (!extension) {
|
||||
return false;
|
||||
}
|
||||
if (maliciousExtensionSet.has(extension.identifier.id)) {
|
||||
extension.isMalicious = true;
|
||||
}
|
||||
// Loading the compatible version only there is an engine property
|
||||
// Otherwise falling back to old way so that we will not make many roundtrips
|
||||
const compatible = gallery.properties.engine ? await this.galleryService.getCompatibleExtension(gallery) : gallery;
|
||||
if (!compatible) {
|
||||
return false;
|
||||
}
|
||||
// Sync the local extension with gallery extension if local extension doesnot has metadata
|
||||
if (extension.local) {
|
||||
const local = extension.local.metadata ? extension.local : await this.server.extensionManagementService.updateMetadata(extension.local, { id: compatible.identifier.uuid, publisherDisplayName: compatible.publisherDisplayName, publisherId: compatible.publisherId });
|
||||
extension.local = local;
|
||||
extension.gallery = compatible;
|
||||
this._onChange.fire(extension);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private getInstalledExtensionMatchingGallery(gallery: IGalleryExtension): Extension | null {
|
||||
for (const installed of this.installed) {
|
||||
if (installed.uuid) { // Installed from Gallery
|
||||
if (installed.uuid === gallery.identifier.uuid) {
|
||||
return installed;
|
||||
}
|
||||
} else {
|
||||
if (areSameExtensions(installed.identifier, gallery.identifier)) { // Installed from other sources
|
||||
return installed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private onInstallExtension(event: InstallExtensionEvent): void {
|
||||
const { gallery } = event;
|
||||
if (gallery) {
|
||||
const extension = this.installed.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0]
|
||||
|| new Extension(this.galleryService, this.stateProvider, this.server, undefined, gallery, this.telemetryService, this.logService, this.fileService);
|
||||
this.installing.push(extension);
|
||||
this._onChange.fire(extension);
|
||||
}
|
||||
}
|
||||
|
||||
private onDidInstallExtension(event: DidInstallExtensionEvent): void {
|
||||
const { local, zipPath, error, gallery } = event;
|
||||
const installingExtension = gallery ? this.installing.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0] : null;
|
||||
this.installing = installingExtension ? this.installing.filter(e => e !== installingExtension) : this.installing;
|
||||
|
||||
let extension: Extension | undefined = installingExtension ? installingExtension : zipPath ? new Extension(this.galleryService, this.stateProvider, this.server, local, undefined, this.telemetryService, this.logService, this.fileService) : undefined;
|
||||
if (extension) {
|
||||
if (local) {
|
||||
const installed = this.installed.filter(e => areSameExtensions(e.identifier, extension!.identifier))[0];
|
||||
if (installed) {
|
||||
extension = installed;
|
||||
} else {
|
||||
this.installed.push(extension);
|
||||
}
|
||||
extension.local = local;
|
||||
if (!extension.gallery) {
|
||||
extension.gallery = gallery;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._onChange.fire(error ? undefined : extension);
|
||||
}
|
||||
|
||||
private onUninstallExtension(identifier: IExtensionIdentifier): void {
|
||||
const extension = this.installed.filter(e => areSameExtensions(e.identifier, identifier))[0];
|
||||
if (extension) {
|
||||
const uninstalling = this.uninstalling.filter(e => areSameExtensions(e.identifier, identifier))[0] || extension;
|
||||
this.uninstalling = [uninstalling, ...this.uninstalling.filter(e => !areSameExtensions(e.identifier, identifier))];
|
||||
this._onChange.fire(uninstalling);
|
||||
}
|
||||
}
|
||||
|
||||
private onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void {
|
||||
if (!error) {
|
||||
this.installed = this.installed.filter(e => !areSameExtensions(e.identifier, identifier));
|
||||
}
|
||||
const uninstalling = this.uninstalling.filter(e => areSameExtensions(e.identifier, identifier))[0];
|
||||
this.uninstalling = this.uninstalling.filter(e => !areSameExtensions(e.identifier, identifier));
|
||||
if (uninstalling) {
|
||||
this._onChange.fire(uninstalling);
|
||||
}
|
||||
}
|
||||
|
||||
private onEnablementChanged(platformExtensions: IPlatformExtension[]) {
|
||||
const extensions = this.local.filter(e => platformExtensions.some(p => areSameExtensions(e.identifier, p.identifier)));
|
||||
for (const extension of extensions) {
|
||||
if (extension.local) {
|
||||
const enablementState = this.extensionEnablementService.getEnablementState(extension.local);
|
||||
if (enablementState !== extension.enablementState) {
|
||||
(extension as Extension).enablementState = enablementState;
|
||||
this._onChange.fire(extension as Extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getExtensionState(extension: Extension): ExtensionState {
|
||||
if (extension.gallery && this.installing.some(e => !!e.gallery && areSameExtensions(e.gallery.identifier, extension.gallery!.identifier))) {
|
||||
return ExtensionState.Installing;
|
||||
}
|
||||
if (this.uninstalling.some(e => areSameExtensions(e.identifier, extension.identifier))) {
|
||||
return ExtensionState.Uninstalling;
|
||||
}
|
||||
const local = this.installed.filter(e => e === extension || (e.gallery && extension.gallery && areSameExtensions(e.gallery.identifier, extension.gallery.identifier)))[0];
|
||||
return local ? ExtensionState.Installed : ExtensionState.Uninstalled;
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtensionsWorkbenchService extends Disposable implements IExtensionsWorkbenchService, IURLHandler {
|
||||
|
||||
private static readonly SyncPeriod = 1000 * 60 * 60 * 12; // 12 hours
|
||||
_serviceBrand: any;
|
||||
|
||||
private readonly localExtensions: Extensions;
|
||||
private readonly remoteExtensions: Extensions | null;
|
||||
private syncDelayer: ThrottledDelayer<void>;
|
||||
private autoUpdateDelayer: ThrottledDelayer<void>;
|
||||
private disposables: IDisposable[] = [];
|
||||
@@ -404,13 +569,15 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
) {
|
||||
this.stateProvider = ext => this.getExtensionState(ext);
|
||||
|
||||
extensionService.onInstallExtension(this.onInstallExtension, this, this.disposables);
|
||||
extensionService.onDidInstallExtension(this.onDidInstallExtension, this, this.disposables);
|
||||
extensionService.onUninstallExtension(this.onUninstallExtension, this, this.disposables);
|
||||
extensionService.onDidUninstallExtension(this.onDidUninstallExtension, this, this.disposables);
|
||||
extensionEnablementService.onEnablementChanged(this.onEnablementChanged, this, this.disposables);
|
||||
super();
|
||||
this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer));
|
||||
this._register(this.localExtensions.onChange(e => this._onChange.fire(e)));
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.remoteExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.remoteExtensionManagementServer));
|
||||
this._register(this.remoteExtensions.onChange(e => this._onChange.fire(e)));
|
||||
} else {
|
||||
this.remoteExtensions = null;
|
||||
}
|
||||
|
||||
this.syncDelayer = new ThrottledDelayer<void>(ExtensionsWorkbenchService.SyncPeriod);
|
||||
this.autoUpdateDelayer = new ThrottledDelayer<void>(1000);
|
||||
@@ -438,29 +605,40 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
}
|
||||
|
||||
get local(): IExtension[] {
|
||||
const installing = this.installing
|
||||
.filter(e => !this.installed.some(installed => areSameExtensions(installed.identifier, e.identifier)))
|
||||
.map(e => e);
|
||||
|
||||
return [...this.installed, ...installing];
|
||||
const result = [...this.localExtensions.local];
|
||||
if (!this.remoteExtensions) {
|
||||
return result;
|
||||
}
|
||||
result.push(...this.remoteExtensions.local);
|
||||
const byId = groupByExtension(result, r => r.identifier);
|
||||
return byId.reduce((result, extensions) => { result.push(this.getPrimaryExtension(extensions)); return result; }, []);
|
||||
}
|
||||
|
||||
queryLocal(): Promise<IExtension[]> {
|
||||
return this.extensionService.getInstalled()
|
||||
.then(installed => {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
installed = installed.filter(installed => this.belongsToWindow(installed));
|
||||
}
|
||||
const installedById = index(this.installed, e => e.identifier.id);
|
||||
this.installed = installed.map(local => {
|
||||
const extension = installedById[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, local, undefined, this.telemetryService, this.logService, this.fileService);
|
||||
extension.enablementState = this.extensionEnablementService.getEnablementState(local);
|
||||
return extension;
|
||||
});
|
||||
get outdated(): IExtension[] {
|
||||
const allLocal = [...this.localExtensions.local];
|
||||
if (this.remoteExtensions) {
|
||||
allLocal.push(...this.remoteExtensions.local);
|
||||
}
|
||||
return allLocal.filter(e => e.outdated && e.local && e.state === ExtensionState.Installed);
|
||||
}
|
||||
|
||||
this._onChange.fire(undefined);
|
||||
return this.local;
|
||||
});
|
||||
async queryLocal(server?: IExtensionManagementServer): Promise<IExtension[]> {
|
||||
if (server) {
|
||||
if (this.extensionManagementServerService.localExtensionManagementServer === server) {
|
||||
return this.localExtensions.queryInstalled();
|
||||
}
|
||||
if (this.remoteExtensions && this.extensionManagementServerService.remoteExtensionManagementServer === server) {
|
||||
return this.remoteExtensions.queryInstalled();
|
||||
}
|
||||
}
|
||||
|
||||
await this.localExtensions.queryInstalled();
|
||||
if (this.remoteExtensions) {
|
||||
await Promise.all([this.localExtensions.queryInstalled(), this.remoteExtensions.queryInstalled()]);
|
||||
} else {
|
||||
await this.localExtensions.queryInstalled();
|
||||
}
|
||||
return this.local;
|
||||
}
|
||||
|
||||
queryGallery(token: CancellationToken): Promise<IPager<IExtension>>;
|
||||
@@ -509,50 +687,41 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
return Promise.resolve(this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension), undefined, sideByside ? SIDE_GROUP : ACTIVE_GROUP));
|
||||
}
|
||||
|
||||
private belongsToWindow(extension: ILocalExtension): boolean {
|
||||
if (!this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
return true;
|
||||
private getPrimaryExtension(extensions: IExtension[]): IExtension {
|
||||
if (extensions.length === 1) {
|
||||
return extensions[0];
|
||||
}
|
||||
const extensionManagementServer = this.extensionManagementServerService.getExtensionManagementServer(extension.location);
|
||||
if (isUIExtension(extension.manifest, this.configurationService)) {
|
||||
if (this.extensionManagementServerService.localExtensionManagementServer === extensionManagementServer) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (this.extensionManagementServerService.remoteExtensionManagementServer === extensionManagementServer) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
const pickRemoteOrFirstExtension = (from: IExtension[]): IExtension => {
|
||||
const remoteExtension = from.filter(e => e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0];
|
||||
return remoteExtension ? remoteExtension : from[0];
|
||||
};
|
||||
const enabledExtensions = extensions.filter(e => e.local && this.extensionEnablementService.isEnabled(e.local));
|
||||
return enabledExtensions.length === 1 ? enabledExtensions[0] : pickRemoteOrFirstExtension(extensions);
|
||||
}
|
||||
|
||||
private fromGallery(gallery: IGalleryExtension, maliciousExtensionSet: Set<string>): Extension {
|
||||
let result = this.getInstalledExtensionMatchingGallery(gallery);
|
||||
private fromGallery(gallery: IGalleryExtension, maliciousExtensionSet: Set<string>): IExtension {
|
||||
Promise.all([this.localExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet), this.remoteExtensions ? this.localExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet) : Promise.resolve(false)])
|
||||
.then(result => {
|
||||
if (result[0] || result[1]) {
|
||||
this.eventuallyAutoUpdateExtensions();
|
||||
}
|
||||
});
|
||||
|
||||
if (result) {
|
||||
// Loading the compatible version only there is an engine property
|
||||
// Otherwise falling back to old way so that we will not make many roundtrips
|
||||
if (gallery.properties.engine) {
|
||||
this.galleryService.getCompatibleExtension(gallery)
|
||||
.then(compatible => compatible ? this.syncLocalWithGalleryExtension(result!, compatible) : null);
|
||||
} else {
|
||||
this.syncLocalWithGalleryExtension(result, gallery);
|
||||
}
|
||||
} else {
|
||||
result = new Extension(this.galleryService, this.stateProvider, undefined, gallery, this.telemetryService, this.logService, this.fileService);
|
||||
const installed = this.getInstalledExtensionMatchingGallery(gallery);
|
||||
if (installed) {
|
||||
return installed;
|
||||
}
|
||||
|
||||
if (maliciousExtensionSet.has(result.identifier.id)) {
|
||||
result.isMalicious = true;
|
||||
const extension = new Extension(this.galleryService, ext => this.getExtensionState(ext), undefined, undefined, gallery, this.telemetryService, this.logService, this.fileService);
|
||||
if (maliciousExtensionSet.has(extension.identifier.id)) {
|
||||
extension.isMalicious = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
return extension;
|
||||
}
|
||||
|
||||
private getInstalledExtensionMatchingGallery(gallery: IGalleryExtension): Extension | null {
|
||||
for (const installed of this.installed) {
|
||||
if (installed.uuid) { // Installed from Gallery
|
||||
if (installed.uuid === gallery.identifier.uuid) {
|
||||
private getInstalledExtensionMatchingGallery(gallery: IGalleryExtension): IExtension | null {
|
||||
for (const installed of this.local) {
|
||||
if (installed.identifier.uuid) { // Installed from Gallery
|
||||
if (installed.identifier.uuid === gallery.identifier.uuid) {
|
||||
return installed;
|
||||
}
|
||||
} else {
|
||||
@@ -564,19 +733,14 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
return null;
|
||||
}
|
||||
|
||||
private syncLocalWithGalleryExtension(extension: Extension, gallery: IGalleryExtension) {
|
||||
// Sync the local extension with gallery extension if local extension doesnot has metadata
|
||||
if (extension.local) {
|
||||
(extension.local.metadata ? Promise.resolve(extension.local) : this.extensionService.updateMetadata(extension.local, { id: gallery.identifier.uuid, publisherDisplayName: gallery.publisherDisplayName, publisherId: gallery.publisherId }))
|
||||
.then(local => {
|
||||
extension.local = local;
|
||||
extension.gallery = gallery;
|
||||
this._onChange.fire(extension);
|
||||
this.eventuallyAutoUpdateExtensions();
|
||||
});
|
||||
} else {
|
||||
this._onChange.fire(extension);
|
||||
private getExtensionState(extension: Extension): ExtensionState {
|
||||
if (this.remoteExtensions) {
|
||||
const state = this.remoteExtensions.getExtensionState(extension);
|
||||
if (state !== ExtensionState.Uninstalled) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
return this.localExtensions.getExtensionState(extension);
|
||||
}
|
||||
|
||||
checkForUpdates(): Promise<void> {
|
||||
@@ -602,10 +766,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
|
||||
private syncWithGallery(): Promise<void> {
|
||||
const ids: string[] = [], names: string[] = [];
|
||||
for (const installed of this.installed) {
|
||||
for (const installed of this.local) {
|
||||
if (installed.type === ExtensionType.User) {
|
||||
if (installed.uuid) {
|
||||
ids.push(installed.uuid);
|
||||
if (installed.identifier.uuid) {
|
||||
ids.push(installed.identifier.uuid);
|
||||
} else {
|
||||
names.push(installed.identifier.id);
|
||||
}
|
||||
@@ -634,9 +798,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}} - Add && !e.downloadPage condition
|
||||
const toUpdate = this.local.filter(e =>
|
||||
e.outdated && e.state !== ExtensionState.Installing
|
||||
&& e.local && !this.isAutoUpdateIgnored(new ExtensionIdentifierWithVersion(e.identifier, e.version)) && !e.downloadPage);
|
||||
const toUpdate = this.outdated.filter(e => !this.isAutoUpdateIgnored(new ExtensionIdentifierWithVersion(e.identifier, e.version)) && !e.downloadPage);
|
||||
return Promise.all(toUpdate.map(e => this.install(e)));
|
||||
}
|
||||
|
||||
@@ -689,7 +851,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
// The check is added here because we want to fail fast instead of downloading the VSIX and then fail.
|
||||
if (gallery.properties.engine && (!isEngineValid(gallery.properties.engine, product.vscodeVersion)
|
||||
|| (gallery.properties.azDataEngine && !isEngineValid(gallery.properties.azDataEngine, pkg.version)))) {
|
||||
return Promise.reject(new ExtensionManagementError(nls.localize('incompatible', "Unable to install version '{2}' of extension '{0}' as it is not compatible with Azure Data Studio '{1}'.", extension.gallery!.identifier.id, pkg.version, gallery.version), INSTALL_ERROR_INCOMPATIBLE));
|
||||
return Promise.reject(new ExtensionManagementError(nls.localize('incompatible2', "Unable to install version '{2}' of extension '{0}' as it is not compatible with Azure Data Studio '{1}'.", extension.gallery!.identifier.id, pkg.version, gallery.version), INSTALL_ERROR_INCOMPATIBLE));
|
||||
}
|
||||
|
||||
return this.installWithProgress(async () => {
|
||||
@@ -723,14 +885,14 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
}
|
||||
|
||||
uninstall(extension: IExtension): Promise<void> {
|
||||
const ext = extension.local ? extension : this.installed.filter(e => areSameExtensions(e.identifier, extension.identifier))[0];
|
||||
const ext = extension.local ? extension : this.local.filter(e => areSameExtensions(e.identifier, extension.identifier))[0];
|
||||
const toUninstall: ILocalExtension | null = ext && ext.local ? ext.local : null;
|
||||
|
||||
if (!toUninstall) {
|
||||
return Promise.reject(new Error('Missing local'));
|
||||
}
|
||||
|
||||
this.logService.info(`Requested uninstalling the extension ${extension.identifier.id} from window ${this.windowService.getCurrentWindowId()}`);
|
||||
this.logService.info(`Requested uninstalling the extension ${extension.identifier.id} from window ${this.windowService.windowId}`);
|
||||
return this.progressService.withProgress({
|
||||
location: ProgressLocation.Extensions,
|
||||
title: nls.localize('uninstallingExtension', 'Uninstalling extension....'),
|
||||
@@ -765,7 +927,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
}
|
||||
|
||||
reinstall(extension: IExtension): Promise<IExtension> {
|
||||
const ext = extension.local ? extension : this.installed.filter(e => areSameExtensions(e.identifier, extension.identifier))[0];
|
||||
const ext = extension.local ? extension : this.local.filter(e => areSameExtensions(e.identifier, extension.identifier))[0];
|
||||
const toReinstall: ILocalExtension | null = ext && ext.local ? ext.local : null;
|
||||
|
||||
if (!toReinstall) {
|
||||
@@ -925,101 +1087,6 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
|
||||
return this._extensionAllowedBadgeProviders;
|
||||
}
|
||||
|
||||
private onInstallExtension(event: InstallExtensionEvent): void {
|
||||
const { gallery } = event;
|
||||
|
||||
if (!gallery) {
|
||||
return;
|
||||
}
|
||||
|
||||
let extension = this.installed.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0];
|
||||
|
||||
if (!extension) {
|
||||
extension = new Extension(this.galleryService, this.stateProvider, undefined, gallery, this.telemetryService, this.logService, this.fileService);
|
||||
}
|
||||
|
||||
this.installing.push(extension);
|
||||
|
||||
this._onChange.fire(extension);
|
||||
}
|
||||
|
||||
private onDidInstallExtension(event: DidInstallExtensionEvent): void {
|
||||
const { local, zipPath, error, gallery } = event;
|
||||
const installingExtension = gallery ? this.installing.filter(e => areSameExtensions(e.identifier, gallery.identifier))[0] : null;
|
||||
this.installing = installingExtension ? this.installing.filter(e => e !== installingExtension) : this.installing;
|
||||
|
||||
if (local && !this.belongsToWindow(local)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let extension: Extension | undefined = installingExtension ? installingExtension : zipPath ? new Extension(this.galleryService, this.stateProvider, local, undefined, this.telemetryService, this.logService, this.fileService) : undefined;
|
||||
if (extension) {
|
||||
if (local) {
|
||||
const installed = this.installed.filter(e => areSameExtensions(e.identifier, extension!.identifier))[0];
|
||||
if (installed) {
|
||||
extension = installed;
|
||||
} else {
|
||||
this.installed.push(extension);
|
||||
}
|
||||
extension.local = local;
|
||||
extension.gallery = gallery;
|
||||
}
|
||||
}
|
||||
this._onChange.fire(error ? undefined : extension);
|
||||
}
|
||||
|
||||
private onUninstallExtension(identifier: IExtensionIdentifier): void {
|
||||
const extension = this.installed.filter(e => areSameExtensions(e.identifier, identifier))[0];
|
||||
if (!extension) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uninstalling = this.uninstalling.filter(e => areSameExtensions(e.identifier, identifier))[0] || extension;
|
||||
this.uninstalling = [uninstalling, ...this.uninstalling.filter(e => !areSameExtensions(e.identifier, identifier))];
|
||||
|
||||
this._onChange.fire(uninstalling);
|
||||
}
|
||||
|
||||
private onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void {
|
||||
if (!error) {
|
||||
this.installed = this.installed.filter(e => !areSameExtensions(e.identifier, identifier));
|
||||
}
|
||||
|
||||
const uninstalling = this.uninstalling.filter(e => areSameExtensions(e.identifier, identifier))[0];
|
||||
this.uninstalling = this.uninstalling.filter(e => !areSameExtensions(e.identifier, identifier));
|
||||
if (!uninstalling) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._onChange.fire(uninstalling);
|
||||
}
|
||||
|
||||
private onEnablementChanged(platformExtensions: IPlatformExtension[]) {
|
||||
const extensions = this.local.filter(e => platformExtensions.some(p => areSameExtensions(e.identifier, p.identifier)));
|
||||
for (const extension of extensions) {
|
||||
if (extension.local) {
|
||||
const enablementState = this.extensionEnablementService.getEnablementState(extension.local);
|
||||
if (enablementState !== extension.enablementState) {
|
||||
extension.enablementState = enablementState;
|
||||
this._onChange.fire(extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getExtensionState(extension: Extension): ExtensionState {
|
||||
if (extension.gallery && this.installing.some(e => !!e.gallery && areSameExtensions(e.gallery.identifier, extension.gallery!.identifier))) {
|
||||
return ExtensionState.Installing;
|
||||
}
|
||||
|
||||
if (this.uninstalling.some(e => areSameExtensions(e.identifier, extension.identifier))) {
|
||||
return ExtensionState.Uninstalling;
|
||||
}
|
||||
|
||||
const local = this.installed.filter(e => e === extension || (e.gallery && extension.gallery && areSameExtensions(e.gallery.identifier, extension.gallery.identifier)))[0];
|
||||
return local ? ExtensionState.Installed : ExtensionState.Uninstalled;
|
||||
}
|
||||
|
||||
private onError(err: any): void {
|
||||
if (isPromiseCanceledError(err)) {
|
||||
return;
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
import * as assert from 'assert';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { IExtensionsWorkbenchService, ExtensionContainers } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import * as ExtensionsActions from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService';
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, IGalleryExtension,
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, EnablementState, InstallOperation, IExtensionManagementServerService
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, EnablementState, InstallOperation, IExtensionManagementServerService, IExtensionManagementServer
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
@@ -33,12 +33,13 @@ import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||
import { ExtensionIdentifier, IExtensionContributions, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService';
|
||||
|
||||
suite('ExtensionsActions Test', () => {
|
||||
|
||||
@@ -74,9 +75,17 @@ suite('ExtensionsActions Test', () => {
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService));
|
||||
instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService {
|
||||
private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' };
|
||||
constructor() {
|
||||
super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService));
|
||||
}
|
||||
get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; }
|
||||
set localExtensionManagementServer(server: IExtensionManagementServer) { }
|
||||
}());
|
||||
|
||||
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||
instantiationService.stub(ILabelService, { onDidChangeFormatters: new Emitter<void>().event });
|
||||
|
||||
instantiationService.set(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService));
|
||||
instantiationService.stub(IURLService, URLService);
|
||||
@@ -105,7 +114,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test Install action when state is installed', () => {
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
return workbenchService.queryLocal()
|
||||
@@ -124,7 +133,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test Install action when state is installing', () => {
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return workbenchService.queryGallery(CancellationToken.None)
|
||||
@@ -141,7 +150,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test Install action when state is uninstalled', () => {
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return workbenchService.queryGallery(CancellationToken.None)
|
||||
@@ -154,7 +163,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test Install action when extension is system action', () => {
|
||||
const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', {}, { type: ExtensionType.System });
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -169,7 +178,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test Install action when extension doesnot has gallery', () => {
|
||||
const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -184,14 +193,14 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Uninstall action is disabled when there is no extension', () => {
|
||||
const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
|
||||
assert.ok(!testObject.enabled);
|
||||
});
|
||||
|
||||
test('Test Uninstall action when state is uninstalling', () => {
|
||||
const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -207,7 +216,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test Uninstall action when state is installed and is user extension', () => {
|
||||
const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -222,7 +231,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test Uninstall action when state is installed and is system extension', () => {
|
||||
const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', {}, { type: ExtensionType.System });
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -237,7 +246,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test Uninstall action when state is installing and is user extension', () => {
|
||||
const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -254,7 +263,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test Uninstall action after extension is installed', () => {
|
||||
const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
@@ -273,7 +282,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test CombinedInstallAction when there is no extension', () => {
|
||||
const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
|
||||
assert.ok(!testObject.enabled);
|
||||
assert.equal('extension-action prominent install no-extension', testObject.class);
|
||||
@@ -281,7 +290,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test CombinedInstallAction when extension is system extension', () => {
|
||||
const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', {}, { type: ExtensionType.System });
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -296,7 +305,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test CombinedInstallAction when installAction is enabled', () => {
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
@@ -311,7 +320,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test CombinedInstallAction when unInstallAction is enabled', () => {
|
||||
const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -326,7 +335,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test CombinedInstallAction when state is installing', () => {
|
||||
const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
@@ -343,7 +352,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test CombinedInstallAction when state is installing during update', () => {
|
||||
const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -362,7 +371,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test CombinedInstallAction when state is uninstalling', () => {
|
||||
const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -378,14 +387,14 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test UpdateAction when there is no extension', () => {
|
||||
const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
|
||||
assert.ok(!testObject.enabled);
|
||||
});
|
||||
|
||||
test('Test UpdateAction when extension is uninstalled', () => {
|
||||
const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a', { version: '1.0.0' });
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
@@ -397,7 +406,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test UpdateAction when extension is installed and not outdated', () => {
|
||||
const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', { version: '1.0.0' });
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -412,7 +421,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test UpdateAction when extension is installed outdated and system extension', () => {
|
||||
const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', { version: '1.0.0' }, { type: ExtensionType.System });
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -427,7 +436,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test UpdateAction when extension is installed outdated and user extension', () => {
|
||||
const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', { version: '1.0.0' });
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -450,7 +459,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test UpdateAction when extension is installing and outdated and user extension', () => {
|
||||
const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', { version: '1.0.0' });
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -469,14 +478,14 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test ManageExtensionAction when there is no extension', () => {
|
||||
const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
|
||||
assert.ok(!testObject.enabled);
|
||||
});
|
||||
|
||||
test('Test ManageExtensionAction when extension is installed', () => {
|
||||
const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -491,7 +500,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test ManageExtensionAction when extension is uninstalled', () => {
|
||||
const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
@@ -506,7 +515,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test ManageExtensionAction when extension is installing', () => {
|
||||
const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
@@ -523,7 +532,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test ManageExtensionAction when extension is queried from gallery and installed', () => {
|
||||
const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
@@ -541,7 +550,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test ManageExtensionAction when extension is system extension', () => {
|
||||
const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', {}, { type: ExtensionType.System });
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -556,7 +565,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test ManageExtensionAction when extension is uninstalling', () => {
|
||||
const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -767,7 +776,7 @@ suite('ExtensionsActions Test', () => {
|
||||
.then(page => {
|
||||
const testObject: ExtensionsActions.EnableDropDownAction = instantiationService.createInstance(ExtensionsActions.EnableDropDownAction);
|
||||
testObject.extension = page.firstPage[0];
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
|
||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||
assert.ok(!testObject.enabled);
|
||||
@@ -951,7 +960,7 @@ suite('ExtensionsActions Test', () => {
|
||||
.then(page => {
|
||||
const testObject: ExtensionsActions.DisableDropDownAction = instantiationService.createInstance(ExtensionsActions.DisableDropDownAction, [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a') }]);
|
||||
testObject.extension = page.firstPage[0];
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||
assert.ok(!testObject.enabled);
|
||||
});
|
||||
@@ -965,7 +974,7 @@ suite('ExtensionsActions Test', () => {
|
||||
.then(extensions => {
|
||||
const testObject: ExtensionsActions.DisableDropDownAction = instantiationService.createInstance(ExtensionsActions.DisableDropDownAction, [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a') }]);
|
||||
testObject.extension = extensions[0];
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
uninstallEvent.fire(local.identifier);
|
||||
assert.ok(!testObject.enabled);
|
||||
});
|
||||
@@ -1046,14 +1055,14 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test ReloadAction when there is no extension', () => {
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
|
||||
assert.ok(!testObject.enabled);
|
||||
});
|
||||
|
||||
test('Test ReloadAction when extension state is installing', () => {
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
@@ -1068,7 +1077,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
test('Test ReloadAction when extension state is uninstalling', () => {
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -1083,7 +1092,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test ReloadAction when extension is newly installed', async () => {
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
@@ -1094,7 +1103,7 @@ suite('ExtensionsActions Test', () => {
|
||||
return new Promise(c => {
|
||||
testObject.onDidChange(() => {
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to complete the installation of this extension.') {
|
||||
if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to enable this extension.') {
|
||||
c();
|
||||
}
|
||||
});
|
||||
@@ -1106,7 +1115,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test ReloadAction when extension is installed and uninstalled', () => {
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryGallery(CancellationToken.None)
|
||||
@@ -1123,9 +1132,9 @@ suite('ExtensionsActions Test', () => {
|
||||
});
|
||||
|
||||
test('Test ReloadAction when extension is uninstalled', async () => {
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a') }]);
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a'), version: '1.0.0' }]);
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
const extensions = await instantiationService.get(IExtensionsWorkbenchService).queryLocal();
|
||||
@@ -1146,7 +1155,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test ReloadAction when extension is uninstalled and installed', () => {
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.0', extensionLocation: URI.file('pub.a') }]);
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
return instantiationService.get(IExtensionsWorkbenchService).queryLocal()
|
||||
@@ -1167,7 +1176,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test ReloadAction when extension is updated while running', async () => {
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.1', extensionLocation: URI.file('pub.a') }]);
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', { version: '1.0.1' });
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
@@ -1177,7 +1186,7 @@ suite('ExtensionsActions Test', () => {
|
||||
return new Promise(c => {
|
||||
testObject.onDidChange(() => {
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to complete the updating of this extension.') {
|
||||
if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to enable the updated extension.') {
|
||||
c();
|
||||
}
|
||||
});
|
||||
@@ -1193,7 +1202,7 @@ suite('ExtensionsActions Test', () => {
|
||||
return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled)
|
||||
.then(() => {
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
return workbenchService.queryLocal()
|
||||
@@ -1212,7 +1221,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test ReloadAction when extension is disabled when running', () => {
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), extensionLocation: URI.file('pub.a') }]);
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
@@ -1223,7 +1232,7 @@ suite('ExtensionsActions Test', () => {
|
||||
.then(() => {
|
||||
assert.ok(testObject.enabled);
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
assert.equal('Please reload Azure Data Studio to complete the disabling of this extension.', testObject.tooltip);
|
||||
assert.equal('Please reload Azure Data Studio to disable this extension.', testObject.tooltip);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1231,7 +1240,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test ReloadAction when extension enablement is toggled when running', () => {
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.0', extensionLocation: URI.file('pub.a') }]);
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a');
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
@@ -1250,7 +1259,7 @@ suite('ExtensionsActions Test', () => {
|
||||
return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled)
|
||||
.then(() => {
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
return workbenchService.queryLocal()
|
||||
@@ -1261,7 +1270,7 @@ suite('ExtensionsActions Test', () => {
|
||||
.then(() => {
|
||||
assert.ok(testObject.enabled);
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
assert.equal('Please reload Azure Data Studio to complete the enabling of this extension.', testObject.tooltip);
|
||||
assert.equal('Please reload Azure Data Studio to enable this extension.', testObject.tooltip);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1273,7 +1282,7 @@ suite('ExtensionsActions Test', () => {
|
||||
return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled)
|
||||
.then(() => {
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
return workbenchService.queryLocal()
|
||||
@@ -1292,7 +1301,7 @@ suite('ExtensionsActions Test', () => {
|
||||
return instantiationService.get(IExtensionEnablementService).setEnablement([local], EnablementState.Disabled)
|
||||
.then(() => {
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
return workbenchService.queryLocal()
|
||||
@@ -1307,7 +1316,7 @@ suite('ExtensionsActions Test', () => {
|
||||
.then(() => {
|
||||
assert.ok(testObject.enabled);
|
||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
assert.equal('Please reload Azure Data Studio to complete the enabling of this extension.', testObject.tooltip);
|
||||
assert.equal('Please reload Azure Data Studio to enable this extension.', testObject.tooltip);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1317,7 +1326,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test ReloadAction when a localization extension is newly installed', async () => {
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.b'), extensionLocation: URI.file('pub.b') }]);
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const gallery = aGalleryExtension('a');
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
|
||||
|
||||
@@ -1333,7 +1342,7 @@ suite('ExtensionsActions Test', () => {
|
||||
test('Test ReloadAction when a localization extension is updated while running', async () => {
|
||||
instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ identifier: new ExtensionIdentifier('pub.a'), version: '1.0.1', extensionLocation: URI.file('pub.a') }]);
|
||||
const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
|
||||
instantiationService.get(IExtensionsWorkbenchService).onChange(() => testObject.update());
|
||||
instantiationService.createInstance(ExtensionContainers, [testObject]);
|
||||
const local = aLocalExtension('a', { version: '1.0.1', contributes: <IExtensionContributions>{ localizations: [{ languageId: 'de', translations: [] }] } });
|
||||
const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
|
||||
@@ -37,7 +37,6 @@ import { SinonStub } from 'sinon';
|
||||
import { IExperimentService, ExperimentService, ExperimentState, ExperimentActionType } from 'vs/workbench/contrib/experiments/node/experimentService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||
import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService';
|
||||
import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
||||
|
||||
@@ -90,7 +89,11 @@ suite('ExtensionsListView Tests', () => {
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService));
|
||||
instantiationService.stub(IExtensionManagementServerService, <IExtensionManagementServerService>{
|
||||
localExtensionManagementServer: {
|
||||
extensionManagementService: instantiationService.get(IExtensionManagementService)
|
||||
}
|
||||
});
|
||||
|
||||
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
||||
@@ -77,7 +76,6 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
});
|
||||
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService));
|
||||
|
||||
instantiationService.stub(IExtensionManagementService, ExtensionManagementService);
|
||||
instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event);
|
||||
@@ -85,6 +83,12 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
instantiationService.stub(IExtensionManagementService, 'onUninstallExtension', uninstallEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
|
||||
instantiationService.stub(IExtensionManagementServerService, <IExtensionManagementServerService>{
|
||||
localExtensionManagementServer: {
|
||||
extensionManagementService: instantiationService.get(IExtensionManagementService)
|
||||
}
|
||||
});
|
||||
|
||||
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||
|
||||
instantiationService.set(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService));
|
||||
|
||||
@@ -310,6 +310,12 @@ export class FeedbackDropdown extends Dropdown {
|
||||
};
|
||||
}
|
||||
|
||||
private updateFeedbackDescription() {
|
||||
if (this.feedbackDescriptionInput && this.feedbackDescriptionInput.textLength > this.maxFeedbackCharacters) {
|
||||
this.feedbackDescriptionInput.value = this.feedbackDescriptionInput.value.substring(0, this.maxFeedbackCharacters);
|
||||
}
|
||||
}
|
||||
|
||||
private getCharCountText(charCount: number): string {
|
||||
const remaining = this.maxFeedbackCharacters - charCount;
|
||||
const text = (remaining === 1)
|
||||
@@ -349,6 +355,7 @@ export class FeedbackDropdown extends Dropdown {
|
||||
|
||||
this.sentiment = smile ? 1 : 0;
|
||||
this.maxFeedbackCharacters = this.feedbackDelegate.getCharacterLimit(this.sentiment);
|
||||
this.updateFeedbackDescription();
|
||||
this.updateCharCountText();
|
||||
if (this.feedbackDescriptionInput) {
|
||||
this.feedbackDescriptionInput.maxLength = this.maxFeedbackCharacters;
|
||||
|
||||
@@ -186,7 +186,7 @@ export class TextFileEditor extends BaseTextEditor {
|
||||
return Promise.reject(createErrorWithActions(toErrorMessage(error), {
|
||||
actions: [
|
||||
new Action('workbench.files.action.createMissingFile', nls.localize('createFile', "Create File"), undefined, true, () => {
|
||||
return this.fileService.updateContent(input.getResource(), '').then(() => this.editorService.openEditor({
|
||||
return this.textFileService.create(input.getResource()).then(() => this.editorService.openEditor({
|
||||
resource: input.getResource(),
|
||||
options: {
|
||||
pinned: true // new file gets pinned by default
|
||||
|
||||
@@ -968,6 +968,7 @@ async function openExplorerAndCreate(accessor: ServicesAccessor, isFolder: boole
|
||||
const listService = accessor.get(IListService);
|
||||
const explorerService = accessor.get(IExplorerService);
|
||||
const fileService = accessor.get(IFileService);
|
||||
const textFileService = accessor.get(ITextFileService);
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const viewletService = accessor.get(IViewletService);
|
||||
const activeViewlet = viewletService.getActiveViewlet();
|
||||
@@ -995,7 +996,7 @@ async function openExplorerAndCreate(accessor: ServicesAccessor, isFolder: boole
|
||||
folder.addChild(newStat);
|
||||
|
||||
const onSuccess = async (value: string) => {
|
||||
const createPromise = isFolder ? fileService.createFolder(resources.joinPath(folder.resource, value)) : fileService.createFile(resources.joinPath(folder.resource, value));
|
||||
const createPromise = isFolder ? fileService.createFolder(resources.joinPath(folder.resource, value)) : textFileService.create(resources.joinPath(folder.resource, value));
|
||||
return createPromise.then(created => {
|
||||
refreshIfSeparator(value, explorerService);
|
||||
return isFolder ? explorerService.select(created.resource, true)
|
||||
|
||||
@@ -40,8 +40,9 @@ import { IEditorService, SIDE_GROUP, IResourceEditorReplacement } from 'vs/workb
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { basename, toLocalResource } from 'vs/base/common/resources';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
||||
@@ -104,7 +105,8 @@ function save(
|
||||
untitledEditorService: IUntitledEditorService,
|
||||
textFileService: ITextFileService,
|
||||
editorGroupService: IEditorGroupsService,
|
||||
queryEditorService: IQueryEditorService
|
||||
queryEditorService: IQueryEditorService,
|
||||
environmentService: IWorkbenchEnvironmentService
|
||||
): Promise<any> {
|
||||
|
||||
function ensureForcedSave(options?: ISaveOptions): ISaveOptions {
|
||||
@@ -146,9 +148,9 @@ function save(
|
||||
// Special case: an untitled file with associated path gets saved directly unless "saveAs" is true
|
||||
let savePromise: Promise<URI | undefined>;
|
||||
if (!isSaveAs && resource.scheme === Schemas.untitled && untitledEditorService.hasAssociatedFilePath(resource)) {
|
||||
savePromise = textFileService.save(resource, options).then((result) => {
|
||||
savePromise = textFileService.save(resource, options).then(result => {
|
||||
if (result) {
|
||||
return resource.with({ scheme: Schemas.file });
|
||||
return toLocalResource(resource, environmentService.configuration.remoteAuthority);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@@ -165,7 +167,7 @@ function save(
|
||||
savePromise = textFileService.saveAs(resource, undefined, options);
|
||||
}
|
||||
|
||||
return savePromise.then((target) => {
|
||||
return savePromise.then(target => {
|
||||
if (!target || target.toString() === resource.toString()) {
|
||||
return false; // save canceled or same resource used
|
||||
}
|
||||
@@ -238,7 +240,7 @@ function saveAll(saveAllArguments: any, editorService: IEditorService, untitledE
|
||||
});
|
||||
|
||||
// Save all
|
||||
return textFileService.saveAll(saveAllArguments).then((result) => {
|
||||
return textFileService.saveAll(saveAllArguments).then(result => {
|
||||
groupIdToUntitledResourceInput.forEach((inputs, groupId) => {
|
||||
// {{SQL CARBON EDIT}}
|
||||
// Update untitled resources to the saved ones, so we open the proper files
|
||||
@@ -325,6 +327,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
const textModelService = accessor.get(ITextModelService);
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const fileService = accessor.get(IFileService);
|
||||
|
||||
// Register provider at first as needed
|
||||
let registerEditorListener = false;
|
||||
@@ -336,9 +339,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
providerDisposables.push(textModelService.registerTextModelContentProvider(COMPARE_WITH_SAVED_SCHEMA, provider));
|
||||
}
|
||||
|
||||
// Open editor (only files supported)
|
||||
// Open editor (only resources that can be handled by file service are supported)
|
||||
const uri = getResourceForCommand(resource, accessor.get(IListService), editorService);
|
||||
if (uri && uri.scheme === Schemas.file /* only files on disk supported for now */) {
|
||||
if (uri && fileService.canHandleResource(uri)) {
|
||||
const name = basename(uri);
|
||||
const editorLabel = nls.localize('modifiedLabel', "{0} (on disk) ↔ {1}", name, name);
|
||||
|
||||
@@ -542,7 +545,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
return save(resource, true, undefined, editorService, accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupsService), accessor.get(IQueryEditorService));
|
||||
return save(resource, true, undefined, editorService, accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupsService), accessor.get(IQueryEditorService), accessor.get(IWorkbenchEnvironmentService));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -558,7 +561,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
if (resources.length === 1) {
|
||||
// If only one resource is selected explictly call save since the behavior is a bit different than save all #41841
|
||||
// {{SQL CARBON EDIT}}
|
||||
return save(resources[0], false, undefined, editorService, accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupsService), accessor.get(IQueryEditorService));
|
||||
return save(resources[0], false, undefined, editorService, accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupsService), accessor.get(IQueryEditorService), accessor.get(IWorkbenchEnvironmentService));
|
||||
}
|
||||
return saveAll(resources, editorService, accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupsService));
|
||||
}
|
||||
@@ -576,7 +579,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
const resource = toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource) {
|
||||
// {{SQL CARBON EDIT}}
|
||||
return save(resource, false, { skipSaveParticipants: true }, editorService, accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupsService), accessor.get(IQueryEditorService));
|
||||
return save(resource, false, { skipSaveParticipants: true }, editorService, accessor.get(IFileService), accessor.get(IUntitledEditorService), accessor.get(ITextFileService), accessor.get(IEditorGroupsService), accessor.get(IQueryEditorService), accessor.get(IWorkbenchEnvironmentService));
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -32,6 +32,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export const CONFLICT_RESOLUTION_CONTEXT = 'saveConflictResolutionContext';
|
||||
export const CONFLICT_RESOLUTION_SCHEME = 'conflictResolution';
|
||||
@@ -136,13 +137,13 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
|
||||
const triedToMakeWriteable = isReadonly && fileOperationError.options && fileOperationError.options.overwriteReadonly;
|
||||
const isPermissionDenied = fileOperationError.fileOperationResult === FileOperationResult.FILE_PERMISSION_DENIED;
|
||||
|
||||
// Save Elevated
|
||||
if (isPermissionDenied || triedToMakeWriteable) {
|
||||
// Save Elevated (TODO@remote cannot write elevated https://github.com/Microsoft/vscode/issues/48659)
|
||||
if (resource.scheme === Schemas.file && (isPermissionDenied || triedToMakeWriteable)) {
|
||||
actions.primary!.push(this.instantiationService.createInstance(SaveElevatedAction, model, triedToMakeWriteable));
|
||||
}
|
||||
|
||||
// Overwrite
|
||||
else if (isReadonly) {
|
||||
// Overwrite (TODO@remote cannot overwrite readonly https://github.com/Microsoft/vscode/issues/48659)
|
||||
else if (resource.scheme === Schemas.file && isReadonly) {
|
||||
actions.primary!.push(this.instantiationService.createInstance(OverwriteReadonlyAction, model));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { localize } from 'vs/nls';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { basenameOrAuthority, dirname } from 'vs/base/common/resources';
|
||||
import { dirname } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditorModel, Verbosity, IRevertOptions } from 'vs/workbench/common/editor';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
@@ -118,7 +118,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
|
||||
|
||||
getName(): string {
|
||||
if (!this.name) {
|
||||
this.name = basenameOrAuthority(this.resource);
|
||||
this.name = basename(this.labelService.getUriLabel(this.resource));
|
||||
}
|
||||
|
||||
return this.decorateLabel(this.name);
|
||||
@@ -195,6 +195,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
|
||||
if (model && model.hasState(ModelState.ORPHAN)) {
|
||||
return localize('orphanedFile', "{0} (deleted from disk)", label);
|
||||
}
|
||||
|
||||
if (model && model.isReadonly()) {
|
||||
return localize('readonlyFile', "{0} (read-only)", label);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
|
||||
import { once } from 'vs/base/common/functional';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { toLocalResource } from 'vs/base/common/resources';
|
||||
|
||||
/**
|
||||
* Explorer viewlet id.
|
||||
@@ -138,12 +140,13 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider {
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IModeService private readonly modeService: IModeService,
|
||||
@IModelService private readonly modelService: IModelService
|
||||
@IModelService private readonly modelService: IModelService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
}
|
||||
|
||||
provideTextContent(resource: URI): Promise<ITextModel> {
|
||||
const fileOnDiskResource = resource.with({ scheme: Schemas.file });
|
||||
const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority);
|
||||
|
||||
// Make sure our file from disk is resolved up to date
|
||||
return this.resolveEditorModel(resource).then(codeEditorModel => {
|
||||
@@ -151,7 +154,7 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider {
|
||||
// Make sure to keep contents on disk up to date when it changes
|
||||
if (!this.fileWatcherDisposable) {
|
||||
this.fileWatcherDisposable = this.fileService.onFileChanges(changes => {
|
||||
if (changes.contains(fileOnDiskResource, FileChangeType.UPDATED)) {
|
||||
if (changes.contains(savedFileResource, FileChangeType.UPDATED)) {
|
||||
this.resolveEditorModel(resource, false /* do not create if missing */); // update model when resource changes
|
||||
}
|
||||
});
|
||||
@@ -171,20 +174,20 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider {
|
||||
private resolveEditorModel(resource: URI, createAsNeeded?: true): Promise<ITextModel>;
|
||||
private resolveEditorModel(resource: URI, createAsNeeded?: boolean): Promise<ITextModel | null>;
|
||||
private resolveEditorModel(resource: URI, createAsNeeded: boolean = true): Promise<ITextModel | null> {
|
||||
const fileOnDiskResource = resource.with({ scheme: Schemas.file });
|
||||
const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority);
|
||||
|
||||
return this.textFileService.resolveTextContent(fileOnDiskResource).then(content => {
|
||||
return this.textFileService.resolve(savedFileResource).then(content => {
|
||||
let codeEditorModel = this.modelService.getModel(resource);
|
||||
if (codeEditorModel) {
|
||||
this.modelService.updateModel(codeEditorModel, content.value);
|
||||
} else if (createAsNeeded) {
|
||||
const fileOnDiskModel = this.modelService.getModel(fileOnDiskResource);
|
||||
const fileOnDiskModel = this.modelService.getModel(savedFileResource);
|
||||
|
||||
let languageSelector: ILanguageSelection;
|
||||
if (fileOnDiskModel) {
|
||||
languageSelector = this.modeService.create(fileOnDiskModel.getModeId());
|
||||
} else {
|
||||
languageSelector = this.modeService.createByFilepathOrFirstLine(fileOnDiskResource.fsPath);
|
||||
languageSelector = this.modeService.createByFilepathOrFirstLine(savedFileResource.fsPath);
|
||||
}
|
||||
|
||||
codeEditorModel = this.modelService.createModel(content.value, languageSelector, resource);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user