Archived
Merge from vscode 0f73473c08055054f317c1c94502f7f39fdbb164 (#6892)
* Merge from vscode 0f73473c08055054f317c1c94502f7f39fdbb164 * fix tslinting
This commit is contained in:
@@ -1202,5 +1202,8 @@ export function asDomUri(uri: URI): URI {
|
||||
* returns url('...')
|
||||
*/
|
||||
export function asCSSUrl(uri: URI): string {
|
||||
if (!uri) {
|
||||
return `url('')`;
|
||||
}
|
||||
return `url('${asDomUri(uri).toString(true).replace(/'/g, '%27')}')`;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,15 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { Iterator, IteratorResult, FIN } from './iterator';
|
||||
|
||||
|
||||
export function fromArray<T>(array: readonly T[]): Set<T> {
|
||||
const result = new Set<T>();
|
||||
for (const element of array) {
|
||||
result.add(element);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function values<V = any>(set: Set<V>): V[];
|
||||
export function values<K = any, V = any>(map: Map<K, V>): V[];
|
||||
export function values<V>(forEachable: { forEach(callback: (value: V, ...more: any[]) => any): void }): V[] {
|
||||
|
||||
@@ -12,7 +12,11 @@ export function buildReplaceStringWithCasePreserved(matches: string[] | null, pa
|
||||
} else if (matches[0].toLowerCase() === matches[0]) {
|
||||
return pattern.toLowerCase();
|
||||
} else if (strings.containsUppercaseCharacter(matches[0][0])) {
|
||||
return pattern[0].toUpperCase() + pattern.substr(1);
|
||||
if (validateSpecificSpecialCharacter(matches, pattern, '-')) {
|
||||
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-');
|
||||
} else {
|
||||
return pattern[0].toUpperCase() + pattern.substr(1);
|
||||
}
|
||||
} else {
|
||||
// we don't understand its pattern yet.
|
||||
return pattern;
|
||||
@@ -21,3 +25,19 @@ export function buildReplaceStringWithCasePreserved(matches: string[] | null, pa
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
||||
function validateSpecificSpecialCharacter(matches: string[], pattern: string, specialCharacter: string): boolean {
|
||||
const doesConatinSpecialCharacter = matches[0].indexOf(specialCharacter) !== -1 && pattern.indexOf(specialCharacter) !== -1;
|
||||
return doesConatinSpecialCharacter && matches[0].split(specialCharacter).length === pattern.split(specialCharacter).length;
|
||||
}
|
||||
|
||||
function buildReplaceStringForSpecificSpecialCharacter(matches: string[], pattern: string, specialCharacter: string): string {
|
||||
const splitPatternAtSpecialCharacter = pattern.split(specialCharacter);
|
||||
const splitMatchAtSpecialCharacter = matches[0].split(specialCharacter);
|
||||
let replaceString: string = '';
|
||||
splitPatternAtSpecialCharacter.forEach((splitValue, index) => {
|
||||
replaceString += buildReplaceStringWithCasePreserved([splitMatchAtSpecialCharacter[index]], splitValue) + specialCharacter;
|
||||
});
|
||||
|
||||
return replaceString.slice(0, -1);
|
||||
}
|
||||
|
||||
@@ -32,4 +32,4 @@ suite('Keytar', () => {
|
||||
}
|
||||
})().then(done, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,7 +70,7 @@ import { startsWith } from 'vs/base/common/strings';
|
||||
import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService';
|
||||
import { IBackupMainService } from 'vs/platform/backup/common/backup';
|
||||
import { HistoryMainService } from 'vs/platform/history/electron-main/historyMainService';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
|
||||
import { statSync } from 'fs';
|
||||
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc';
|
||||
|
||||
@@ -404,7 +404,7 @@ export interface CompletionItem {
|
||||
* A modifier to the `kind` which affect how the item
|
||||
* is rendered, e.g. Deprecated is rendered with a strikeout
|
||||
*/
|
||||
kindModifier?: CompletionItemKindModifier;
|
||||
kindModifier?: Set<CompletionItemKindModifier>;
|
||||
/**
|
||||
* A human-readable string with additional information
|
||||
* about this item, like type or symbol information.
|
||||
@@ -867,6 +867,9 @@ export const enum SymbolKind {
|
||||
TypeParameter = 25
|
||||
}
|
||||
|
||||
export const enum SymbolKindTag {
|
||||
Deprecated = 1,
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -910,6 +913,7 @@ export interface DocumentSymbol {
|
||||
name: string;
|
||||
detail: string;
|
||||
kind: SymbolKind;
|
||||
kindTags: SymbolKindTag[];
|
||||
containerName?: string;
|
||||
range: IRange;
|
||||
selectionRange: IRange;
|
||||
|
||||
@@ -660,4 +660,8 @@ export enum SymbolKind {
|
||||
Event = 23,
|
||||
Operator = 24,
|
||||
TypeParameter = 25
|
||||
}
|
||||
|
||||
export enum SymbolKindTag {
|
||||
Deprecated = 1
|
||||
}
|
||||
@@ -20,6 +20,11 @@
|
||||
color: var(--outline-element-color);
|
||||
}
|
||||
|
||||
.monaco-list .outline-element .deprecated {
|
||||
text-decoration: line-through;
|
||||
opacity: 0.66;
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-row.focused .outline-element .outline-element-detail {
|
||||
visibility: inherit;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { createMatches, FuzzyScore } from 'vs/base/common/filters';
|
||||
import 'vs/css!./media/outlineTree';
|
||||
import 'vs/css!./media/symbol-icons';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { SymbolKind, symbolKindToCssClass } from 'vs/editor/common/modes';
|
||||
import { SymbolKind, symbolKindToCssClass, SymbolKindTag } from 'vs/editor/common/modes';
|
||||
import { OutlineElement, OutlineGroup, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
@@ -127,6 +127,10 @@ export class OutlineElementRenderer implements ITreeRenderer<OutlineElement, Fuz
|
||||
// add styles for the icons
|
||||
options.extraClasses.push(`outline-element-icon ${symbolKindToCssClass(element.symbol.kind, true)}`);
|
||||
}
|
||||
if (element.symbol.kindTags.indexOf(SymbolKindTag.Deprecated) >= 0) {
|
||||
options.extraClasses.push(`deprecated`);
|
||||
options.matches = [];
|
||||
}
|
||||
template.iconLabel.setLabel(element.symbol.name, element.symbol.detail, options);
|
||||
this._renderMarkerInfo(element, template);
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ suite('OutlineModel', function () {
|
||||
name,
|
||||
detail: 'fake',
|
||||
kind: SymbolKind.Boolean,
|
||||
kindTags: [],
|
||||
selectionRange: range,
|
||||
range: range
|
||||
};
|
||||
|
||||
@@ -176,6 +176,13 @@ suite('Replace Pattern test', () => {
|
||||
assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'Def');
|
||||
actual = ['aBC'];
|
||||
assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'Def');
|
||||
|
||||
actual = ['Foo-Bar'];
|
||||
assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar'), 'Newfoo-Newbar');
|
||||
actual = ['Foo-Bar-Abc'];
|
||||
assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar-newabc'), 'Newfoo-Newbar-Newabc');
|
||||
actual = ['Foo-Bar-abc'];
|
||||
assert.equal(buildReplaceStringWithCasePreserved(actual, 'newfoo-newbar'), 'Newfoo-newbar');
|
||||
});
|
||||
|
||||
test('preserve case', () => {
|
||||
@@ -198,5 +205,17 @@ suite('Replace Pattern test', () => {
|
||||
assert.equal(actual, 'Def');
|
||||
actual = replacePattern.buildReplaceString(['aBC'], true);
|
||||
assert.equal(actual, 'Def');
|
||||
|
||||
replacePattern = parseReplaceString('newfoo-newbar');
|
||||
actual = replacePattern.buildReplaceString(['Foo-Bar'], true);
|
||||
assert.equal(actual, 'Newfoo-Newbar');
|
||||
|
||||
replacePattern = parseReplaceString('newfoo-newbar-newabc');
|
||||
actual = replacePattern.buildReplaceString(['Foo-Bar-Abc'], true);
|
||||
assert.equal(actual, 'Newfoo-Newbar-Newabc');
|
||||
|
||||
replacePattern = parseReplaceString('newfoo-newbar');
|
||||
actual = replacePattern.buildReplaceString(['Foo-Bar-abc'], true);
|
||||
assert.equal(actual, 'Newfoo-newbar');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -51,6 +51,7 @@ function flatten(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideCo
|
||||
for (let entry of entries) {
|
||||
bucket.push({
|
||||
kind: entry.kind,
|
||||
kindTags: [],
|
||||
name: entry.name,
|
||||
detail: entry.detail,
|
||||
containerName: entry.containerName || overrideContainerLabel,
|
||||
|
||||
@@ -97,10 +97,6 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget-deprecated span {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
/** Icon styles **/
|
||||
|
||||
.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close,
|
||||
@@ -115,8 +111,8 @@
|
||||
.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close {
|
||||
background-image: url('./close-light.svg');
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
@@ -159,9 +155,16 @@
|
||||
}
|
||||
|
||||
/** Styles for each row in the list **/
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated {
|
||||
opacity: 0.66;
|
||||
}
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated > .monaco-icon-label-description-container {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label::before {
|
||||
height: 100%;
|
||||
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon {
|
||||
@@ -257,7 +260,7 @@
|
||||
text-overflow: ellipsis;
|
||||
opacity: 0.7;
|
||||
word-break: break-all;
|
||||
margin: 0px 24px 0 0;
|
||||
margin: 0 24px 0 0;
|
||||
padding: 4px 0 12px 5px;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ import { IdleValue } from 'vs/base/common/async';
|
||||
import { isObject } from 'vs/base/common/types';
|
||||
import { CommitCharacterController } from './suggestCommitCharacters';
|
||||
|
||||
const _sticky = false; // for development purposes only
|
||||
|
||||
export class SuggestController implements IEditorContribution {
|
||||
|
||||
private static readonly ID: string = 'editor.contrib.suggestController';
|
||||
@@ -47,7 +49,6 @@ export class SuggestController implements IEditorContribution {
|
||||
private readonly _alternatives: IdleValue<SuggestAlternatives>;
|
||||
private readonly _toDispose = new DisposableStore();
|
||||
|
||||
private readonly _sticky = false; // for development purposes only
|
||||
|
||||
constructor(
|
||||
private _editor: ICodeEditor,
|
||||
@@ -127,7 +128,7 @@ export class SuggestController implements IEditorContribution {
|
||||
}
|
||||
}));
|
||||
this._toDispose.add(this._editor.onDidBlurEditorWidget(() => {
|
||||
if (!this._sticky) {
|
||||
if (!_sticky) {
|
||||
this._model.cancel();
|
||||
this._model.clear();
|
||||
}
|
||||
|
||||
@@ -193,8 +193,9 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
||||
];
|
||||
}
|
||||
|
||||
if (suggestion.kindModifier && suggestion.kindModifier & CompletionItemKindModifier.Deprecated) {
|
||||
labelOptions.extraClasses = (labelOptions.extraClasses || []).concat(['suggest-widget-deprecated']);
|
||||
if (suggestion.kindModifier && suggestion.kindModifier.has(CompletionItemKindModifier.Deprecated)) {
|
||||
labelOptions.extraClasses = (labelOptions.extraClasses || []).concat(['deprecated']);
|
||||
labelOptions.matches = [];
|
||||
}
|
||||
|
||||
data.iconLabel.setLabel(suggestion.label, undefined, labelOptions);
|
||||
|
||||
@@ -565,6 +565,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages {
|
||||
CompletionItemKindModifier: standaloneEnums.CompletionItemKindModifier,
|
||||
CompletionItemInsertTextRule: standaloneEnums.CompletionItemInsertTextRule,
|
||||
SymbolKind: standaloneEnums.SymbolKind,
|
||||
SymbolKindTag: standaloneEnums.SymbolKindTag,
|
||||
IndentAction: standaloneEnums.IndentAction,
|
||||
CompletionTriggerKind: standaloneEnums.CompletionTriggerKind,
|
||||
SignatureHelpTriggerKind: standaloneEnums.SignatureHelpTriggerKind,
|
||||
|
||||
Vendored
+6
-1
@@ -4826,7 +4826,7 @@ declare namespace monaco.languages {
|
||||
* A modifier to the `kind` which affect how the item
|
||||
* is rendered, e.g. Deprecated is rendered with a strikeout
|
||||
*/
|
||||
kindModifier?: CompletionItemKindModifier;
|
||||
kindModifier?: Set<CompletionItemKindModifier>;
|
||||
/**
|
||||
* A human-readable string with additional information
|
||||
* about this item, like type or symbol information.
|
||||
@@ -5236,10 +5236,15 @@ declare namespace monaco.languages {
|
||||
TypeParameter = 25
|
||||
}
|
||||
|
||||
export enum SymbolKindTag {
|
||||
Deprecated = 1
|
||||
}
|
||||
|
||||
export interface DocumentSymbol {
|
||||
name: string;
|
||||
detail: string;
|
||||
kind: SymbolKind;
|
||||
kindTags: SymbolKindTag[];
|
||||
containerName?: string;
|
||||
range: IRange;
|
||||
selectionRange: IRange;
|
||||
|
||||
@@ -50,6 +50,7 @@ export interface IProgressOptions {
|
||||
source?: string;
|
||||
total?: number;
|
||||
cancellable?: boolean;
|
||||
buttons?: string[];
|
||||
}
|
||||
|
||||
export interface IProgressNotificationOptions extends IProgressOptions {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Emitter } from 'vs/base/common/event';
|
||||
import { RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { ISignService } from 'vs/platform/sign/common/sign';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
|
||||
export const enum ConnectionType {
|
||||
Management = 1,
|
||||
@@ -245,9 +246,15 @@ export async function connectRemoteAgentTunnel(options: IConnectionOptions, tunn
|
||||
return protocol;
|
||||
}
|
||||
|
||||
function sleep(seconds: number): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
setTimeout(resolve, seconds * 1000);
|
||||
function sleep(seconds: number): CancelablePromise<void> {
|
||||
return createCancelablePromise(token => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(resolve, seconds * 1000);
|
||||
token.onCancellationRequested(() => {
|
||||
clearTimeout(timeout);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -264,8 +271,13 @@ export class ConnectionLostEvent {
|
||||
export class ReconnectionWaitEvent {
|
||||
public readonly type = PersistentConnectionEventType.ReconnectionWait;
|
||||
constructor(
|
||||
public readonly durationSeconds: number
|
||||
public readonly durationSeconds: number,
|
||||
private readonly cancellableTimer: CancelablePromise<void>
|
||||
) { }
|
||||
|
||||
public skipWait(): void {
|
||||
this.cancellableTimer.cancel();
|
||||
}
|
||||
}
|
||||
export class ReconnectionRunningEvent {
|
||||
public readonly type = PersistentConnectionEventType.ReconnectionRunning;
|
||||
@@ -330,8 +342,12 @@ abstract class PersistentConnection extends Disposable {
|
||||
attempt++;
|
||||
const waitTime = (attempt < TIMES.length ? TIMES[attempt] : TIMES[TIMES.length - 1]);
|
||||
try {
|
||||
this._onDidStateChange.fire(new ReconnectionWaitEvent(waitTime));
|
||||
await sleep(waitTime);
|
||||
const sleepPromise = sleep(waitTime);
|
||||
this._onDidStateChange.fire(new ReconnectionWaitEvent(waitTime, sleepPromise));
|
||||
|
||||
try {
|
||||
await sleepPromise;
|
||||
} catch { } // User canceled timer
|
||||
|
||||
// connection was lost, let's try to re-establish it
|
||||
this._onDidStateChange.fire(new ReconnectionRunningEvent());
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export const IURLService = createDecorator<IURLService>('urlService');
|
||||
@@ -14,8 +14,17 @@ export interface IURLHandler {
|
||||
}
|
||||
|
||||
export interface IURLService {
|
||||
_serviceBrand: any;
|
||||
|
||||
_serviceBrand: ServiceIdentifier<any>;
|
||||
|
||||
/**
|
||||
* Create a URL that can be called to trigger IURLhandlers.
|
||||
* The URL that gets passed to the IURLHandlers carries over
|
||||
* any of the provided IURLCreateOption values.
|
||||
*/
|
||||
create(options?: Partial<UriComponents>): URI;
|
||||
|
||||
open(url: URI): Promise<boolean>;
|
||||
|
||||
registerHandler(handler: IURLHandler): IDisposable;
|
||||
}
|
||||
|
||||
@@ -4,18 +4,20 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { first } from 'vs/base/common/async';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { first } from 'vs/base/common/async';
|
||||
import { toDisposable, IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export class URLService implements IURLService {
|
||||
export abstract class AbstractURLService extends Disposable implements IURLService {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
|
||||
private handlers = new Set<IURLHandler>();
|
||||
|
||||
abstract create(options?: Partial<UriComponents>): URI;
|
||||
|
||||
open(uri: URI): Promise<boolean> {
|
||||
const handlers = values(this.handlers);
|
||||
return first(handlers.map(h => () => h.handleURL(uri)), undefined, false).then(val => val || false);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
|
||||
@@ -39,6 +39,10 @@ export class URLServiceChannelClient implements IURLService {
|
||||
registerHandler(handler: IURLHandler): IDisposable {
|
||||
throw new Error('Not implemented.');
|
||||
}
|
||||
|
||||
create(_options?: Partial<UriComponents>): URI {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
export class URLHandlerChannel implements IServerChannel {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { AbstractURLService } from 'vs/platform/url/common/urlService';
|
||||
|
||||
export class URLService extends AbstractURLService {
|
||||
|
||||
create(options?: Partial<UriComponents>): URI {
|
||||
const { authority, path, query, fragment } = options ? options : { authority: undefined, path: undefined, query: undefined, fragment: undefined };
|
||||
|
||||
return URI.from({ scheme: product.urlProtocol, authority, path, query, fragment });
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -6882,6 +6882,13 @@ declare module 'vscode' {
|
||||
* Whether to show collapse all action or not.
|
||||
*/
|
||||
showCollapseAll?: boolean;
|
||||
|
||||
/**
|
||||
* Whether the tree supports multi-select. When the tree supports multi-select and a command is executed from the tree,
|
||||
* the first argument to the command is the tree item that the command was executed on and the second argument is an
|
||||
* array containing the other selected tree items.
|
||||
*/
|
||||
canSelectMany?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Vendored
+60
-13
@@ -881,6 +881,11 @@ declare module 'vscode' {
|
||||
/**
|
||||
* An event that when fired will signal that the pty is closed and dispose of the terminal.
|
||||
*
|
||||
* A number can be used to provide an exit code for the terminal. Exit codes must be
|
||||
* positive and a non-zero exit codes signals failure which shows a notification for a
|
||||
* regular terminal and allows dependent tasks to proceed when used with the
|
||||
* `CustomExecution2` API.
|
||||
*
|
||||
* **Example:** Exit the terminal when "y" is pressed, otherwise show a notification.
|
||||
* ```typescript
|
||||
* const writeEmitter = new vscode.EventEmitter<string>();
|
||||
@@ -899,7 +904,7 @@ declare module 'vscode' {
|
||||
* };
|
||||
* vscode.window.createTerminal({ name: 'Exit example', pty });
|
||||
*/
|
||||
onDidClose?: Event<void>;
|
||||
onDidClose?: Event<void | number>;
|
||||
|
||||
/**
|
||||
* Implement to handle when the pty is open and ready to start firing events.
|
||||
@@ -1030,15 +1035,6 @@ declare module 'vscode' {
|
||||
*/
|
||||
constructor(label: TreeItemLabel, collapsibleState?: TreeItemCollapsibleState);
|
||||
}
|
||||
|
||||
export interface TreeViewOptions2<T> extends TreeViewOptions<T> {
|
||||
/**
|
||||
* Whether the tree supports multi-select. When the tree supports multi-select and a command is executed from the tree,
|
||||
* the first argument to the command is the tree item that the command was executed on and the second argument is an
|
||||
* array containing the other selected tree items.
|
||||
*/
|
||||
canSelectMany?: boolean;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region CustomExecution
|
||||
@@ -1142,13 +1138,64 @@ declare module 'vscode' {
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Deprecated support
|
||||
//#region Joh - CompletionItemKindModifier, https://github.com/microsoft/vscode/issues/23927
|
||||
|
||||
export enum CompletionItemKindModifier {
|
||||
Deprecated = 1
|
||||
}
|
||||
|
||||
export interface CompletionItem {
|
||||
|
||||
/**
|
||||
* Indicates if this item is deprecated.
|
||||
*
|
||||
*/
|
||||
deprecated?: boolean;
|
||||
kind2?: CompletionItemKind | { base: CompletionItemKind, modifier: ReadonlyArray<CompletionItemKindModifier> };
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
// #region Ben - extension auth flow (desktop+web)
|
||||
|
||||
export interface AppUriOptions {
|
||||
payload?: {
|
||||
path?: string;
|
||||
query?: string;
|
||||
fragment?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace env {
|
||||
|
||||
/**
|
||||
* Creates a Uri that - if opened in a browser - will result in a
|
||||
* registered [UriHandler](#UriHandler) to fire. The handler's
|
||||
* Uri will be configured with the path, query and fragment of
|
||||
* [AppUriOptions](#AppUriOptions) if provided, otherwise it will be empty.
|
||||
*
|
||||
* Extensions should not make any assumptions about the resulting
|
||||
* Uri and should not alter it in anyway. Rather, extensions can e.g.
|
||||
* use this Uri in an authentication flow, by adding the Uri as
|
||||
* callback query argument to the server to authenticate to.
|
||||
*
|
||||
* Note: If the server decides to add additional query parameters to the Uri
|
||||
* (e.g. a token or secret), it will appear in the Uri that is passed
|
||||
* to the [UriHandler](#UriHandler).
|
||||
*
|
||||
* **Example** of an authentication flow:
|
||||
* ```typescript
|
||||
* vscode.window.registerUriHandler({
|
||||
* handleUri(uri: vscode.Uri): vscode.ProviderResult<void> {
|
||||
* if (uri.path === '/did-authenticate') {
|
||||
* console.log(uri.toString());
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* const callableUri = await vscode.env.createAppUri({ payload: { path: '/did-authenticate' } });
|
||||
* await vscode.env.openExternal(callableUri);
|
||||
* ```
|
||||
*/
|
||||
export function createAppUri(options?: AppUriOptions): Thenable<Uri>;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { fromArray } from 'vs/base/common/map';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
|
||||
@@ -330,7 +331,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
return {
|
||||
label: data.a,
|
||||
kind: data.b,
|
||||
kindModifier: data.n ? modes.CompletionItemKindModifier.Deprecated : undefined,
|
||||
kindModifier: data.n && fromArray(data.n),
|
||||
detail: data.c,
|
||||
documentation: data.d,
|
||||
sortText: data.e,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { ExtHostContext, IExtHostContext, MainContext, MainThreadUrlsShape, ExtHostUrlsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -68,6 +68,16 @@ export class MainThreadUrls implements MainThreadUrlsShape {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
async $createAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial<UriComponents> }): Promise<URI> {
|
||||
const payload: Partial<UriComponents> = options && options.payload ? options.payload : Object.create(null);
|
||||
|
||||
// we define the authority to be the extension ID to ensure
|
||||
// that the Uri gets routed back to the extension properly.
|
||||
payload.authority = extensionId.value;
|
||||
|
||||
return this.urlService.create(payload);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.handlers.forEach(({ disposable }) => disposable.dispose());
|
||||
this.handlers.clear();
|
||||
|
||||
@@ -73,14 +73,6 @@ export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
}
|
||||
|
||||
function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
|
||||
if (extension.enableProposedApi) {
|
||||
return fn;
|
||||
} else {
|
||||
return throwProposedApiError.bind(null, extension) as any as T;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method instantiates and returns the extension API surface
|
||||
*/
|
||||
@@ -208,7 +200,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
});
|
||||
});
|
||||
},
|
||||
registerDiffInformationCommand: proposedApiFunction(extension, (id: string, callback: (diff: vscode.LineChange[], ...args: any[]) => any, thisArg?: any): vscode.Disposable => {
|
||||
registerDiffInformationCommand: (id: string, callback: (diff: vscode.LineChange[], ...args: any[]) => any, thisArg?: any): vscode.Disposable => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostCommands.registerCommand(true, id, async (...args: any[]): Promise<any> => {
|
||||
const activeTextEditor = extHostEditors.getActiveTextEditor();
|
||||
if (!activeTextEditor) {
|
||||
@@ -219,7 +212,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const diff = await extHostEditors.getDiffInformation(activeTextEditor.id);
|
||||
callback.apply(thisArg, [diff, ...args]);
|
||||
});
|
||||
}),
|
||||
},
|
||||
executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
|
||||
return extHostCommands.executeCommand<T>(id, ...args);
|
||||
},
|
||||
@@ -236,6 +229,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
get appName() { return initData.environment.appName; },
|
||||
get appRoot() { return initData.environment.appRoot!.fsPath; },
|
||||
get uriScheme() { return initData.environment.appUriScheme; },
|
||||
createAppUri(options?) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostUrls.createAppUri(extension.identifier, options);
|
||||
},
|
||||
get logLevel() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return typeConverters.LogLevel.to(extHostLogService.getLevel());
|
||||
@@ -531,9 +528,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
|
||||
return extHostWebviews.registerWebviewPanelSerializer(viewType, serializer);
|
||||
},
|
||||
registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider) => {
|
||||
registerDecorationProvider(provider: vscode.DecorationProvider) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostDecorations.registerDecorationProvider(provider, extension.identifier);
|
||||
}),
|
||||
},
|
||||
registerUriHandler(handler: vscode.UriHandler) {
|
||||
return extHostUrls.registerUriHandler(extension.identifier, handler);
|
||||
},
|
||||
@@ -548,6 +546,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
// namespace: workspace
|
||||
const workspace: typeof vscode.workspace = {
|
||||
get rootPath() {
|
||||
console.warn(`[Deprecation Warning] 'workspace.rootPath' is deprecated and should no longer be used. Please use 'workspace.workspaceFolders' instead. (${extension.publisher}.${extension.name})`);
|
||||
return extHostWorkspace.getPath();
|
||||
},
|
||||
set rootPath(value) {
|
||||
@@ -668,24 +667,30 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
get fs() {
|
||||
return extHostFileSystem.fileSystem;
|
||||
},
|
||||
registerFileSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.FileSearchProvider) => {
|
||||
registerFileSearchProvider: (scheme: string, provider: vscode.FileSearchProvider) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostSearch.registerFileSearchProvider(scheme, provider);
|
||||
}),
|
||||
registerTextSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.TextSearchProvider) => {
|
||||
},
|
||||
registerTextSearchProvider: (scheme: string, provider: vscode.TextSearchProvider) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostSearch.registerTextSearchProvider(scheme, provider);
|
||||
}),
|
||||
registerRemoteAuthorityResolver: proposedApiFunction(extension, (authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver) => {
|
||||
},
|
||||
registerRemoteAuthorityResolver: (authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extensionService.registerRemoteAuthorityResolver(authorityPrefix, resolver);
|
||||
}),
|
||||
registerResourceLabelFormatter: proposedApiFunction(extension, (formatter: vscode.ResourceLabelFormatter) => {
|
||||
},
|
||||
registerResourceLabelFormatter: (formatter: vscode.ResourceLabelFormatter) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostLabelService.$registerResourceLabelFormatter(formatter);
|
||||
}),
|
||||
onDidRenameFile: proposedApiFunction(extension, (listener: (e: vscode.FileRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
|
||||
},
|
||||
onDidRenameFile: (listener: (e: vscode.FileRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostFileSystemEvent.onDidRenameFile(listener, thisArg, disposables);
|
||||
}),
|
||||
onWillRenameFile: proposedApiFunction(extension, (listener: (e: vscode.FileWillRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
|
||||
},
|
||||
onWillRenameFile: (listener: (e: vscode.FileWillRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostFileSystemEvent.getOnWillRenameFileEvent(extension)(listener, thisArg, disposables);
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// namespace: scm
|
||||
@@ -810,6 +815,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
CommentMode: extHostTypes.CommentMode,
|
||||
CompletionItem: extHostTypes.CompletionItem,
|
||||
CompletionItemKind: extHostTypes.CompletionItemKind,
|
||||
CompletionItemKindModifier: extHostTypes.CompletionItemKindModifier,
|
||||
CompletionList: extHostTypes.CompletionList,
|
||||
CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
|
||||
ConfigurationTarget: extHostTypes.ConfigurationTarget,
|
||||
|
||||
@@ -571,6 +571,7 @@ export interface ExtHostWebviewsShape {
|
||||
export interface MainThreadUrlsShape extends IDisposable {
|
||||
$registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise<void>;
|
||||
$unregisterUriHandler(handle: number): Promise<void>;
|
||||
$createAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial<UriComponents> }): Promise<UriComponents>;
|
||||
}
|
||||
|
||||
export interface ExtHostUrlsShape {
|
||||
@@ -939,7 +940,7 @@ export interface ISuggestDataDto {
|
||||
k/* commitCharacters */?: string[];
|
||||
l/* additionalTextEdits */?: ISingleEditOperation[];
|
||||
m/* command */?: modes.Command;
|
||||
n/* deprecated */?: boolean;
|
||||
n/* kindModifier */?: modes.CompletionItemKindModifier[];
|
||||
// not-standard
|
||||
x?: ChainedCacheId;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ class DocumentSymbolAdapter {
|
||||
const element = <modes.DocumentSymbol>{
|
||||
name: info.name || '!!MISSING: name!!',
|
||||
kind: typeConvert.SymbolKind.from(info.kind),
|
||||
kindTags: [],
|
||||
detail: undefined!, // Strict null override — avoid changing behavior
|
||||
containerName: info.containerName,
|
||||
range: typeConvert.Range.from(info.location.range),
|
||||
@@ -736,9 +737,14 @@ class SuggestAdapter {
|
||||
k: item.commitCharacters,
|
||||
l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
|
||||
m: this._commands.toInternal(item.command, disposables),
|
||||
n: item.deprecated
|
||||
};
|
||||
|
||||
// kind2
|
||||
if (typeof item.kind2 === 'object') {
|
||||
result.b = typeConvert.CompletionItemKind.from(item.kind2.base);
|
||||
result.n = item.kind2.modifier.map(typeConvert.CompletionItemKindModifier.from);
|
||||
}
|
||||
|
||||
// 'insertText'-logic
|
||||
if (item.textEdit) {
|
||||
result.h = item.textEdit.newText;
|
||||
|
||||
@@ -198,7 +198,7 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
private refreshPromise: Promise<void> = Promise.resolve();
|
||||
private refreshQueue: Promise<void> = Promise.resolve();
|
||||
|
||||
constructor(private viewId: string, options: vscode.TreeViewOptions2<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) {
|
||||
constructor(private viewId: string, options: vscode.TreeViewOptions<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) {
|
||||
super();
|
||||
this.dataProvider = options.treeDataProvider;
|
||||
// {{SQL CARBON EDIT}}
|
||||
|
||||
@@ -582,7 +582,8 @@ export namespace DocumentSymbol {
|
||||
detail: info.detail,
|
||||
range: Range.from(info.range),
|
||||
selectionRange: Range.from(info.selectionRange),
|
||||
kind: SymbolKind.from(info.kind)
|
||||
kind: SymbolKind.from(info.kind),
|
||||
kindTags: []
|
||||
};
|
||||
if (info.children) {
|
||||
result.children = info.children.map(from);
|
||||
@@ -681,6 +682,21 @@ export namespace CompletionContext {
|
||||
}
|
||||
}
|
||||
|
||||
export namespace CompletionItemKindModifier {
|
||||
|
||||
export function from(kind: types.CompletionItemKindModifier): modes.CompletionItemKindModifier {
|
||||
switch (kind) {
|
||||
case types.CompletionItemKindModifier.Deprecated: return modes.CompletionItemKindModifier.Deprecated;
|
||||
}
|
||||
}
|
||||
|
||||
export function to(kind: modes.CompletionItemKindModifier): types.CompletionItemKindModifier {
|
||||
switch (kind) {
|
||||
case modes.CompletionItemKindModifier.Deprecated: return types.CompletionItemKindModifier.Deprecated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace CompletionItemKind {
|
||||
|
||||
export function from(kind: types.CompletionItemKind | undefined): modes.CompletionItemKind {
|
||||
|
||||
@@ -1308,11 +1308,16 @@ export enum CompletionItemKind {
|
||||
TypeParameter = 24
|
||||
}
|
||||
|
||||
export enum CompletionItemKindModifier {
|
||||
Deprecated = 1,
|
||||
}
|
||||
|
||||
@es5ClassCompat
|
||||
export class CompletionItem implements vscode.CompletionItem {
|
||||
|
||||
label: string;
|
||||
kind?: CompletionItemKind;
|
||||
kind2?: CompletionItemKind | { base: CompletionItemKind, modifier: CompletionItemKindModifier[] };
|
||||
detail?: string;
|
||||
documentation?: string | MarkdownString;
|
||||
sortText?: string;
|
||||
|
||||
@@ -55,4 +55,8 @@ export class ExtHostUrls implements ExtHostUrlsShape {
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
async createAppUri(extensionId: ExtensionIdentifier, options?: vscode.AppUriOptions): Promise<vscode.Uri> {
|
||||
return URI.revive(await this._proxy.$createAppUri(extensionId, options));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -738,7 +738,7 @@ class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
// Attach the listeners
|
||||
this._pty.onDidWrite(e => this._onProcessData.fire(e));
|
||||
if (this._pty.onDidClose) {
|
||||
this._pty.onDidClose(e => this._onProcessExit.fire(0));
|
||||
this._pty.onDidClose(e => this._onProcessExit.fire(e || 0));
|
||||
}
|
||||
if (this._pty.onDidOverrideDimensions) {
|
||||
this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBON EDIT}} strict-null-checks
|
||||
|
||||
@@ -617,10 +617,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
// To properly reset line numbers we need to read the configuration for each editor respecting it's uri.
|
||||
if (!lineNumbers && isCodeEditor(editor) && editor.hasModel()) {
|
||||
const model = editor.getModel();
|
||||
this.configurationService.getValue('editor.lineNumbers', { resource: model.uri });
|
||||
} else {
|
||||
editor.updateOptions({ lineNumbers });
|
||||
lineNumbers = this.configurationService.getValue('editor.lineNumbers', { resource: model.uri });
|
||||
}
|
||||
if (!lineNumbers) {
|
||||
lineNumbers = this.configurationService.getValue('editor.lineNumbers');
|
||||
}
|
||||
|
||||
editor.updateOptions({ lineNumbers });
|
||||
});
|
||||
|
||||
// Check if zen mode transitioned to full screen and if now we are out of zen mode
|
||||
@@ -1292,4 +1295,3 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
this.disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -999,7 +999,7 @@ export class ChangeModeAction extends Action {
|
||||
private configureFileAssociation(resource: URI): void {
|
||||
const extension = extname(resource);
|
||||
const base = basename(resource);
|
||||
const currentAssociation = this.modeService.getModeIdByFilepathOrFirstLine(resource.with({ path: base }));
|
||||
const currentAssociation = this.modeService.getModeIdByFilepathOrFirstLine(URI.file(base));
|
||||
|
||||
const languages = this.modeService.getRegisteredLanguageNames();
|
||||
const picks: IQuickPickItem[] = languages.sort().map((lang, index) => {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { mark } from 'vs/base/common/performance';
|
||||
import { domContentLoaded, addDisposableListener, EventType, addClass } from 'vs/base/browser/dom';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ILogService, ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
||||
import { Workbench } from 'vs/workbench/browser/workbench';
|
||||
@@ -44,7 +44,8 @@ import { StaticExtensionsService, IStaticExtensionsService } from 'vs/workbench/
|
||||
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
|
||||
import { FileLogService } from 'vs/platform/log/common/fileLogService';
|
||||
import { toLocalISOString } from 'vs/base/common/date';
|
||||
import { INDEXEDDB_LOG_SCHEME, IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedDBLogProvider';
|
||||
import { IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedDBLogProvider';
|
||||
import { InMemoryLogProvider } from 'vs/workbench/services/log/common/inMemoryLogProvider';
|
||||
|
||||
class CodeRendererMain extends Disposable {
|
||||
|
||||
@@ -120,7 +121,7 @@ class CodeRendererMain extends Disposable {
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
// Log
|
||||
const logsPath = URI.file(toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')).with({ scheme: INDEXEDDB_LOG_SCHEME });
|
||||
const logsPath = URI.file(toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')).with({ scheme: 'vscode-log' });
|
||||
const logService = new BufferLogService();
|
||||
serviceCollection.set(ILogService, logService);
|
||||
|
||||
@@ -151,8 +152,19 @@ class CodeRendererMain extends Disposable {
|
||||
serviceCollection.set(IFileService, fileService);
|
||||
|
||||
// Logger
|
||||
fileService.registerProvider(INDEXEDDB_LOG_SCHEME, new IndexedDBLogProvider());
|
||||
logService.logger = new FileLogService('window', environmentService.logFile, logService.getLevel(), fileService);
|
||||
const indexedDBLogProvider = new IndexedDBLogProvider(logsPath.scheme);
|
||||
indexedDBLogProvider.database.then(
|
||||
() => fileService.registerProvider(logsPath.scheme, indexedDBLogProvider),
|
||||
e => {
|
||||
(<ILogService>logService).info('Error while creating indexedDB log provider. Falling back to in-memory log provider.');
|
||||
(<ILogService>logService).error(e);
|
||||
fileService.registerProvider(logsPath.scheme, new InMemoryLogProvider(logsPath.scheme));
|
||||
}
|
||||
).then(() => {
|
||||
const consoleLogService = new ConsoleLogService(logService.getLevel());
|
||||
const fileLogService = new FileLogService('window', environmentService.logFile, logService.getLevel(), fileService);
|
||||
logService.logger = new MultiplexLogService([consoleLogService, fileLogService]);
|
||||
});
|
||||
|
||||
// Static Extensions
|
||||
const staticExtensions = new StaticExtensionsService(this.configuration.staticExtensions || []);
|
||||
|
||||
@@ -7,11 +7,8 @@ import { URI } from 'vs/base/common/uri';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IUpdateService, State } from 'vs/platform/update/common/update';
|
||||
import { IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IURIToOpen, IMessageBoxResult, IWindowsService, IOpenSettings, IWindowSettings } from 'vs/platform/windows/common/windows';
|
||||
@@ -20,7 +17,6 @@ import { IRecentlyOpened, IRecent, isRecentFile, isRecentFolder } from 'vs/platf
|
||||
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
|
||||
// tslint:disable-next-line: import-patterns
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { addDisposableListener, EventType, windowOpenNoOpener } from 'vs/base/browser/dom';
|
||||
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -38,29 +34,6 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
|
||||
// tslint:disable-next-line: import-patterns
|
||||
import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats';
|
||||
|
||||
//#region Extension URL Handler
|
||||
|
||||
export const IExtensionUrlHandler = createDecorator<IExtensionUrlHandler>('inactiveExtensionUrlHandler');
|
||||
|
||||
export interface IExtensionUrlHandler {
|
||||
readonly _serviceBrand: any;
|
||||
registerExtensionHandler(extensionId: ExtensionIdentifier, handler: IURLHandler): void;
|
||||
unregisterExtensionHandler(extensionId: ExtensionIdentifier): void;
|
||||
}
|
||||
|
||||
export class SimpleExtensionURLHandler implements IExtensionUrlHandler {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
registerExtensionHandler(extensionId: ExtensionIdentifier, handler: IURLHandler): void { }
|
||||
|
||||
unregisterExtensionHandler(extensionId: ExtensionIdentifier): void { }
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionUrlHandler, SimpleExtensionURLHandler, true);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Update
|
||||
|
||||
export class SimpleUpdateService implements IUpdateService {
|
||||
@@ -95,24 +68,6 @@ registerSingleton(IUpdateService, SimpleUpdateService);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region URL
|
||||
|
||||
export class SimpleURLService implements IURLService {
|
||||
_serviceBrand: any;
|
||||
|
||||
open(url: URI): Promise<boolean> {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
registerHandler(handler: IURLHandler): IDisposable {
|
||||
return Disposable.None;
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IURLService, SimpleURLService);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Window
|
||||
|
||||
export class SimpleWindowService extends Disposable implements IWindowService {
|
||||
|
||||
@@ -590,7 +590,12 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
|
||||
constructor(private debugService: IDebugService) { }
|
||||
|
||||
hasChildren(element: IDebugModel | CallStackItem): boolean {
|
||||
return isDebugModel(element) || isDebugSession(element) || (element instanceof Thread && element.stopped);
|
||||
if (isDebugSession(element)) {
|
||||
const threads = element.getAllThreads();
|
||||
return (threads.length > 1) || (threads.length === 1 && threads[0].stopped) || (this.debugService.getModel().getSessions().filter(s => s.parentSession === element).length > 0);
|
||||
}
|
||||
|
||||
return isDebugModel(element) || (element instanceof Thread && element.stopped);
|
||||
}
|
||||
|
||||
async getChildren(element: IDebugModel | CallStackItem): Promise<CallStackItem[]> {
|
||||
|
||||
@@ -236,16 +236,18 @@ export class Debugger implements IDebugger {
|
||||
};
|
||||
properties['preLaunchTask'] = {
|
||||
anyOf: [taskSchema, {
|
||||
type: ['string', 'null'],
|
||||
type: ['string']
|
||||
}],
|
||||
default: '',
|
||||
defaultSnippets: [{ body: { task: '', type: '' } }],
|
||||
description: nls.localize('debugPrelaunchTask', "Task to run before debug session starts.")
|
||||
};
|
||||
properties['postDebugTask'] = {
|
||||
anyOf: [taskSchema, {
|
||||
type: ['string', 'null'],
|
||||
type: ['string'],
|
||||
}],
|
||||
default: '',
|
||||
defaultSnippets: [{ body: { task: '', type: '' } }],
|
||||
description: nls.localize('debugPostDebugTask', "Task to run after debug session ends.")
|
||||
};
|
||||
properties['internalConsoleOptions'] = INTERNAL_CONSOLE_OPTIONS_SCHEMA;
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import { IExtensionEnablementService } from 'vs/workbench/services/extensionMana
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
|
||||
@@ -31,7 +31,7 @@ import { TestContextService, TestWindowService, TestSharedProcessService } from
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { INotificationService, Severity, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||
import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
|
||||
@@ -31,7 +31,7 @@ import { TestContextService, TestWindowService, TestSharedProcessService } from
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { SinonStub } from 'sinon';
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { ProgressService } from 'vs/workbench/services/progress/browser/progressService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
@@ -22,7 +22,7 @@ export class LogsDataCleaner extends Disposable {
|
||||
}
|
||||
|
||||
private cleanUpOldLogsSoon(): void {
|
||||
let handle: NodeJS.Timeout | undefined = setTimeout(async () => {
|
||||
let handle: any = setTimeout(async () => {
|
||||
handle = undefined;
|
||||
const logsPath = URI.file(this.environmentService.logsPath).with({ scheme: this.environmentService.logFile.scheme });
|
||||
const stat = await this.fileService.resolve(dirname(logsPath));
|
||||
|
||||
@@ -369,6 +369,10 @@
|
||||
margin-top: -1px;
|
||||
z-index: 1;
|
||||
}
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-item-contents.invalid-input .setting-item-validation-message {
|
||||
position: static;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-text .setting-item-validation-message {
|
||||
width: 500px;
|
||||
|
||||
@@ -224,8 +224,9 @@ interface ISettingComplexItemTemplate extends ISettingItemTemplate<void> {
|
||||
button: Button;
|
||||
}
|
||||
|
||||
interface ISettingListItemTemplate extends ISettingItemTemplate<void> {
|
||||
interface ISettingListItemTemplate extends ISettingItemTemplate<string[] | undefined> {
|
||||
listWidget: ListSettingWidget;
|
||||
validationErrorMessageElement: HTMLElement;
|
||||
}
|
||||
|
||||
interface ISettingExcludeItemTemplate extends ISettingItemTemplate<void> {
|
||||
@@ -679,6 +680,9 @@ export class SettingArrayRenderer extends AbstractSettingRenderer implements ITr
|
||||
|
||||
renderTemplate(container: HTMLElement): ISettingListItemTemplate {
|
||||
const common = this.renderCommonTemplate(null, container, 'list');
|
||||
const descriptionElement = common.containerElement.querySelector('.setting-item-description')!;
|
||||
const validationErrorMessageElement = $('.setting-item-validation-message');
|
||||
descriptionElement.after(validationErrorMessageElement);
|
||||
|
||||
const listWidget = this._instantiationService.createInstance(ListSettingWidget, common.controlElement);
|
||||
listWidget.domNode.classList.add(AbstractSettingRenderer.CONTROL_CLASS);
|
||||
@@ -686,19 +690,40 @@ export class SettingArrayRenderer extends AbstractSettingRenderer implements ITr
|
||||
|
||||
const template: ISettingListItemTemplate = {
|
||||
...common,
|
||||
listWidget
|
||||
listWidget,
|
||||
validationErrorMessageElement
|
||||
};
|
||||
|
||||
this.addSettingElementFocusHandler(template);
|
||||
|
||||
common.toDispose.push(listWidget.onDidChangeList(e => this.onDidChangeList(template, e)));
|
||||
common.toDispose.push(
|
||||
listWidget.onDidChangeList(e => {
|
||||
const newList = this.computeNewList(template, e);
|
||||
this.onDidChangeList(template, newList);
|
||||
if (newList !== null && template.onChange) {
|
||||
template.onChange(newList);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
private onDidChangeList(template: ISettingListItemTemplate, e: IListChangeEvent): void {
|
||||
private onDidChangeList(template: ISettingListItemTemplate, newList: string[] | undefined | null): void {
|
||||
if (!template.context || newList === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._onDidChangeSetting.fire({
|
||||
key: template.context.setting.key,
|
||||
value: newList,
|
||||
type: template.context.valueType
|
||||
});
|
||||
}
|
||||
|
||||
private computeNewList(template: ISettingListItemTemplate, e: IListChangeEvent): string[] | undefined | null {
|
||||
if (template.context) {
|
||||
let newValue: any[] = [];
|
||||
let newValue: string[] = [];
|
||||
if (isArray(template.context.scopeValue)) {
|
||||
newValue = [...template.context.scopeValue];
|
||||
} else if (isArray(template.context.value)) {
|
||||
@@ -732,29 +757,30 @@ export class SettingArrayRenderer extends AbstractSettingRenderer implements ITr
|
||||
template.context.defaultValue.length === newValue.length &&
|
||||
template.context.defaultValue.join() === newValue.join()
|
||||
) {
|
||||
return this._onDidChangeSetting.fire({
|
||||
key: template.context.setting.key,
|
||||
value: undefined, // reset setting
|
||||
type: template.context.valueType
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this._onDidChangeSetting.fire({
|
||||
key: template.context.setting.key,
|
||||
value: newValue,
|
||||
type: template.context.valueType
|
||||
});
|
||||
return newValue;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<SettingsTreeSettingElement, never>, index: number, templateData: ISettingListItemTemplate): void {
|
||||
super.renderSettingElement(element, index, templateData);
|
||||
}
|
||||
|
||||
protected renderValue(dataElement: SettingsTreeSettingElement, template: ISettingListItemTemplate, onChange: (value: string) => void): void {
|
||||
protected renderValue(dataElement: SettingsTreeSettingElement, template: ISettingListItemTemplate, onChange: (value: string[] | undefined) => void): void {
|
||||
const value = getListDisplayValue(dataElement);
|
||||
template.listWidget.setValue(value);
|
||||
template.context = dataElement;
|
||||
|
||||
template.onChange = (v) => {
|
||||
onChange(v);
|
||||
renderArrayValidations(dataElement, template, v, false);
|
||||
};
|
||||
|
||||
renderArrayValidations(dataElement, template, value.map(v => v.value), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1237,6 +1263,29 @@ function renderValidations(dataElement: SettingsTreeSettingElement, template: IS
|
||||
DOM.removeClass(template.containerElement, 'invalid-input');
|
||||
}
|
||||
|
||||
function renderArrayValidations(
|
||||
dataElement: SettingsTreeSettingElement,
|
||||
template: ISettingListItemTemplate,
|
||||
value: string[] | undefined,
|
||||
calledOnStartup: boolean
|
||||
) {
|
||||
DOM.addClass(template.containerElement, 'invalid-input');
|
||||
if (dataElement.setting.validator) {
|
||||
const errMsg = dataElement.setting.validator(value);
|
||||
if (errMsg && errMsg !== '') {
|
||||
DOM.addClass(template.containerElement, 'invalid-input');
|
||||
template.validationErrorMessageElement.innerText = errMsg;
|
||||
const validationError = localize('validationError', "Validation Error.");
|
||||
template.containerElement.setAttribute('aria-label', [dataElement.setting.key, validationError, errMsg].join(' '));
|
||||
if (!calledOnStartup) { ariaAlert(validationError + ' ' + errMsg); }
|
||||
return;
|
||||
} else {
|
||||
template.containerElement.setAttribute('aria-label', dataElement.setting.key);
|
||||
DOM.removeClass(template.containerElement, 'invalid-input');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cleanRenderedMarkdown(element: Node): void {
|
||||
for (let i = 0; i < element.childNodes.length; i++) {
|
||||
const child = element.childNodes.item(i);
|
||||
|
||||
@@ -30,7 +30,7 @@ import { ipcRenderer as ipc } from 'electron';
|
||||
import { IDiagnosticInfoOptions, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IProgressService, IProgress, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import { PersistentConnectionEventType, ReconnectionWaitEvent } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
@@ -315,7 +315,58 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
||||
if (connection) {
|
||||
let currentProgressPromiseResolve: (() => void) | null = null;
|
||||
let progressReporter: ProgressReporter | null = null;
|
||||
let lastLocation: ProgressLocation | null = null;
|
||||
let currentTimer: ReconnectionTimer | null = null;
|
||||
let reconnectWaitEvent: ReconnectionWaitEvent | null = null;
|
||||
|
||||
function showProgress(location: ProgressLocation, buttons?: string[]) {
|
||||
if (currentProgressPromiseResolve) {
|
||||
currentProgressPromiseResolve();
|
||||
}
|
||||
|
||||
const promise = new Promise<void>((resolve) => currentProgressPromiseResolve = resolve);
|
||||
lastLocation = location;
|
||||
|
||||
if (location === ProgressLocation.Dialog) {
|
||||
// Show dialog
|
||||
progressService!.withProgress(
|
||||
{ location: ProgressLocation.Dialog, buttons },
|
||||
(progress) => { progressReporter = new ProgressReporter(progress); return promise; },
|
||||
(choice?) => {
|
||||
// Handle choice from dialog
|
||||
if (choice === 0 && buttons && reconnectWaitEvent) {
|
||||
reconnectWaitEvent.skipWait();
|
||||
} else {
|
||||
showProgress(ProgressLocation.Notification, buttons);
|
||||
}
|
||||
|
||||
progressReporter!.report();
|
||||
});
|
||||
} else {
|
||||
// Show notification
|
||||
progressService!.withProgress(
|
||||
{ location: ProgressLocation.Notification, buttons },
|
||||
(progress) => { if (progressReporter) { progressReporter.currentProgress = progress; } return promise; },
|
||||
(choice?) => {
|
||||
// Handle choice from notification
|
||||
if (choice === 0 && buttons && reconnectWaitEvent) {
|
||||
reconnectWaitEvent.skipWait();
|
||||
progressReporter!.report();
|
||||
} else {
|
||||
hideProgress();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hideProgress() {
|
||||
if (currentProgressPromiseResolve) {
|
||||
currentProgressPromiseResolve();
|
||||
}
|
||||
|
||||
currentProgressPromiseResolve = null;
|
||||
progressReporter = null;
|
||||
}
|
||||
|
||||
connection.onDidStateChange((e) => {
|
||||
if (currentTimer) {
|
||||
@@ -325,31 +376,24 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
||||
switch (e.type) {
|
||||
case PersistentConnectionEventType.ConnectionLost:
|
||||
if (!currentProgressPromiseResolve) {
|
||||
let promise = new Promise<void>((resolve) => currentProgressPromiseResolve = resolve);
|
||||
progressService!.withProgress(
|
||||
{ location: ProgressLocation.Dialog },
|
||||
(progress: IProgress<IProgressStep> | null) => { progressReporter = new ProgressReporter(progress!); return promise; },
|
||||
() => {
|
||||
currentProgressPromiseResolve!();
|
||||
promise = new Promise<void>((resolve) => currentProgressPromiseResolve = resolve);
|
||||
progressService!.withProgress({ location: ProgressLocation.Notification }, (progress) => { if (progressReporter) { progressReporter.currentProgress = progress; } return promise; });
|
||||
progressReporter!.report();
|
||||
}
|
||||
);
|
||||
showProgress(ProgressLocation.Dialog, [nls.localize('reconnectNow', "Reconnect Now")]);
|
||||
}
|
||||
|
||||
progressReporter!.report(nls.localize('connectionLost', "Connection Lost"));
|
||||
break;
|
||||
case PersistentConnectionEventType.ReconnectionWait:
|
||||
hideProgress();
|
||||
reconnectWaitEvent = e;
|
||||
showProgress(lastLocation || ProgressLocation.Notification, [nls.localize('reconnectNow', "Reconnect Now")]);
|
||||
currentTimer = new ReconnectionTimer(progressReporter!, Date.now() + 1000 * e.durationSeconds);
|
||||
break;
|
||||
case PersistentConnectionEventType.ReconnectionRunning:
|
||||
hideProgress();
|
||||
showProgress(lastLocation || ProgressLocation.Notification);
|
||||
progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect..."));
|
||||
break;
|
||||
case PersistentConnectionEventType.ReconnectionPermanentFailure:
|
||||
currentProgressPromiseResolve!();
|
||||
currentProgressPromiseResolve = null;
|
||||
progressReporter = null;
|
||||
hideProgress();
|
||||
|
||||
dialogService.show(Severity.Error, nls.localize('reconnectionPermanentFailure', "Cannot reconnect. Please reload the window."), [nls.localize('reloadWindow', "Reload Window"), nls.localize('cancel', "Cancel")], { cancelId: 1 }).then(choice => {
|
||||
// Reload the window
|
||||
@@ -359,9 +403,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
||||
});
|
||||
break;
|
||||
case PersistentConnectionEventType.ConnectionGain:
|
||||
currentProgressPromiseResolve!();
|
||||
currentProgressPromiseResolve = null;
|
||||
progressReporter = null;
|
||||
hideProgress();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -147,7 +147,9 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
||||
@ISharedProcessService private readonly sharedProcessService: ISharedProcessService,
|
||||
@IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService
|
||||
) {
|
||||
this.report();
|
||||
if (this.telemetryService.isOptedIn) {
|
||||
this.report();
|
||||
}
|
||||
}
|
||||
|
||||
private report(): void {
|
||||
|
||||
@@ -44,6 +44,7 @@ import { Schemas } from 'vs/base/common/network';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { env as processEnv, cwd as processCwd } from 'vs/base/common/process';
|
||||
|
||||
interface TerminalData {
|
||||
terminal: ITerminalInstance;
|
||||
@@ -339,7 +340,9 @@ export class TerminalTaskSystem implements ITaskSystem {
|
||||
private async executeTask(task: Task, resolver: ITaskResolver, trigger: string): Promise<ITaskSummary> {
|
||||
let promises: Promise<ITaskSummary>[] = [];
|
||||
if (task.configurationProperties.dependsOn) {
|
||||
for (const dependency of task.configurationProperties.dependsOn) { //{{SQL CARBON EDIT}} change to for of for linting
|
||||
// tslint:disable-next-line: no-for-in-array
|
||||
for (let index in task.configurationProperties.dependsOn) {
|
||||
const dependency = task.configurationProperties.dependsOn[index];
|
||||
let dependencyTask = resolver.resolve(dependency.workspaceFolder, dependency.task!);
|
||||
if (dependencyTask) {
|
||||
let key = dependencyTask.getMapKey();
|
||||
@@ -1374,7 +1377,7 @@ export class TerminalTaskSystem implements ITaskSystem {
|
||||
return command;
|
||||
}
|
||||
if (cwd === undefined) {
|
||||
cwd = process.cwd();
|
||||
cwd = processCwd();
|
||||
}
|
||||
const dir = path.dirname(command);
|
||||
if (dir !== '.') {
|
||||
@@ -1382,8 +1385,8 @@ export class TerminalTaskSystem implements ITaskSystem {
|
||||
// to the current working directory.
|
||||
return path.join(cwd, command);
|
||||
}
|
||||
if (paths === undefined && Types.isString(process.env.PATH)) {
|
||||
paths = process.env.PATH.split(path.delimiter);
|
||||
if (paths === undefined && Types.isString(processEnv.PATH)) {
|
||||
paths = processEnv.PATH.split(path.delimiter);
|
||||
}
|
||||
// No PATH environment. Make path absolute to the cwd.
|
||||
if (paths === undefined || paths.length === 0) {
|
||||
|
||||
@@ -985,14 +985,15 @@ export namespace KeyedTaskIdentifier {
|
||||
function sortedStringify(literal: any): string {
|
||||
const keys = Object.keys(literal).sort();
|
||||
let result: string = '';
|
||||
for (const position of keys) { // {{SQL CARBON EDIT}} change to of for linting
|
||||
let stringified = literal[position];
|
||||
// tslint:disable-next-line: no-for-in-array
|
||||
for (let position in keys) {
|
||||
let stringified = literal[keys[position]];
|
||||
if (stringified instanceof Object) {
|
||||
stringified = sortedStringify(stringified);
|
||||
} else if (typeof stringified === 'string') {
|
||||
stringified = stringified.replace(/,/g, ',,');
|
||||
}
|
||||
result += position + ',' + stringified + ',';
|
||||
result += keys[position] + ',' + stringified + ',';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -72,17 +72,17 @@ configurationRegistry.registerConfiguration({
|
||||
type: 'object',
|
||||
properties: {
|
||||
'terminal.integrated.automationShell.linux': {
|
||||
markdownDescription: nls.localize('terminal.integrated.automationShell.linux', "A path that when set will override {0} and ignore {1} and {2} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.linux`', '`shellArgs`', '`env`'),
|
||||
markdownDescription: nls.localize('terminal.integrated.automationShell.linux', "A path that when set will override {0} and ignore {1} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.linux`', '`shellArgs`'),
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
},
|
||||
'terminal.integrated.automationShell.osx': {
|
||||
markdownDescription: nls.localize('terminal.integrated.automationShell.osx', "A path that when set will override {0} and ignore {1} and {2} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.osx`', '`shellArgs`', '`env`'),
|
||||
markdownDescription: nls.localize('terminal.integrated.automationShell.osx', "A path that when set will override {0} and ignore {1} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.osx`', '`shellArgs`'),
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
},
|
||||
'terminal.integrated.automationShell.windows': {
|
||||
markdownDescription: nls.localize('terminal.integrated.automationShell.windows', "A path that when set will override {0} and ignore {1} and {2} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.windows`', '`shellArgs`', '`env`'),
|
||||
markdownDescription: nls.localize('terminal.integrated.automationShell.windows', "A path that when set will override {0} and ignore {1} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.windows`', '`shellArgs`'),
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
},
|
||||
@@ -530,6 +530,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNe
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find next', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, {
|
||||
primary: KeyCode.F3,
|
||||
secondary: [KeyMod.Shift | KeyCode.Enter],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3, KeyMod.Shift | KeyCode.Enter] }
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find next');
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID_TERMINAL_FOCUS, FindPrevious.LABEL, {
|
||||
@@ -538,6 +539,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, Fi
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find previous', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, {
|
||||
primary: KeyMod.Shift | KeyCode.F3,
|
||||
secondary: [KeyCode.Enter],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3, KeyCode.Enter] },
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find previous');
|
||||
|
||||
|
||||
@@ -500,7 +500,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
// Force line data to be sent when the cursor is moved, the main purpose for
|
||||
// this is because ConPTY will often not do a line feed but instead move the
|
||||
// cursor, in which case we still want to send the current line's data to tasks.
|
||||
xterm.addCsiHandler('H', () => {
|
||||
xterm.parser.addCsiHandler({ final: 'H' }, () => {
|
||||
this._onCursorMove();
|
||||
return false;
|
||||
});
|
||||
@@ -865,7 +865,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
return;
|
||||
}
|
||||
this.focus();
|
||||
this._xterm._core._coreService.triggerDataEvent(await this._clipboardService.readText(), true);
|
||||
this._xterm.paste(await this._clipboardService.readText());
|
||||
}
|
||||
|
||||
public write(text: string): void {
|
||||
|
||||
@@ -248,6 +248,7 @@ export interface ITerminalService {
|
||||
/**
|
||||
* Creates a raw terminal instance, this should not be used outside of the terminal part.
|
||||
*/
|
||||
// tslint:disable-next-line: no-dom-globals
|
||||
createInstance(container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance;
|
||||
getInstanceFromId(terminalId: number): ITerminalInstance | undefined;
|
||||
getInstanceFromIndex(terminalIndex: number): ITerminalInstance;
|
||||
@@ -279,6 +280,7 @@ export interface ITerminalService {
|
||||
|
||||
selectDefaultWindowsShell(): Promise<void>;
|
||||
|
||||
// tslint:disable-next-line: no-dom-globals
|
||||
setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
|
||||
manageWorkspaceShellPermissions(): void;
|
||||
|
||||
@@ -337,6 +339,7 @@ export interface ITerminalTab {
|
||||
focusNextPane(): void;
|
||||
resizePane(direction: Direction): void;
|
||||
setActiveInstanceByIndex(index: number): void;
|
||||
// tslint:disable-next-line: no-dom-globals
|
||||
attachToElement(element: HTMLElement): void;
|
||||
setVisible(visible: boolean): void;
|
||||
layout(width: number, height: number): void;
|
||||
@@ -611,6 +614,7 @@ export interface ITerminalInstance {
|
||||
*
|
||||
* @param container The element to attach the terminal instance to.
|
||||
*/
|
||||
// tslint:disable-next-line: no-dom-globals
|
||||
attachToElement(container: HTMLElement): void;
|
||||
|
||||
/**
|
||||
|
||||
@@ -122,7 +122,9 @@ export abstract class TerminalService implements ITerminalService {
|
||||
protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void;
|
||||
|
||||
public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
|
||||
// tslint:disable-next-line: no-dom-globals
|
||||
public abstract createInstance(container: HTMLElement, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance;
|
||||
// tslint:disable-next-line: no-dom-globals
|
||||
public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
|
||||
|
||||
public getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance {
|
||||
|
||||
@@ -50,14 +50,17 @@ Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions).registe
|
||||
localize('developer', 'Developer')
|
||||
);
|
||||
|
||||
const VSCODE_DOMAIN = 'https://code.visualstudio.com';
|
||||
const DEAFULT_TRUSTED_DOMAINS = [
|
||||
'https://code.visualstudio.com',
|
||||
'https://go.microsoft.com'
|
||||
];
|
||||
|
||||
const configureTrustedDomainsHandler = async (
|
||||
quickInputService: IQuickInputService,
|
||||
storageService: IStorageService,
|
||||
domainToConfigure?: string
|
||||
) => {
|
||||
let trustedDomains: string[] = [VSCODE_DOMAIN];
|
||||
let trustedDomains: string[] = DEAFULT_TRUSTED_DOMAINS;
|
||||
|
||||
try {
|
||||
const trustedDomainsSrc = storageService.get('http.trustedDomains', StorageScope.GLOBAL);
|
||||
@@ -158,7 +161,7 @@ class OpenerValidatorContributions implements IWorkbenchContribution {
|
||||
return true;
|
||||
}
|
||||
|
||||
let trustedDomains: string[] = [VSCODE_DOMAIN];
|
||||
let trustedDomains: string[] = DEAFULT_TRUSTED_DOMAINS;
|
||||
try {
|
||||
const trustedDomainsSrc = this._storageService.get('http.trustedDomains', StorageScope.GLOBAL);
|
||||
if (trustedDomainsSrc) {
|
||||
|
||||
@@ -283,17 +283,30 @@ export class EditorService extends Disposable implements EditorServiceImpl {
|
||||
}
|
||||
|
||||
// Respect option to reveal an editor if it is open (not necessarily visible)
|
||||
// Still prefer to reveal an editor in a group where the editor is active though.
|
||||
if (!targetGroup) {
|
||||
if ((options && options.revealIfOpened) || this.configurationService.getValue<boolean>('workbench.editor.revealIfOpen')) {
|
||||
let groupWithInputActive: IEditorGroup | undefined = undefined;
|
||||
let groupWithInputOpened: IEditorGroup | undefined = undefined;
|
||||
|
||||
for (const group of groupsByLastActive) {
|
||||
if (group.isOpened(input) && group.isActive(input)) {
|
||||
targetGroup = group;
|
||||
break;
|
||||
if (group.isOpened(input)) {
|
||||
if (!groupWithInputOpened) {
|
||||
groupWithInputOpened = group;
|
||||
}
|
||||
|
||||
if (!groupWithInputActive && group.isActive(input)) {
|
||||
groupWithInputActive = group;
|
||||
}
|
||||
}
|
||||
if (group.isOpened(input) && !targetGroup) {
|
||||
targetGroup = group;
|
||||
|
||||
if (groupWithInputOpened && groupWithInputActive) {
|
||||
break; // we found all groups we wanted
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer a target group where the input is visible
|
||||
targetGroup = groupWithInputActive || groupWithInputOpened;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
// tslint:disable-next-line: import-patterns
|
||||
import { commandsExtensionPoint } from 'vs/workbench/api/common/menusExtensionPoint';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
|
||||
@@ -5,23 +5,21 @@
|
||||
|
||||
import { KeyValueLogProvider } from 'vs/workbench/services/log/common/keyValueLogProvider';
|
||||
|
||||
export const INDEXEDDB_LOG_SCHEME = 'vscode-logs-indexedbd';
|
||||
export const INDEXEDDB_LOGS_DB = 'vscode-logs-db';
|
||||
export const INDEXEDDB_VSCODE_DB = 'vscode-web-db';
|
||||
export const INDEXEDDB_LOGS_OBJECT_STORE = 'vscode-logs-store';
|
||||
|
||||
export class IndexedDBLogProvider extends KeyValueLogProvider {
|
||||
|
||||
private readonly database: Promise<IDBDatabase>;
|
||||
readonly database: Promise<IDBDatabase>;
|
||||
|
||||
constructor(
|
||||
) {
|
||||
super(INDEXEDDB_LOG_SCHEME);
|
||||
constructor(scheme: string) {
|
||||
super(scheme);
|
||||
this.database = this.openDatabase(1);
|
||||
}
|
||||
|
||||
private openDatabase(version: number): Promise<IDBDatabase> {
|
||||
return new Promise((c, e) => {
|
||||
const request = window.indexedDB.open(INDEXEDDB_LOGS_DB, version);
|
||||
const request = window.indexedDB.open(INDEXEDDB_VSCODE_DB, version);
|
||||
request.onerror = (err) => e(request.error);
|
||||
request.onsuccess = () => {
|
||||
const db = request.result;
|
||||
|
||||
@@ -6,17 +6,10 @@
|
||||
import { KeyValueLogProvider } from 'vs/workbench/services/log/common/keyValueLogProvider';
|
||||
import { keys } from 'vs/base/common/map';
|
||||
|
||||
export const INMEMORY_LOG_SCHEME = 'vscode-logs-inmemory';
|
||||
|
||||
export class InMemoryLogProvider extends KeyValueLogProvider {
|
||||
|
||||
private readonly logs: Map<string, string> = new Map<string, string>();
|
||||
|
||||
constructor(
|
||||
) {
|
||||
super(INMEMORY_LOG_SCHEME);
|
||||
}
|
||||
|
||||
protected async getAllKeys(): Promise<string[]> {
|
||||
return keys(this.logs);
|
||||
}
|
||||
|
||||
@@ -1028,6 +1028,67 @@ class SettingsContentBuilder {
|
||||
}
|
||||
|
||||
export function createValidator(prop: IConfigurationPropertySchema): (value: any) => (string | null) {
|
||||
// Only for array of string
|
||||
if (prop.type === 'array' && prop.items && !isArray(prop.items) && prop.items.type === 'string') {
|
||||
const propItems = prop.items;
|
||||
if (propItems && !isArray(propItems) && propItems.type === 'string') {
|
||||
const withQuotes = (s: string) => `'` + s + `'`;
|
||||
|
||||
return value => {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let message = '';
|
||||
|
||||
const stringArrayValue = value as string[];
|
||||
|
||||
if (prop.minItems && stringArrayValue.length < prop.minItems) {
|
||||
message += nls.localize('validations.stringArrayMinItem', 'Array must have at least {0} items', prop.minItems);
|
||||
message += '\n';
|
||||
}
|
||||
|
||||
if (prop.maxItems && stringArrayValue.length > prop.maxItems) {
|
||||
message += nls.localize('validations.stringArrayMaxItem', 'Array must have less than {0} items', prop.maxItems);
|
||||
message += '\n';
|
||||
}
|
||||
|
||||
if (typeof propItems.pattern === 'string') {
|
||||
const patternRegex = new RegExp(propItems.pattern);
|
||||
stringArrayValue.forEach(v => {
|
||||
if (!patternRegex.test(v)) {
|
||||
message +=
|
||||
propItems.patternErrorMessage ||
|
||||
nls.localize(
|
||||
'validations.stringArrayItemPattern',
|
||||
'Value {0} must match regex {1}.',
|
||||
withQuotes(v),
|
||||
withQuotes(propItems.pattern!)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const propItemsEnum = propItems.enum;
|
||||
if (propItemsEnum) {
|
||||
stringArrayValue.forEach(v => {
|
||||
if (propItemsEnum.indexOf(v) === -1) {
|
||||
message += nls.localize(
|
||||
'validations.stringArrayItemEnum',
|
||||
'Value {0} is not one of {1}',
|
||||
withQuotes(v),
|
||||
'[' + propItemsEnum.map(withQuotes).join(', ') + ']'
|
||||
);
|
||||
message += '\n';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return message;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return value => {
|
||||
let exclusiveMax: number | undefined;
|
||||
let exclusiveMin: number | undefined;
|
||||
|
||||
@@ -250,4 +250,82 @@ suite('Preferences Model test', () => {
|
||||
withMessage.rejects(' ').withMessage('always error!');
|
||||
withMessage.rejects('1').withMessage('always error!');
|
||||
});
|
||||
});
|
||||
|
||||
class ArrayTester {
|
||||
private validator: (value: any) => string | null;
|
||||
|
||||
constructor(private settings: IConfigurationPropertySchema) {
|
||||
this.validator = createValidator(settings)!;
|
||||
}
|
||||
|
||||
public accepts(input: string[]) {
|
||||
assert.equal(this.validator(input), '', `Expected ${JSON.stringify(this.settings)} to accept \`${JSON.stringify(input)}\`. Got ${this.validator(input)}.`);
|
||||
}
|
||||
|
||||
public rejects(input: any[]) {
|
||||
assert.notEqual(this.validator(input), '', `Expected ${JSON.stringify(this.settings)} to reject \`${JSON.stringify(input)}\`.`);
|
||||
return {
|
||||
withMessage:
|
||||
(message: string) => {
|
||||
const actual = this.validator(input);
|
||||
assert.ok(actual);
|
||||
assert(actual!.indexOf(message) > -1,
|
||||
`Expected error of ${JSON.stringify(this.settings)} on \`${input}\` to contain ${message}. Got ${this.validator(input)}.`);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
test('simple array', () => {
|
||||
{
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string' } });
|
||||
arr.accepts([]);
|
||||
arr.accepts(['foo']);
|
||||
arr.accepts(['foo', 'bar']);
|
||||
}
|
||||
});
|
||||
|
||||
test('min-max items array', () => {
|
||||
{
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string' }, minItems: 1, maxItems: 2 });
|
||||
arr.rejects([]).withMessage('Array must have at least 1 items');
|
||||
arr.accepts(['a']);
|
||||
arr.accepts(['a', 'a']);
|
||||
arr.rejects(['a', 'a', 'a']).withMessage('Array must have less than 2 items');
|
||||
}
|
||||
});
|
||||
|
||||
test('array of enums', () => {
|
||||
{
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string', enum: ['a', 'b'] } });
|
||||
arr.accepts(['a']);
|
||||
arr.accepts(['a', 'b']);
|
||||
|
||||
arr.rejects(['c']).withMessage(`Value 'c' is not one of`);
|
||||
arr.rejects(['a', 'c']).withMessage(`Value 'c' is not one of`);
|
||||
|
||||
arr.rejects(['c', 'd']).withMessage(`Value 'c' is not one of`);
|
||||
arr.rejects(['c', 'd']).withMessage(`Value 'd' is not one of`);
|
||||
}
|
||||
});
|
||||
|
||||
test('min-max and enum', () => {
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string', enum: ['a', 'b'] }, minItems: 1, maxItems: 2 });
|
||||
|
||||
arr.rejects(['a', 'b', 'c']).withMessage('Array must have less than 2 items');
|
||||
arr.rejects(['a', 'b', 'c']).withMessage(`Value 'c' is not one of`);
|
||||
});
|
||||
|
||||
test('pattern', () => {
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string', pattern: '^(hello)*$' } });
|
||||
|
||||
arr.accepts(['hello']);
|
||||
arr.rejects(['a']).withMessage(`Value 'a' must match regex`);
|
||||
});
|
||||
|
||||
test('pattern with error message', () => {
|
||||
const arr = new ArrayTester({ type: 'array', items: { type: 'string', pattern: '^(hello)*$', patternErrorMessage: 'err: must be friendly' } });
|
||||
|
||||
arr.rejects(['a']).withMessage(`err: must be friendly`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
super();
|
||||
}
|
||||
|
||||
withProgress<R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: () => void): Promise<R> {
|
||||
withProgress<R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: (choice?: number) => void): Promise<R> {
|
||||
const { location } = options;
|
||||
if (typeof location === 'string') {
|
||||
if (this.viewletService.getProgressIndicator(location)) {
|
||||
@@ -142,7 +142,7 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
}
|
||||
}
|
||||
|
||||
private withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P {
|
||||
private withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: (choice?: number) => void): P {
|
||||
const toDispose = new DisposableStore();
|
||||
|
||||
const createNotification = (message: string | undefined, increment?: number): INotificationHandle | undefined => {
|
||||
@@ -152,6 +152,29 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
|
||||
const primaryActions = options.primaryActions ? Array.from(options.primaryActions) : [];
|
||||
const secondaryActions = options.secondaryActions ? Array.from(options.secondaryActions) : [];
|
||||
|
||||
if (options.buttons) {
|
||||
options.buttons.forEach((button, index) => {
|
||||
const buttonAction = new class extends Action {
|
||||
constructor() {
|
||||
super(`progress.button.${button}`, button, undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
if (typeof onDidCancel === 'function') {
|
||||
onDidCancel(index);
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
toDispose.add(buttonAction);
|
||||
|
||||
primaryActions.push(buttonAction);
|
||||
});
|
||||
}
|
||||
|
||||
if (options.cancellable) {
|
||||
const cancelAction = new class extends Action {
|
||||
constructor() {
|
||||
@@ -182,6 +205,10 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
updateProgress(handle, increment);
|
||||
|
||||
Event.once(handle.onDidClose)(() => {
|
||||
if (typeof onDidCancel === 'function') {
|
||||
onDidCancel();
|
||||
}
|
||||
|
||||
toDispose.dispose();
|
||||
});
|
||||
|
||||
@@ -317,7 +344,7 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
return promise;
|
||||
}
|
||||
|
||||
private withDialogProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => P, onDidCancel?: () => void): P {
|
||||
private withDialogProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => P, onDidCancel?: (choice?: number) => void): P {
|
||||
const disposables = new DisposableStore();
|
||||
const allowableCommands = [
|
||||
'workbench.action.quit',
|
||||
@@ -327,12 +354,17 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
let dialog: Dialog;
|
||||
|
||||
const createDialog = (message: string) => {
|
||||
|
||||
const buttons = options.buttons || [];
|
||||
buttons.push(options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss"));
|
||||
|
||||
dialog = new Dialog(
|
||||
this.layoutService.container,
|
||||
message,
|
||||
[options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")],
|
||||
buttons,
|
||||
{
|
||||
type: 'pending',
|
||||
cancelId: buttons.length - 1,
|
||||
keyEventProcessor: (event: StandardKeyboardEvent) => {
|
||||
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
|
||||
if (resolved && resolved.commandId) {
|
||||
@@ -347,9 +379,9 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
disposables.add(dialog);
|
||||
disposables.add(attachDialogStyler(dialog, this.themeService));
|
||||
|
||||
dialog.show().then(() => {
|
||||
dialog.show().then((dialogResult) => {
|
||||
if (typeof onDidCancel === 'function') {
|
||||
onDidCancel();
|
||||
onDidCancel(dialogResult.button);
|
||||
}
|
||||
|
||||
dispose(dialog);
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ServiceIdentifier, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { AbstractURLService } from 'vs/platform/url/common/urlService';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { streamToBuffer } from 'vs/base/common/buffer';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
export interface IURLCallbackProvider {
|
||||
|
||||
/**
|
||||
* Indicates that a Uri has been opened outside of VSCode. The Uri
|
||||
* will be forwarded to all installed Uri handlers in the system.
|
||||
*/
|
||||
readonly onCallback: Event<URI>;
|
||||
|
||||
/**
|
||||
* Creates a Uri that - if opened in a browser - must result in
|
||||
* the `onCallback` to fire.
|
||||
*
|
||||
* The optional `Partial<UriComponents>` must be properly restored for
|
||||
* the Uri passed to the `onCallback` handler.
|
||||
*
|
||||
* For example: if a Uri is to be created with `scheme:"vscode"`,
|
||||
* `authority:"foo"` and `path:"bar"` the `onCallback` should fire
|
||||
* with a Uri `vscode://foo/bar`.
|
||||
*
|
||||
* If there are additional `query` values in the Uri, they should
|
||||
* be added to the list of provided `query` arguments from the
|
||||
* `Partial<UriComponents>`.
|
||||
*/
|
||||
create(options?: Partial<UriComponents>): URI;
|
||||
}
|
||||
|
||||
export class BrowserURLService extends AbstractURLService {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<any>;
|
||||
|
||||
private provider: IURLCallbackProvider;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.provider = environmentService.options && environmentService.options.urlCallbackProvider ? environmentService.options.urlCallbackProvider : instantiationService.createInstance(SelfhostURLCallbackProvider);
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(this.provider.onCallback(uri => this.open(uri)));
|
||||
}
|
||||
|
||||
create(options?: Partial<UriComponents>): URI {
|
||||
return this.provider.create(options);
|
||||
}
|
||||
}
|
||||
|
||||
class SelfhostURLCallbackProvider extends Disposable implements IURLCallbackProvider {
|
||||
|
||||
static FETCH_INTERVAL = 500; // fetch every 500ms
|
||||
static FETCH_TIMEOUT = 5 * 60 * 1000; // ...but stop after 5min
|
||||
|
||||
static QUERY_KEYS = {
|
||||
REQUEST_ID: 'vscode-requestId',
|
||||
SCHEME: 'vscode-scheme',
|
||||
AUTHORITY: 'vscode-authority',
|
||||
PATH: 'vscode-path',
|
||||
QUERY: 'vscode-query',
|
||||
FRAGMENT: 'vscode-fragment'
|
||||
};
|
||||
|
||||
private readonly _onCallback: Emitter<URI> = this._register(new Emitter<URI>());
|
||||
readonly onCallback: Event<URI> = this._onCallback.event;
|
||||
|
||||
constructor(
|
||||
@IRequestService private readonly requestService: IRequestService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
create(options?: Partial<UriComponents>): URI {
|
||||
const queryValues: Map<string, string> = new Map();
|
||||
|
||||
const requestId = generateUuid();
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId);
|
||||
|
||||
const { scheme, authority, path, query, fragment } = options ? options : { scheme: undefined, authority: undefined, path: undefined, query: undefined, fragment: undefined };
|
||||
|
||||
if (scheme) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.SCHEME, scheme);
|
||||
}
|
||||
|
||||
if (authority) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.AUTHORITY, authority);
|
||||
}
|
||||
|
||||
if (path) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.PATH, path);
|
||||
}
|
||||
|
||||
if (query) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.QUERY, query);
|
||||
}
|
||||
|
||||
if (fragment) {
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.FRAGMENT, fragment);
|
||||
}
|
||||
|
||||
// Start to poll on the callback being fired
|
||||
this.periodicFetchCallback(requestId, Date.now());
|
||||
|
||||
return this.doCreateUri('/callback', queryValues);
|
||||
}
|
||||
|
||||
private async periodicFetchCallback(requestId: string, startTime: number): Promise<void> {
|
||||
|
||||
// Ask server for callback results
|
||||
const queryValues: Map<string, string> = new Map();
|
||||
queryValues.set(SelfhostURLCallbackProvider.QUERY_KEYS.REQUEST_ID, requestId);
|
||||
|
||||
const result = await this.requestService.request({
|
||||
url: this.doCreateUri('/fetch-callback', queryValues).toString(true)
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Check for callback results
|
||||
const content = await streamToBuffer(result.stream);
|
||||
if (content.byteLength > 0) {
|
||||
try {
|
||||
this._onCallback.fire(URI.revive(JSON.parse(content.toString())));
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
}
|
||||
|
||||
return; // done
|
||||
}
|
||||
|
||||
// Continue fetching unless we hit the timeout
|
||||
if (Date.now() - startTime < SelfhostURLCallbackProvider.FETCH_TIMEOUT) {
|
||||
setTimeout(() => this.periodicFetchCallback(requestId, startTime), SelfhostURLCallbackProvider.FETCH_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
private doCreateUri(path: string, queryValues: Map<string, string>): URI {
|
||||
let query: string | undefined = undefined;
|
||||
|
||||
if (queryValues) {
|
||||
let index = 0;
|
||||
queryValues.forEach((value, key) => {
|
||||
if (!query) {
|
||||
query = '';
|
||||
}
|
||||
|
||||
const prefix = (index++ === 0) ? '' : '&';
|
||||
query += `${prefix}${key}=${encodeURIComponent(value)}`;
|
||||
});
|
||||
}
|
||||
|
||||
return URI.parse(window.location.href).with({ path, query });
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IURLService, BrowserURLService, true);
|
||||
+4
-1
@@ -7,9 +7,10 @@ import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
|
||||
import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/node/urlIpc';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
export class RelayURLService extends URLService implements IURLHandler {
|
||||
|
||||
@@ -43,3 +44,5 @@ export class RelayURLService extends URLService implements IURLHandler {
|
||||
return super.open(uri);
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IURLService, RelayURLService);
|
||||
@@ -53,6 +53,7 @@ import 'vs/workbench/browser/parts/views/views';
|
||||
|
||||
//#region --- workbench services
|
||||
|
||||
import 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
|
||||
import 'vs/workbench/services/bulkEdit/browser/bulkEditService';
|
||||
import 'vs/workbench/services/keybinding/common/keybindingEditing';
|
||||
import 'vs/workbench/services/decorations/browser/decorationsService';
|
||||
|
||||
@@ -31,7 +31,6 @@ import 'vs/workbench/electron-browser/desktop.main';
|
||||
import 'vs/workbench/services/integrity/node/integrityService';
|
||||
import 'vs/workbench/services/textMate/electron-browser/textMateService';
|
||||
import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService';
|
||||
import 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
|
||||
import 'vs/workbench/services/search/node/searchService';
|
||||
import 'vs/workbench/services/output/node/outputChannelModelService';
|
||||
import 'vs/workbench/services/textfile/node/textFileService';
|
||||
@@ -50,6 +49,7 @@ import 'vs/workbench/services/accessibility/node/accessibilityService';
|
||||
import 'vs/workbench/services/remote/node/tunnelService';
|
||||
import 'vs/workbench/services/backup/node/backupFileService';
|
||||
import 'vs/workbench/services/credentials/node/credentialsService';
|
||||
import 'vs/workbench/services/url/electron-browser/urlService';
|
||||
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
@@ -71,8 +71,6 @@ import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { WorkspacesService } from 'vs/platform/workspaces/electron-browser/workspacesService';
|
||||
import { IMenubarService } from 'vs/platform/menubar/node/menubar';
|
||||
import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { RelayURLService } from 'vs/platform/url/electron-browser/urlService';
|
||||
import { StaticExtensionsService, IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
|
||||
|
||||
registerSingleton(IClipboardService, ClipboardService, true);
|
||||
@@ -85,7 +83,6 @@ registerSingleton(IUpdateService, UpdateService);
|
||||
registerSingleton(IIssueService, IssueService);
|
||||
registerSingleton(IWorkspacesService, WorkspacesService);
|
||||
registerSingleton(IMenubarService, MenubarService);
|
||||
registerSingleton(IURLService, RelayURLService);
|
||||
registerSingleton(IStaticExtensionsService, class extends StaticExtensionsService { constructor() { super([]); } });
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -10,6 +10,7 @@ import { IFileSystemProvider } from 'vs/platform/files/common/files';
|
||||
import { IWebSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory';
|
||||
import { ICredentialsProvider } from 'vs/workbench/services/credentials/browser/credentialsService';
|
||||
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
|
||||
import { IURLCallbackProvider } from 'vs/workbench/services/url/browser/urlService';
|
||||
|
||||
export interface IWorkbenchConstructionOptions {
|
||||
|
||||
@@ -65,6 +66,11 @@ export interface IWorkbenchConstructionOptions {
|
||||
* Experimental: Add static extensions that cannot be uninstalled but only be disabled.
|
||||
*/
|
||||
staticExtensions?: { packageJSON: IExtensionManifest, extensionLocation: UriComponents }[];
|
||||
|
||||
/**
|
||||
* Experimental: Support for URL callbacks.
|
||||
*/
|
||||
urlCallbackProvider?: IURLCallbackProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,7 @@ import 'vs/workbench/services/extensionManagement/common/extensionManagementServ
|
||||
import 'vs/workbench/services/telemetry/browser/telemetryService';
|
||||
import 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
|
||||
import 'vs/workbench/services/credentials/browser/credentialsService';
|
||||
import 'vs/workbench/services/url/browser/urlService';
|
||||
import 'vs/workbench/browser/web.simpleservices';
|
||||
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
Reference in New Issue
Block a user