Merge from vscode 0f73473c08055054f317c1c94502f7f39fdbb164 (#6892)

* Merge from vscode 0f73473c08055054f317c1c94502f7f39fdbb164

* fix tslinting
This commit is contained in:
Anthony Dresser
2019-08-22 22:07:01 -07:00
committed by GitHub
parent 1372cbaee1
commit 658cf51887
91 changed files with 1092 additions and 317 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ export class Table<T extends Slick.SlickData> extends Widget implements IDisposa
private _container: HTMLElement;
private _tableContainer: HTMLElement;
private _classChangeTimeout: NodeJS.Timer;
private _classChangeTimeout: any;
private _onContextMenu = new Emitter<ITableMouseEvent>();
public readonly onContextMenu: Event<ITableMouseEvent> = this._onContextMenu.event;
@@ -162,7 +162,7 @@ export class TaskService implements ITaskService {
this.dialogService.show(Severity.Warning, message, options).then(choice => {
switch (choice) {
case 0:
let timeout: NodeJS.Timer;
let timeout: any;
let isTimeout = false;
this.cancelAllTasks().then(() => {
clearTimeout(timeout);
@@ -45,7 +45,7 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
private refreshGridTimeoutInMs = 200;
// The timeout handle for the refresh grid task
private refreshGridTimeoutHandle: NodeJS.Timer;
private refreshGridTimeoutHandle: any;
// Optimized for the edit top 200 rows scenario, only need to retrieve the data once
// to make the scroll experience smoother
@@ -16,7 +16,7 @@ export class TreeSelectionHandler {
// progressRunner: IProgressRunner;
private _lastClicked: any[];
private _clickTimer: NodeJS.Timer = undefined;
private _clickTimer: any = undefined;
// constructor(@IProgressService private _progressService: IProgressService) {
@@ -83,7 +83,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
private _resizeSash: Sash;
private searchTimeoutHandle: NodeJS.Timer;
private searchTimeoutHandle: any;
constructor(
tableController: ITableController,
+1 -8
View File
@@ -23,13 +23,6 @@
"sqltest/*": [
"./sqltest/*"
]
},
"types": [
"keytar",
"mocha",
"semver",
"sinon",
"winreg"
]
}
}
}
+7
View File
@@ -11,6 +11,13 @@
"es5",
"es2015.iterable",
"webworker"
],
"types": [
"keytar",
"mocha",
"semver",
"sinon",
"winreg"
]
},
"include": [
+149 -58
View File
@@ -207,47 +207,47 @@ declare module 'xterm' {
*/
export interface ITheme {
/** The default foreground color */
foreground?: string,
foreground?: string;
/** The default background color */
background?: string,
background?: string;
/** The cursor color */
cursor?: string,
cursor?: string;
/** The accent color of the cursor (fg color for a block cursor) */
cursorAccent?: string,
cursorAccent?: string;
/** The selection background color (can be transparent) */
selection?: string,
selection?: string;
/** ANSI black (eg. `\x1b[30m`) */
black?: string,
black?: string;
/** ANSI red (eg. `\x1b[31m`) */
red?: string,
red?: string;
/** ANSI green (eg. `\x1b[32m`) */
green?: string,
green?: string;
/** ANSI yellow (eg. `\x1b[33m`) */
yellow?: string,
yellow?: string;
/** ANSI blue (eg. `\x1b[34m`) */
blue?: string,
blue?: string;
/** ANSI magenta (eg. `\x1b[35m`) */
magenta?: string,
magenta?: string;
/** ANSI cyan (eg. `\x1b[36m`) */
cyan?: string,
cyan?: string;
/** ANSI white (eg. `\x1b[37m`) */
white?: string,
white?: string;
/** ANSI bright black (eg. `\x1b[1;30m`) */
brightBlack?: string,
brightBlack?: string;
/** ANSI bright red (eg. `\x1b[1;31m`) */
brightRed?: string,
brightRed?: string;
/** ANSI bright green (eg. `\x1b[1;32m`) */
brightGreen?: string,
brightGreen?: string;
/** ANSI bright yellow (eg. `\x1b[1;33m`) */
brightYellow?: string,
brightYellow?: string;
/** ANSI bright blue (eg. `\x1b[1;34m`) */
brightBlue?: string,
brightBlue?: string;
/** ANSI bright magenta (eg. `\x1b[1;35m`) */
brightMagenta?: string,
brightMagenta?: string;
/** ANSI bright cyan (eg. `\x1b[1;36m`) */
brightCyan?: string,
brightCyan?: string;
/** ANSI bright white (eg. `\x1b[1;37m`) */
brightWhite?: string
brightWhite?: string;
}
/**
@@ -386,6 +386,12 @@ declare module 'xterm' {
*/
readonly markers: ReadonlyArray<IMarker>;
/**
* (EXPERIMENTAL) Get the parser interface to register
* custom escape sequence handlers.
*/
readonly parser: IParser;
/**
* Natural language strings that can be localized.
*/
@@ -500,32 +506,6 @@ declare module 'xterm' {
*/
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void;
/**
* (EXPERIMENTAL) Adds a handler for CSI escape sequences.
* @param flag The flag should be one-character string, which specifies the
* final character (e.g "m" for SGR) of the CSI sequence.
* @param callback The function to handle the escape sequence. The callback
* is called with the numerical params, as well as the special characters
* (e.g. "$" for DECSCPP). If the sequence has subparams the array will
* contain subarrays with their numercial values.
* Return true if the sequence was handled; false if
* we should try a previous handler (set by addCsiHandler or setCsiHandler).
* The most recently-added handler is tried first.
* @return An IDisposable you can call to remove this handler.
*/
addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable;
/**
* (EXPERIMENTAL) Adds a handler for OSC escape sequences.
* @param ident The number (first parameter) of the sequence.
* @param callback The function to handle the escape sequence. The callback
* is called with OSC data string. Return true if the sequence was handled;
* false if we should try a previous handler (set by addOscHandler or
* setOscHandler). The most recently-added handler is tried first.
* @return An IDisposable you can call to remove this handler.
*/
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable;
/**
* (EXPERIMENTAL) Registers a link matcher, allowing custom link patterns to
* be matched and handled.
@@ -689,6 +669,12 @@ declare module 'xterm' {
*/
writeUtf8(data: Uint8Array): void;
/**
* Writes text to the terminal, performing the necessary transformations for pasted text.
* @param data The text to write to the terminal.
*/
paste(data: string): void;
/**
* Retrieves an option's value from the terminal.
* @param key The option key.
@@ -804,18 +790,10 @@ declare module 'xterm' {
/**
* Perform a full reset (RIS, aka '\x1bc').
*/
reset(): void
reset(): void;
/**
* Applies an addon to the Terminal prototype, making it available to all
* newly created Terminals.
* @param addon The addon to apply.
* @deprecated Use the new loadAddon API/addon format.
*/
static applyAddon(addon: any): void;
/**
* (EXPERIMENTAL) Loads an addon into this instance of xterm.js.
* Loads an addon into this instance of xterm.js.
* @param addon The addon to load.
*/
loadAddon(addon: ITerminalAddon): void;
@@ -951,6 +929,119 @@ declare module 'xterm' {
*/
readonly width: number;
}
/**
* (EXPERIMENTAL) Data type to register a CSI, DCS or ESC callback in the parser
* in the form:
* ESC I..I F
* CSI Prefix P..P I..I F
* DCS Prefix P..P I..I F data_bytes ST
*
* with these rules/restrictions:
* - prefix can only be used with CSI and DCS
* - only one leading prefix byte is recognized by the parser
* before any other parameter bytes (P..P)
* - intermediate bytes are recognized up to 2
*
* For custom sequences make sure to read ECMA-48 and the resources at
* vt100.net to not clash with existing sequences or reserved address space.
* General recommendations:
* - use private address space (see ECMA-48)
* - use max one intermediate byte (technically not limited by the spec,
* in practice there are no sequences with more than one intermediate byte,
* thus parsers might get confused with more intermediates)
* - test against other common emulators to check whether they escape/ignore
* the sequence correctly
*
* Notes: OSC command registration is handled differently (see addOscHandler)
* APC, PM or SOS is currently not supported.
*/
export interface IFunctionIdentifier {
/**
* Optional prefix byte, must be in range \x3c .. \x3f.
* Usable in CSI and DCS.
*/
prefix?: string;
/**
* Optional intermediate bytes, must be in range \x20 .. \x2f.
* Usable in CSI, DCS and ESC.
*/
intermediates?: string;
/**
* Final byte, must be in range \x40 .. \x7e for CSI and DCS,
* \x30 .. \x7e for ESC.
*/
final: string;
}
/**
* (EXPERIMENTAL) Parser interface.
*/
export interface IParser {
/**
* Adds a handler for CSI escape sequences.
* @param id Specifies the function identifier under which the callback
* gets registered, e.g. {final: 'm'} for SGR.
* @param callback The function to handle the sequence. The callback is
* called with the numerical params. If the sequence has subparams the
* array will contain subarrays with their numercial values.
* Return true if the sequence was handled; false if we should try
* a previous handler (set by addCsiHandler or setCsiHandler).
* The most recently-added handler is tried first.
* @return An IDisposable you can call to remove this handler.
*/
addCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean): IDisposable;
/**
* Adds a handler for DCS escape sequences.
* @param id Specifies the function identifier under which the callback
* gets registered, e.g. {intermediates: '$' final: 'q'} for DECRQSS.
* @param callback The function to handle the sequence. Note that the
* function will only be called once if the sequence finished sucessfully.
* There is currently no way to intercept smaller data chunks, data chunks
* will be stored up until the sequence is finished. Since DCS sequences
* are not limited by the amount of data this might impose a problem for
* big payloads. Currently xterm.js limits DCS payload to 10 MB
* which should give enough room for most use cases.
* The function gets the payload and numerical parameters as arguments.
* Return true if the sequence was handled; false if we should try
* a previous handler (set by addDcsHandler or setDcsHandler).
* The most recently-added handler is tried first.
* @return An IDisposable you can call to remove this handler.
*/
addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean): IDisposable;
/**
* Adds a handler for ESC escape sequences.
* @param id Specifies the function identifier under which the callback
* gets registered, e.g. {intermediates: '%' final: 'G'} for
* default charset selection.
* @param callback The function to handle the sequence.
* Return true if the sequence was handled; false if we should try
* a previous handler (set by addEscHandler or setEscHandler).
* The most recently-added handler is tried first.
* @return An IDisposable you can call to remove this handler.
*/
addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable;
/**
* Adds a handler for OSC escape sequences.
* @param ident The number (first parameter) of the sequence.
* @param callback The function to handle the sequence. Note that the
* function will only be called once if the sequence finished sucessfully.
* There is currently no way to intercept smaller data chunks, data chunks
* will be stored up until the sequence is finished. Since OSC sequences
* are not limited by the amount of data this might impose a problem for
* big payloads. Currently xterm.js limits OSC payload to 10 MB
* which should give enough room for most use cases.
* The callback is called with OSC data string.
* Return true if the sequence was handled; false if we should try
* a previous handler (set by addOscHandler or setOscHandler).
* The most recently-added handler is tried first.
* @return An IDisposable you can call to remove this handler.
*/
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable;
}
}
@@ -986,4 +1077,4 @@ declare module 'xterm' {
interface Terminal {
_core: TerminalCore;
}
}
}
+3
View File
@@ -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')}')`;
}
+9
View File
@@ -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[] {
+21 -1
View File
@@ -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);
}
+1 -1
View File
@@ -32,4 +32,4 @@ suite('Keytar', () => {
}
})().then(done, done);
});
});
});
+1 -1
View File
@@ -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';
+5 -1
View File
@@ -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,
+6 -1
View File
@@ -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());
+12 -3
View File
@@ -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;
}
+6 -4
View File
@@ -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);
+5 -1
View File
@@ -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 {
+17
View File
@@ -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 });
}
}
+7
View File
@@ -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;
}
/**
+60 -13
View File
@@ -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,
+11 -1
View File
@@ -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();
+30 -24
View File
@@ -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
+6 -4
View File
@@ -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) => {
+17 -5
View File
@@ -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 || []);
+1 -46
View File
@@ -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;
@@ -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';
@@ -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';
@@ -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);
@@ -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';
+1 -4
View File
@@ -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
+6
View File
@@ -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;
}
/**
+1
View File
@@ -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';