Archived
Merge from vscode 591842cc4b71958c81947b254924a215fe3edcbd (#4886)
This commit is contained in:
@@ -3,12 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
import * as vscode from 'vscode';
|
||||
import { getLocation, visit, parse, ParseErrorCode } from 'jsonc-parser';
|
||||
import { getLocation, parse, visit } from 'jsonc-parser';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { SettingsDocument } from './settingsDocumentHelper';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
const fadedDecoration = vscode.window.createTextEditorDecorationType({
|
||||
light: {
|
||||
@@ -45,50 +45,6 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
}
|
||||
}, null, context.subscriptions));
|
||||
updateLaunchJsonDecorations(vscode.window.activeTextEditor);
|
||||
|
||||
context.subscriptions.push(vscode.workspace.onWillSaveTextDocument(e => {
|
||||
if (!e.document.fileName.endsWith('/settings.json')) {
|
||||
return;
|
||||
}
|
||||
|
||||
autoFixSettingsJSON(e);
|
||||
}));
|
||||
}
|
||||
|
||||
function autoFixSettingsJSON(willSaveEvent: vscode.TextDocumentWillSaveEvent): void {
|
||||
const document = willSaveEvent.document;
|
||||
const text = document.getText();
|
||||
const edit = new vscode.WorkspaceEdit();
|
||||
|
||||
let lastEndOfSomething = -1;
|
||||
visit(text, {
|
||||
onArrayEnd(offset: number, length: number): void {
|
||||
lastEndOfSomething = offset + length;
|
||||
},
|
||||
|
||||
onLiteralValue(_value: any, offset: number, length: number): void {
|
||||
lastEndOfSomething = offset + length;
|
||||
},
|
||||
|
||||
onObjectEnd(offset: number, length: number): void {
|
||||
lastEndOfSomething = offset + length;
|
||||
},
|
||||
|
||||
onError(error: ParseErrorCode, _offset: number, _length: number): void {
|
||||
if (error === ParseErrorCode.CommaExpected && lastEndOfSomething > -1) {
|
||||
const fixPosition = document.positionAt(lastEndOfSomething);
|
||||
|
||||
// Don't insert a comma immediately before a : or ' :'
|
||||
const colonRange = document.getWordRangeAtPosition(fixPosition, / *:/);
|
||||
if (!colonRange) {
|
||||
edit.insert(document.uri, fixPosition, ',');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
willSaveEvent.waitUntil(
|
||||
vscode.workspace.applyEdit(edit));
|
||||
}
|
||||
|
||||
function registerSettingsCompletions(): vscode.Disposable {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"git": {
|
||||
"name": "MagicStack/MagicPython",
|
||||
"repositoryUrl": "https://github.com/MagicStack/MagicPython",
|
||||
"commitHash": "8ff35b3e5fcde471fae62a57ea1ae1c7cd34c9fc"
|
||||
"commitHash": "38422d302fe0b3e7716d26ce8cd7d0b9685f3a38"
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/MagicStack/MagicPython/commit/8ff35b3e5fcde471fae62a57ea1ae1c7cd34c9fc",
|
||||
"version": "https://github.com/MagicStack/MagicPython/commit/38422d302fe0b3e7716d26ce8cd7d0b9685f3a38",
|
||||
"name": "MagicPython",
|
||||
"scopeName": "source.python",
|
||||
"patterns": [
|
||||
@@ -826,7 +826,7 @@
|
||||
]
|
||||
},
|
||||
"f-expression": {
|
||||
"comment": "All valid Python expressions, except comments and line cont",
|
||||
"comment": "All valid Python expressions, except comments and line continuation",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#expression-bare"
|
||||
|
||||
Vendored
+10
@@ -30,6 +30,16 @@ exports.load = function (modulePaths, resultCallback, options) {
|
||||
const path = require('path');
|
||||
|
||||
const args = parseURLQueryArgs();
|
||||
/**
|
||||
* // configuration: IWindowConfiguration
|
||||
* @type {{
|
||||
* zoomLevel?: number,
|
||||
* extensionDevelopmentPath?: string | string[],
|
||||
* extensionTestsPath?: string,
|
||||
* userEnv?: { [key: string]: string | undefined },
|
||||
* appRoot?: string,
|
||||
* nodeCachedDataDir?: string
|
||||
* }} */
|
||||
const configuration = JSON.parse(args['config'] || '{}') || {};
|
||||
|
||||
// Apply zoom level early to avoid glitches
|
||||
|
||||
@@ -107,7 +107,6 @@ export class WebviewContent extends AngularDisposable implements OnInit, IDashbo
|
||||
}
|
||||
|
||||
this._webview = this.instantiationService.createInstance(WebviewElement,
|
||||
this.layoutService.getContainer(Parts.EDITOR_PART),
|
||||
{},
|
||||
{
|
||||
allowScripts: true
|
||||
|
||||
@@ -104,7 +104,6 @@ export class WebviewWidget extends DashboardWidget implements IDashboardWidget,
|
||||
}
|
||||
|
||||
this._webview = this.instantiationService.createInstance(WebviewElement,
|
||||
this.layoutService.getContainer(Parts.EDITOR_PART),
|
||||
{},
|
||||
{
|
||||
allowScripts: true,
|
||||
|
||||
@@ -77,7 +77,6 @@ export default class WebViewComponent extends ComponentBase implements IComponen
|
||||
|
||||
private _createWebview(): void {
|
||||
this._webview = this.instantiationService.createInstance(WebviewElement,
|
||||
this.layoutService.getContainer(Parts.EDITOR_PART),
|
||||
{
|
||||
allowSvgs: true
|
||||
},
|
||||
|
||||
@@ -88,7 +88,6 @@ export class WebViewDialog extends Modal {
|
||||
this._body = DOM.append(container, DOM.$('div.webview-dialog'));
|
||||
|
||||
this._webview = this._instantiationService.createInstance(WebviewElement,
|
||||
this.layoutService.getContainer(Parts.EDITOR_PART),
|
||||
{},
|
||||
{
|
||||
allowScripts: true
|
||||
|
||||
@@ -274,7 +274,7 @@ export class BreadcrumbsWidget {
|
||||
this._onDidSelectItem.fire({ type: 'select', item: this._items[this._selectedItemIdx], node: this._nodes[this._selectedItemIdx], payload });
|
||||
}
|
||||
|
||||
getItems(): ReadonlyArray<BreadcrumbsItem> {
|
||||
getItems(): readonly BreadcrumbsItem[] {
|
||||
return this._items;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { sep, posix, normalize } from 'vs/base/common/path';
|
||||
import { endsWith, ltrim, startsWithIgnoreCase, rtrim, startsWith } from 'vs/base/common/strings';
|
||||
import { endsWith, startsWithIgnoreCase, rtrim, startsWith } from 'vs/base/common/strings';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isLinux, isWindows, isMacintosh } from 'vs/base/common/platform';
|
||||
import { isEqual, basename } from 'vs/base/common/resources';
|
||||
import { isEqual, basename, relativePath } from 'vs/base/common/resources';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
export interface IWorkspaceFolderProvider {
|
||||
@@ -40,8 +40,7 @@ export function getPathLabel(resource: URI | string, userHomeProvider?: IUserHom
|
||||
if (isEqual(baseResource.uri, resource)) {
|
||||
pathLabel = ''; // no label if paths are identical
|
||||
} else {
|
||||
// TODO: isidor use resources.relative
|
||||
pathLabel = normalize(ltrim(resource.path.substr(baseResource.uri.path.length), posix.sep)!);
|
||||
pathLabel = relativePath(baseResource.uri, resource)!;
|
||||
}
|
||||
|
||||
if (hasMultipleRoots) {
|
||||
|
||||
@@ -917,6 +917,18 @@ export class IssueReporter extends Disposable {
|
||||
<tr><td>VM</td><td>${systemInfo.vmHint}</td></tr>
|
||||
</table>`;
|
||||
|
||||
systemInfo.remoteData.forEach(remote => {
|
||||
renderedData += `
|
||||
<hr>
|
||||
<table>
|
||||
<tr><td>Remote</td><td>${remote.hostName}</td></tr>
|
||||
<tr><td>OS</td><td>${remote.machineInfo.os}</td></tr>
|
||||
<tr><td>CPUs</td><td>${remote.machineInfo.cpus}</td></tr>
|
||||
<tr><td>Memory (System)</td><td>${remote.machineInfo.memory}</td></tr>
|
||||
<tr><td>VM</td><td>${remote.machineInfo.vmHint}</td></tr>
|
||||
</table>`;
|
||||
});
|
||||
|
||||
target.innerHTML = renderedData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,11 +69,19 @@ ${this._data.issueDescription}
|
||||
|
||||
Azure Data Studio version: ${this._data.versionInfo && this._data.versionInfo.vscodeVersion}
|
||||
OS version: ${this._data.versionInfo && this._data.versionInfo.os}
|
||||
|
||||
${this.getRemoteOSes()}
|
||||
${this.getInfos()}
|
||||
<!-- generated by issue reporter -->`;
|
||||
}
|
||||
|
||||
private getRemoteOSes(): string {
|
||||
if (this._data.systemInfo && this._data.systemInfo.remoteData.length) {
|
||||
return this._data.systemInfo.remoteData.map(remote => `Remote OS version: ${remote.machineInfo.os}`).join('\n') + '\n';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
fileOnExtension(): boolean | undefined {
|
||||
const fileOnExtensionSupported = this._data.issueType === IssueType.Bug
|
||||
|| this._data.issueType === IssueType.PerformanceIssue
|
||||
@@ -159,6 +167,18 @@ ${this.getInfos()}
|
||||
|Process Argv|${this._data.systemInfo.processArgs}|
|
||||
|Screen Reader|${this._data.systemInfo.screenReader}|
|
||||
|VM|${this._data.systemInfo.vmHint}|`;
|
||||
|
||||
this._data.systemInfo.remoteData.forEach(remote => {
|
||||
md += `
|
||||
|
||||
|Item|Value|
|
||||
|---|---|
|
||||
|Remote|${remote.hostName}|
|
||||
|OS|${remote.machineInfo.os}|
|
||||
|CPUs|${remote.machineInfo.cpus}|
|
||||
|Memory (System)|${remote.machineInfo.memory}|
|
||||
|VM|${remote.machineInfo.vmHint}|`;
|
||||
});
|
||||
}
|
||||
|
||||
md += '\n</details>';
|
||||
|
||||
@@ -50,6 +50,7 @@ Extensions: none
|
||||
vmHint: '0%',
|
||||
processArgs: '',
|
||||
screenReader: 'no',
|
||||
remoteData: [],
|
||||
gpuStatus: {
|
||||
'2d_canvas': 'enabled',
|
||||
'checker_imaging': 'disabled_off'
|
||||
@@ -82,6 +83,67 @@ OS version: undefined
|
||||
<!-- generated by issue reporter -->`);
|
||||
});
|
||||
|
||||
test('serializes remote information when data is provided', () => {
|
||||
const issueReporterModel = new IssueReporterModel({
|
||||
issueType: 0,
|
||||
systemInfo: {
|
||||
os: 'Darwin',
|
||||
cpus: 'Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz (8 x 2800)',
|
||||
memory: '16.00GB',
|
||||
vmHint: '0%',
|
||||
processArgs: '',
|
||||
screenReader: 'no',
|
||||
gpuStatus: {
|
||||
'2d_canvas': 'enabled',
|
||||
'checker_imaging': 'disabled_off'
|
||||
},
|
||||
remoteData: [
|
||||
{
|
||||
hostName: 'SSH: Pineapple',
|
||||
machineInfo: {
|
||||
os: 'Linux x64 4.18.0',
|
||||
cpus: 'Intel(R) Xeon(R) CPU E5-2673 v4 @ 2.30GHz (2 x 2294)',
|
||||
memory: '8GB',
|
||||
vmHint: '100%'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
assert.equal(issueReporterModel.serialize(),
|
||||
`
|
||||
Issue Type: <b>Bug</b>
|
||||
|
||||
undefined
|
||||
|
||||
VS Code version: undefined
|
||||
OS version: undefined
|
||||
Remote OS version: Linux x64 4.18.0
|
||||
|
||||
<details>
|
||||
<summary>System Info</summary>
|
||||
|
||||
|Item|Value|
|
||||
|---|---|
|
||||
|CPUs|Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz (8 x 2800)|
|
||||
|GPU Status|2d_canvas: enabled<br>checker_imaging: disabled_off|
|
||||
|Load (avg)|undefined|
|
||||
|Memory (System)|16.00GB|
|
||||
|Process Argv||
|
||||
|Screen Reader|no|
|
||||
|VM|0%|
|
||||
|
||||
|Item|Value|
|
||||
|---|---|
|
||||
|Remote|SSH: Pineapple|
|
||||
|OS|Linux x64 4.18.0|
|
||||
|CPUs|Intel(R) Xeon(R) CPU E5-2673 v4 @ 2.30GHz (2 x 2294)|
|
||||
|Memory (System)|8GB|
|
||||
|VM|100%|
|
||||
</details>Extensions: none
|
||||
<!-- generated by issue reporter -->`);
|
||||
});
|
||||
|
||||
test('should normalize GitHub urls', () => {
|
||||
[
|
||||
'https://github.com/repo',
|
||||
|
||||
@@ -64,7 +64,14 @@ bootstrapWindow.load([
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {object} configuration
|
||||
* // configuration: IWindowConfiguration
|
||||
* @param {{
|
||||
* partsSplashPath?: string,
|
||||
* highContrast?: boolean,
|
||||
* extensionDevelopmentPath?: string | string[],
|
||||
* folderUri?: object,
|
||||
* workspace?: object
|
||||
* }} configuration
|
||||
*/
|
||||
function showPartsSplash(configuration) {
|
||||
perf.mark('willShowPartsSplash');
|
||||
|
||||
@@ -30,7 +30,7 @@ import { endsWith } from 'vs/base/common/strings';
|
||||
|
||||
export interface IWindowCreationOptions {
|
||||
state: IWindowState;
|
||||
extensionDevelopmentPath?: string;
|
||||
extensionDevelopmentPath?: string | string[];
|
||||
isExtensionTestHost?: boolean;
|
||||
}
|
||||
|
||||
@@ -220,9 +220,11 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
return !!this.config.extensionTestsPath;
|
||||
}
|
||||
|
||||
get extensionDevelopmentPath(): string | undefined {
|
||||
/*
|
||||
get extensionDevelopmentPaths(): string | string[] | undefined {
|
||||
return this.config.extensionDevelopmentPath;
|
||||
}
|
||||
*/
|
||||
|
||||
get config(): IWindowConfiguration {
|
||||
return this.currentConfig;
|
||||
|
||||
@@ -26,7 +26,7 @@ import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/
|
||||
import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows';
|
||||
import { IHistoryMainService, IRecent } from 'vs/platform/history/common/history';
|
||||
import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_FILTER, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -899,7 +899,7 @@ export class WindowsManager implements IWindowsMainService {
|
||||
for (let f of fileUris) {
|
||||
const fileUri = this.argToUri(f);
|
||||
if (fileUri) {
|
||||
const path = this.parseUri({ fileUri }, parseOptions);
|
||||
const path = this.parseUri(hasWorkspaceFileExtension(f) ? { workspaceUri: fileUri } : { fileUri }, parseOptions);
|
||||
if (path) {
|
||||
pathsToOpen.push(path);
|
||||
}
|
||||
@@ -1153,7 +1153,7 @@ export class WindowsManager implements IWindowsMainService {
|
||||
return { openFolderInNewWindow: !!openFolderInNewWindow, openFilesInNewWindow };
|
||||
}
|
||||
|
||||
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string, openConfig: IOpenConfiguration): void {
|
||||
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string | string[], openConfig: IOpenConfiguration): void {
|
||||
|
||||
// Reload an existing extension development host window on the same path
|
||||
// We currently do not allow more than one extension development window
|
||||
@@ -1207,9 +1207,30 @@ export class WindowsManager implements IWindowsMainService {
|
||||
openConfig.cli['folder-uri'] = folderUris;
|
||||
openConfig.cli['file-uri'] = fileUris;
|
||||
|
||||
const match = extensionDevelopmentPath.match(/^vscode-remote:\/\/([^\/]+)/);
|
||||
if (match) {
|
||||
openConfig.cli['remote'] = URI.parse(extensionDevelopmentPath).authority;
|
||||
if (Array.isArray(extensionDevelopmentPath)) {
|
||||
let authority: string | undefined = undefined;
|
||||
for (let p of extensionDevelopmentPath) {
|
||||
const match = p.match(/^vscode-remote:\/\/([^\/]+)/);
|
||||
if (match) {
|
||||
const auth = URI.parse(p).authority;
|
||||
if (authority) {
|
||||
if (auth !== authority) {
|
||||
console.log('more than one authority');
|
||||
}
|
||||
} else {
|
||||
authority = auth;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (authority) {
|
||||
openConfig.cli['remote'] = authority;
|
||||
}
|
||||
|
||||
} else {
|
||||
const match = extensionDevelopmentPath.match(/^vscode-remote:\/\/([^\/]+)/);
|
||||
if (match) {
|
||||
openConfig.cli['remote'] = URI.parse(extensionDevelopmentPath).authority;
|
||||
}
|
||||
}
|
||||
|
||||
// Open it
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface ISimpleWindow {
|
||||
openedWorkspace?: IWorkspaceIdentifier;
|
||||
openedFolderUri?: URI;
|
||||
|
||||
extensionDevelopmentPath?: string;
|
||||
extensionDevelopmentPath?: string | string[];
|
||||
lastFocusTime: number;
|
||||
}
|
||||
|
||||
@@ -95,13 +95,33 @@ export function findWindowOnWorkspace<W extends ISimpleWindow>(windows: W[], wor
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findWindowOnExtensionDevelopmentPath<W extends ISimpleWindow>(windows: W[], extensionDevelopmentPath: string): W | null {
|
||||
export function findWindowOnExtensionDevelopmentPath<W extends ISimpleWindow>(windows: W[], extensionDevelopmentPath: string | string[]): W | null {
|
||||
|
||||
const matches = (uriString: string): boolean => {
|
||||
if (Array.isArray(extensionDevelopmentPath)) {
|
||||
return extensionDevelopmentPath.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */));
|
||||
} else if (extensionDevelopmentPath) {
|
||||
return extpath.isEqual(extensionDevelopmentPath, uriString, !platform.isLinux /* ignorecase */);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (const window of windows) {
|
||||
// match on extension development path. The path can be a path or uri string, using paths.isEqual is not 100% correct but good enough
|
||||
if (window.extensionDevelopmentPath && extpath.isEqual(window.extensionDevelopmentPath, extensionDevelopmentPath, !platform.isLinux /* ignorecase */)) {
|
||||
return window;
|
||||
// match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough
|
||||
|
||||
if (window.extensionDevelopmentPath) {
|
||||
if (Array.isArray(window.extensionDevelopmentPath)) {
|
||||
if (window.extensionDevelopmentPath.some(p => matches(p))) {
|
||||
return window;
|
||||
}
|
||||
} else if (window.extensionDevelopmentPath) {
|
||||
if (matches(window.extensionDevelopmentPath)) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1001,11 +1001,16 @@ export interface ILink {
|
||||
range: IRange;
|
||||
url?: URI | string;
|
||||
}
|
||||
|
||||
export interface ILinksList {
|
||||
links: ILink[];
|
||||
dispose?(): void;
|
||||
}
|
||||
/**
|
||||
* A provider of links.
|
||||
*/
|
||||
export interface LinkProvider {
|
||||
provideLinks(model: model.ITextModel, token: CancellationToken): ProviderResult<ILink[]>;
|
||||
provideLinks(model: model.ITextModel, token: CancellationToken): ProviderResult<ILinksList>;
|
||||
resolveLink?: (link: ILink, token: CancellationToken) => ProviderResult<ILink>;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,12 +58,14 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker
|
||||
this._workerManager = this._register(new WorkerManager(this._modelService));
|
||||
|
||||
// todo@joh make sure this happens only once
|
||||
this._register(modes.LinkProviderRegistry.register('*', <modes.LinkProvider>{
|
||||
this._register(modes.LinkProviderRegistry.register('*', {
|
||||
provideLinks: (model, token) => {
|
||||
if (!canSyncModel(this._modelService, model.uri)) {
|
||||
return Promise.resolve([]); // File too large
|
||||
return Promise.resolve({ links: [] }); // File too large
|
||||
}
|
||||
return this._workerManager.withWorker().then(client => client.computeLinks(model.uri));
|
||||
return this._workerManager.withWorker().then(client => client.computeLinks(model.uri)).then(links => {
|
||||
return links && { links };
|
||||
});
|
||||
}
|
||||
}));
|
||||
this._register(modes.CompletionProviderRegistry.register('*', new WordBasedCompletionItemProvider(this._workerManager, configurationService, this._modelService)));
|
||||
|
||||
@@ -32,7 +32,7 @@ export class CodeActionSet {
|
||||
}
|
||||
}
|
||||
|
||||
public readonly actions: ReadonlyArray<CodeAction>;
|
||||
public readonly actions: readonly CodeAction[];
|
||||
|
||||
public constructor(actions: CodeAction[]) {
|
||||
this.actions = mergeSort(actions, CodeActionSet.codeActionsComparator);
|
||||
|
||||
@@ -8,9 +8,11 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILink, LinkProvider, LinkProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { ILink, LinkProvider, LinkProviderRegistry, ILinksList } from 'vs/editor/common/modes';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { isDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
|
||||
export class Link implements ILink {
|
||||
|
||||
@@ -66,77 +68,99 @@ export class Link implements ILink {
|
||||
}
|
||||
}
|
||||
|
||||
export function getLinks(model: ITextModel, token: CancellationToken): Promise<Link[]> {
|
||||
export class LinksList extends Disposable {
|
||||
|
||||
let links: Link[] = [];
|
||||
readonly links: Link[];
|
||||
|
||||
constructor(tuples: [ILinksList, LinkProvider][]) {
|
||||
super();
|
||||
let links: Link[] = [];
|
||||
for (const [list, provider] of tuples) {
|
||||
// merge all links
|
||||
const newLinks = list.links.map(link => new Link(link, provider));
|
||||
links = LinksList._union(links, newLinks);
|
||||
// register disposables
|
||||
if (isDisposable(provider)) {
|
||||
this._register(provider);
|
||||
}
|
||||
}
|
||||
this.links = links;
|
||||
}
|
||||
|
||||
private static _union(oldLinks: Link[], newLinks: Link[]): Link[] {
|
||||
// reunite oldLinks with newLinks and remove duplicates
|
||||
let result: Link[] = [];
|
||||
let oldIndex: number;
|
||||
let oldLen: number;
|
||||
let newIndex: number;
|
||||
let newLen: number;
|
||||
|
||||
for (oldIndex = 0, newIndex = 0, oldLen = oldLinks.length, newLen = newLinks.length; oldIndex < oldLen && newIndex < newLen;) {
|
||||
const oldLink = oldLinks[oldIndex];
|
||||
const newLink = newLinks[newIndex];
|
||||
|
||||
if (Range.areIntersectingOrTouching(oldLink.range, newLink.range)) {
|
||||
// Remove the oldLink
|
||||
oldIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const comparisonResult = Range.compareRangesUsingStarts(oldLink.range, newLink.range);
|
||||
|
||||
if (comparisonResult < 0) {
|
||||
// oldLink is before
|
||||
result.push(oldLink);
|
||||
oldIndex++;
|
||||
} else {
|
||||
// newLink is before
|
||||
result.push(newLink);
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
for (; oldIndex < oldLen; oldIndex++) {
|
||||
result.push(oldLinks[oldIndex]);
|
||||
}
|
||||
for (; newIndex < newLen; newIndex++) {
|
||||
result.push(newLinks[newIndex]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function getLinks(model: ITextModel, token: CancellationToken): Promise<LinksList> {
|
||||
|
||||
const lists: [ILinksList, LinkProvider][] = [];
|
||||
|
||||
// ask all providers for links in parallel
|
||||
const promises = LinkProviderRegistry.ordered(model).reverse().map(provider => {
|
||||
const promises = LinkProviderRegistry.ordered(model).reverse().map((provider, i) => {
|
||||
return Promise.resolve(provider.provideLinks(model, token)).then(result => {
|
||||
if (Array.isArray(result)) {
|
||||
const newLinks = result.map(link => new Link(link, provider));
|
||||
links = union(links, newLinks);
|
||||
if (result) {
|
||||
lists[i] = [result, provider];
|
||||
}
|
||||
}, onUnexpectedExternalError);
|
||||
});
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
return links;
|
||||
});
|
||||
return Promise.all(promises).then(() => new LinksList(coalesce(lists)));
|
||||
}
|
||||
|
||||
function union(oldLinks: Link[], newLinks: Link[]): Link[] {
|
||||
// reunite oldLinks with newLinks and remove duplicates
|
||||
let result: Link[] = [];
|
||||
let oldIndex: number;
|
||||
let oldLen: number;
|
||||
let newIndex: number;
|
||||
let newLen: number;
|
||||
|
||||
for (oldIndex = 0, newIndex = 0, oldLen = oldLinks.length, newLen = newLinks.length; oldIndex < oldLen && newIndex < newLen;) {
|
||||
const oldLink = oldLinks[oldIndex];
|
||||
const newLink = newLinks[newIndex];
|
||||
|
||||
if (Range.areIntersectingOrTouching(oldLink.range, newLink.range)) {
|
||||
// Remove the oldLink
|
||||
oldIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const comparisonResult = Range.compareRangesUsingStarts(oldLink.range, newLink.range);
|
||||
|
||||
if (comparisonResult < 0) {
|
||||
// oldLink is before
|
||||
result.push(oldLink);
|
||||
oldIndex++;
|
||||
} else {
|
||||
// newLink is before
|
||||
result.push(newLink);
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
for (; oldIndex < oldLen; oldIndex++) {
|
||||
result.push(oldLinks[oldIndex]);
|
||||
}
|
||||
for (; newIndex < newLen; newIndex++) {
|
||||
result.push(newLinks[newIndex]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand('_executeLinkProvider', (accessor, ...args) => {
|
||||
|
||||
CommandsRegistry.registerCommand('_executeLinkProvider', async (accessor, ...args): Promise<ILink[]> => {
|
||||
const [uri] = args;
|
||||
if (!(uri instanceof URI)) {
|
||||
return undefined;
|
||||
return [];
|
||||
}
|
||||
|
||||
const model = accessor.get(IModelService).getModel(uri);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
return [];
|
||||
}
|
||||
|
||||
return getLinks(model, CancellationToken.None);
|
||||
const list = await getLinks(model, CancellationToken.None);
|
||||
if (!list) {
|
||||
return [];
|
||||
}
|
||||
const result = list.links.slice(0);
|
||||
list.dispose();
|
||||
return result;
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, TrackedRangeSti
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { LinkProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { ClickLinkGesture, ClickLinkKeyboardEvent, ClickLinkMouseEvent } from 'vs/editor/contrib/goToDefinition/clickLinkGesture';
|
||||
import { Link, getLinks } from 'vs/editor/contrib/links/getLinks';
|
||||
import { Link, getLinks, LinksList } from 'vs/editor/contrib/links/getLinks';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
@@ -157,7 +157,8 @@ class LinkDetector implements editorCommon.IEditorContribution {
|
||||
private enabled: boolean;
|
||||
private listenersToRemove: IDisposable[];
|
||||
private readonly timeout: async.TimeoutTimer;
|
||||
private computePromise: async.CancelablePromise<Link[]> | null;
|
||||
private computePromise: async.CancelablePromise<LinksList> | null;
|
||||
private activeLinksList: LinksList | null;
|
||||
private activeLinkDecorationId: string | null;
|
||||
private readonly openerService: IOpenerService;
|
||||
private readonly notificationService: INotificationService;
|
||||
@@ -210,6 +211,7 @@ class LinkDetector implements editorCommon.IEditorContribution {
|
||||
|
||||
this.timeout = new async.TimeoutTimer();
|
||||
this.computePromise = null;
|
||||
this.activeLinksList = null;
|
||||
this.currentOccurrences = {};
|
||||
this.activeLinkDecorationId = null;
|
||||
this.beginCompute();
|
||||
@@ -246,10 +248,15 @@ class LinkDetector implements editorCommon.IEditorContribution {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.activeLinksList) {
|
||||
this.activeLinksList.dispose();
|
||||
this.activeLinksList = null;
|
||||
}
|
||||
|
||||
this.computePromise = async.createCancelablePromise(token => getLinks(model, token));
|
||||
try {
|
||||
const links = await this.computePromise;
|
||||
this.updateDecorations(links);
|
||||
this.activeLinksList = await this.computePromise;
|
||||
this.updateDecorations(this.activeLinksList.links);
|
||||
} catch (err) {
|
||||
onUnexpectedError(err);
|
||||
} finally {
|
||||
@@ -380,6 +387,9 @@ class LinkDetector implements editorCommon.IEditorContribution {
|
||||
|
||||
private stop(): void {
|
||||
this.timeout.cancel();
|
||||
if (this.activeLinksList) {
|
||||
this.activeLinksList.dispose();
|
||||
}
|
||||
if (this.computePromise) {
|
||||
this.computePromise.cancel();
|
||||
this.computePromise = null;
|
||||
|
||||
Vendored
+6
-1
@@ -5253,11 +5253,16 @@ declare namespace monaco.languages {
|
||||
url?: Uri | string;
|
||||
}
|
||||
|
||||
export interface ILinksList {
|
||||
links: ILink[];
|
||||
dispose?(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A provider of links.
|
||||
*/
|
||||
export interface LinkProvider {
|
||||
provideLinks(model: editor.ITextModel, token: CancellationToken): ProviderResult<ILink[]>;
|
||||
provideLinks(model: editor.ITextModel, token: CancellationToken): ProviderResult<ILinksList>;
|
||||
resolveLink?: (link: ILink, token: CancellationToken) => ProviderResult<ILink>;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,6 @@ export interface IConfigurationData {
|
||||
user: IConfigurationModel;
|
||||
workspace: IConfigurationModel;
|
||||
folders: { [folder: string]: IConfigurationModel };
|
||||
isComplete: boolean;
|
||||
}
|
||||
|
||||
export function compare(from: IConfigurationModel, to: IConfigurationModel): { added: string[], removed: string[], updated: string[] } {
|
||||
|
||||
@@ -513,8 +513,7 @@ export class Configuration {
|
||||
const { contents, overrides, keys } = this._folderConfigurations.get(folder)!;
|
||||
result[folder.toString()] = { contents, overrides, keys };
|
||||
return result;
|
||||
}, Object.create({})),
|
||||
isComplete: true
|
||||
}, Object.create({}))
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,14 @@ export interface SystemInfo extends IMachineInfo {
|
||||
processArgs: string;
|
||||
gpuStatus: any;
|
||||
screenReader: string;
|
||||
remoteData: IRemoteDiagnosticInfo[];
|
||||
load?: string;
|
||||
}
|
||||
|
||||
export interface IRemoteDiagnosticInfo extends IDiagnosticInfo {
|
||||
hostName: string;
|
||||
}
|
||||
|
||||
export interface IDiagnosticInfoOptions {
|
||||
includeProcesses?: boolean;
|
||||
folders?: UriComponents[];
|
||||
|
||||
@@ -15,7 +15,7 @@ import { app } from 'electron';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { WorkspaceStats, SystemInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||
import { IMachineInfo, WorkspaceStats, SystemInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||
import { collectWorkspaceStats, getMachineInfo } from 'vs/platform/diagnostics/node/diagnosticsService';
|
||||
import { ProcessItem } from 'vs/base/common/processes';
|
||||
|
||||
@@ -46,12 +46,21 @@ export interface PerformanceInfo {
|
||||
processInfo?: string;
|
||||
workspaceInfo?: string;
|
||||
}
|
||||
|
||||
export class DiagnosticsService implements IDiagnosticsService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
formatEnvironment(info: IMainProcessInfo): string {
|
||||
private formatMachineInfo(info: IMachineInfo): string {
|
||||
const output: string[] = [];
|
||||
output.push(`OS Version: ${info.os}`);
|
||||
output.push(`CPUs: ${info.cpus}`);
|
||||
output.push(`Memory (System): ${info.memory}`);
|
||||
output.push(`VM: ${info.vmHint}`);
|
||||
|
||||
return output.join('\n');
|
||||
}
|
||||
|
||||
private formatEnvironment(info: IMainProcessInfo): string {
|
||||
const MB = 1024 * 1024;
|
||||
const GB = 1024 * MB;
|
||||
|
||||
@@ -76,10 +85,40 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
|
||||
async getPerformanceInfo(launchService: ILaunchService): Promise<PerformanceInfo> {
|
||||
const info = await launchService.getMainProcessInfo();
|
||||
return Promise.all<ProcessItem, string>([listProcesses(info.mainPID), this.formatWorkspaceMetadata(info)]).then(result => {
|
||||
const [rootProcess, workspaceInfo] = result;
|
||||
return Promise.all<ProcessItem, string>([listProcesses(info.mainPID), this.formatWorkspaceMetadata(info)]).then(async result => {
|
||||
let [rootProcess, workspaceInfo] = result;
|
||||
let processInfo = this.formatProcessList(info, rootProcess);
|
||||
|
||||
try {
|
||||
const remoteData = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
|
||||
remoteData.forEach(diagnostics => {
|
||||
processInfo += `\n\nRemote: ${diagnostics.hostName}`;
|
||||
if (diagnostics.processes) {
|
||||
processInfo += `\n${this.formatProcessList(info, diagnostics.processes)}`;
|
||||
}
|
||||
|
||||
if (diagnostics.workspaceMetadata) {
|
||||
workspaceInfo += `\n| Remote: ${diagnostics.hostName}`;
|
||||
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
||||
const metadata = diagnostics.workspaceMetadata[folder];
|
||||
|
||||
let countMessage = `${metadata.fileCount} files`;
|
||||
if (metadata.maxFilesReached) {
|
||||
countMessage = `more than ${countMessage}`;
|
||||
}
|
||||
|
||||
workspaceInfo += `| Folder (${folder}): ${countMessage}`;
|
||||
workspaceInfo += this.formatWorkspaceStats(metadata);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
processInfo += `\nFetching remote data failed: ${e}`;
|
||||
workspaceInfo += `\nFetching remote data failed: ${e}`;
|
||||
}
|
||||
|
||||
return {
|
||||
processInfo: this.formatProcessList(info, rootProcess),
|
||||
processInfo,
|
||||
workspaceInfo
|
||||
};
|
||||
});
|
||||
@@ -95,7 +134,8 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
vmHint,
|
||||
processArgs: `${info.mainArguments.join(' ')}`,
|
||||
gpuStatus: app.getGPUFeatureStatus(),
|
||||
screenReader: `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`
|
||||
screenReader: `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`,
|
||||
remoteData: await launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })
|
||||
};
|
||||
|
||||
|
||||
@@ -120,12 +160,42 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
output.push(this.formatProcessList(info, rootProcess));
|
||||
|
||||
// Workspace Stats
|
||||
if (info.windows.some(window => window.folderURIs && window.folderURIs.length > 0)) {
|
||||
if (info.windows.some(window => window.folderURIs && window.folderURIs.length > 0 && !window.remoteAuthority)) {
|
||||
output.push('');
|
||||
output.push('Workspace Stats: ');
|
||||
output.push(await this.formatWorkspaceMetadata(info));
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
|
||||
data.forEach(diagnostics => {
|
||||
output.push('\n\n');
|
||||
output.push(`Remote: ${diagnostics.hostName}`);
|
||||
output.push(this.formatMachineInfo(diagnostics.machineInfo));
|
||||
|
||||
if (diagnostics.processes) {
|
||||
output.push(this.formatProcessList(info, diagnostics.processes));
|
||||
}
|
||||
|
||||
if (diagnostics.workspaceMetadata) {
|
||||
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
||||
const metadata = diagnostics.workspaceMetadata[folder];
|
||||
|
||||
let countMessage = `${metadata.fileCount} files`;
|
||||
if (metadata.maxFilesReached) {
|
||||
countMessage = `more than ${countMessage}`;
|
||||
}
|
||||
|
||||
output.push(`Folder (${folder}): ${countMessage}`);
|
||||
output.push(this.formatWorkspaceStats(metadata));
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
output.push('\n\n');
|
||||
output.push(`Fetching status information from remotes failed: ${e.message}`);
|
||||
}
|
||||
|
||||
output.push('');
|
||||
output.push('');
|
||||
|
||||
@@ -195,7 +265,7 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
const workspaceStatPromises: Promise<void>[] = [];
|
||||
|
||||
info.windows.forEach(window => {
|
||||
if (window.folderURIs.length === 0) {
|
||||
if (window.folderURIs.length === 0 || !!window.remoteAuthority) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export interface ParsedArgs {
|
||||
logExtensionHostCommunication?: boolean;
|
||||
'extensions-dir'?: string;
|
||||
'builtin-extensions-dir'?: string;
|
||||
extensionDevelopmentPath?: string; // either a local path or a URI
|
||||
extensionDevelopmentPath?: string | string[]; // one or more local paths or URIs
|
||||
extensionTestsPath?: string; // either a local path or a URI
|
||||
'inspect-extensions'?: string;
|
||||
'inspect-brk-extensions'?: string;
|
||||
@@ -124,7 +124,7 @@ export interface IEnvironmentService {
|
||||
disableExtensions: boolean | string[];
|
||||
builtinExtensionsPath: string;
|
||||
extensionsPath: string;
|
||||
extensionDevelopmentLocationURI?: URI;
|
||||
extensionDevelopmentLocationURI?: URI | URI[];
|
||||
extensionTestsLocationURI?: URI;
|
||||
|
||||
debugExtensionHost: IExtensionHostDebugParams;
|
||||
|
||||
@@ -172,9 +172,16 @@ export class EnvironmentService implements IEnvironmentService {
|
||||
}
|
||||
|
||||
@memoize
|
||||
get extensionDevelopmentLocationURI(): URI | undefined {
|
||||
get extensionDevelopmentLocationURI(): URI | URI[] | undefined {
|
||||
const s = this._args.extensionDevelopmentPath;
|
||||
if (s) {
|
||||
if (Array.isArray(s)) {
|
||||
return s.map(p => {
|
||||
if (/^[^:/?#]+?:\/\//.test(p)) {
|
||||
return URI.parse(p);
|
||||
}
|
||||
return URI.file(path.normalize(p));
|
||||
});
|
||||
} else if (s) {
|
||||
if (/^[^:/?#]+?:\/\//.test(s)) {
|
||||
return URI.parse(s);
|
||||
}
|
||||
|
||||
@@ -245,12 +245,6 @@ export interface IExtensionEnablementService {
|
||||
*/
|
||||
onEnablementChanged: Event<IExtension[]>;
|
||||
|
||||
/**
|
||||
* Returns all disabled extension identifiers for current workspace
|
||||
* Returns an empty array if none exist
|
||||
*/
|
||||
getDisabledExtensions(): Promise<IExtensionIdentifier[]>;
|
||||
|
||||
/**
|
||||
* Returns the enablement state for the given extension
|
||||
*/
|
||||
|
||||
@@ -15,10 +15,11 @@ import { whenDeleted } from 'vs/base/node/pfs';
|
||||
import { IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { BrowserWindow } from 'electron';
|
||||
import { BrowserWindow, ipcMain, Event as IpcEvent } from 'electron';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { hasArgs } from 'vs/platform/environment/node/argv';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||
|
||||
export const ID = 'launchService';
|
||||
export const ILaunchService = createDecorator<ILaunchService>(ID);
|
||||
@@ -32,6 +33,7 @@ export interface IWindowInfo {
|
||||
pid: number;
|
||||
title: string;
|
||||
folderURIs: UriComponents[];
|
||||
remoteAuthority?: string;
|
||||
}
|
||||
|
||||
export interface IMainProcessInfo {
|
||||
@@ -41,6 +43,11 @@ export interface IMainProcessInfo {
|
||||
windows: IWindowInfo[];
|
||||
}
|
||||
|
||||
export interface IRemoteDiagnosticOptions {
|
||||
includeProcesses?: boolean;
|
||||
includeWorkspaceMetadata?: boolean;
|
||||
}
|
||||
|
||||
function parseOpenUrl(args: ParsedArgs): URI[] {
|
||||
if (args['open-url'] && args._urls && args._urls.length > 0) {
|
||||
// --open-url must contain -- followed by the url(s)
|
||||
@@ -64,6 +71,7 @@ export interface ILaunchService {
|
||||
getMainProcessId(): Promise<number>;
|
||||
getMainProcessInfo(): Promise<IMainProcessInfo>;
|
||||
getLogsPath(): Promise<string>;
|
||||
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]>;
|
||||
}
|
||||
|
||||
export class LaunchChannel implements IServerChannel {
|
||||
@@ -88,6 +96,9 @@ export class LaunchChannel implements IServerChannel {
|
||||
|
||||
case 'get-logs-path':
|
||||
return this.service.getLogsPath();
|
||||
|
||||
case 'get-remote-diagnostics':
|
||||
return this.service.getRemoteDiagnostics(arg);
|
||||
}
|
||||
|
||||
throw new Error(`Call not found: ${command}`);
|
||||
@@ -115,6 +126,10 @@ export class LaunchChannelClient implements ILaunchService {
|
||||
getLogsPath(): Promise<string> {
|
||||
return this.channel.call('get-logs-path', null);
|
||||
}
|
||||
|
||||
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]> {
|
||||
return this.channel.call('get-remote-diagnostics', options);
|
||||
}
|
||||
}
|
||||
|
||||
export class LaunchService implements ILaunchService {
|
||||
@@ -284,7 +299,45 @@ export class LaunchService implements ILaunchService {
|
||||
return Promise.resolve(this.environmentService.logsPath);
|
||||
}
|
||||
|
||||
private codeWindowToInfo(window: ICodeWindow): IWindowInfo {
|
||||
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]> {
|
||||
const windows = this.windowsMainService.getWindows();
|
||||
const promises: Promise<IDiagnosticInfo | undefined>[] = windows.map(window => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (window.remoteAuthority) {
|
||||
const replyChannel = `vscode:getDiagnosticInfoResponse${window.id}`;
|
||||
const args: IDiagnosticInfoOptions = {
|
||||
includeProcesses: options.includeProcesses,
|
||||
folders: options.includeWorkspaceMetadata ? this.getFolderURIs(window) : undefined
|
||||
};
|
||||
|
||||
window.sendWhenReady('vscode:getDiagnosticInfo', { replyChannel, args });
|
||||
|
||||
ipcMain.once(replyChannel, (_: IpcEvent, data: IRemoteDiagnosticInfo) => {
|
||||
// No data is returned if getting the connection fails.
|
||||
if (!data) {
|
||||
resolve();
|
||||
}
|
||||
|
||||
if (typeof (data) === 'string') {
|
||||
reject(new Error(data));
|
||||
}
|
||||
|
||||
resolve(data);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, 5000);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(promises).then(diagnostics => diagnostics.filter((x): x is IRemoteDiagnosticInfo => !!x));
|
||||
}
|
||||
|
||||
private getFolderURIs(window: ICodeWindow): URI[] {
|
||||
const folderURIs: URI[] = [];
|
||||
|
||||
if (window.openedFolderUri) {
|
||||
@@ -303,14 +356,20 @@ export class LaunchService implements ILaunchService {
|
||||
}
|
||||
}
|
||||
|
||||
return this.browserWindowToInfo(window.win, folderURIs);
|
||||
return folderURIs;
|
||||
}
|
||||
|
||||
private browserWindowToInfo(win: BrowserWindow, folderURIs: URI[] = []): IWindowInfo {
|
||||
private codeWindowToInfo(window: ICodeWindow): IWindowInfo {
|
||||
const folderURIs = this.getFolderURIs(window);
|
||||
return this.browserWindowToInfo(window.win, folderURIs, window.remoteAuthority);
|
||||
}
|
||||
|
||||
private browserWindowToInfo(win: BrowserWindow, folderURIs: URI[] = [], remoteAuthority?: string): IWindowInfo {
|
||||
return {
|
||||
pid: win.webContents.getOSProcessId(),
|
||||
title: win.getTitle(),
|
||||
folderURIs
|
||||
folderURIs,
|
||||
remoteAuthority
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ export interface IRemoteExtensionHostStartParams {
|
||||
debugId?: string;
|
||||
break?: boolean;
|
||||
port?: number | null;
|
||||
updatePort?: boolean;
|
||||
}
|
||||
|
||||
interface IExtensionHostConnectionResult {
|
||||
|
||||
@@ -11,8 +11,6 @@ export interface ResolvedAuthority {
|
||||
readonly authority: string;
|
||||
readonly host: string;
|
||||
readonly port: number;
|
||||
readonly debugListenPort?: number;
|
||||
readonly debugConnectPort?: number;
|
||||
}
|
||||
|
||||
export interface IRemoteAuthorityResolverService {
|
||||
|
||||
@@ -97,7 +97,7 @@ export interface IWindowsMainService {
|
||||
enterWorkspace(win: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | undefined>;
|
||||
closeWorkspace(win: ICodeWindow): void;
|
||||
open(openConfig: IOpenConfiguration): ICodeWindow[];
|
||||
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string, openConfig: IOpenConfiguration): void;
|
||||
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string | string[], openConfig: IOpenConfiguration): void;
|
||||
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
||||
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
||||
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
||||
|
||||
Vendored
-14
@@ -75,8 +75,6 @@ declare module 'vscode' {
|
||||
export class ResolvedAuthority {
|
||||
readonly host: string;
|
||||
readonly port: number;
|
||||
debugListenPort?: number;
|
||||
debugConnectPort?: number;
|
||||
|
||||
constructor(host: string, port: number);
|
||||
}
|
||||
@@ -473,11 +471,6 @@ declare module 'vscode' {
|
||||
}
|
||||
|
||||
export namespace workspace {
|
||||
/**
|
||||
* DEPRECATED
|
||||
*/
|
||||
export function registerSearchProvider(): Disposable;
|
||||
|
||||
/**
|
||||
* Register a search provider.
|
||||
*
|
||||
@@ -1017,9 +1010,7 @@ declare module 'vscode' {
|
||||
* Provide a list of ranges which allow new comment threads creation or null for a given document
|
||||
*/
|
||||
provideCommentingRanges(document: TextDocument, token: CancellationToken): ProviderResult<Range[]>;
|
||||
}
|
||||
|
||||
export interface EmptyCommentThreadFactory {
|
||||
/**
|
||||
* The method `createEmptyCommentThread` is called when users attempt to create new comment thread from the gutter or command palette.
|
||||
* Extensions still need to call `createCommentThread` inside this call when appropriate.
|
||||
@@ -1054,11 +1045,6 @@ declare module 'vscode' {
|
||||
*/
|
||||
commentingRangeProvider?: CommentingRangeProvider;
|
||||
|
||||
/**
|
||||
* Optional new comment thread factory.
|
||||
*/
|
||||
emptyCommentThreadFactory?: EmptyCommentThreadFactory;
|
||||
|
||||
/**
|
||||
* Optional reaction provider
|
||||
*/
|
||||
|
||||
@@ -357,6 +357,7 @@ export class MainThreadCommentController {
|
||||
|
||||
return <ICommentInfo>{
|
||||
owner: this._uniqueId,
|
||||
label: this.label,
|
||||
threads: ret,
|
||||
commentingRanges: commentingRanges ?
|
||||
{
|
||||
|
||||
@@ -377,7 +377,6 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
command: data.m,
|
||||
// not-standard
|
||||
_id: data.x,
|
||||
_pid: data.y
|
||||
};
|
||||
}
|
||||
|
||||
@@ -393,14 +392,14 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
return {
|
||||
suggestions: result.b.map(d => MainThreadLanguageFeatures._inflateSuggestDto(result.a, d)),
|
||||
incomplete: result.c,
|
||||
dispose: () => this._proxy.$releaseCompletionItems(handle, result.x)
|
||||
dispose: () => typeof result.x === 'number' && this._proxy.$releaseCompletionItems(handle, result.x)
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
if (supportsResolveDetails) {
|
||||
provider.resolveCompletionItem = (model, position, suggestion, token) => {
|
||||
return this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion._id, suggestion._pid, token).then(result => {
|
||||
return this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion._id, token).then(result => {
|
||||
if (!result) {
|
||||
return suggestion;
|
||||
}
|
||||
@@ -428,29 +427,36 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
// --- links
|
||||
|
||||
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
|
||||
this._registrations[handle] = modes.LinkProviderRegistry.register(selector, <modes.LinkProvider>{
|
||||
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[], supportsResolve: boolean): void {
|
||||
const provider: modes.LinkProvider = {
|
||||
provideLinks: (model, token) => {
|
||||
return this._proxy.$provideDocumentLinks(handle, model.uri, token).then(dto => {
|
||||
if (dto) {
|
||||
dto.forEach(obj => {
|
||||
MainThreadLanguageFeatures._reviveLinkDTO(obj);
|
||||
this._heapService.trackObject(obj);
|
||||
});
|
||||
if (!dto) {
|
||||
return undefined;
|
||||
}
|
||||
return dto;
|
||||
});
|
||||
},
|
||||
resolveLink: (link, token) => {
|
||||
return this._proxy.$resolveDocumentLink(handle, link, token).then(obj => {
|
||||
if (obj) {
|
||||
MainThreadLanguageFeatures._reviveLinkDTO(obj);
|
||||
this._heapService.trackObject(obj);
|
||||
}
|
||||
return obj;
|
||||
return {
|
||||
links: dto.links.map(MainThreadLanguageFeatures._reviveLinkDTO),
|
||||
dispose: () => {
|
||||
if (typeof dto.id === 'number') {
|
||||
this._proxy.$releaseDocumentLinks(handle, dto.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
if (supportsResolve) {
|
||||
provider.resolveLink = (link, token) => {
|
||||
const dto: LinkDto = link;
|
||||
if (!dto.cacheId) {
|
||||
return link;
|
||||
}
|
||||
return this._proxy.$resolveDocumentLink(handle, dto.cacheId, token).then(obj => {
|
||||
return obj && MainThreadLanguageFeatures._reviveLinkDTO(obj);
|
||||
});
|
||||
};
|
||||
}
|
||||
this._registrations[handle] = modes.LinkProviderRegistry.register(selector, provider);
|
||||
}
|
||||
|
||||
// --- colors
|
||||
|
||||
@@ -335,7 +335,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
private async applyCodeActions(actionsToRun: ReadonlyArray<CodeAction>) {
|
||||
private async applyCodeActions(actionsToRun: readonly CodeAction[]) {
|
||||
for (const action of actionsToRun) {
|
||||
await applyCodeAction(action, this._bulkEditService, this._commandService);
|
||||
}
|
||||
|
||||
@@ -52,9 +52,12 @@ import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
|
||||
|
||||
export interface IEnvironment {
|
||||
isExtensionDevelopmentDebug: boolean;
|
||||
appName: string;
|
||||
appRoot?: URI;
|
||||
appLanguage: string;
|
||||
appUriScheme: string;
|
||||
appSettingsHome?: URI;
|
||||
extensionDevelopmentLocationURI?: URI;
|
||||
extensionDevelopmentLocationURI?: URI | URI[];
|
||||
extensionTestsLocationURI?: URI;
|
||||
globalStorageHome: URI;
|
||||
userHome: URI;
|
||||
@@ -71,6 +74,7 @@ export interface IWorkspaceData extends IStaticWorkspaceData {
|
||||
}
|
||||
|
||||
export interface IInitData {
|
||||
version: string;
|
||||
commit?: string;
|
||||
parentPid: number;
|
||||
environment: IEnvironment;
|
||||
@@ -318,8 +322,8 @@ export interface ISerializedDocumentFilter {
|
||||
}
|
||||
|
||||
export interface ISerializedSignatureHelpProviderMetadata {
|
||||
readonly triggerCharacters: ReadonlyArray<string>;
|
||||
readonly retriggerCharacters: ReadonlyArray<string>;
|
||||
readonly triggerCharacters: readonly string[];
|
||||
readonly retriggerCharacters: readonly string[];
|
||||
}
|
||||
|
||||
export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
@@ -343,7 +347,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$registerRenameSupport(handle: number, selector: ISerializedDocumentFilter[], supportsResolveInitialValues: boolean): void;
|
||||
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void;
|
||||
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], metadata: ISerializedSignatureHelpProviderMetadata): void;
|
||||
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[], supportsResolve: boolean): void;
|
||||
$registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
@@ -878,12 +882,11 @@ export interface SuggestDataDto {
|
||||
l/* additionalTextEdits */?: ISingleEditOperation[];
|
||||
m/* command */?: modes.Command;
|
||||
// not-standard
|
||||
x: number;
|
||||
y: number;
|
||||
x?: ChainedCacheId;
|
||||
}
|
||||
|
||||
export interface SuggestResultDto {
|
||||
x: number;
|
||||
x?: number;
|
||||
a: IRange;
|
||||
b: SuggestDataDto[];
|
||||
c?: boolean;
|
||||
@@ -961,7 +964,16 @@ export interface CodeActionDto {
|
||||
isPreferred?: boolean;
|
||||
}
|
||||
|
||||
export interface LinkDto extends ObjectIdentifier {
|
||||
export type CacheId = number;
|
||||
export type ChainedCacheId = [CacheId, CacheId];
|
||||
|
||||
export interface LinksListDto {
|
||||
id?: CacheId;
|
||||
links: LinkDto[];
|
||||
}
|
||||
|
||||
export interface LinkDto {
|
||||
cacheId?: ChainedCacheId;
|
||||
range: IRange;
|
||||
url?: string | UriComponents;
|
||||
}
|
||||
@@ -1007,11 +1019,12 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise<WorkspaceEditDto | undefined>;
|
||||
$resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.RenameLocation | undefined>;
|
||||
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<SuggestResultDto | undefined>;
|
||||
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: number, pid: number, token: CancellationToken): Promise<SuggestDataDto | undefined>;
|
||||
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise<SuggestDataDto | undefined>;
|
||||
$releaseCompletionItems(handle: number, id: number): void;
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise<modes.SignatureHelp | undefined>;
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<LinkDto[] | undefined>;
|
||||
$resolveDocumentLink(handle: number, link: LinkDto, token: CancellationToken): Promise<LinkDto | undefined>;
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<LinksListDto | undefined>;
|
||||
$resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<LinkDto | undefined>;
|
||||
$releaseDocumentLinks(handle: number, id: number): void;
|
||||
$provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise<IRawColorInfo[]>;
|
||||
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined>;
|
||||
$provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise<modes.FoldingRange[] | undefined>;
|
||||
|
||||
@@ -25,7 +25,6 @@ import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/we
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWebviews)
|
||||
@@ -61,7 +60,6 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -136,7 +134,6 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
// 4) continue to forward messages to the webview
|
||||
const webview = this._instantiationService.createInstance(
|
||||
WebviewElement,
|
||||
this._layoutService.getContainer(Parts.EDITOR_PART),
|
||||
{
|
||||
extension: {
|
||||
location: URI.revive(extensionLocation),
|
||||
|
||||
@@ -9,7 +9,6 @@ import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||
@@ -17,8 +16,6 @@ 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 pkg from 'vs/platform/product/node/package';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
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';
|
||||
@@ -27,6 +24,8 @@ import { ExtHostComments } from 'vs/workbench/api/node/extHostComments';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/node/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';
|
||||
@@ -68,6 +67,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
|
||||
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';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
@@ -134,7 +134,7 @@ export function createApiFactory(
|
||||
}
|
||||
|
||||
// Check that no named customers are missing
|
||||
const expected: ProxyIdentifier<any>[] = Object.keys(ExtHostContext).map((key) => (<any>ExtHostContext)[key]);
|
||||
const expected: ProxyIdentifier<any>[] = values(ExtHostContext);
|
||||
rpcProtocol.assertRegistered(expected);
|
||||
|
||||
// Other instances
|
||||
@@ -234,10 +234,10 @@ export function createApiFactory(
|
||||
const env: typeof vscode.env = Object.freeze({
|
||||
get machineId() { return initData.telemetryInfo.machineId; },
|
||||
get sessionId() { return initData.telemetryInfo.sessionId; },
|
||||
get language() { return platform.language!; },
|
||||
get appName() { return product.nameLong; },
|
||||
get language() { return initData.environment.appLanguage; },
|
||||
get appName() { return initData.environment.appName; },
|
||||
get appRoot() { return initData.environment.appRoot!.fsPath; },
|
||||
get uriScheme() { return product.urlProtocol; },
|
||||
get uriScheme() { return initData.environment.appUriScheme; },
|
||||
get logLevel() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return typeConverters.LogLevel.to(extHostLogService.getLevel());
|
||||
@@ -628,10 +628,6 @@ export function createApiFactory(
|
||||
registerFileSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.FileSearchProvider) => {
|
||||
return extHostSearch.registerFileSearchProvider(scheme, provider);
|
||||
}),
|
||||
registerSearchProvider: proposedApiFunction(extension, () => {
|
||||
// Temp for live share in Insiders
|
||||
return { dispose: () => { } };
|
||||
}),
|
||||
registerTextSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.TextSearchProvider) => {
|
||||
return extHostSearch.registerTextSearchProvider(scheme, provider);
|
||||
}),
|
||||
|
||||
@@ -149,12 +149,25 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
$createNewCommentWidgetCallback(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, token: CancellationToken): Promise<void> {
|
||||
const commentController = this._commentControllers.get(commentControllerHandle);
|
||||
|
||||
if (!commentController || !commentController.emptyCommentThreadFactory) {
|
||||
if (!commentController) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!(commentController as any).emptyCommentThreadFactory && !(commentController.commentingRangeProvider && commentController.commentingRangeProvider.createEmptyCommentThread)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const document = this._documents.getDocument(URI.revive(uriComponents));
|
||||
return asPromise(() => commentController.emptyCommentThreadFactory!.createEmptyCommentThread(document, extHostTypeConverter.Range.to(range))).then(() => Promise.resolve());
|
||||
return asPromise(() => {
|
||||
// TODO, remove this once GH PR stable deprecates `emptyCommentThreadFactory`.
|
||||
if ((commentController as any).emptyCommentThreadFactory) {
|
||||
return (commentController as any).emptyCommentThreadFactory!.createEmptyCommentThread(document, extHostTypeConverter.Range.to(range));
|
||||
}
|
||||
|
||||
if (commentController.commentingRangeProvider && commentController.commentingRangeProvider.createEmptyCommentThread) {
|
||||
return commentController.commentingRangeProvider.createEmptyCommentThread(document, extHostTypeConverter.Range.to(range));
|
||||
}
|
||||
}).then(() => Promise.resolve());
|
||||
}
|
||||
|
||||
registerWorkspaceCommentProvider(
|
||||
@@ -558,8 +571,6 @@ class ExtHostCommentController implements vscode.CommentController {
|
||||
|
||||
private _threads: Map<number, ExtHostCommentThread> = new Map<number, ExtHostCommentThread>();
|
||||
commentingRangeProvider?: vscode.CommentingRangeProvider;
|
||||
emptyCommentThreadFactory?: vscode.EmptyCommentThreadFactory;
|
||||
|
||||
|
||||
private _commentReactionProvider?: vscode.CommentReactionProvider;
|
||||
|
||||
|
||||
@@ -707,8 +707,6 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
authority: remoteAuthority,
|
||||
host: result.host,
|
||||
port: result.port,
|
||||
debugListenPort: result.debugListenPort,
|
||||
debugConnectPort: result.debugConnectPort,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ 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 { 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 } 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 '../common/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';
|
||||
@@ -623,8 +623,7 @@ class SuggestAdapter {
|
||||
private _commands: CommandsConverter;
|
||||
private _provider: vscode.CompletionItemProvider;
|
||||
|
||||
private _cache = new Map<number, vscode.CompletionItem[]>();
|
||||
private _idPool = 0;
|
||||
private _cache = new Cache<vscode.CompletionItem>();
|
||||
|
||||
constructor(documents: ExtHostDocuments, commands: CommandsConverter, provider: vscode.CompletionItemProvider) {
|
||||
this._documents = documents;
|
||||
@@ -639,33 +638,32 @@ class SuggestAdapter {
|
||||
|
||||
return asPromise(() => this._provider.provideCompletionItems(doc, pos, token, typeConvert.CompletionContext.to(context))).then(value => {
|
||||
|
||||
const _id = this._idPool++;
|
||||
if (!value) {
|
||||
// undefined and null are valid results
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let list = Array.isArray(value) ? new CompletionList(value) : value;
|
||||
let pid: number | undefined;
|
||||
|
||||
// keep result for providers that support resolving
|
||||
if (SuggestAdapter.supportsResolving(this._provider)) {
|
||||
pid = this._cache.add(list.items);
|
||||
}
|
||||
|
||||
// the default text edit range
|
||||
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos))
|
||||
.with({ end: pos });
|
||||
|
||||
const result: SuggestResultDto = {
|
||||
x: _id,
|
||||
x: pid,
|
||||
b: [],
|
||||
a: typeConvert.Range.from(wordRangeBeforePos),
|
||||
c: list.isIncomplete || undefined
|
||||
};
|
||||
|
||||
let list: CompletionList;
|
||||
if (!value) {
|
||||
// undefined and null are valid results
|
||||
return undefined;
|
||||
|
||||
} else if (Array.isArray(value)) {
|
||||
list = new CompletionList(value);
|
||||
|
||||
} else {
|
||||
list = value;
|
||||
result.c = list.isIncomplete;
|
||||
}
|
||||
|
||||
for (let i = 0; i < list.items.length; i++) {
|
||||
const suggestion = this._convertCompletionItem2(list.items[i], pos, i, _id);
|
||||
const suggestion = this._convertCompletionItem(list.items[i], pos, pid && [pid, i] || undefined);
|
||||
// check for bad completion item
|
||||
// for the converter did warn
|
||||
if (suggestion) {
|
||||
@@ -673,21 +671,17 @@ class SuggestAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
if (SuggestAdapter.supportsResolving(this._provider)) {
|
||||
this._cache.set(_id, list.items);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
resolveCompletionItem(_resource: URI, position: IPosition, id: number, pid: number, token: CancellationToken): Promise<SuggestDataDto | undefined> {
|
||||
resolveCompletionItem(_resource: URI, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise<SuggestDataDto | undefined> {
|
||||
|
||||
if (typeof this._provider.resolveCompletionItem !== 'function') {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const item = this._cache.has(pid) ? this._cache.get(pid)![id] : undefined;
|
||||
const item = this._cache.get(...id);
|
||||
if (!item) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
@@ -699,7 +693,7 @@ class SuggestAdapter {
|
||||
}
|
||||
|
||||
const pos = typeConvert.Position.to(position);
|
||||
return this._convertCompletionItem2(resolvedItem, pos, id, pid);
|
||||
return this._convertCompletionItem(resolvedItem, pos, id);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -707,7 +701,7 @@ class SuggestAdapter {
|
||||
this._cache.delete(id);
|
||||
}
|
||||
|
||||
private _convertCompletionItem2(item: vscode.CompletionItem, position: vscode.Position, id: number, pid: number): SuggestDataDto | undefined {
|
||||
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: ChainedCacheId | undefined): SuggestDataDto | undefined {
|
||||
if (typeof item.label !== 'string' || item.label.length === 0) {
|
||||
console.warn('INVALID text edit -> must have at least a label');
|
||||
return undefined;
|
||||
@@ -716,7 +710,6 @@ class SuggestAdapter {
|
||||
const result: SuggestDataDto = {
|
||||
//
|
||||
x: id,
|
||||
y: pid,
|
||||
//
|
||||
a: item.label,
|
||||
b: typeConvert.CompletionItemKind.from(item.kind),
|
||||
@@ -800,49 +793,78 @@ class SignatureHelpAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
class Cache<T> {
|
||||
|
||||
private _data = new Map<number, T[]>();
|
||||
private _idPool = 1;
|
||||
|
||||
add(item: T[]): number {
|
||||
const id = this._idPool++;
|
||||
this._data.set(id, item);
|
||||
return id;
|
||||
}
|
||||
|
||||
get(pid: number, id: number): T | undefined {
|
||||
return this._data.has(pid) ? this._data.get(pid)![id] : undefined;
|
||||
}
|
||||
|
||||
delete(id: number) {
|
||||
this._data.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
class LinkProviderAdapter {
|
||||
|
||||
private _cache = new Cache<vscode.DocumentLink>();
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _heapService: ExtHostHeapService,
|
||||
private readonly _provider: vscode.DocumentLinkProvider
|
||||
) { }
|
||||
|
||||
provideLinks(resource: URI, token: CancellationToken): Promise<LinkDto[] | undefined> {
|
||||
provideLinks(resource: URI, token: CancellationToken): Promise<LinksListDto | undefined> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
|
||||
return asPromise(() => this._provider.provideDocumentLinks(doc, token)).then(links => {
|
||||
if (!Array.isArray(links)) {
|
||||
if (!Array.isArray(links) || links.length === 0) {
|
||||
// bad result
|
||||
return undefined;
|
||||
}
|
||||
const result: LinkDto[] = [];
|
||||
for (const link of links) {
|
||||
const data = typeConvert.DocumentLink.from(link);
|
||||
const id = this._heapService.keep(link);
|
||||
result.push(ObjectIdentifier.mixin(data, id));
|
||||
|
||||
if (typeof this._provider.resolveDocumentLink !== 'function') {
|
||||
// no resolve -> no caching
|
||||
return { links: links.map(typeConvert.DocumentLink.from) };
|
||||
|
||||
} else {
|
||||
// cache links for future resolving
|
||||
const pid = this._cache.add(links);
|
||||
const result: LinksListDto = { links: [], id: pid };
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
const dto: LinkDto = typeConvert.DocumentLink.from(links[i]);
|
||||
dto.cacheId = [pid, i];
|
||||
result.links.push(dto);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
resolveLink(link: LinkDto, token: CancellationToken): Promise<LinkDto | undefined> {
|
||||
resolveLink(id: ChainedCacheId, token: CancellationToken): Promise<LinkDto | undefined> {
|
||||
if (typeof this._provider.resolveDocumentLink !== 'function') {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const id = ObjectIdentifier.of(link);
|
||||
const item = this._heapService.get<vscode.DocumentLink>(id);
|
||||
const item = this._cache.get(...id);
|
||||
if (!item) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
return asPromise(() => this._provider.resolveDocumentLink!(item, token)).then(value => {
|
||||
if (value) {
|
||||
return typeConvert.DocumentLink.from(value);
|
||||
}
|
||||
return undefined;
|
||||
return value && typeConvert.DocumentLink.from(value) || undefined;
|
||||
});
|
||||
}
|
||||
|
||||
releaseLinks(id: number): any {
|
||||
this._cache.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
class ColorProviderAdapter {
|
||||
@@ -1373,8 +1395,8 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(URI.revive(resource), position, context, token), undefined);
|
||||
}
|
||||
|
||||
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: number, pid: number, token: CancellationToken): Promise<SuggestDataDto | undefined> {
|
||||
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(URI.revive(resource), position, id, pid, token), undefined);
|
||||
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, id: ChainedCacheId, token: CancellationToken): Promise<SuggestDataDto | undefined> {
|
||||
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(URI.revive(resource), position, id, token), undefined);
|
||||
}
|
||||
|
||||
$releaseCompletionItems(handle: number, id: number): void {
|
||||
@@ -1400,17 +1422,21 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
// --- links
|
||||
|
||||
registerDocumentLinkProvider(extension: IExtensionDescription | undefined, selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new LinkProviderAdapter(this._documents, this._heapService, provider), extension);
|
||||
this._proxy.$registerDocumentLinkProvider(handle, this._transformDocumentSelector(selector));
|
||||
const handle = this._addNewAdapter(new LinkProviderAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerDocumentLinkProvider(handle, this._transformDocumentSelector(selector), typeof provider.resolveDocumentLink === 'function');
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<LinkDto[] | undefined> {
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<LinksListDto | undefined> {
|
||||
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource), token), undefined);
|
||||
}
|
||||
|
||||
$resolveDocumentLink(handle: number, link: modes.ILink, token: CancellationToken): Promise<LinkDto | undefined> {
|
||||
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(link, token), undefined);
|
||||
$resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<LinkDto | undefined> {
|
||||
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(id, token), undefined);
|
||||
}
|
||||
|
||||
$releaseDocumentLinks(handle: number, id: number): void {
|
||||
this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.releaseLinks(id), undefined);
|
||||
}
|
||||
|
||||
registerColorProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
|
||||
|
||||
@@ -432,8 +432,6 @@ export class Selection extends Range {
|
||||
export class ResolvedAuthority {
|
||||
readonly host: string;
|
||||
readonly port: number;
|
||||
debugListenPort?: number;
|
||||
debugConnectPort?: number;
|
||||
|
||||
constructor(host: string, port: number) {
|
||||
if (typeof host !== 'string' || host.length === 0) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as resources from 'vs/base/common/resources';
|
||||
import { IconLabel, IIconLabelValueOptions, IIconLabelCreationOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { toResource, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { toResource, IEditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -332,7 +332,7 @@ class ResourceLabelWidget extends IconLabel {
|
||||
|
||||
setEditor(editor: IEditorInput, options?: IResourceLabelOptions): void {
|
||||
this.setResource({
|
||||
resource: withNullAsUndefined(toResource(editor, { supportSideBySide: true })),
|
||||
resource: withNullAsUndefined(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER })),
|
||||
name: withNullAsUndefined(editor.getName()),
|
||||
description: withNullAsUndefined(editor.getDescription())
|
||||
}, options);
|
||||
|
||||
@@ -45,6 +45,11 @@ class CodeRendererMain extends Disposable {
|
||||
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().
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
return { serviceCollection, logService };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ import { SimpleConfigurationService as StandaloneEditorConfigurationService, Sta
|
||||
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 { IExtensionGalleryService, IQueryOptions, IGalleryExtension, InstallOperation, StatisticType, ITranslation, IGalleryExtensionVersion, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
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 } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionManifest, ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { NullExtensionService, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -251,7 +251,7 @@ export class SimpleEnvironmentService implements IEnvironmentService {
|
||||
disableExtensions: boolean | string[];
|
||||
builtinExtensionsPath: string;
|
||||
extensionsPath: string;
|
||||
extensionDevelopmentLocationURI?: URI;
|
||||
extensionDevelopmentLocationURI?: URI | URI[];
|
||||
extensionTestsPath?: string;
|
||||
debugExtensionHost: IExtensionHostDebugParams;
|
||||
debugSearch: IDebugParams;
|
||||
@@ -354,6 +354,38 @@ registerSingleton(IExtensionGalleryService, SimpleExtensionGalleryService, true)
|
||||
|
||||
//#region Extension Management
|
||||
|
||||
//#region Extension Enablement
|
||||
|
||||
export class SimpleExtensionEnablementService implements IExtensionEnablementService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
readonly onEnablementChanged = Event.None;
|
||||
|
||||
readonly allUserExtensionsDisabled = true;
|
||||
|
||||
getEnablementState(extension: IExtension): EnablementState {
|
||||
return EnablementState.Disabled;
|
||||
}
|
||||
|
||||
canChangeEnablement(extension: IExtension): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
setEnablement(extensions: IExtension[], newState: EnablementState): Promise<boolean[]> {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
isEnabled(extension: IExtension): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionEnablementService, SimpleExtensionEnablementService, true);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Extension Tips
|
||||
|
||||
export class SimpleExtensionTipsService implements IExtensionTipsService {
|
||||
|
||||
@@ -73,6 +73,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
||||
this.visibleComposites = [];
|
||||
this.compositeSizeInBar = new Map<string, number>();
|
||||
this.compositeTransfer = LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>();
|
||||
this.computeSizes(this.model.visibleItems);
|
||||
}
|
||||
|
||||
getCompositeBarItems(): ICompositeBarItem[] {
|
||||
|
||||
@@ -15,7 +15,7 @@ import { QuickOpenHandler } from 'vs/workbench/browser/quickopen';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService, IEditorGroup, EditorsOrder, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { EditorInput, toResource } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
@@ -50,7 +50,7 @@ export class EditorPickerEntry extends QuickOpenEntryGroup {
|
||||
}
|
||||
|
||||
getResource() {
|
||||
return toResource(this.editor, { supportSideBySide: true });
|
||||
return toResource(this.editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
}
|
||||
|
||||
getAriaLabel(): string {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Language } from 'vs/base/common/platform';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput, IEditor as IBaseEditor, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput, IEditor as IBaseEditor, IEditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { IDisposable, combinedDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IEditorAction } from 'vs/editor/common/editorCommon';
|
||||
@@ -772,7 +772,7 @@ export class EditorStatus implements IStatusbarItem {
|
||||
private onResourceEncodingChange(resource: URI): void {
|
||||
const activeControl = this.editorService.activeControl;
|
||||
if (activeControl) {
|
||||
const activeResource = toResource(activeControl.input, { supportSideBySide: true });
|
||||
const activeResource = toResource(activeControl.input, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (activeResource && activeResource.toString() === resource.toString()) {
|
||||
return this.onEncodingChange(<IBaseEditor>activeControl); // only update if the encoding changed for the active resource
|
||||
}
|
||||
@@ -850,7 +850,7 @@ export class ChangeModeAction extends Action {
|
||||
}
|
||||
|
||||
const textModel = activeTextEditorWidget.getModel();
|
||||
const resource = this.editorService.activeEditor ? toResource(this.editorService.activeEditor, { supportSideBySide: true }) : null;
|
||||
const resource = this.editorService.activeEditor ? toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null;
|
||||
|
||||
let hasLanguageSupport = !!resource;
|
||||
if (resource && resource.scheme === Schemas.untitled && !this.untitledEditorService.hasAssociatedFilePath(resource)) {
|
||||
@@ -976,7 +976,7 @@ export class ChangeModeAction extends Action {
|
||||
if (pick === autoDetectMode) {
|
||||
if (textModel) {
|
||||
// {{SQL CARBON EDIT}} - use activeEditor.input instead of activeEditor
|
||||
const resource = toResource(activeEditor.input, { supportSideBySide: true });
|
||||
const resource = toResource(activeEditor.input, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource) {
|
||||
languageSelection = this.modeService.createByFilepathOrFirstLine(resource.fsPath, textModel.getLineContent(1));
|
||||
}
|
||||
@@ -1195,7 +1195,7 @@ export class ChangeEncodingAction extends Action {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const resource = toResource(activeControl!.input, { supportSideBySide: true });
|
||||
const resource = toResource(activeControl!.input, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
|
||||
return timeout(50 /* quick open is sensitive to being opened so soon after another */)
|
||||
.then(() => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/notabstitlecontrol';
|
||||
import { toResource, Verbosity, IEditorInput, IEditorPartOptions } from 'vs/workbench/common/editor';
|
||||
import { toResource, Verbosity, IEditorInput, IEditorPartOptions, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { TitleControl, IToolbarActions } from 'vs/workbench/browser/parts/editor/titleControl';
|
||||
import { ResourceLabel, IResourceLabel } from 'vs/workbench/browser/labels';
|
||||
import { TAB_ACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
@@ -237,7 +237,7 @@ export class NoTabsTitleControl extends TitleControl {
|
||||
this.updateEditorDirty(editor);
|
||||
|
||||
// Editor Label
|
||||
const resource = toResource(editor, { supportSideBySide: true });
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
const name = editor.getName() || '';
|
||||
|
||||
const { labelFormat } = this.accessor.partOptions;
|
||||
|
||||
@@ -21,6 +21,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
export class SideBySideEditor extends BaseEditor {
|
||||
|
||||
static readonly ID: string = 'workbench.editor.sidebysideEditor';
|
||||
static MASTER: SideBySideEditor | undefined;
|
||||
|
||||
get minimumMasterWidth() { return this.masterEditor ? this.masterEditor.minimumWidth : 0; }
|
||||
get maximumMasterWidth() { return this.masterEditor ? this.masterEditor.maximumWidth : Number.POSITIVE_INFINITY; }
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./media/tabstitlecontrol';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { shorten } from 'vs/base/common/labels';
|
||||
import { toResource, GroupIdentifier, IEditorInput, Verbosity, EditorCommandsContextActionRunner, IEditorPartOptions } from 'vs/workbench/common/editor';
|
||||
import { toResource, GroupIdentifier, IEditorInput, Verbosity, EditorCommandsContextActionRunner, IEditorPartOptions, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
@@ -608,7 +608,7 @@ export class TabsTitleControl extends TitleControl {
|
||||
e.dataTransfer!.effectAllowed = 'copyMove';
|
||||
|
||||
// Apply some datatransfer types to allow for dragging the element outside of the application
|
||||
const resource = toResource(editor, { supportSideBySide: true });
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource) {
|
||||
this.instantiationService.invokeFunction(fillResourceDataTransfers, [resource], e);
|
||||
}
|
||||
@@ -899,7 +899,7 @@ export class TabsTitleControl extends TitleControl {
|
||||
tabContainer.title = title;
|
||||
|
||||
// Label
|
||||
tabLabelWidget.setResource({ name, description, resource: toResource(editor, { supportSideBySide: true }) || undefined }, { title, extraClasses: ['tab-label'], italic: !this.group.isPinned(editor) });
|
||||
tabLabelWidget.setResource({ name, description, resource: toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }) || undefined }, { title, extraClasses: ['tab-label'], italic: !this.group.isPinned(editor) });
|
||||
|
||||
// {{SQL CARBON EDIT}} -- Display the editor's tab color
|
||||
const isTabActive = this.group.isActive(editor);
|
||||
|
||||
@@ -33,7 +33,7 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs';
|
||||
import { BreadcrumbsControl, IBreadcrumbsControlOptions } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
|
||||
import { EDITOR_TITLE_HEIGHT, IEditorGroupsAccessor, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { EditorCommandsContextActionRunner, IEditorCommandsContext, IEditorInput, toResource, IEditorPartOptions } from 'vs/workbench/common/editor';
|
||||
import { EditorCommandsContextActionRunner, IEditorCommandsContext, IEditorInput, toResource, IEditorPartOptions, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { ResourceContextKey } from 'vs/workbench/common/resources';
|
||||
import { Themable } from 'vs/workbench/common/theme';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -219,7 +219,7 @@ export abstract class TitleControl extends Themable {
|
||||
this.editorToolBarMenuDisposables = dispose(this.editorToolBarMenuDisposables);
|
||||
|
||||
// Update the resource context
|
||||
this.resourceContext.set(this.group.activeEditor ? toResource(this.group.activeEditor, { supportSideBySide: true }) : null);
|
||||
this.resourceContext.set(this.group.activeEditor ? toResource(this.group.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null);
|
||||
|
||||
// Editor actions require the editor control to be there, so we retrieve it via service
|
||||
const activeControl = this.group.activeControl;
|
||||
@@ -259,7 +259,7 @@ export abstract class TitleControl extends Themable {
|
||||
|
||||
// If tabs are disabled, treat dragging as if an editor tab was dragged
|
||||
if (!this.accessor.partOptions.showTabs) {
|
||||
const resource = this.group.activeEditor ? toResource(this.group.activeEditor, { supportSideBySide: true }) : null;
|
||||
const resource = this.group.activeEditor ? toResource(this.group.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null;
|
||||
if (resource) {
|
||||
this.instantiationService.invokeFunction(fillResourceDataTransfers, [resource], e);
|
||||
}
|
||||
@@ -286,7 +286,7 @@ export abstract class TitleControl extends Themable {
|
||||
|
||||
// Update the resource context
|
||||
const currentContext = this.resourceContext.get();
|
||||
this.resourceContext.set(toResource(editor, { supportSideBySide: true }));
|
||||
this.resourceContext.set(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }));
|
||||
|
||||
// Find target anchor
|
||||
let anchor: HTMLElement | { x: number, y: number } = node;
|
||||
|
||||
@@ -191,6 +191,10 @@ export class NotificationsToasts extends Themable {
|
||||
|
||||
// Update when item height potentially changes due to label changes
|
||||
itemDisposeables.push(item.onDidLabelChange(e => {
|
||||
if (!item.expanded) {
|
||||
return; // dynamic height only applies to expanded notifications
|
||||
}
|
||||
|
||||
if (e.kind === NotificationViewItemLabelKind.ACTIONS || e.kind === NotificationViewItemLabelKind.MESSAGE) {
|
||||
notificationList.updateNotificationsList(0, 1, [item]);
|
||||
}
|
||||
|
||||
@@ -350,6 +350,9 @@ export class NotificationTemplateRenderer {
|
||||
case NotificationViewItemLabelKind.PROGRESS:
|
||||
this.renderProgress(notification);
|
||||
break;
|
||||
case NotificationViewItemLabelKind.MESSAGE:
|
||||
this.renderMessage(notification);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -45,10 +45,12 @@
|
||||
}
|
||||
|
||||
/* adding padding to the most left status bar item */
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.left:first-child, .monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.left {
|
||||
.monaco-workbench .part.statusbar > .statusbar-item.left:first-child,
|
||||
.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 {
|
||||
.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 */
|
||||
|
||||
@@ -17,7 +17,7 @@ import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/co
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import * as nls from 'vs/nls';
|
||||
import { EditorInput, toResource, Verbosity } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, toResource, Verbosity, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
@@ -179,7 +179,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
}
|
||||
|
||||
private updateRepresentedFilename(): void {
|
||||
const file = toResource(this.editorService.activeEditor, { supportSideBySide: true, filter: 'file' });
|
||||
const file = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: 'file' });
|
||||
const path = file ? file.fsPath : '';
|
||||
|
||||
// Apply to window
|
||||
@@ -282,7 +282,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
// Compute folder resource
|
||||
// Single Root Workspace: always the root single workspace in this case
|
||||
// Otherwise: root folder of the currently active file if any
|
||||
const folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(editor, { supportSideBySide: true })!);
|
||||
const folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER })!);
|
||||
|
||||
// Variables
|
||||
const activeEditorShort = editor ? editor.getTitle(Verbosity.SHORT) : '';
|
||||
|
||||
@@ -205,8 +205,7 @@ export class Workbench extends Layout {
|
||||
|
||||
// TODO@Sandeep debt around cyclic dependencies
|
||||
const configurationService = accessor.get(IConfigurationService) as any;
|
||||
if (typeof configurationService.acquireFileService === 'function') {
|
||||
configurationService.acquireFileService(fileService);
|
||||
if (typeof configurationService.acquireInstantiationService === 'function') {
|
||||
configurationService.acquireInstantiationService(instantiationService);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { isUndefinedOrNull, withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon';
|
||||
@@ -14,7 +14,6 @@ import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from
|
||||
import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ICompositeControl } from 'vs/workbench/common/composite';
|
||||
import { ActionRunner, IAction } from 'vs/base/common/actions';
|
||||
@@ -582,7 +581,7 @@ export class SideBySideEditorInput extends EditorInput {
|
||||
getTelemetryDescriptor(): object {
|
||||
const descriptor = this.master.getTelemetryDescriptor();
|
||||
|
||||
return objects.assign(descriptor, super.getTelemetryDescriptor());
|
||||
return assign(descriptor, super.getTelemetryDescriptor());
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
@@ -838,7 +837,7 @@ export class TextEditorOptions extends EditorOptions {
|
||||
* Returns if this options object has objects defined for the editor.
|
||||
*/
|
||||
hasOptionsDefined(): boolean {
|
||||
return !!this.editorViewState || (!types.isUndefinedOrNull(this.startLineNumber) && !types.isUndefinedOrNull(this.startColumn));
|
||||
return !!this.editorViewState || (!isUndefinedOrNull(this.startLineNumber) && !isUndefinedOrNull(this.startColumn));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -886,10 +885,10 @@ export class TextEditorOptions extends EditorOptions {
|
||||
}
|
||||
|
||||
// Otherwise check for selection
|
||||
else if (!types.isUndefinedOrNull(this.startLineNumber) && !types.isUndefinedOrNull(this.startColumn)) {
|
||||
else if (!isUndefinedOrNull(this.startLineNumber) && !isUndefinedOrNull(this.startColumn)) {
|
||||
|
||||
// Select
|
||||
if (!types.isUndefinedOrNull(this.endLineNumber) && !types.isUndefinedOrNull(this.endColumn)) {
|
||||
if (!isUndefinedOrNull(this.endLineNumber) && !isUndefinedOrNull(this.endColumn)) {
|
||||
const range = {
|
||||
startLineNumber: this.startLineNumber,
|
||||
startColumn: this.startColumn,
|
||||
@@ -990,9 +989,14 @@ export interface IEditorPartOptions extends IEditorPartConfiguration {
|
||||
iconTheme?: string;
|
||||
}
|
||||
|
||||
export enum SideBySideEditor {
|
||||
MASTER = 1,
|
||||
DETAILS = 2
|
||||
}
|
||||
|
||||
export interface IResourceOptions {
|
||||
supportSideBySide?: boolean;
|
||||
filter?: string | string[];
|
||||
supportSideBySide?: SideBySideEditor;
|
||||
filterByScheme?: string | string[];
|
||||
}
|
||||
|
||||
export function toResource(editor: IEditorInput | null | undefined, options?: IResourceOptions): URI | null {
|
||||
@@ -1000,35 +1004,20 @@ export function toResource(editor: IEditorInput | null | undefined, options?: IR
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check for side by side if we are asked to
|
||||
if (options && options.supportSideBySide && editor instanceof SideBySideEditorInput) {
|
||||
editor = editor.master;
|
||||
editor = options.supportSideBySide === SideBySideEditor.MASTER ? editor.master : editor.details;
|
||||
}
|
||||
|
||||
const resource = editor.getResource();
|
||||
if (!options || !options.filter) {
|
||||
return types.withUndefinedAsNull(resource); // return early if no filter is specified
|
||||
if (!resource || !options || !options.filterByScheme) {
|
||||
return withUndefinedAsNull(resource);
|
||||
}
|
||||
|
||||
if (!resource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let includeFiles: boolean;
|
||||
let includeUntitled: boolean;
|
||||
if (Array.isArray(options.filter)) {
|
||||
includeFiles = (options.filter.indexOf(Schemas.file) >= 0);
|
||||
includeUntitled = (options.filter.indexOf(Schemas.untitled) >= 0);
|
||||
} else {
|
||||
includeFiles = (options.filter === Schemas.file);
|
||||
includeUntitled = (options.filter === Schemas.untitled);
|
||||
}
|
||||
|
||||
if (includeFiles && resource.scheme === Schemas.file) {
|
||||
if (Array.isArray(options.filterByScheme) && options.filterByScheme.some(scheme => resource.scheme === scheme)) {
|
||||
return resource;
|
||||
}
|
||||
|
||||
if (includeUntitled && resource.scheme === Schemas.untitled) {
|
||||
if (options.filterByScheme === resource.scheme) {
|
||||
return resource;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Extensions, IEditorInputFactoryRegistry, EditorInput, toResource, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { Extensions, IEditorInputFactoryRegistry, EditorInput, toResource, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -157,7 +157,7 @@ export class EditorGroup extends Disposable {
|
||||
}
|
||||
|
||||
for (const editor of this.editors) {
|
||||
const editorResource = toResource(editor, { supportSideBySide: true });
|
||||
const editorResource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (editorResource && editorResource.toString() === resource.toString()) {
|
||||
return editor;
|
||||
}
|
||||
@@ -541,7 +541,7 @@ export class EditorGroup extends Disposable {
|
||||
}
|
||||
|
||||
private updateResourceMap(editor: EditorInput, remove: boolean): void {
|
||||
const resource = toResource(editor, { supportSideBySide: true });
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource) {
|
||||
|
||||
// It is possible to have the same resource opened twice (once as normal input and once as diff input)
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface IResourceCommentThreadEvent {
|
||||
|
||||
export interface ICommentInfo extends CommentInfo {
|
||||
owner: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export interface IWorkspaceCommentThreadsEvent {
|
||||
|
||||
@@ -34,6 +34,9 @@ import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/c
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ctxCommentEditorFocused, SimpleCommentEditor } from 'vs/workbench/contrib/comments/browser/simpleCommentEditor';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
|
||||
import { IQuickInputService, QuickPickInput, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
|
||||
export const ID = 'editor.contrib.review';
|
||||
|
||||
@@ -61,7 +64,7 @@ class CommentingRangeDecoration {
|
||||
return this._decorationId;
|
||||
}
|
||||
|
||||
constructor(private _editor: ICodeEditor, private _ownerId: string, private _extensionId: string | undefined, private _range: IRange, private _reply: modes.Command | undefined, commentingOptions: ModelDecorationOptions, private commentingRangesInfo?: modes.CommentingRanges) {
|
||||
constructor(private _editor: ICodeEditor, private _ownerId: string, private _extensionId: string | undefined, private _label: string | undefined, private _range: IRange, private _reply: modes.Command | undefined, commentingOptions: ModelDecorationOptions, private commentingRangesInfo?: modes.CommentingRanges) {
|
||||
const startLineNumber = _range.startLineNumber;
|
||||
const endLineNumber = _range.endLineNumber;
|
||||
let commentingRangeDecorations = [{
|
||||
@@ -78,9 +81,10 @@ class CommentingRangeDecoration {
|
||||
}
|
||||
}
|
||||
|
||||
public getCommentAction(): { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined } {
|
||||
public getCommentAction(): { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined } {
|
||||
return {
|
||||
extensionId: this._extensionId,
|
||||
label: this._label,
|
||||
replyCommand: this._reply,
|
||||
ownerId: this._ownerId,
|
||||
commentingRangesInfo: this.commentingRangesInfo
|
||||
@@ -120,11 +124,11 @@ class CommentingRangeDecorator {
|
||||
for (const info of commentInfos) {
|
||||
if (Array.isArray(info.commentingRanges)) {
|
||||
info.commentingRanges.forEach(range => {
|
||||
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, range, info.reply, this.decorationOptions));
|
||||
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, info.label, range, info.reply, this.decorationOptions));
|
||||
});
|
||||
} else {
|
||||
(info.commentingRanges ? info.commentingRanges.ranges : []).forEach(range => {
|
||||
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, range, (info.commentingRanges as modes.CommentingRanges).newCommentThreadCommand, this.decorationOptions, info.commentingRanges as modes.CommentingRanges));
|
||||
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, info.label, range, (info.commentingRanges as modes.CommentingRanges).newCommentThreadCommand, this.decorationOptions, info.commentingRanges as modes.CommentingRanges));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -136,14 +140,15 @@ class CommentingRangeDecorator {
|
||||
}
|
||||
|
||||
public getMatchedCommentAction(line: number) {
|
||||
let result = [];
|
||||
for (const decoration of this.commentingRangeDecorations) {
|
||||
const range = decoration.getActiveRange();
|
||||
if (range && range.startLineNumber <= line && line <= range.endLineNumber) {
|
||||
return decoration.getCommentAction();
|
||||
result.push(decoration.getCommentAction());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return result;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -164,7 +169,7 @@ export class ReviewController implements IEditorContribution {
|
||||
private _commentingRangeSpaceReserved = false;
|
||||
private _computePromise: CancelablePromise<Array<ICommentInfo | null>> | null;
|
||||
private _addInProgress: boolean;
|
||||
private _emptyThreadsToAddQueue: number[] = [];
|
||||
private _emptyThreadsToAddQueue: [number, IEditorMouseEvent | undefined][] = [];
|
||||
private _computeCommentingRangePromise: CancelablePromise<ICommentInfo[]> | null;
|
||||
private _computeCommentingRangeScheduler: Delayer<Array<ICommentInfo | null>> | null;
|
||||
private _pendingCommentCache: { [key: number]: { [key: string]: string } };
|
||||
@@ -178,6 +183,7 @@ export class ReviewController implements IEditorContribution {
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
|
||||
@IContextMenuService readonly contextMenuService: IContextMenuService,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService
|
||||
) {
|
||||
this.editor = editor;
|
||||
this.globalToDispose = [];
|
||||
@@ -547,11 +553,11 @@ export class ReviewController implements IEditorContribution {
|
||||
|
||||
if (e.target.element.className.indexOf('comment-diff-added') >= 0) {
|
||||
const lineNumber = e.target.position!.lineNumber;
|
||||
this.addOrToggleCommentAtLine(lineNumber);
|
||||
this.addOrToggleCommentAtLine(lineNumber, e);
|
||||
}
|
||||
}
|
||||
|
||||
public async addOrToggleCommentAtLine(lineNumber: number): Promise<void> {
|
||||
public async addOrToggleCommentAtLine(lineNumber: number, e: IEditorMouseEvent | undefined): Promise<void> {
|
||||
// If an add is already in progress, queue the next add and process it after the current one finishes to
|
||||
// prevent empty comment threads from being added to the same line.
|
||||
if (!this._addInProgress) {
|
||||
@@ -563,29 +569,98 @@ export class ReviewController implements IEditorContribution {
|
||||
this.processNextThreadToAdd();
|
||||
return;
|
||||
} else {
|
||||
this.addCommentAtLine(lineNumber);
|
||||
this.addCommentAtLine(lineNumber, e);
|
||||
}
|
||||
} else {
|
||||
this._emptyThreadsToAddQueue.push(lineNumber);
|
||||
this._emptyThreadsToAddQueue.push([lineNumber, e]);
|
||||
}
|
||||
}
|
||||
|
||||
private processNextThreadToAdd(): void {
|
||||
this._addInProgress = false;
|
||||
const lineNumber = this._emptyThreadsToAddQueue.shift();
|
||||
if (lineNumber) {
|
||||
this.addOrToggleCommentAtLine(lineNumber);
|
||||
const info = this._emptyThreadsToAddQueue.shift();
|
||||
if (info) {
|
||||
this.addOrToggleCommentAtLine(info[0], info[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public addCommentAtLine(lineNumber: number): Promise<void> {
|
||||
const newCommentInfo = this._commentingRangeDecorator.getMatchedCommentAction(lineNumber);
|
||||
if (!newCommentInfo || !this.editor.hasModel()) {
|
||||
public addCommentAtLine(lineNumber: number, e: IEditorMouseEvent | undefined): Promise<void> {
|
||||
const newCommentInfos = this._commentingRangeDecorator.getMatchedCommentAction(lineNumber);
|
||||
if (!newCommentInfos.length || !this.editor.hasModel()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const { replyCommand, ownerId, extensionId, commentingRangesInfo } = newCommentInfo;
|
||||
if (newCommentInfos.length > 1) {
|
||||
if (e) {
|
||||
const anchor = { x: e.event.posx, y: e.event.posy };
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => this.getContextMenuActions(newCommentInfos, lineNumber),
|
||||
getActionsContext: () => newCommentInfos.length ? newCommentInfos[0] : undefined,
|
||||
onHide: () => { this._addInProgress = false; }
|
||||
});
|
||||
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
const picks = this.getCommentProvidersQuickPicks(newCommentInfos);
|
||||
return this.quickInputService.pick(picks, { placeHolder: nls.localize('pickCommentService', "Select Comment Provider"), matchOnDescription: true }).then(pick => {
|
||||
if (!pick) {
|
||||
return;
|
||||
}
|
||||
|
||||
const commentInfos = newCommentInfos.filter(info => info.ownerId === pick.id);
|
||||
|
||||
if (commentInfos.length) {
|
||||
const { replyCommand, ownerId, extensionId, commentingRangesInfo } = commentInfos[0];
|
||||
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo);
|
||||
}
|
||||
}).then(() => {
|
||||
this._addInProgress = false;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const { replyCommand, ownerId, extensionId, commentingRangesInfo } = newCommentInfos[0]!;
|
||||
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private getCommentProvidersQuickPicks(commentInfos: { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined }[]) {
|
||||
const picks: QuickPickInput[] = commentInfos.map((commentInfo) => {
|
||||
const { ownerId, extensionId, label } = commentInfo;
|
||||
|
||||
return <IQuickPickItem>{
|
||||
label: label || extensionId,
|
||||
id: ownerId
|
||||
};
|
||||
});
|
||||
|
||||
return picks;
|
||||
}
|
||||
|
||||
private getContextMenuActions(commentInfos: { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined }[], lineNumber: number): (IAction | ContextSubMenu)[] {
|
||||
const actions: (IAction | ContextSubMenu)[] = [];
|
||||
|
||||
commentInfos.forEach(commentInfo => {
|
||||
const { replyCommand, ownerId, extensionId, label, commentingRangesInfo } = commentInfo;
|
||||
|
||||
actions.push(new Action(
|
||||
'addCommentThread',
|
||||
`${label || extensionId}`,
|
||||
undefined,
|
||||
true,
|
||||
() => {
|
||||
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo);
|
||||
return Promise.resolve();
|
||||
}
|
||||
));
|
||||
});
|
||||
return actions;
|
||||
}
|
||||
|
||||
public addCommentAtLine2(lineNumber: number, replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined) {
|
||||
if (commentingRangesInfo) {
|
||||
let range = new Range(lineNumber, 1, lineNumber, 1);
|
||||
if (commentingRangesInfo.newCommentThreadCommand) {
|
||||
@@ -597,7 +672,7 @@ export class ReviewController implements IEditorContribution {
|
||||
this._addInProgress = false;
|
||||
}
|
||||
} else if (commentingRangesInfo.newCommentThreadCallback) {
|
||||
return commentingRangesInfo.newCommentThreadCallback(this.editor.getModel().uri, range)
|
||||
return commentingRangesInfo.newCommentThreadCallback(this.editor.getModel()!.uri, range)
|
||||
.then(_ => {
|
||||
this.processNextThreadToAdd();
|
||||
})
|
||||
@@ -621,7 +696,6 @@ export class ReviewController implements IEditorContribution {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
|
||||
private setComments(commentInfos: ICommentInfo[]): void {
|
||||
if (!this.editor) {
|
||||
return;
|
||||
@@ -762,7 +836,7 @@ CommandsRegistry.registerCommand({
|
||||
}
|
||||
|
||||
const position = activeEditor.getPosition();
|
||||
return controller.addOrToggleCommentAtLine(position.lineNumber);
|
||||
return controller.addOrToggleCommentAtLine(position.lineNumber, undefined);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -797,7 +797,7 @@ export class DebugModel implements IDebugModel {
|
||||
// Make sure to de-dupe if a session is re-intialized. In case of EH debugging we are adding a session again after an attach.
|
||||
return false;
|
||||
}
|
||||
if (s.state === State.Inactive && s.getLabel() === session.getLabel()) {
|
||||
if (s.state === State.Inactive && s.configuration.name === session.configuration.name) {
|
||||
// Make sure to remove all inactive sessions that are using the same configuration as the new session
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -783,6 +783,7 @@ export class DebugSession implements IDebugSession {
|
||||
}));
|
||||
|
||||
this.rawListeners.push(this.raw.onDidExitAdapter(event => {
|
||||
this.initialized = true;
|
||||
this._onDidEndAdapter.fire(event);
|
||||
}));
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import {
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
+19
-19
@@ -83,30 +83,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', () => {
|
||||
|
||||
|
||||
@@ -115,20 +115,16 @@ export function onExtensionChanged(accessor: ServicesAccessor): Event<IExtension
|
||||
});
|
||||
}
|
||||
|
||||
export function getInstalledExtensions(accessor: ServicesAccessor): Promise<IExtensionStatus[]> {
|
||||
export async function getInstalledExtensions(accessor: ServicesAccessor): Promise<IExtensionStatus[]> {
|
||||
const extensionService = accessor.get(IExtensionManagementService);
|
||||
const extensionEnablementService = accessor.get(IExtensionEnablementService);
|
||||
return extensionService.getInstalled().then(extensions => {
|
||||
return extensionEnablementService.getDisabledExtensions()
|
||||
.then(disabledExtensions => {
|
||||
return extensions.map(extension => {
|
||||
return {
|
||||
identifier: extension.identifier,
|
||||
local: extension,
|
||||
globallyEnabled: disabledExtensions.every(disabled => !areSameExtensions(disabled, extension.identifier))
|
||||
};
|
||||
});
|
||||
});
|
||||
const extensions = await extensionService.getInstalled();
|
||||
return extensions.map(extension => {
|
||||
return {
|
||||
identifier: extension.identifier,
|
||||
local: extension,
|
||||
globallyEnabled: extensionEnablementService.isEnabled(extension)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/we
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -200,7 +199,6 @@ export class ExtensionEditor extends BaseEditor {
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
|
||||
@IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@@ -546,7 +544,6 @@ export class ExtensionEditor extends BaseEditor {
|
||||
.then(removeEmbeddedSVGs)
|
||||
.then(body => {
|
||||
const wbeviewElement = this.instantiationService.createInstance(WebviewElement,
|
||||
this.layoutService.getContainer(Parts.EDITOR_PART),
|
||||
{
|
||||
enableFindWidget: true,
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./media/extensionActions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { Throttler, Delayer } from 'vs/base/common/async';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import * as json from 'vs/base/common/json';
|
||||
@@ -1044,9 +1044,10 @@ export class ReloadAction extends ExtensionAction {
|
||||
private static readonly EnabledClass = 'extension-action reload';
|
||||
private static readonly DisabledClass = `${ReloadAction.EnabledClass} disabled`;
|
||||
|
||||
// Use delayer to wait for more updates
|
||||
private throttler: Throttler;
|
||||
private disposables: IDisposable[] = [];
|
||||
private _runningExtensions: IExtensionDescription[] = [];
|
||||
private get runningExtensions(): IExtensionDescription[] { return this._runningExtensions; }
|
||||
private set runningExtensions(runningExtensions: IExtensionDescription[]) { this._runningExtensions = runningExtensions; this.update(); }
|
||||
|
||||
constructor(
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@@ -1055,39 +1056,38 @@ export class ReloadAction extends ExtensionAction {
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
|
||||
) {
|
||||
super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
|
||||
this.throttler = new Throttler();
|
||||
this.extensionService.onDidChangeExtensions(this.update, this, this.disposables);
|
||||
this.update();
|
||||
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
|
||||
this.updateRunningExtensions();
|
||||
}
|
||||
|
||||
update(): Promise<void> {
|
||||
return this.throttler.queue(() => {
|
||||
this.enabled = false;
|
||||
this.tooltip = '';
|
||||
if (!this.extension) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
const state = this.extension.state;
|
||||
if (state === ExtensionState.Installing || state === ExtensionState.Uninstalling) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
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) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
return this.extensionService.getExtensions()
|
||||
.then(runningExtensions => this.computeReloadState(runningExtensions, installed));
|
||||
}).then(() => {
|
||||
this.class = this.enabled ? ReloadAction.EnabledClass : ReloadAction.DisabledClass;
|
||||
});
|
||||
private updateRunningExtensions(): void {
|
||||
this.extensionService.getExtensions().then(runningExtensions => this.runningExtensions = runningExtensions);
|
||||
}
|
||||
|
||||
private computeReloadState(runningExtensions: IExtensionDescription[], installed: IExtension): void {
|
||||
update(): void {
|
||||
this.enabled = false;
|
||||
this.tooltip = '';
|
||||
if (!this.extension) {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
this.computeReloadState(installed);
|
||||
this.class = this.enabled ? ReloadAction.EnabledClass : ReloadAction.DisabledClass;
|
||||
}
|
||||
|
||||
private computeReloadState(installed: IExtension): void {
|
||||
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 = 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 (runningExtension) {
|
||||
|
||||
@@ -11,12 +11,12 @@ import * as ExtensionsActions from 'vs/workbench/contrib/extensions/electron-bro
|
||||
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService';
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, IGalleryExtension,
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, EnablementState, InstallOperation, IExtensionManagementServerService, IExtensionManagementServer
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, EnablementState, InstallOperation, IExtensionManagementServerService
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/electron-browser/extensionTipsService';
|
||||
import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
@@ -74,7 +74,7 @@ suite('ExtensionsActions Test', () => {
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService, <IExtensionManagementServer>{ authority: 'vscode-local', extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local' }));
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService));
|
||||
|
||||
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||
|
||||
@@ -1202,7 +1202,7 @@ suite('ExtensionsActions Test', () => {
|
||||
|
||||
const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' });
|
||||
installEvent.fire({ identifier: gallery.identifier, gallery });
|
||||
didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Install, local: aLocalExtension('a', gallery, gallery) });
|
||||
didInstallEvent.fire({ identifier: gallery.identifier, gallery, operation: InstallOperation.Update, local: aLocalExtension('a', gallery, gallery) });
|
||||
|
||||
assert.ok(!testObject.enabled);
|
||||
});
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/ex
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ConfigurationKey } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
|
||||
@@ -12,12 +12,12 @@ import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/com
|
||||
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService';
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, IGalleryExtension, IQueryOptions,
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, IExtensionManagementServerService, IExtensionManagementServer, EnablementState, ExtensionRecommendationReason, SortBy
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, IExtensionManagementServerService, EnablementState, ExtensionRecommendationReason, SortBy
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/electron-browser/extensionTipsService';
|
||||
import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
@@ -90,7 +90,7 @@ suite('ExtensionsListView Tests', () => {
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService, <IExtensionManagementServer>{ authority: 'vscode-local', extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local' }));
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService));
|
||||
|
||||
instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||
|
||||
|
||||
+3
-3
@@ -12,12 +12,12 @@ import { IExtensionsWorkbenchService, ExtensionState, AutoCheckUpdatesConfigurat
|
||||
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService';
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, IGalleryExtension,
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier, EnablementState, InstallOperation, IExtensionManagementServerService, IExtensionManagementServer
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier, EnablementState, InstallOperation, IExtensionManagementServerService
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/electron-browser/extensionTipsService';
|
||||
import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
@@ -77,7 +77,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
});
|
||||
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService, <IExtensionManagementServer>{ authority: 'vscode-local', extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local' }));
|
||||
instantiationService.stub(IExtensionManagementServerService, instantiationService.createInstance(ExtensionManagementServerService));
|
||||
|
||||
instantiationService.stub(IExtensionManagementService, ExtensionManagementService);
|
||||
instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { IEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { toResource, SideBySideEditorInput, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor';
|
||||
import { toResource, SideBySideEditorInput, IWorkbenchEditorConfiguration, SideBySideEditor as SideBySideEditorChoice } from 'vs/workbench/common/editor';
|
||||
import { ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { FileOperationEvent, FileOperation, IFileService, FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
@@ -94,7 +94,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
|
||||
distinct(
|
||||
coalesce(this.editorService.visibleEditors
|
||||
.map(editorInput => {
|
||||
const resource = toResource(editorInput, { supportSideBySide: true });
|
||||
const resource = toResource(editorInput, { supportSideBySide: SideBySideEditorChoice.MASTER });
|
||||
return resource ? this.textFileService.models.get(resource) : undefined;
|
||||
}))
|
||||
.filter(model => !model.isDirty()),
|
||||
@@ -325,7 +325,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
|
||||
private handleUpdatesToVisibleBinaryEditors(e: FileChangesEvent): void {
|
||||
const editors = this.editorService.visibleControls;
|
||||
editors.forEach(editor => {
|
||||
const resource = editor.input ? toResource(editor.input, { supportSideBySide: true }) : undefined;
|
||||
const resource = editor.input ? toResource(editor.input, { supportSideBySide: SideBySideEditorChoice.MASTER }) : undefined;
|
||||
|
||||
// Support side-by-side binary editors too
|
||||
let isBinaryEditor = false;
|
||||
@@ -346,7 +346,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
|
||||
private handleOutOfWorkspaceWatchers(): void {
|
||||
const visibleOutOfWorkspacePaths = new ResourceMap<URI>();
|
||||
coalesce(this.editorService.visibleEditors.map(editorInput => {
|
||||
return toResource(editorInput, { supportSideBySide: true });
|
||||
return toResource(editorInput, { supportSideBySide: SideBySideEditorChoice.MASTER });
|
||||
})).filter(resource => {
|
||||
return this.fileService.canHandleResource(resource) && !this.contextService.isInsideWorkspace(resource);
|
||||
}).forEach(resource => {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { VIEWLET_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IFileService, AutoSaveConfiguration } from 'vs/platform/files/common/files';
|
||||
import { toResource, ITextEditor } from 'vs/workbench/common/editor';
|
||||
import { toResource, ITextEditor, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
@@ -723,7 +723,7 @@ export class ShowActiveFileInExplorer extends Action {
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: true });
|
||||
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource) {
|
||||
this.commandService.executeCommand(REVEAL_IN_EXPLORER_COMMAND_ID, resource);
|
||||
} else {
|
||||
@@ -795,7 +795,7 @@ export class ShowOpenedFileInNewWindow extends Action {
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: true });
|
||||
const fileResource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (fileResource) {
|
||||
if (this.fileService.canHandleResource(fileResource)) {
|
||||
this.windowService.openWindow([{ fileUri: fileResource }], { forceNewWindow: true });
|
||||
@@ -898,7 +898,7 @@ export class CompareWithClipboardAction extends Action {
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: true });
|
||||
const resource = toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource && (this.fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled)) {
|
||||
if (!this.registrationDisposal) {
|
||||
const provider = this.instantiationService.createInstance(ClipboardContentProvider);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
// {{SQL CARBON EDIT}} - Import EditorInput
|
||||
import { toResource, IEditorCommandsContext, EditorInput } from 'vs/workbench/common/editor';
|
||||
import { toResource, IEditorCommandsContext, EditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { IWindowsService, IWindowService, IURIToOpen, IOpenSettings, INewWindowOptions } from 'vs/platform/windows/common/windows';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
@@ -41,6 +41,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
||||
@@ -136,7 +137,7 @@ function save(
|
||||
let viewStateOfSource: IEditorViewState | null;
|
||||
const activeTextEditorWidget = getCodeEditor(editorService.activeTextEditorWidget);
|
||||
if (activeTextEditorWidget) {
|
||||
const activeResource = toResource(editorService.activeEditor, { supportSideBySide: true });
|
||||
const activeResource = toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (activeResource && (fileService.canHandleResource(activeResource) || resource.scheme === Schemas.untitled) && activeResource.toString() === resource.toString()) {
|
||||
viewStateOfSource = activeTextEditorWidget.saveViewState();
|
||||
}
|
||||
@@ -314,28 +315,46 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
});
|
||||
|
||||
const COMPARE_WITH_SAVED_SCHEMA = 'showModifications';
|
||||
let provider: FileOnDiskContentProvider;
|
||||
let providerDisposables: IDisposable[] = [];
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: COMPARE_WITH_SAVED_COMMAND_ID,
|
||||
when: undefined,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_D),
|
||||
handler: (accessor, resource: URI | object) => {
|
||||
if (!provider) {
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
const textModelService = accessor.get(ITextModelService);
|
||||
provider = instantiationService.createInstance(FileOnDiskContentProvider);
|
||||
textModelService.registerTextModelContentProvider(COMPARE_WITH_SAVED_SCHEMA, provider);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
const textModelService = accessor.get(ITextModelService);
|
||||
const editorService = accessor.get(IEditorService);
|
||||
|
||||
// Register provider at first as needed
|
||||
let registerEditorListener = false;
|
||||
if (providerDisposables.length === 0) {
|
||||
registerEditorListener = true;
|
||||
|
||||
const provider = instantiationService.createInstance(FileOnDiskContentProvider);
|
||||
providerDisposables.push(provider);
|
||||
providerDisposables.push(textModelService.registerTextModelContentProvider(COMPARE_WITH_SAVED_SCHEMA, provider));
|
||||
}
|
||||
|
||||
const editorService = accessor.get(IEditorService);
|
||||
// Open editor (only files supported)
|
||||
const uri = getResourceForCommand(resource, accessor.get(IListService), editorService);
|
||||
|
||||
if (uri && uri.scheme === Schemas.file /* only files on disk supported for now */) {
|
||||
const name = basename(uri);
|
||||
const editorLabel = nls.localize('modifiedLabel', "{0} (on disk) ↔ {1}", name, name);
|
||||
|
||||
return editorService.openEditor({ leftResource: uri.with({ scheme: COMPARE_WITH_SAVED_SCHEMA }), rightResource: uri, label: editorLabel }).then(() => undefined);
|
||||
editorService.openEditor({ leftResource: uri.with({ scheme: COMPARE_WITH_SAVED_SCHEMA }), rightResource: uri, label: editorLabel }).then(() => {
|
||||
|
||||
// Dispose once no more diff editor is opened with the scheme
|
||||
if (registerEditorListener) {
|
||||
providerDisposables.push(editorService.onDidVisibleEditorsChange(() => {
|
||||
if (!editorService.editors.some(editor => !!toResource(editor, { supportSideBySide: SideBySideEditor.DETAILS, filterByScheme: COMPARE_WITH_SAVED_SCHEMA }))) {
|
||||
providerDisposables = dispose(providerDisposables);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}, error => {
|
||||
providerDisposables = dispose(providerDisposables);
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
@@ -554,7 +573,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
handler: accessor => {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
|
||||
const resource = toResource(editorService.activeEditor, { supportSideBySide: true });
|
||||
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));
|
||||
@@ -586,7 +605,7 @@ CommandsRegistry.registerCommand({
|
||||
const editorGroup = editorGroupService.getGroup(context.groupId);
|
||||
if (editorGroup) {
|
||||
editorGroup.editors.forEach(editor => {
|
||||
const resource = toResource(editor, { supportSideBySide: true });
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource && (resource.scheme === Schemas.untitled || fileService.canHandleResource(resource))) {
|
||||
saveAllArg.push(resource);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IListService, WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { OpenEditor } from 'vs/workbench/contrib/files/common/files';
|
||||
import { toResource } from 'vs/workbench/common/editor';
|
||||
import { toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
|
||||
@@ -41,7 +41,7 @@ export function getResourceForCommand(resource: URI | object | undefined, listSe
|
||||
}
|
||||
}
|
||||
|
||||
return editorService.activeEditor ? toResource(editorService.activeEditor, { supportSideBySide: true }) : null;
|
||||
return editorService.activeEditor ? toResource(editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null;
|
||||
}
|
||||
|
||||
export function getMultiSelectedResources(resource: URI | object | undefined, listService: IListService, editorService: IEditorService): Array<URI> {
|
||||
|
||||
@@ -25,9 +25,9 @@ export class ExplorerDecorationsProvider implements IDecorationsProvider {
|
||||
this.toDispose.push(contextService.onDidChangeWorkspaceFolders(e => {
|
||||
this._onDidChange.fire(e.changed.concat(e.added).map(wf => wf.uri));
|
||||
}));
|
||||
this.toDispose.push(explorerService.onDidChangeItem(item => {
|
||||
if (item) {
|
||||
this._onDidChange.fire([item.resource]);
|
||||
this.toDispose.push(explorerService.onDidChangeItem(change => {
|
||||
if (change.item) {
|
||||
this._onDidChange.fire([change.item.resource]);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, IExplorerService, ExplorerResourceCut, ExplorerResourceMoveableToTrash } from 'vs/workbench/contrib/files/common/files';
|
||||
import { NewFolderAction, NewFileAction, FileCopiedContext, RefreshExplorerView } from 'vs/workbench/contrib/files/browser/fileActions';
|
||||
import { toResource } from 'vs/workbench/common/editor';
|
||||
import { toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { CollapseAction } from 'vs/workbench/browser/viewlet';
|
||||
@@ -167,11 +167,11 @@ export class ExplorerView extends ViewletPanel {
|
||||
|
||||
this.disposables.push(this.labelService.onDidChangeFormatters(() => {
|
||||
this._onDidChangeTitleArea.fire();
|
||||
this.refresh();
|
||||
this.refresh(true);
|
||||
}));
|
||||
|
||||
this.disposables.push(this.explorerService.onDidChangeRoots(() => this.setTreeInput()));
|
||||
this.disposables.push(this.explorerService.onDidChangeItem(e => this.refresh(e)));
|
||||
this.disposables.push(this.explorerService.onDidChangeItem(e => this.refresh(e.recursive, e.item)));
|
||||
this.disposables.push(this.explorerService.onDidChangeEditable(async e => {
|
||||
const isEditing = !!this.explorerService.getEditableData(e);
|
||||
|
||||
@@ -181,7 +181,7 @@ export class ExplorerView extends ViewletPanel {
|
||||
DOM.removeClass(treeContainer, 'highlight');
|
||||
}
|
||||
|
||||
await this.refresh(e.parent);
|
||||
await this.refresh(false, e.parent);
|
||||
|
||||
if (isEditing) {
|
||||
DOM.addClass(treeContainer, 'highlight');
|
||||
@@ -365,7 +365,7 @@ export class ExplorerView extends ViewletPanel {
|
||||
|
||||
// Refresh viewer as needed if this originates from a config event
|
||||
if (event && needsRefresh) {
|
||||
this.refresh();
|
||||
this.refresh(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,7 +421,7 @@ export class ExplorerView extends ViewletPanel {
|
||||
* Refresh the contents of the explorer to get up to date data from the disk about the file structure.
|
||||
* If the item is passed we refresh only that level of the tree, otherwise we do a full refresh.
|
||||
*/
|
||||
private refresh(item?: ExplorerItem): Promise<void> {
|
||||
private refresh(recursive: boolean, item?: ExplorerItem): Promise<void> {
|
||||
if (!this.tree || !this.isBodyVisible()) {
|
||||
this.shouldRefresh = true;
|
||||
return Promise.resolve(undefined);
|
||||
@@ -432,7 +432,6 @@ export class ExplorerView extends ViewletPanel {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const recursive = !item;
|
||||
const toRefresh = item || this.tree.getInput();
|
||||
|
||||
return this.tree.updateChildren(toRefresh, recursive);
|
||||
@@ -504,7 +503,7 @@ export class ExplorerView extends ViewletPanel {
|
||||
}
|
||||
|
||||
// check for files
|
||||
return withNullAsUndefined(toResource(input, { supportSideBySide: true }));
|
||||
return withNullAsUndefined(toResource(input, { supportSideBySide: SideBySideEditor.MASTER }));
|
||||
}
|
||||
|
||||
private async onSelectResource(resource: URI | undefined, reveal = this.autoReveal): Promise<void> {
|
||||
|
||||
@@ -325,8 +325,7 @@ export class FilesFilter implements ITreeFilter<ExplorerItem, FuzzyScore> {
|
||||
|
||||
// Hide those that match Hidden Patterns
|
||||
const cached = this.hiddenExpressionPerRoot.get(stat.root.resource.toString());
|
||||
if (cached && cached.parsed(path.normalize(path.relative(stat.root.resource.path, stat.resource.path)), stat.name, name => !!(stat.parent && stat.parent.getChild(name)))) {
|
||||
// review (isidor): is path.normalize necessary? path.relative already returns an os path
|
||||
if (cached && cached.parsed(path.relative(stat.root.resource.path, stat.resource.path), stat.name, name => !!(stat.parent && stat.parent.getChild(name)))) {
|
||||
return false; // hidden through pattern
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export class ExplorerService implements IExplorerService {
|
||||
private static readonly EXPLORER_FILE_CHANGES_REACT_DELAY = 500; // delay in ms to react to file changes to give our internal events a chance to react first
|
||||
|
||||
private _onDidChangeRoots = new Emitter<void>();
|
||||
private _onDidChangeItem = new Emitter<ExplorerItem | undefined>();
|
||||
private _onDidChangeItem = new Emitter<{ item?: ExplorerItem, recursive: boolean }>();
|
||||
private _onDidChangeEditable = new Emitter<ExplorerItem>();
|
||||
private _onDidSelectResource = new Emitter<{ resource?: URI, reveal?: boolean }>();
|
||||
private _onDidCopyItems = new Emitter<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>();
|
||||
@@ -40,6 +40,7 @@ export class ExplorerService implements IExplorerService {
|
||||
private editable: { stat: ExplorerItem, data: IEditableData } | undefined;
|
||||
private _sortOrder: SortOrder;
|
||||
private cutItems: ExplorerItem[] | undefined;
|
||||
private fileSystemProviderSchemes = new Set<string>();
|
||||
|
||||
constructor(
|
||||
@IFileService private fileService: IFileService,
|
||||
@@ -60,7 +61,7 @@ export class ExplorerService implements IExplorerService {
|
||||
return this._onDidChangeRoots.event;
|
||||
}
|
||||
|
||||
get onDidChangeItem(): Event<ExplorerItem | undefined> {
|
||||
get onDidChangeItem(): Event<{ item?: ExplorerItem, recursive: boolean }> {
|
||||
return this._onDidChangeItem.event;
|
||||
}
|
||||
|
||||
@@ -98,7 +99,14 @@ export class ExplorerService implements IExplorerService {
|
||||
this.disposables.push(this.fileService.onAfterOperation(e => this.onFileOperation(e)));
|
||||
this.disposables.push(this.fileService.onFileChanges(e => this.onFileChanges(e)));
|
||||
this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue<IFilesConfiguration>())));
|
||||
this.disposables.push(this.fileService.onDidChangeFileSystemProviderRegistrations(() => this._onDidChangeItem.fire(undefined)));
|
||||
this.disposables.push(this.fileService.onDidChangeFileSystemProviderRegistrations(e => {
|
||||
if (e.added && this.fileSystemProviderSchemes.has(e.scheme)) {
|
||||
// A file system provider got re-registered, we should update all file stats since they might change (got read-only)
|
||||
this._onDidChangeItem.fire({ recursive: true });
|
||||
} else {
|
||||
this.fileSystemProviderSchemes.add(e.scheme);
|
||||
}
|
||||
}));
|
||||
this.disposables.push(model.onDidChangeRoots(() => this._onDidChangeRoots.fire()));
|
||||
|
||||
return model;
|
||||
@@ -158,19 +166,19 @@ export class ExplorerService implements IExplorerService {
|
||||
// Update Input with disk Stat
|
||||
ExplorerItem.mergeLocalWithDisk(modelStat, root);
|
||||
const item = root.find(resource);
|
||||
this._onDidChangeItem.fire(item ? item.parent : undefined);
|
||||
this._onDidChangeItem.fire({ item: root, recursive: true });
|
||||
|
||||
// Select and Reveal
|
||||
this._onDidSelectResource.fire({ resource: item ? item.resource : undefined, reveal });
|
||||
}, () => {
|
||||
root.isError = true;
|
||||
this._onDidChangeItem.fire(root);
|
||||
this._onDidChangeItem.fire({ item: root, recursive: false });
|
||||
});
|
||||
}
|
||||
|
||||
refresh(): void {
|
||||
this.model.roots.forEach(r => r.forgetChildren());
|
||||
this._onDidChangeItem.fire(undefined);
|
||||
this._onDidChangeItem.fire({ recursive: true });
|
||||
const resource = this.editorService.activeEditor ? this.editorService.activeEditor.getResource() : undefined;
|
||||
if (resource) {
|
||||
// We did a top level refresh, reveal the active file #67118
|
||||
@@ -205,7 +213,7 @@ export class ExplorerService implements IExplorerService {
|
||||
p.removeChild(childElement);
|
||||
p.addChild(childElement);
|
||||
// Refresh the Parent (View)
|
||||
this._onDidChangeItem.fire(p);
|
||||
this._onDidChangeItem.fire({ item: p, recursive: false });
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -224,7 +232,7 @@ export class ExplorerService implements IExplorerService {
|
||||
modelElements.forEach(modelElement => {
|
||||
// Rename File (Model)
|
||||
modelElement.rename(newElement);
|
||||
this._onDidChangeItem.fire(modelElement.parent);
|
||||
this._onDidChangeItem.fire({ item: modelElement.parent, recursive: false });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -238,8 +246,8 @@ export class ExplorerService implements IExplorerService {
|
||||
modelElements.forEach((modelElement, index) => {
|
||||
const oldParent = modelElement.parent;
|
||||
modelElement.move(newParents[index]);
|
||||
this._onDidChangeItem.fire(oldParent);
|
||||
this._onDidChangeItem.fire(newParents[index]);
|
||||
this._onDidChangeItem.fire({ item: oldParent, recursive: false });
|
||||
this._onDidChangeItem.fire({ item: newParents[index], recursive: false });
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -254,7 +262,7 @@ export class ExplorerService implements IExplorerService {
|
||||
// Remove Element from Parent (Model)
|
||||
parent.removeChild(element);
|
||||
// Refresh Parent (View)
|
||||
this._onDidChangeItem.fire(parent);
|
||||
this._onDidChangeItem.fire({ item: parent, recursive: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -332,7 +340,7 @@ export class ExplorerService implements IExplorerService {
|
||||
|
||||
if (shouldRefresh()) {
|
||||
this.roots.forEach(r => r.forgetChildren());
|
||||
this._onDidChangeItem.fire(undefined);
|
||||
this._onDidChangeItem.fire({ recursive: true });
|
||||
}
|
||||
}, ExplorerService.EXPLORER_FILE_CHANGES_REACT_DELAY);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IWorkbenchEditorConfiguration, IEditorIdentifier, IEditorInput, toResource } from 'vs/workbench/common/editor';
|
||||
import { IWorkbenchEditorConfiguration, IEditorIdentifier, IEditorInput, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { IFilesConfiguration, FileChangeType, IFileService } from 'vs/platform/files/common/files';
|
||||
import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ITextModelContentProvider } from 'vs/editor/common/services/resolverService';
|
||||
@@ -43,7 +43,7 @@ export interface IExplorerService {
|
||||
readonly roots: ExplorerItem[];
|
||||
readonly sortOrder: SortOrder;
|
||||
readonly onDidChangeRoots: Event<void>;
|
||||
readonly onDidChangeItem: Event<ExplorerItem | undefined>;
|
||||
readonly onDidChangeItem: Event<{ item?: ExplorerItem, recursive: boolean }>;
|
||||
readonly onDidChangeEditable: Event<ExplorerItem>;
|
||||
readonly onDidSelectResource: Event<{ resource?: URI, reveal?: boolean }>;
|
||||
readonly onDidCopyItems: Event<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>;
|
||||
@@ -231,7 +231,7 @@ export class OpenEditor implements IEditorIdentifier {
|
||||
}
|
||||
|
||||
public isUntitled(): boolean {
|
||||
return !!toResource(this.editor, { supportSideBySide: true, filter: Schemas.untitled });
|
||||
return !!toResource(this.editor, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: Schemas.untitled });
|
||||
}
|
||||
|
||||
public isDirty(): boolean {
|
||||
@@ -239,6 +239,6 @@ export class OpenEditor implements IEditorIdentifier {
|
||||
}
|
||||
|
||||
public getResource(): URI | null {
|
||||
return toResource(this.editor, { supportSideBySide: true });
|
||||
return toResource(this.editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { LinkProviderRegistry, ILink } from 'vs/editor/common/modes';
|
||||
import { LinkProviderRegistry, ILink, ILinksList } from 'vs/editor/common/modes';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { OUTPUT_MODE_ID, LOG_MODE_ID } from 'vs/workbench/contrib/output/common/output';
|
||||
import { MonacoWebWorker, createWebWorker } from 'vs/editor/common/services/webWorker';
|
||||
@@ -42,8 +42,8 @@ export class OutputLinkProvider {
|
||||
if (folders.length > 0) {
|
||||
if (!this.linkProviderRegistration) {
|
||||
this.linkProviderRegistration = LinkProviderRegistry.register([{ language: OUTPUT_MODE_ID, scheme: '*' }, { language: LOG_MODE_ID, scheme: '*' }], {
|
||||
provideLinks: (model, token): Promise<ILink[]> => {
|
||||
return this.provideLinks(model.uri);
|
||||
provideLinks: (model): Promise<ILinksList> => {
|
||||
return this.provideLinks(model.uri).then(links => links && { links });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ISearchConfiguration, ISearchConfigurationProperties } from 'vs/workben
|
||||
import { SymbolKind, Location, ProviderResult } from 'vs/editor/common/modes';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { toResource } from 'vs/workbench/common/editor';
|
||||
import { toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
@@ -85,7 +85,7 @@ export function getOutOfWorkspaceEditorResources(editorService: IEditorService,
|
||||
const resources: URI[] = [];
|
||||
|
||||
editorService.editors.forEach(editor => {
|
||||
const resource = toResource(editor, { supportSideBySide: true });
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource && !contextService.isInsideWorkspace(resource)) {
|
||||
resources.push(resource);
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ CommandsRegistry.registerCommand('_workbench.captureSyntaxTokens', function (acc
|
||||
|
||||
if (!resource) {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const file = editorService.activeEditor ? toResource(editorService.activeEditor, { filter: 'file' }) : null;
|
||||
const file = editorService.activeEditor ? toResource(editorService.activeEditor, { filterByScheme: 'file' }) : null;
|
||||
if (file) {
|
||||
process(file).then(result => {
|
||||
console.log(result);
|
||||
|
||||
@@ -41,9 +41,9 @@ const defaultCssRules = `
|
||||
body {
|
||||
background-color: var(--vscode-editor-background);
|
||||
color: var(--vscode-editor-foreground);
|
||||
font-family: var(--vscode-editor-font-family);
|
||||
font-weight: var(--vscode-editor-font-weight);
|
||||
font-size: var(--vscode-editor-font-size);
|
||||
font-family: var(--vscode-font-family);
|
||||
font-weight: var(--vscode-font-weight);
|
||||
font-size: var(--vscode-font-size);
|
||||
margin: 0;
|
||||
padding: 0 20px;
|
||||
}
|
||||
@@ -112,16 +112,18 @@ module.exports = function createWebviewManager(host) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {HTMLDocument} document
|
||||
* @param {HTMLElement} body
|
||||
* @param {HTMLDocument?} document
|
||||
* @param {HTMLElement?} body
|
||||
*/
|
||||
const applyStyles = (document, body) => {
|
||||
if (!body) {
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
body.classList.remove('vscode-light', 'vscode-dark', 'vscode-high-contrast');
|
||||
body.classList.add(initData.activeTheme);
|
||||
if (body) {
|
||||
body.classList.remove('vscode-light', 'vscode-dark', 'vscode-high-contrast');
|
||||
body.classList.add(initData.activeTheme);
|
||||
}
|
||||
|
||||
if (initData.styles) {
|
||||
for (const variable of Object.keys(initData.styles)) {
|
||||
@@ -323,7 +325,16 @@ module.exports = function createWebviewManager(host) {
|
||||
|
||||
// write new content onto iframe
|
||||
newFrame.contentDocument.open('text/html', 'replace');
|
||||
|
||||
newFrame.contentWindow.addEventListener('keydown', handleInnerKeydown);
|
||||
|
||||
newFrame.contentWindow.addEventListener('DOMContentLoaded', e => {
|
||||
const contentDocument = e.target ? (/** @type {HTMLDocument} */ (e.target)) : undefined;
|
||||
if (contentDocument) {
|
||||
applyStyles(contentDocument, contentDocument.body);
|
||||
}
|
||||
});
|
||||
|
||||
newFrame.contentWindow.onbeforeunload = () => {
|
||||
if (isInDevelopmentMode) { // Allow reloads while developing a webview
|
||||
host.postMessage('do-reload');
|
||||
|
||||
@@ -22,6 +22,8 @@ import { WebviewFindWidget } from '../browser/webviewFindWidget';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { WebviewContentOptions, WebviewPortMapping, WebviewOptions, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEditorOptions, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
|
||||
interface IKeydownEvent {
|
||||
@@ -306,7 +308,6 @@ export class WebviewElement extends Disposable implements Webview {
|
||||
public get onDidFocus(): Event<void> { return this._onDidFocus.event; }
|
||||
|
||||
constructor(
|
||||
private readonly _styleElement: Element,
|
||||
private readonly _options: WebviewOptions,
|
||||
private _contentOptions: WebviewContentOptions,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@@ -314,6 +315,7 @@ export class WebviewElement extends Disposable implements Webview {
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
) {
|
||||
super();
|
||||
this._webview = document.createElement('webview');
|
||||
@@ -540,9 +542,12 @@ export class WebviewElement extends Disposable implements Webview {
|
||||
});
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
// {{SQL CARBON EDIT}} - make public
|
||||
public style(theme: ITheme): void {
|
||||
const { fontFamily, fontWeight, fontSize } = window.getComputedStyle(this._styleElement); // TODO@theme avoid styleElement
|
||||
const configuration = this._configurationService.getValue<IEditorOptions>('editor');
|
||||
const editorFontFamily = configuration.fontFamily || EDITOR_FONT_DEFAULTS.fontFamily;
|
||||
const editorFontWeight = configuration.fontWeight || EDITOR_FONT_DEFAULTS.fontWeight;
|
||||
const editorFontSize = configuration.fontSize || EDITOR_FONT_DEFAULTS.fontSize;
|
||||
|
||||
const exportedColors = colorRegistry.getColorRegistry().getColors().reduce((colors, entry) => {
|
||||
const color = theme.getColor(entry.id);
|
||||
@@ -554,9 +559,12 @@ export class WebviewElement extends Disposable implements Webview {
|
||||
|
||||
|
||||
const styles = {
|
||||
'vscode-editor-font-family': fontFamily,
|
||||
'vscode-editor-font-weight': fontWeight,
|
||||
'vscode-editor-font-size': fontSize,
|
||||
'vscode-font-family': '-apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif',
|
||||
'vscode-font-weight': 'normal',
|
||||
'vscode-font-size': '13px',
|
||||
'vscode-editor-font-family': editorFontFamily,
|
||||
'vscode-editor-font-weight': editorFontWeight,
|
||||
'vscode-editor-font-size': editorFontSize,
|
||||
...exportedColors
|
||||
};
|
||||
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWebviewService, Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IWebviewService, WebviewOptions, WebviewContentOptions, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
|
||||
export class WebviewService implements IWebviewService {
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) { }
|
||||
|
||||
@@ -21,7 +19,6 @@ export class WebviewService implements IWebviewService {
|
||||
contentOptions: WebviewContentOptions
|
||||
): Webview {
|
||||
const element = this._instantiationService.createInstance(WebviewElement,
|
||||
this._layoutService.getContainer(Parts.EDITOR_PART),
|
||||
options,
|
||||
contentOptions);
|
||||
|
||||
|
||||
@@ -168,6 +168,11 @@ class CodeRendererMain extends Disposable {
|
||||
private initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: StorageService }> {
|
||||
const serviceCollection = new ServiceCollection();
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// NOTE: DO NOT ADD ANY OTHER SERVICE INTO THE COLLECTION HERE.
|
||||
// CONTRIBUTE IT VIA WORKBENCH.MAIN.TS AND registerSingleton().
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
// Main Process
|
||||
const mainProcessService = this._register(new MainProcessService(this.configuration.windowId));
|
||||
serviceCollection.set(IMainProcessService, mainProcessService);
|
||||
@@ -205,7 +210,7 @@ class CodeRendererMain extends Disposable {
|
||||
}
|
||||
|
||||
return this.resolveWorkspaceInitializationPayload(environmentService).then(payload => Promise.all([
|
||||
this.createWorkspaceService(payload, environmentService, remoteAgentService, logService).then(service => {
|
||||
this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => {
|
||||
|
||||
// Workspace
|
||||
serviceCollection.set(IWorkspaceContextService, service);
|
||||
@@ -296,8 +301,11 @@ class CodeRendererMain extends Disposable {
|
||||
}, error => onUnexpectedError(error));
|
||||
}
|
||||
|
||||
private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
|
||||
const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache(environmentService) }, new ConfigurationFileService(), remoteAgentService);
|
||||
private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, fileService: FileService2, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
|
||||
const configurationFileService = new ConfigurationFileService();
|
||||
fileService.whenReady.then(() => configurationFileService.fileService = fileService);
|
||||
|
||||
const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService);
|
||||
|
||||
return workspaceService.initialize(payload).then(() => workspaceService, error => {
|
||||
onUnexpectedError(error);
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as DOM from 'vs/base/browser/dom';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { toResource, IUntitledResourceInput } from 'vs/workbench/common/editor';
|
||||
import { toResource, IUntitledResourceInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWindowsService, IWindowService, IWindowSettings, IOpenFileRequest, IWindowsConfiguration, IAddFoldersRequest, IRunActionInWindowRequest, IPathData, IRunKeybindingInWindowRequest } from 'vs/platform/windows/common/windows';
|
||||
@@ -122,7 +122,7 @@ export class ElectronWindow extends Disposable {
|
||||
if (request.from === 'touchbar') {
|
||||
const activeEditor = this.editorService.activeEditor;
|
||||
if (activeEditor) {
|
||||
const resource = toResource(activeEditor, { supportSideBySide: true });
|
||||
const resource = toResource(activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource) {
|
||||
args.push(resource);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files';
|
||||
import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { WorkspaceConfigurationModelParser, FolderSettingsModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels';
|
||||
import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, IConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
@@ -22,67 +22,36 @@ import { equals } from 'vs/base/common/objects';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IConfigurationModel, compare } from 'vs/platform/configuration/common/configuration';
|
||||
import { createSHA1 } from 'vs/base/browser/hash';
|
||||
|
||||
export class LocalUserConfiguration extends Disposable {
|
||||
|
||||
private readonly userConfigurationResource: URI;
|
||||
private userConfiguration: NodeBasedUserConfiguration | FileServiceBasedUserConfiguration;
|
||||
private changeDisposable: IDisposable = Disposable.None;
|
||||
|
||||
private readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
|
||||
public readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
|
||||
|
||||
constructor(
|
||||
userConfigurationResource: URI,
|
||||
configurationFileService: IConfigurationFileService
|
||||
) {
|
||||
super();
|
||||
this.userConfigurationResource = userConfigurationResource;
|
||||
this.userConfiguration = this._register(new NodeBasedUserConfiguration(this.userConfigurationResource, configurationFileService));
|
||||
}
|
||||
|
||||
initialize(): Promise<ConfigurationModel> {
|
||||
return this.userConfiguration.initialize();
|
||||
}
|
||||
|
||||
reload(): Promise<ConfigurationModel> {
|
||||
return this.userConfiguration.reload();
|
||||
}
|
||||
|
||||
async adopt(fileService: IFileService): Promise<ConfigurationModel | null> {
|
||||
if (this.userConfiguration instanceof NodeBasedUserConfiguration) {
|
||||
const oldConfigurationModel = this.userConfiguration.getConfigurationModel();
|
||||
this.userConfiguration.dispose();
|
||||
dispose(this.changeDisposable);
|
||||
|
||||
let newConfigurationModel = new ConfigurationModel();
|
||||
this.userConfiguration = this._register(new FileServiceBasedUserConfiguration(this.userConfigurationResource, fileService));
|
||||
this.changeDisposable = this._register(this.userConfiguration.onDidChangeConfiguration(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)));
|
||||
newConfigurationModel = await this.userConfiguration.initialize();
|
||||
|
||||
const { added, updated, removed } = compare(oldConfigurationModel, newConfigurationModel);
|
||||
if (added.length > 0 || updated.length > 0 || removed.length > 0) {
|
||||
return newConfigurationModel;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
export class RemoteUserConfiguration extends Disposable {
|
||||
|
||||
private readonly _cachedConfiguration: CachedUserConfiguration;
|
||||
private _userConfiguration: FileServiceBasedUserConfiguration | CachedUserConfiguration;
|
||||
private readonly _configurationFileService: IConfigurationFileService;
|
||||
private _userConfiguration: UserConfiguration | CachedUserConfiguration;
|
||||
private _userConfigurationDisposable: IDisposable = Disposable.None;
|
||||
|
||||
private readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
|
||||
public readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
|
||||
|
||||
constructor(
|
||||
remoteAuthority: string,
|
||||
configurationCache: IConfigurationCache
|
||||
configurationCache: IConfigurationCache,
|
||||
configurationFileService: IConfigurationFileService,
|
||||
remoteAgentService: IRemoteAgentService
|
||||
) {
|
||||
super();
|
||||
this._configurationFileService = configurationFileService;
|
||||
this._userConfiguration = this._cachedConfiguration = new CachedUserConfiguration(remoteAuthority, configurationCache);
|
||||
remoteAgentService.getEnvironment().then(environment => {
|
||||
if (environment) {
|
||||
this._userConfiguration.dispose();
|
||||
this._userConfigurationDisposable.dispose();
|
||||
this._userConfiguration = this._register(new UserConfiguration(environment.appSettingsPath, this._configurationFileService));
|
||||
this._userConfigurationDisposable = this._register(this._userConfiguration.onDidChangeConfiguration(configurationModel => this.onDidUserConfigurationChange(configurationModel)));
|
||||
this._userConfiguration.initialize().then(configurationModel => this.onDidUserConfigurationChange(configurationModel));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
initialize(): Promise<ConfigurationModel> {
|
||||
@@ -93,24 +62,6 @@ export class RemoteUserConfiguration extends Disposable {
|
||||
return this._userConfiguration.reload();
|
||||
}
|
||||
|
||||
async adopt(configurationResource: URI | null, fileService: IFileService): Promise<ConfigurationModel | null> {
|
||||
if (this._userConfiguration instanceof CachedUserConfiguration) {
|
||||
const oldConfigurationModel = this._userConfiguration.getConfigurationModel();
|
||||
let newConfigurationModel = new ConfigurationModel();
|
||||
if (configurationResource) {
|
||||
this._userConfiguration = new FileServiceBasedUserConfiguration(configurationResource, fileService);
|
||||
this._register(this._userConfiguration.onDidChangeConfiguration(configurationModel => this.onDidUserConfigurationChange(configurationModel)));
|
||||
newConfigurationModel = await this._userConfiguration.initialize();
|
||||
}
|
||||
const { added, updated, removed } = compare(oldConfigurationModel, newConfigurationModel);
|
||||
if (added.length > 0 || updated.length > 0 || removed.length > 0) {
|
||||
this.updateCache(newConfigurationModel);
|
||||
return newConfigurationModel;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private onDidUserConfigurationChange(configurationModel: ConfigurationModel): void {
|
||||
this.updateCache(configurationModel);
|
||||
this._onDidChangeConfiguration.fire(configurationModel);
|
||||
@@ -121,51 +72,7 @@ export class RemoteUserConfiguration extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
class NodeBasedUserConfiguration extends Disposable {
|
||||
|
||||
private configuraitonModel: ConfigurationModel = new ConfigurationModel();
|
||||
|
||||
constructor(
|
||||
private readonly userConfigurationResource: URI,
|
||||
private readonly configurationFileService: IConfigurationFileService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
initialize(): Promise<ConfigurationModel> {
|
||||
return this._load();
|
||||
}
|
||||
|
||||
reload(): Promise<ConfigurationModel> {
|
||||
return this._load();
|
||||
}
|
||||
|
||||
getConfigurationModel(): ConfigurationModel {
|
||||
return this.configuraitonModel;
|
||||
}
|
||||
|
||||
async _load(): Promise<ConfigurationModel> {
|
||||
const exists = await this.configurationFileService.exists(this.userConfigurationResource);
|
||||
if (exists) {
|
||||
try {
|
||||
const content = await this.configurationFileService.resolveContent(this.userConfigurationResource);
|
||||
const parser = new ConfigurationModelParser(this.userConfigurationResource.toString());
|
||||
parser.parse(content);
|
||||
this.configuraitonModel = parser.configurationModel;
|
||||
} catch (e) {
|
||||
// ignore error
|
||||
errors.onUnexpectedError(e);
|
||||
this.configuraitonModel = new ConfigurationModel();
|
||||
}
|
||||
} else {
|
||||
this.configuraitonModel = new ConfigurationModel();
|
||||
}
|
||||
return this.configuraitonModel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class FileServiceBasedUserConfiguration extends Disposable {
|
||||
export class UserConfiguration extends Disposable {
|
||||
|
||||
private readonly reloadConfigurationScheduler: RunOnceScheduler;
|
||||
protected readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
|
||||
@@ -176,11 +83,11 @@ export class FileServiceBasedUserConfiguration extends Disposable {
|
||||
|
||||
constructor(
|
||||
private readonly configurationResource: URI,
|
||||
private readonly fileService: IFileService
|
||||
private readonly configurationFileService: IConfigurationFileService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(fileService.onFileChanges(e => this.handleFileEvents(e)));
|
||||
this._register(configurationFileService.onFileChanges(e => this.handleFileEvents(e)));
|
||||
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50));
|
||||
this._register(toDisposable(() => {
|
||||
this.stopWatchingResource();
|
||||
@@ -189,7 +96,7 @@ export class FileServiceBasedUserConfiguration extends Disposable {
|
||||
}
|
||||
|
||||
private watchResource(): void {
|
||||
this.fileWatcherDisposable = this.fileService.watch(this.configurationResource);
|
||||
this.fileWatcherDisposable = this.configurationFileService.watch(this.configurationResource);
|
||||
}
|
||||
|
||||
private stopWatchingResource(): void {
|
||||
@@ -199,7 +106,7 @@ export class FileServiceBasedUserConfiguration extends Disposable {
|
||||
|
||||
private watchDirectory(): void {
|
||||
const directory = resources.dirname(this.configurationResource);
|
||||
this.directoryWatcherDisposable = this.fileService.watch(directory);
|
||||
this.directoryWatcherDisposable = this.configurationFileService.watch(directory);
|
||||
}
|
||||
|
||||
private stopWatchingDirectory(): void {
|
||||
@@ -208,22 +115,34 @@ export class FileServiceBasedUserConfiguration extends Disposable {
|
||||
}
|
||||
|
||||
async initialize(): Promise<ConfigurationModel> {
|
||||
const exists = await this.fileService.exists(this.configurationResource);
|
||||
const exists = await this.configurationFileService.exists(this.configurationResource);
|
||||
this.onResourceExists(exists);
|
||||
return this.reload();
|
||||
const configuraitonModel = await this.reload();
|
||||
if (!this.configurationFileService.isWatching) {
|
||||
this.configurationFileService.whenWatchingStarted.then(() => this.onWatchStarted(configuraitonModel));
|
||||
}
|
||||
return configuraitonModel;
|
||||
}
|
||||
|
||||
async reload(): Promise<ConfigurationModel> {
|
||||
try {
|
||||
const content = await this.fileService.resolveContent(this.configurationResource);
|
||||
const content = await this.configurationFileService.resolveContent(this.configurationResource);
|
||||
const parser = new ConfigurationModelParser(this.configurationResource.toString());
|
||||
parser.parse(content.value);
|
||||
parser.parse(content);
|
||||
return parser.configurationModel;
|
||||
} catch (e) {
|
||||
return new ConfigurationModel();
|
||||
}
|
||||
}
|
||||
|
||||
private async onWatchStarted(currentModel: ConfigurationModel): Promise<void> {
|
||||
const configuraitonModel = await this.reload();
|
||||
const { added, removed, updated } = compare(currentModel, configuraitonModel);
|
||||
if (added.length || removed.length || updated.length) {
|
||||
this._onDidChangeConfiguration.fire(configuraitonModel);
|
||||
}
|
||||
}
|
||||
|
||||
private async handleFileEvents(event: FileChangesEvent): Promise<void> {
|
||||
const events = event.changes;
|
||||
|
||||
@@ -304,41 +223,38 @@ class CachedUserConfiguration extends Disposable {
|
||||
|
||||
export class WorkspaceConfiguration extends Disposable {
|
||||
|
||||
private readonly _cachedConfiguration: CachedWorkspaceConfiguration;
|
||||
private readonly _configurationFileService: IConfigurationFileService;
|
||||
private readonly _cachedConfiguration: CachedWorkspaceConfiguration;
|
||||
private _workspaceConfiguration: IWorkspaceConfiguration;
|
||||
private _workspaceConfigurationChangeDisposable: IDisposable = Disposable.None;
|
||||
private _workspaceIdentifier: IWorkspaceIdentifier | null = null;
|
||||
private _fileService: IFileService | null = null;
|
||||
|
||||
private readonly _onDidUpdateConfiguration: Emitter<void> = this._register(new Emitter<void>());
|
||||
public readonly onDidUpdateConfiguration: Event<void> = this._onDidUpdateConfiguration.event;
|
||||
|
||||
private _loaded: boolean = false;
|
||||
get loaded(): boolean { return this._loaded; }
|
||||
|
||||
constructor(
|
||||
configurationCache: IConfigurationCache,
|
||||
configurationFileService: IConfigurationFileService
|
||||
) {
|
||||
super();
|
||||
this._cachedConfiguration = new CachedWorkspaceConfiguration(configurationCache);
|
||||
this._configurationFileService = configurationFileService;
|
||||
this._workspaceConfiguration = this._cachedConfiguration;
|
||||
this._workspaceConfiguration = this._cachedConfiguration = new CachedWorkspaceConfiguration(configurationCache);
|
||||
}
|
||||
|
||||
adopt(fileService: IFileService): Promise<boolean> {
|
||||
if (!this._fileService) {
|
||||
this._fileService = fileService;
|
||||
if (this.adoptWorkspaceConfiguration()) {
|
||||
if (this._workspaceIdentifier) {
|
||||
return this._workspaceConfiguration.load(this._workspaceIdentifier).then(() => true);
|
||||
}
|
||||
async load(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
|
||||
this._workspaceIdentifier = workspaceIdentifier;
|
||||
if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) {
|
||||
if (this._workspaceIdentifier.configPath.scheme === Schemas.file) {
|
||||
this.switch();
|
||||
} else {
|
||||
this.waitAndSwitch(this._workspaceIdentifier);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
load(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
|
||||
this._workspaceIdentifier = workspaceIdentifier;
|
||||
this.adoptWorkspaceConfiguration();
|
||||
return this._workspaceConfiguration.load(this._workspaceIdentifier);
|
||||
await this._workspaceConfiguration.load(this._workspaceIdentifier);
|
||||
this._loaded = this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration;
|
||||
}
|
||||
|
||||
reload(): Promise<void> {
|
||||
@@ -366,38 +282,26 @@ export class WorkspaceConfiguration extends Disposable {
|
||||
return this.getConfiguration();
|
||||
}
|
||||
|
||||
private adoptWorkspaceConfiguration(): boolean {
|
||||
if (this._workspaceIdentifier) {
|
||||
if (this._fileService) {
|
||||
if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) {
|
||||
const oldWorkspaceConfiguration = this._workspaceConfiguration;
|
||||
this._workspaceConfiguration = new FileServiceBasedWorkspaceConfiguration(this._fileService, oldWorkspaceConfiguration);
|
||||
this._register(this._workspaceConfiguration.onDidChange(e => this.onDidWorkspaceConfigurationChange()));
|
||||
if (oldWorkspaceConfiguration instanceof CachedWorkspaceConfiguration) {
|
||||
this.updateCache();
|
||||
return true;
|
||||
} else {
|
||||
dispose(oldWorkspaceConfiguration);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (this._workspaceIdentifier.configPath.scheme === Schemas.file) {
|
||||
if (!(this._workspaceConfiguration instanceof NodeBasedWorkspaceConfiguration)) {
|
||||
dispose(this._workspaceConfiguration);
|
||||
this._workspaceConfiguration = new NodeBasedWorkspaceConfiguration(this._configurationFileService);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private async waitAndSwitch(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
|
||||
await this._configurationFileService.whenProviderRegistered(workspaceIdentifier.configPath.scheme);
|
||||
if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) {
|
||||
this.switch();
|
||||
this._loaded = true;
|
||||
this.onDidWorkspaceConfigurationChange();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private onDidWorkspaceConfigurationChange(): void {
|
||||
private switch(): void {
|
||||
this._workspaceConfiguration.dispose();
|
||||
this._workspaceConfigurationChangeDisposable.dispose();
|
||||
this._workspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService));
|
||||
this._workspaceConfigurationChangeDisposable = this._register(this._workspaceConfiguration.onDidChange(e => this.onDidWorkspaceConfigurationChange()));
|
||||
}
|
||||
|
||||
private async onDidWorkspaceConfigurationChange(): Promise<void> {
|
||||
await this.reload();
|
||||
this.updateCache();
|
||||
this.reload().then(() => this._onDidUpdateConfiguration.fire());
|
||||
this._onDidUpdateConfiguration.fire();
|
||||
}
|
||||
|
||||
private updateCache(): Promise<void> {
|
||||
@@ -421,20 +325,30 @@ interface IWorkspaceConfiguration extends IDisposable {
|
||||
reprocessWorkspaceSettings(): ConfigurationModel;
|
||||
}
|
||||
|
||||
abstract class AbstractWorkspaceConfiguration extends Disposable implements IWorkspaceConfiguration {
|
||||
class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWorkspaceConfiguration {
|
||||
|
||||
workspaceConfigurationModelParser: WorkspaceConfigurationModelParser;
|
||||
workspaceSettings: ConfigurationModel;
|
||||
private _workspaceIdentifier: IWorkspaceIdentifier | null = null;
|
||||
private workspaceConfigWatcher: IDisposable;
|
||||
private readonly reloadConfigurationScheduler: RunOnceScheduler;
|
||||
|
||||
protected readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
constructor(from?: IWorkspaceConfiguration) {
|
||||
constructor(private configurationFileService: IConfigurationFileService) {
|
||||
super();
|
||||
|
||||
this.workspaceConfigurationModelParser = from ? from.workspaceConfigurationModelParser : new WorkspaceConfigurationModelParser('');
|
||||
this.workspaceSettings = from ? from.workspaceSettings : new ConfigurationModel();
|
||||
this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser('');
|
||||
this.workspaceSettings = new ConfigurationModel();
|
||||
|
||||
this._register(configurationFileService.onFileChanges(e => this.handleWorkspaceFileEvents(e)));
|
||||
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50));
|
||||
this.workspaceConfigWatcher = this._register(this.watchWorkspaceConfigurationFile());
|
||||
|
||||
if (!this.configurationFileService.isWatching) {
|
||||
this.configurationFileService.whenWatchingStarted.then(() => this.onWatchStarted());
|
||||
}
|
||||
}
|
||||
|
||||
get workspaceIdentifier(): IWorkspaceIdentifier | null {
|
||||
@@ -442,13 +356,20 @@ abstract class AbstractWorkspaceConfiguration extends Disposable implements IWor
|
||||
}
|
||||
|
||||
async load(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
|
||||
this._workspaceIdentifier = workspaceIdentifier;
|
||||
this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(workspaceIdentifier.id);
|
||||
if (!this._workspaceIdentifier || this._workspaceIdentifier.id !== workspaceIdentifier.id) {
|
||||
this._workspaceIdentifier = workspaceIdentifier;
|
||||
this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(this._workspaceIdentifier.id);
|
||||
dispose(this.workspaceConfigWatcher);
|
||||
this.workspaceConfigWatcher = this._register(this.watchWorkspaceConfigurationFile());
|
||||
}
|
||||
let contents = '';
|
||||
try {
|
||||
contents = (await this.loadWorkspaceConfigurationContents(workspaceIdentifier.configPath)) || '';
|
||||
} catch (e) {
|
||||
errors.onUnexpectedError(e);
|
||||
contents = await this.configurationFileService.resolveContent(this._workspaceIdentifier.configPath);
|
||||
} catch (error) {
|
||||
const exists = await this.configurationFileService.exists(this._workspaceIdentifier.configPath);
|
||||
if (exists) {
|
||||
errors.onUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
this.workspaceConfigurationModelParser.parse(contents);
|
||||
this.consolidate();
|
||||
@@ -472,69 +393,34 @@ abstract class AbstractWorkspaceConfiguration extends Disposable implements IWor
|
||||
return this.getWorkspaceSettings();
|
||||
}
|
||||
|
||||
private async onWatchStarted(): Promise<void> {
|
||||
if (this.workspaceIdentifier) {
|
||||
const currentModel = this.getConfigurationModel();
|
||||
await this.load(this.workspaceIdentifier);
|
||||
const newModel = this.getConfigurationModel();
|
||||
const { added, removed, updated } = compare(currentModel, newModel);
|
||||
if (added.length || removed.length || updated.length) {
|
||||
this._onDidChange.fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private consolidate(): void {
|
||||
this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel);
|
||||
}
|
||||
|
||||
protected abstract loadWorkspaceConfigurationContents(workspaceConfigurationResource: URI): Promise<string | undefined>;
|
||||
}
|
||||
|
||||
class NodeBasedWorkspaceConfiguration extends AbstractWorkspaceConfiguration {
|
||||
|
||||
constructor(private readonly configurationFileService: IConfigurationFileService) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async loadWorkspaceConfigurationContents(workspaceConfigurationResource: URI): Promise<string | undefined> {
|
||||
const exists = await this.configurationFileService.exists(workspaceConfigurationResource);
|
||||
if (exists) {
|
||||
return this.configurationFileService.resolveContent(workspaceConfigurationResource);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FileServiceBasedWorkspaceConfiguration extends AbstractWorkspaceConfiguration {
|
||||
|
||||
private workspaceConfig: URI | null = null;
|
||||
private workspaceConfigWatcher: IDisposable;
|
||||
|
||||
private readonly reloadConfigurationScheduler: RunOnceScheduler;
|
||||
|
||||
constructor(private fileService: IFileService, from?: IWorkspaceConfiguration) {
|
||||
super(from);
|
||||
this.workspaceConfig = from && from.workspaceIdentifier ? from.workspaceIdentifier.configPath : null;
|
||||
this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e)));
|
||||
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50));
|
||||
this.workspaceConfigWatcher = this.watchWorkspaceConfigurationFile();
|
||||
}
|
||||
|
||||
private watchWorkspaceConfigurationFile(): IDisposable {
|
||||
if (this.workspaceConfig) {
|
||||
return this.fileService.watch(this.workspaceConfig);
|
||||
}
|
||||
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
protected loadWorkspaceConfigurationContents(workspaceConfigurationResource: URI): Promise<string> {
|
||||
if (!(this.workspaceConfig && resources.isEqual(this.workspaceConfig, workspaceConfigurationResource))) {
|
||||
dispose(this.workspaceConfigWatcher);
|
||||
this.workspaceConfig = workspaceConfigurationResource;
|
||||
this.workspaceConfigWatcher = this.watchWorkspaceConfigurationFile();
|
||||
}
|
||||
return this.fileService.resolveContent(this.workspaceConfig).then(content => content.value);
|
||||
return this._workspaceIdentifier ? this.configurationFileService.watch(this._workspaceIdentifier.configPath) : Disposable.None;
|
||||
}
|
||||
|
||||
private handleWorkspaceFileEvents(event: FileChangesEvent): void {
|
||||
if (this.workspaceConfig) {
|
||||
if (this._workspaceIdentifier) {
|
||||
const events = event.changes;
|
||||
|
||||
let affectedByChanges = false;
|
||||
// Find changes that affect workspace file
|
||||
for (let i = 0, len = events.length; i < len && !affectedByChanges; i++) {
|
||||
affectedByChanges = resources.isEqual(this.workspaceConfig, events[i].resource);
|
||||
affectedByChanges = resources.isEqual(this._workspaceIdentifier.configPath, events[i].resource);
|
||||
}
|
||||
|
||||
if (affectedByChanges) {
|
||||
@@ -542,12 +428,6 @@ class FileServiceBasedWorkspaceConfiguration extends AbstractWorkspaceConfigurat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
dispose(this.workspaceConfigWatcher);
|
||||
}
|
||||
}
|
||||
|
||||
class CachedWorkspaceConfiguration extends Disposable implements IWorkspaceConfiguration {
|
||||
@@ -617,45 +497,50 @@ class CachedWorkspaceConfiguration extends Disposable implements IWorkspaceConfi
|
||||
|
||||
export interface IFolderConfiguration extends IDisposable {
|
||||
readonly onDidChange: Event<void>;
|
||||
readonly loaded: boolean;
|
||||
loadConfiguration(): Promise<ConfigurationModel>;
|
||||
reprocess(): ConfigurationModel;
|
||||
}
|
||||
|
||||
export abstract class AbstractFolderConfiguration extends Disposable implements IFolderConfiguration {
|
||||
class FileServiceBasedFolderConfiguration extends Disposable implements IFolderConfiguration {
|
||||
|
||||
private _folderSettingsModelParser: FolderSettingsModelParser;
|
||||
private _standAloneConfigurations: ConfigurationModel[];
|
||||
private _cache: ConfigurationModel;
|
||||
private _loaded: boolean = false;
|
||||
|
||||
private readonly configurationNames: string[];
|
||||
protected readonly configurationResources: URI[];
|
||||
private changeEventTriggerScheduler: RunOnceScheduler;
|
||||
protected readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
constructor(protected readonly configurationFolder: URI, workbenchState: WorkbenchState, from?: AbstractFolderConfiguration) {
|
||||
constructor(protected readonly configurationFolder: URI, workbenchState: WorkbenchState, private configurationFileService: IConfigurationFileService) {
|
||||
super();
|
||||
|
||||
this.configurationNames = [FOLDER_SETTINGS_NAME /*First one should be settings */, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY];
|
||||
this.configurationNames = [FOLDER_SETTINGS_NAME /*First one should be settings */, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY];
|
||||
this.configurationResources = this.configurationNames.map(name => resources.joinPath(this.configurationFolder, `${name}.json`));
|
||||
this._folderSettingsModelParser = from ? from._folderSettingsModelParser : new FolderSettingsModelParser(FOLDER_SETTINGS_PATH, WorkbenchState.WORKSPACE === workbenchState ? [ConfigurationScope.RESOURCE] : [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]);
|
||||
this._standAloneConfigurations = from ? from._standAloneConfigurations : [];
|
||||
this._cache = from ? from._cache : new ConfigurationModel();
|
||||
}
|
||||
this._folderSettingsModelParser = new FolderSettingsModelParser(FOLDER_SETTINGS_PATH, WorkbenchState.WORKSPACE === workbenchState ? [ConfigurationScope.RESOURCE] : [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]);
|
||||
this._standAloneConfigurations = [];
|
||||
this._cache = new ConfigurationModel();
|
||||
|
||||
get loaded(): boolean {
|
||||
return this._loaded;
|
||||
this.changeEventTriggerScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50));
|
||||
this._register(configurationFileService.onFileChanges(e => this.handleWorkspaceFileEvents(e)));
|
||||
if (!this.configurationFileService.isWatching) {
|
||||
this.configurationFileService.whenWatchingStarted.then(() => this.onWatchStarted());
|
||||
}
|
||||
}
|
||||
|
||||
async loadConfiguration(): Promise<ConfigurationModel> {
|
||||
const configurationContents = await Promise.all(this.configurationResources.map(resource =>
|
||||
this.loadConfigurationResourceContents(resource)
|
||||
.then(undefined, error => {
|
||||
/* never fail */
|
||||
const configurationContents = await Promise.all(this.configurationResources.map(async resource => {
|
||||
try {
|
||||
return await this.configurationFileService.resolveContent(resource);
|
||||
} catch (error) {
|
||||
const exists = await this.configurationFileService.exists(resource);
|
||||
if (exists) {
|
||||
errors.onUnexpectedError(error);
|
||||
return undefined;
|
||||
})));
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}));
|
||||
|
||||
// reset
|
||||
this._standAloneConfigurations = [];
|
||||
@@ -677,7 +562,6 @@ export abstract class AbstractFolderConfiguration extends Disposable implements
|
||||
// Consolidate (support *.json files in the workspace settings folder)
|
||||
this.consolidate();
|
||||
|
||||
this._loaded = true;
|
||||
return this._cache;
|
||||
}
|
||||
|
||||
@@ -694,41 +578,13 @@ export abstract class AbstractFolderConfiguration extends Disposable implements
|
||||
this._cache = this._folderSettingsModelParser.configurationModel.merge(...this._standAloneConfigurations);
|
||||
}
|
||||
|
||||
protected abstract loadConfigurationResourceContents(configurationResource: URI): Promise<string | undefined>;
|
||||
}
|
||||
|
||||
export class NodeBasedFolderConfiguration extends AbstractFolderConfiguration {
|
||||
|
||||
constructor(private readonly configurationFileService: IConfigurationFileService, configurationFolder: URI, workbenchState: WorkbenchState) {
|
||||
super(configurationFolder, workbenchState);
|
||||
}
|
||||
|
||||
protected async loadConfigurationResourceContents(configurationResource: URI): Promise<string | undefined> {
|
||||
const exists = await this.configurationFileService.exists(configurationResource);
|
||||
if (exists) {
|
||||
return this.configurationFileService.resolveContent(configurationResource);
|
||||
private async onWatchStarted(): Promise<void> {
|
||||
const currentModel = this._cache;
|
||||
const newModel = await this.loadConfiguration();
|
||||
const { added, removed, updated } = compare(currentModel, newModel);
|
||||
if (added.length || removed.length || updated.length) {
|
||||
this._onDidChange.fire();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class FileServiceBasedFolderConfiguration extends AbstractFolderConfiguration {
|
||||
|
||||
private changeEventTriggerScheduler: RunOnceScheduler;
|
||||
|
||||
constructor(configurationFolder: URI, workbenchState: WorkbenchState, private fileService: IFileService, from?: AbstractFolderConfiguration) {
|
||||
super(configurationFolder, workbenchState, from);
|
||||
this.changeEventTriggerScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50));
|
||||
this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e)));
|
||||
}
|
||||
|
||||
protected async loadConfigurationResourceContents(configurationResource: URI): Promise<string | undefined> {
|
||||
const exists = await this.fileService.exists(configurationResource);
|
||||
if (exists) {
|
||||
const contents = await this.fileService.resolveContent(configurationResource);
|
||||
return contents.value;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private handleWorkspaceFileEvents(event: FileChangesEvent): void {
|
||||
@@ -784,7 +640,6 @@ class CachedFolderConfiguration extends Disposable implements IFolderConfigurati
|
||||
|
||||
private configurationModel: ConfigurationModel;
|
||||
private readonly key: Thenable<ConfigurationKey>;
|
||||
loaded: boolean = false;
|
||||
|
||||
constructor(
|
||||
folder: URI,
|
||||
@@ -802,7 +657,6 @@ class CachedFolderConfiguration extends Disposable implements IFolderConfigurati
|
||||
const contents = await this.configurationCache.read(key);
|
||||
const parsed: IConfigurationModel = JSON.parse(contents.toString());
|
||||
this.configurationModel = new ConfigurationModel(parsed.contents, parsed.keys, parsed.overrides);
|
||||
this.loaded = true;
|
||||
} catch (e) {
|
||||
}
|
||||
return this.configurationModel;
|
||||
@@ -832,79 +686,44 @@ export class FolderConfiguration extends Disposable implements IFolderConfigurat
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
private folderConfiguration: IFolderConfiguration;
|
||||
private folderConfigurationDisposable: IDisposable = Disposable.None;
|
||||
private readonly configurationFolder: URI;
|
||||
private cachedFolderConfiguration: CachedFolderConfiguration;
|
||||
private _loaded: boolean = false;
|
||||
|
||||
constructor(
|
||||
readonly workspaceFolder: IWorkspaceFolder,
|
||||
configFolderRelativePath: string,
|
||||
private readonly workbenchState: WorkbenchState,
|
||||
configurationFileService: IConfigurationFileService,
|
||||
configurationCache: IConfigurationCache,
|
||||
fileService?: IFileService
|
||||
configurationCache: IConfigurationCache
|
||||
) {
|
||||
super();
|
||||
|
||||
this.configurationFolder = resources.joinPath(workspaceFolder.uri, configFolderRelativePath);
|
||||
this.cachedFolderConfiguration = new CachedFolderConfiguration(workspaceFolder.uri, configFolderRelativePath, configurationCache);
|
||||
this.folderConfiguration = this.cachedFolderConfiguration;
|
||||
if (fileService) {
|
||||
this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, fileService);
|
||||
} else if (workspaceFolder.uri.scheme === Schemas.file) {
|
||||
this.folderConfiguration = new NodeBasedFolderConfiguration(configurationFileService, this.configurationFolder, this.workbenchState);
|
||||
this.folderConfiguration = this.cachedFolderConfiguration = new CachedFolderConfiguration(workspaceFolder.uri, configFolderRelativePath, configurationCache);
|
||||
if (workspaceFolder.uri.scheme === Schemas.file) {
|
||||
this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, configurationFileService);
|
||||
} else {
|
||||
configurationFileService.whenProviderRegistered(workspaceFolder.uri.scheme)
|
||||
.then(() => {
|
||||
this.folderConfiguration.dispose();
|
||||
this.folderConfigurationDisposable.dispose();
|
||||
this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, configurationFileService);
|
||||
this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange()));
|
||||
this.onDidFolderConfigurationChange();
|
||||
});
|
||||
}
|
||||
this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange()));
|
||||
this.folderConfigurationDisposable = this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange()));
|
||||
}
|
||||
|
||||
loadConfiguration(): Promise<ConfigurationModel> {
|
||||
return this.folderConfiguration.loadConfiguration()
|
||||
.then(model => {
|
||||
this._loaded = this.folderConfiguration.loaded;
|
||||
return model;
|
||||
});
|
||||
return this.folderConfiguration.loadConfiguration();
|
||||
}
|
||||
|
||||
reprocess(): ConfigurationModel {
|
||||
return this.folderConfiguration.reprocess();
|
||||
}
|
||||
|
||||
get loaded(): boolean {
|
||||
return this._loaded;
|
||||
}
|
||||
|
||||
adopt(fileService: IFileService): Promise<boolean> {
|
||||
if (fileService) {
|
||||
if (this.folderConfiguration instanceof CachedFolderConfiguration) {
|
||||
return this.adoptFromCachedConfiguration(fileService);
|
||||
}
|
||||
|
||||
if (this.folderConfiguration instanceof NodeBasedFolderConfiguration) {
|
||||
return this.adoptFromNodeBasedConfiguration(fileService);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
private adoptFromCachedConfiguration(fileService: IFileService): Promise<boolean> {
|
||||
const folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, fileService);
|
||||
return folderConfiguration.loadConfiguration()
|
||||
.then(() => {
|
||||
this.folderConfiguration = folderConfiguration;
|
||||
this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange()));
|
||||
this.updateCache();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private adoptFromNodeBasedConfiguration(fileService: IFileService): Promise<boolean> {
|
||||
const oldFolderConfiguration = this.folderConfiguration;
|
||||
this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, fileService, <AbstractFolderConfiguration>oldFolderConfiguration);
|
||||
oldFolderConfiguration.dispose();
|
||||
this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange()));
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
private onDidFolderConfigurationChange(): void {
|
||||
this.updateCache();
|
||||
this._onDidChange.fire();
|
||||
|
||||
@@ -13,7 +13,6 @@ import { Queue, Barrier } from 'vs/base/common/async';
|
||||
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ConfigurationChangeEvent, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels';
|
||||
@@ -23,13 +22,12 @@ import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resour
|
||||
import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, isSingleFolderWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, useSlashForPath, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditingService';
|
||||
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, LocalUserConfiguration } from 'vs/workbench/services/configuration/browser/configuration';
|
||||
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration } from 'vs/workbench/services/configuration/browser/configuration';
|
||||
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
|
||||
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isEqual, dirname } from 'vs/base/common/resources';
|
||||
import { mark } from 'vs/base/common/performance';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
export class WorkspaceService extends Disposable implements IConfigurationService, IWorkspaceContextService {
|
||||
@@ -41,7 +39,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
|
||||
private readonly configurationCache: IConfigurationCache;
|
||||
private _configuration: Configuration;
|
||||
private defaultConfiguration: DefaultConfigurationModel;
|
||||
private localUserConfiguration: LocalUserConfiguration | null = null;
|
||||
private localUserConfiguration: UserConfiguration | null = null;
|
||||
private remoteUserConfiguration: RemoteUserConfiguration | null = null;
|
||||
private workspaceConfiguration: WorkspaceConfiguration;
|
||||
private cachedFolderConfigs: ResourceMap<FolderConfiguration>;
|
||||
@@ -60,14 +58,13 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
|
||||
protected readonly _onDidChangeWorkbenchState: Emitter<WorkbenchState> = this._register(new Emitter<WorkbenchState>());
|
||||
public readonly onDidChangeWorkbenchState: Event<WorkbenchState> = this._onDidChangeWorkbenchState.event;
|
||||
|
||||
private fileService: IFileService;
|
||||
private configurationEditingService: ConfigurationEditingService;
|
||||
private jsonEditingService: JSONEditingService;
|
||||
|
||||
constructor(
|
||||
{ userSettingsResource, remoteAuthority, configurationCache }: { userSettingsResource?: URI, remoteAuthority?: string, configurationCache: IConfigurationCache },
|
||||
private readonly configurationFileService: IConfigurationFileService,
|
||||
private readonly remoteAgentService: IRemoteAgentService,
|
||||
remoteAgentService: IRemoteAgentService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -75,11 +72,11 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
|
||||
this.defaultConfiguration = new DefaultConfigurationModel();
|
||||
this.configurationCache = configurationCache;
|
||||
if (userSettingsResource) {
|
||||
this.localUserConfiguration = this._register(new LocalUserConfiguration(userSettingsResource, configurationFileService));
|
||||
this.localUserConfiguration = this._register(new UserConfiguration(userSettingsResource, configurationFileService));
|
||||
this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration)));
|
||||
}
|
||||
if (remoteAuthority) {
|
||||
this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache));
|
||||
this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, configurationFileService, remoteAgentService));
|
||||
this._register(this.remoteUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onRemoteUserConfigurationChanged(userConfiguration)));
|
||||
}
|
||||
this.workspaceConfiguration = this._register(new WorkspaceConfiguration(configurationCache, this.configurationFileService));
|
||||
@@ -229,9 +226,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
|
||||
// Workspace Configuration Service Impl
|
||||
|
||||
getConfigurationData(): IConfigurationData {
|
||||
const configurationData = this._configuration.toData();
|
||||
configurationData.isComplete = this.cachedFolderConfigs.values().every(c => c.loaded);
|
||||
return configurationData;
|
||||
return this._configuration.toData();
|
||||
}
|
||||
|
||||
getValue<T>(): T;
|
||||
@@ -294,45 +289,6 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
|
||||
});
|
||||
}
|
||||
|
||||
acquireFileService(fileService: IFileService): void {
|
||||
this.fileService = fileService;
|
||||
const changedWorkspaceFolders: IWorkspaceFolder[] = [];
|
||||
if (this.localUserConfiguration) {
|
||||
this.localUserConfiguration.adopt(fileService)
|
||||
.then(changedModel => {
|
||||
if (changedModel) {
|
||||
this.onLocalUserConfigurationChanged(changedModel);
|
||||
}
|
||||
});
|
||||
}
|
||||
Promise.all([this.workspaceConfiguration.adopt(fileService), ...this.cachedFolderConfigs.values()
|
||||
.map(folderConfiguration => folderConfiguration.adopt(fileService)
|
||||
.then(result => {
|
||||
if (result) {
|
||||
changedWorkspaceFolders.push(folderConfiguration.workspaceFolder);
|
||||
}
|
||||
return result;
|
||||
}))])
|
||||
.then(([workspaceChanged]) => {
|
||||
if (workspaceChanged) {
|
||||
this.onWorkspaceConfigurationChanged();
|
||||
}
|
||||
for (const workspaceFolder of changedWorkspaceFolders) {
|
||||
this.onWorkspaceFolderConfigurationChanged(workspaceFolder);
|
||||
}
|
||||
this.releaseWorkspaceBarrier();
|
||||
});
|
||||
if (this.remoteUserConfiguration) {
|
||||
this.remoteAgentService.getEnvironment()
|
||||
.then(environment => this.remoteUserConfiguration!.adopt(environment ? environment.appSettingsPath : null, fileService)
|
||||
.then(changedModel => {
|
||||
if (changedModel) {
|
||||
this.onRemoteUserConfigurationChanged(changedModel);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
acquireInstantiationService(instantiationService: IInstantiationService): void {
|
||||
this.configurationEditingService = instantiationService.createInstance(ConfigurationEditingService);
|
||||
this.jsonEditingService = instantiationService.createInstance(JSONEditingService);
|
||||
@@ -357,8 +313,8 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
|
||||
const workspaceFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), dirname(workspaceConfigPath));
|
||||
const workspaceId = workspaceIdentifier.id;
|
||||
const workspace = new Workspace(workspaceId, workspaceFolders, workspaceConfigPath);
|
||||
if (workspace.configuration!.scheme === Schemas.file) {
|
||||
this.releaseWorkspaceBarrier(); // Release barrier as workspace is complete because it is from disk.
|
||||
if (this.workspaceConfiguration.loaded) {
|
||||
this.releaseWorkspaceBarrier();
|
||||
}
|
||||
return workspace;
|
||||
});
|
||||
@@ -583,6 +539,9 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
|
||||
this.triggerConfigurationChange(workspaceConfigurationChangeEvent, ConfigurationTarget.WORKSPACE);
|
||||
}
|
||||
}
|
||||
if (this.workspaceConfiguration.loaded) {
|
||||
this.releaseWorkspaceBarrier();
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
@@ -629,7 +588,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
|
||||
return Promise.all([...folders.map(folder => {
|
||||
let folderConfiguration = this.cachedFolderConfigs.get(folder.uri);
|
||||
if (!folderConfiguration) {
|
||||
folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.configurationFileService, this.configurationCache, this.fileService);
|
||||
folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.configurationFileService, this.configurationCache);
|
||||
this._register(folderConfiguration.onDidChange(() => this.onWorkspaceFolderConfigurationChanged(folder)));
|
||||
this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { FileChangesEvent, IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
export const FOLDER_CONFIG_FOLDER_NAME = '.azuredatastudio';
|
||||
export const FOLDER_SETTINGS_NAME = 'settings';
|
||||
@@ -34,6 +37,48 @@ export interface IConfigurationCache {
|
||||
}
|
||||
|
||||
export interface IConfigurationFileService {
|
||||
fileService: IFileService | null;
|
||||
readonly onFileChanges: Event<FileChangesEvent>;
|
||||
readonly isWatching: boolean;
|
||||
readonly whenWatchingStarted: Promise<void>;
|
||||
whenProviderRegistered(scheme: string): Promise<void>;
|
||||
watch(resource: URI): IDisposable;
|
||||
exists(resource: URI): Promise<boolean>;
|
||||
resolveContent(resource: URI): Promise<string>;
|
||||
}
|
||||
|
||||
export class ConfigurationFileService implements IConfigurationFileService {
|
||||
|
||||
constructor(public fileService: IFileService) { }
|
||||
|
||||
get onFileChanges() { return this.fileService.onFileChanges; }
|
||||
readonly whenWatchingStarted: Promise<void> = Promise.resolve();
|
||||
readonly isWatching: boolean = true;
|
||||
|
||||
whenProviderRegistered(scheme: string): Promise<void> {
|
||||
if (this.fileService.canHandleResource(URI.from({ scheme }))) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((c, e) => {
|
||||
const disposable = this.fileService.onDidChangeFileSystemProviderRegistrations(e => {
|
||||
if (e.scheme === scheme && e.added) {
|
||||
disposable.dispose();
|
||||
c();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
watch(resource: URI): IDisposable {
|
||||
return this.fileService.watch(resource);
|
||||
}
|
||||
|
||||
exists(resource: URI): Promise<boolean> {
|
||||
return this.fileService.exists(resource);
|
||||
}
|
||||
|
||||
resolveContent(resource: URI): Promise<string> {
|
||||
return this.fileService.resolveContent(resource, { encoding: 'utf8' }).then(content => content.value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,18 +4,76 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { IConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { IConfigurationFileService, ConfigurationFileService as FileServiceBasedConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { FileChangesEvent, IFileService } from 'vs/platform/files/common/files';
|
||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export class ConfigurationFileService implements IConfigurationFileService {
|
||||
export class ConfigurationFileService extends Disposable implements IConfigurationFileService {
|
||||
|
||||
private _fileServiceBasedConfigurationFileService: FileServiceBasedConfigurationFileService | null = null;
|
||||
private _fileServiceBasedConfigurationFileServiceCallback: (fileServiceBasedConfigurationFileService: FileServiceBasedConfigurationFileService) => void;
|
||||
private _whenFileServiceBasedConfigurationFileServiceAvailable: Promise<FileServiceBasedConfigurationFileService> = new Promise((c) => this._fileServiceBasedConfigurationFileServiceCallback = c);
|
||||
private _watchResources: { resource: URI, disposable: { disposable: IDisposable | null } }[] = [];
|
||||
readonly whenWatchingStarted: Promise<void> = this._whenFileServiceBasedConfigurationFileServiceAvailable.then(() => undefined);
|
||||
|
||||
private readonly _onFileChanges: Emitter<FileChangesEvent> = this._register(new Emitter<FileChangesEvent>());
|
||||
readonly onFileChanges: Event<FileChangesEvent> = this._onFileChanges.event;
|
||||
|
||||
get isWatching(): boolean {
|
||||
return this._fileServiceBasedConfigurationFileService ? this._fileServiceBasedConfigurationFileService.isWatching : false;
|
||||
}
|
||||
|
||||
watch(resource: URI): IDisposable {
|
||||
if (this._fileServiceBasedConfigurationFileService) {
|
||||
return this._fileServiceBasedConfigurationFileService.watch(resource);
|
||||
}
|
||||
const disposable: { disposable: IDisposable | null } = { disposable: null };
|
||||
this._watchResources.push({ resource, disposable });
|
||||
return toDisposable(() => {
|
||||
if (disposable.disposable) {
|
||||
disposable.disposable.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
whenProviderRegistered(scheme: string): Promise<void> {
|
||||
if (scheme === Schemas.file) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._whenFileServiceBasedConfigurationFileServiceAvailable
|
||||
.then(fileServiceBasedConfigurationFileService => fileServiceBasedConfigurationFileService.whenProviderRegistered(scheme));
|
||||
}
|
||||
|
||||
exists(resource: URI): Promise<boolean> {
|
||||
return pfs.exists(resource.fsPath);
|
||||
return this._fileServiceBasedConfigurationFileService ? this._fileServiceBasedConfigurationFileService.exists(resource) : pfs.exists(resource.fsPath);
|
||||
}
|
||||
|
||||
async resolveContent(resource: URI): Promise<string> {
|
||||
const contents = await pfs.readFile(resource.fsPath);
|
||||
return contents.toString();
|
||||
if (this._fileServiceBasedConfigurationFileService) {
|
||||
return this._fileServiceBasedConfigurationFileService.resolveContent(resource);
|
||||
} else {
|
||||
const contents = await pfs.readFile(resource.fsPath);
|
||||
return contents.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private _fileService: IFileService | null;
|
||||
get fileService(): IFileService | null {
|
||||
return this._fileService;
|
||||
}
|
||||
|
||||
set fileService(fileService: IFileService | null) {
|
||||
if (fileService && !this._fileServiceBasedConfigurationFileService) {
|
||||
this._fileServiceBasedConfigurationFileService = new FileServiceBasedConfigurationFileService(fileService);
|
||||
this._fileService = fileService;
|
||||
this._register(this._fileServiceBasedConfigurationFileService.onFileChanges(e => this._onFileChanges.fire(e)));
|
||||
for (const { resource, disposable } of this._watchResources) {
|
||||
disposable.disposable = this._fileServiceBasedConfigurationFileService.watch(resource);
|
||||
}
|
||||
this._fileServiceBasedConfigurationFileServiceCallback(this._fileServiceBasedConfigurationFileService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ export class ConfigurationResolverService extends AbstractVariableResolverServic
|
||||
if (activeEditor instanceof DiffEditorInput) {
|
||||
activeEditor = activeEditor.modifiedInput;
|
||||
}
|
||||
const fileResource = toResource(activeEditor, { filter: Schemas.file });
|
||||
const fileResource = toResource(activeEditor, { filterByScheme: Schemas.file });
|
||||
if (!fileResource) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ export class FileDialogService implements IFileDialogService {
|
||||
return this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }).then(uri => {
|
||||
if (uri) {
|
||||
return (this.fileService.resolve(uri)).then(stat => {
|
||||
const toOpen: IURIToOpen = stat.isDirectory ? { fileUri: uri } : { folderUri: uri };
|
||||
const toOpen: IURIToOpen = stat.isDirectory ? { folderUri: uri } : { fileUri: uri };
|
||||
return this.windowService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow });
|
||||
});
|
||||
}
|
||||
@@ -210,7 +210,7 @@ export class FileDialogService implements IFileDialogService {
|
||||
|
||||
showOpenDialog(options: IOpenDialogOptions): Promise<URI[] | undefined> {
|
||||
const schema = this.getFileSystemSchema(options);
|
||||
if (schema !== Schemas.file) {
|
||||
if (this.shouldUseSimplified(schema)) {
|
||||
if (!options.availableFileSystems) {
|
||||
options.availableFileSystems = [schema]; // by default only allow loading in the own file system
|
||||
}
|
||||
|
||||
@@ -110,10 +110,13 @@ export class RemoteFileDialog {
|
||||
let defaultUri = options.defaultUri;
|
||||
const filename = (defaultUri && isSave && (resources.dirname(defaultUri).path === '/')) ? resources.basename(defaultUri) : undefined;
|
||||
if (!defaultUri || filename) {
|
||||
const env = await this.remoteAgentService.getEnvironment();
|
||||
if (env) {
|
||||
defaultUri = env.userHome;
|
||||
} else {
|
||||
if (this.scheme !== Schemas.file) {
|
||||
const env = await this.remoteAgentService.getEnvironment();
|
||||
if (env) {
|
||||
defaultUri = env.userHome;
|
||||
}
|
||||
}
|
||||
if (!defaultUri) {
|
||||
defaultUri = URI.from({ scheme: this.scheme, path: this.environmentService.userHome });
|
||||
}
|
||||
if (filename) {
|
||||
@@ -192,7 +195,7 @@ export class RemoteFileDialog {
|
||||
if (validated) {
|
||||
isResolving = true;
|
||||
this.filePickBox.hide();
|
||||
resolve(resolveValue);
|
||||
doResolve(this, resolveValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -200,6 +203,13 @@ export class RemoteFileDialog {
|
||||
this.filePickBox.title = this.options.title;
|
||||
this.filePickBox.value = this.pathFromUri(this.currentFolder);
|
||||
this.filePickBox.items = [];
|
||||
|
||||
function doResolve(dialog: RemoteFileDialog, uri: URI | undefined) {
|
||||
resolve(uri);
|
||||
dialog.contextKey.set(false);
|
||||
dialog.filePickBox.dispose();
|
||||
}
|
||||
|
||||
this.filePickBox.onDidAccept(_ => {
|
||||
if (isAcceptHandled || this.filePickBox.busy) {
|
||||
return;
|
||||
@@ -210,9 +220,9 @@ export class RemoteFileDialog {
|
||||
this.onDidAccept().then(resolveValue => {
|
||||
if (resolveValue) {
|
||||
this.filePickBox.hide();
|
||||
resolve(resolveValue);
|
||||
doResolve(this, resolveValue);
|
||||
} else if (this.hidden) {
|
||||
resolve(undefined);
|
||||
doResolve(this, undefined);
|
||||
} else {
|
||||
isResolving = false;
|
||||
isAcceptHandled = false;
|
||||
@@ -221,6 +231,10 @@ export class RemoteFileDialog {
|
||||
});
|
||||
this.filePickBox.onDidChangeActive(i => {
|
||||
isAcceptHandled = false;
|
||||
// update input box to match the first selected item
|
||||
if (i.length === 1) {
|
||||
this.setAutoComplete(this.userValue, resources.basename(this.remoteUriFrom(this.userValue)), i[0], true);
|
||||
}
|
||||
});
|
||||
|
||||
this.filePickBox.onDidChangeValue(async value => {
|
||||
@@ -229,13 +243,11 @@ export class RemoteFileDialog {
|
||||
if (value !== this.userValue) {
|
||||
this.filePickBox.validationMessage = undefined;
|
||||
this.shouldOverwriteFile = false;
|
||||
const trimmedPickBoxValue = ((this.filePickBox.value.length > 1) && this.endsWithSlash(this.filePickBox.value)) ? this.filePickBox.value.substr(0, this.filePickBox.value.length - 1) : this.filePickBox.value;
|
||||
const valueUri = this.remoteUriFrom(trimmedPickBoxValue);
|
||||
if (!resources.isEqual(this.currentFolder, valueUri, true)) {
|
||||
const valueUri = this.remoteUriFrom(this.trimTrailingSlash(this.filePickBox.value));
|
||||
if (!resources.isEqual(this.remoteUriFrom(this.trimTrailingSlash(this.pathFromUri(this.currentFolder))), valueUri, true)) {
|
||||
await this.tryUpdateItems(value, this.remoteUriFrom(this.filePickBox.value));
|
||||
}
|
||||
this.setActiveItems(value);
|
||||
this.userValue = value;
|
||||
} else {
|
||||
this.filePickBox.activeItems = [];
|
||||
}
|
||||
@@ -244,10 +256,8 @@ export class RemoteFileDialog {
|
||||
this.filePickBox.onDidHide(() => {
|
||||
this.hidden = true;
|
||||
if (!isResolving) {
|
||||
resolve(undefined);
|
||||
doResolve(this, undefined);
|
||||
}
|
||||
this.contextKey.set(false);
|
||||
this.filePickBox.dispose();
|
||||
});
|
||||
|
||||
this.filePickBox.show();
|
||||
@@ -361,15 +371,8 @@ export class RemoteFileDialog {
|
||||
let hasMatch = false;
|
||||
for (let i = 0; i < this.filePickBox.items.length; i++) {
|
||||
const item = <FileQuickPickItem>this.filePickBox.items[i];
|
||||
const itemBasename = (item.label === '..') ? item.label : resources.basename(item.uri);
|
||||
if ((itemBasename.length >= inputBasename.length) && (itemBasename.substr(0, inputBasename.length).toLowerCase() === inputBasename.toLowerCase())) {
|
||||
if (this.setAutoComplete(value, inputBasename, item)) {
|
||||
this.filePickBox.activeItems = [item];
|
||||
const insertValue = itemBasename.substr(inputBasename.length);
|
||||
this.autoComplete = value + insertValue;
|
||||
if (this.filePickBox.inputHasFocus()) {
|
||||
document.execCommand('insertText', false, insertValue);
|
||||
this.filePickBox.valueSelection = [value.length, this.filePickBox.value.length];
|
||||
}
|
||||
hasMatch = true;
|
||||
break;
|
||||
}
|
||||
@@ -377,6 +380,44 @@ export class RemoteFileDialog {
|
||||
if (!hasMatch) {
|
||||
this.filePickBox.activeItems = [];
|
||||
}
|
||||
} else {
|
||||
this.userValue = value;
|
||||
this.autoComplete = '';
|
||||
}
|
||||
}
|
||||
|
||||
private setAutoComplete(startingValue: string, startingBasename: string, quickPickItem: FileQuickPickItem, force: boolean = false): boolean {
|
||||
const itemBasename = (quickPickItem.label === '..') ? quickPickItem.label : resources.basename(quickPickItem.uri);
|
||||
const itemPathLabel = (itemBasename === '..') ? this.pathAppend(this.currentFolder, itemBasename) : this.pathFromUri(quickPickItem.uri);
|
||||
if (this.trimTrailingSlash(this.filePickBox.value) !== itemPathLabel) {
|
||||
// Either foce the autocomplete, or the old value should be one smaller than the new value and match the new value.
|
||||
if (!force && (itemBasename.length >= startingBasename.length) && (itemBasename.substr(0, startingBasename.length).toLowerCase() === startingBasename.toLowerCase())) {
|
||||
this.userValue = startingValue;
|
||||
const autoCompleteValue = itemBasename.substr(startingBasename.length);
|
||||
this.autoComplete = startingValue + autoCompleteValue;
|
||||
this.insertText(this.autoComplete, autoCompleteValue);
|
||||
this.filePickBox.valueSelection = [startingValue.length, this.filePickBox.value.length];
|
||||
return true;
|
||||
} else if (force) {
|
||||
this.userValue = this.pathFromUri(this.currentFolder, true);
|
||||
this.autoComplete = this.pathAppend(this.currentFolder, itemBasename);
|
||||
this.filePickBox.valueSelection = [this.userValue.length, this.filePickBox.value.length];
|
||||
// use insert text to preserve undo buffer
|
||||
this.insertText(this.autoComplete, itemBasename);
|
||||
this.filePickBox.valueSelection = [this.filePickBox.value.length - itemBasename.length, this.filePickBox.value.length];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
this.userValue = startingValue;
|
||||
this.autoComplete = '';
|
||||
return false;
|
||||
}
|
||||
|
||||
private insertText(wholeValue: string, insertText: string) {
|
||||
if (this.filePickBox.inputHasFocus()) {
|
||||
document.execCommand('insertText', false, insertText);
|
||||
} else {
|
||||
this.filePickBox.value = wholeValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,6 +447,39 @@ export class RemoteFileDialog {
|
||||
return result;
|
||||
}
|
||||
|
||||
private trimTrailingSlash(path: string): string {
|
||||
return ((path.length > 1) && this.endsWithSlash(path)) ? path.substr(0, path.length - 1) : path;
|
||||
}
|
||||
|
||||
private yesNoPrompt(message: string): Promise<boolean> {
|
||||
interface YesNoItem extends IQuickPickItem {
|
||||
value: boolean;
|
||||
}
|
||||
const prompt = this.quickInputService.createQuickPick<YesNoItem>();
|
||||
const no = nls.localize('remoteFileDialog.no', 'No');
|
||||
prompt.items = [{ label: no, value: false }, { label: nls.localize('remoteFileDialog.yes', 'Yes'), value: true }];
|
||||
prompt.title = message;
|
||||
prompt.placeholder = no;
|
||||
let isResolving = false;
|
||||
return new Promise<boolean>(resolve => {
|
||||
prompt.onDidAccept(() => {
|
||||
isResolving = true;
|
||||
prompt.hide();
|
||||
resolve(prompt.selectedItems ? prompt.selectedItems[0].value : false);
|
||||
});
|
||||
prompt.onDidHide(() => {
|
||||
if (!isResolving) {
|
||||
resolve(false);
|
||||
}
|
||||
this.filePickBox.show();
|
||||
this.hidden = false;
|
||||
this.filePickBox.items = this.filePickBox.items;
|
||||
prompt.dispose();
|
||||
});
|
||||
prompt.show();
|
||||
});
|
||||
}
|
||||
|
||||
private async validate(uri: URI): Promise<boolean> {
|
||||
let stat: IFileStat | undefined;
|
||||
let statDirname: IFileStat | undefined;
|
||||
@@ -424,8 +498,9 @@ export class RemoteFileDialog {
|
||||
} else if (stat && !this.shouldOverwriteFile) {
|
||||
// Replacing a file.
|
||||
this.shouldOverwriteFile = true;
|
||||
this.filePickBox.validationMessage = nls.localize('remoteFileDialog.validateExisting', '{0} already exists. Are you sure you want to overwrite it?', resources.basename(uri));
|
||||
return Promise.resolve(false);
|
||||
// Show a yes/no prompt
|
||||
const message = nls.localize('remoteFileDialog.validateExisting', '{0} already exists. Are you sure you want to overwrite it?', resources.basename(uri));
|
||||
return this.yesNoPrompt(message);
|
||||
} else if (!this.isValidBaseName(resources.basename(uri))) {
|
||||
// Filename not allowed
|
||||
this.filePickBox.validationMessage = nls.localize('remoteFileDialog.validateBadFilename', 'Please enter a valid file name.');
|
||||
@@ -455,7 +530,11 @@ export class RemoteFileDialog {
|
||||
|
||||
private updateItems(newFolder: URI, trailing?: string) {
|
||||
this.currentFolder = newFolder;
|
||||
this.filePickBox.value = trailing ? this.pathFromUri(resources.joinPath(newFolder, trailing)) : this.pathFromUri(newFolder, true);
|
||||
this.userValue = this.pathFromUri(newFolder);
|
||||
this.autoComplete = '';
|
||||
this.filePickBox.valueSelection = [0, this.filePickBox.value.length];
|
||||
const newValue = trailing ? this.pathFromUri(resources.joinPath(newFolder, trailing)) : this.pathFromUri(newFolder, true);
|
||||
this.insertText(newValue, newValue);
|
||||
this.filePickBox.busy = true;
|
||||
this.createItems(this.currentFolder).then(items => {
|
||||
this.filePickBox.items = items;
|
||||
@@ -480,6 +559,14 @@ export class RemoteFileDialog {
|
||||
return result;
|
||||
}
|
||||
|
||||
private pathAppend(uri: URI, additional: string): string {
|
||||
if (additional === '..') {
|
||||
return this.pathFromUri(uri) + this.labelService.getSeparator(uri.scheme, uri.authority) + additional;
|
||||
} else {
|
||||
return this.pathFromUri(resources.joinPath(uri, additional));
|
||||
}
|
||||
}
|
||||
|
||||
private isValidBaseName(name: string): boolean {
|
||||
if (!name || name.length === 0 || /^\s+$/.test(name)) {
|
||||
return false; // require a name that is not just whitespace
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { IInstantiationService, ServicesAccessor, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IResourceInput, ITextEditorOptions, IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorInput, IEditor, GroupIdentifier, IFileEditorInput, IUntitledResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInputFactoryRegistry, Extensions as EditorExtensions, IFileInputFactory, EditorInput, SideBySideEditorInput, IEditorInputWithOptions, isEditorInputWithOptions, EditorOptions, TextEditorOptions, IEditorIdentifier, IEditorCloseEvent, ITextEditor, ITextDiffEditor, ITextSideBySideEditor, toResource } from 'vs/workbench/common/editor';
|
||||
import { IEditorInput, IEditor, GroupIdentifier, IFileEditorInput, IUntitledResourceInput, IResourceDiffInput, IResourceSideBySideInput, IEditorInputFactoryRegistry, Extensions as EditorExtensions, IFileInputFactory, EditorInput, SideBySideEditorInput, IEditorInputWithOptions, isEditorInputWithOptions, EditorOptions, TextEditorOptions, IEditorIdentifier, IEditorCloseEvent, ITextEditor, ITextDiffEditor, ITextSideBySideEditor, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
||||
import { DataUriEditorInput } from 'vs/workbench/common/editor/dataUriEditorInput';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
@@ -419,7 +419,7 @@ export class EditorService extends Disposable implements EditorServiceImpl {
|
||||
// Resource editor
|
||||
else {
|
||||
for (const editorInGroup of group.editors) {
|
||||
const resource = toResource(editorInGroup, { supportSideBySide: true });
|
||||
const resource = toResource(editorInGroup, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (!resource) {
|
||||
continue; // need a resource to compare with
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user