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
+3
View File
@@ -1,3 +1,6 @@
pool:
vmImage: 'Ubuntu-16.04'
trigger: trigger:
branches: branches:
include: ['master', 'release/*'] include: ['master', 'release/*']
+3 -10
View File
@@ -1,3 +1,6 @@
pool:
vmImage: 'Ubuntu-16.04'
trigger: trigger:
branches: branches:
include: ['master'] include: ['master']
@@ -10,20 +13,10 @@ steps:
inputs: inputs:
versionSpec: "10.15.1" versionSpec: "10.15.1"
- task: AzureKeyVault@1
displayName: 'Azure Key Vault: Get Secrets'
inputs:
azureSubscription: 'vscode-builds-subscription'
KeyVaultName: vscode
- script: | - script: |
set -e set -e
cat << EOF > ~/.netrc cat << EOF > ~/.netrc
machine github.com
login vscode
password $(github-distro-mixin-password)
EOF
git config user.email "vscode@microsoft.com" git config user.email "vscode@microsoft.com"
git config user.name "VSCode" git config user.name "VSCode"
+2 -2
View File
@@ -143,8 +143,8 @@ trigger: none
pr: none pr: none
schedules: schedules:
- cron: "0 5 * * Mon-Fri" - cron: "10 5 * * Mon-Fri"
displayName: Mon-Fri at 7:00 displayName: Mon-Fri at 7:10
branches: branches:
include: include:
- master - master
+1 -1
View File
@@ -252,7 +252,7 @@ gulp.task('tslint', () => {
.pipe(filter(tslintExtensionsFilter)) .pipe(filter(tslintExtensionsFilter))
.pipe(gulptslint.default({ rulesDirectory: 'build/lib/tslint' })) .pipe(gulptslint.default({ rulesDirectory: 'build/lib/tslint' }))
.pipe(gulptslint.default.report({ emitError: true })) .pipe(gulptslint.default.report({ emitError: true }))
]).pipe(es.through()); // {{SQL CARBON EDIT}} fix issue ]).pipe(es.through());
}); });
function hygiene(some) { function hygiene(some) {
@@ -26,6 +26,7 @@ class NoNodejsGlobalsRuleWalker extends abstractGlobalsRule_1.AbstractGlobalsRul
getDisallowedGlobals() { getDisallowedGlobals() {
// https://nodejs.org/api/globals.html#globals_global_objects // https://nodejs.org/api/globals.html#globals_global_objects
return [ return [
"NodeJS",
"Buffer", "Buffer",
"__dirname", "__dirname",
"__filename", "__filename",
@@ -37,6 +37,7 @@ class NoNodejsGlobalsRuleWalker extends AbstractGlobalsRuleWalker {
getDisallowedGlobals(): string[] { getDisallowedGlobals(): string[] {
// https://nodejs.org/api/globals.html#globals_global_objects // https://nodejs.org/api/globals.html#globals_global_objects
return [ return [
"NodeJS",
"Buffer", "Buffer",
"__dirname", "__dirname",
"__filename", "__filename",
+2 -1
View File
@@ -77,7 +77,7 @@
"vscode-ripgrep": "^1.5.6", "vscode-ripgrep": "^1.5.6",
"vscode-sqlite3": "4.0.8", "vscode-sqlite3": "4.0.8",
"vscode-textmate": "^4.2.2", "vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta99", "xterm": "3.15.0-beta101",
"xterm-addon-search": "0.2.0-beta5", "xterm-addon-search": "0.2.0-beta5",
"xterm-addon-web-links": "0.1.0-beta10", "xterm-addon-web-links": "0.1.0-beta10",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
@@ -87,6 +87,7 @@
"devDependencies": { "devDependencies": {
"7zip": "0.0.6", "7zip": "0.0.6",
"@types/chart.js": "^2.7.31", "@types/chart.js": "^2.7.31",
"@types/cookie": "^0.3.3",
"@types/htmlparser2": "^3.7.31", "@types/htmlparser2": "^3.7.31",
"@types/keytar": "^4.4.0", "@types/keytar": "^4.4.0",
"@types/mocha": "2.2.39", "@types/mocha": "2.2.39",
+1 -1
View File
@@ -21,7 +21,7 @@
"vscode-proxy-agent": "0.4.0", "vscode-proxy-agent": "0.4.0",
"vscode-ripgrep": "^1.5.6", "vscode-ripgrep": "^1.5.6",
"vscode-textmate": "^4.2.2", "vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta99", "xterm": "3.15.0-beta101",
"xterm-addon-search": "0.2.0-beta5", "xterm-addon-search": "0.2.0-beta5",
"xterm-addon-web-links": "0.1.0-beta10", "xterm-addon-web-links": "0.1.0-beta10",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
+4 -4
View File
@@ -1225,10 +1225,10 @@ xterm-addon-web-links@0.1.0-beta10:
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23"
integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg==
xterm@3.15.0-beta99: xterm@3.15.0-beta101:
version "3.15.0-beta99" version "3.15.0-beta101"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta99.tgz#0010a7ea5d56cbb08a1e3a525b353c96a158e7a0" resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta101.tgz#38ffa0df5a3e9bdcb1818e74fe59b2f98b0fff69"
integrity sha512-Vm0ZWToWwO4uk/28Kqvqt9L92h5EU2z4WR9I6xcQaPIBmkJPINIARU4LWQnvaOfgFhRbpwBMveTfh8/jM97lPg== integrity sha512-HRa7+FDqQ8iWBTvb1Ni+uMGILnu6k9mF7JHMHRHfWxFoQlSoGYCyfdyXlJjk68YN8GsEQREmrII6cPLiQizdEQ==
yauzl@^2.9.2: yauzl@^2.9.2:
version "2.10.0" version "2.10.0"
+1 -1
View File
@@ -41,7 +41,7 @@ export class Table<T extends Slick.SlickData> extends Widget implements IDisposa
private _container: HTMLElement; private _container: HTMLElement;
private _tableContainer: HTMLElement; private _tableContainer: HTMLElement;
private _classChangeTimeout: NodeJS.Timer; private _classChangeTimeout: any;
private _onContextMenu = new Emitter<ITableMouseEvent>(); private _onContextMenu = new Emitter<ITableMouseEvent>();
public readonly onContextMenu: Event<ITableMouseEvent> = this._onContextMenu.event; 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 => { this.dialogService.show(Severity.Warning, message, options).then(choice => {
switch (choice) { switch (choice) {
case 0: case 0:
let timeout: NodeJS.Timer; let timeout: any;
let isTimeout = false; let isTimeout = false;
this.cancelAllTasks().then(() => { this.cancelAllTasks().then(() => {
clearTimeout(timeout); clearTimeout(timeout);
@@ -45,7 +45,7 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
private refreshGridTimeoutInMs = 200; private refreshGridTimeoutInMs = 200;
// The timeout handle for the refresh grid task // 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 // Optimized for the edit top 200 rows scenario, only need to retrieve the data once
// to make the scroll experience smoother // to make the scroll experience smoother
@@ -16,7 +16,7 @@ export class TreeSelectionHandler {
// progressRunner: IProgressRunner; // progressRunner: IProgressRunner;
private _lastClicked: any[]; private _lastClicked: any[];
private _clickTimer: NodeJS.Timer = undefined; private _clickTimer: any = undefined;
// constructor(@IProgressService private _progressService: IProgressService) { // constructor(@IProgressService private _progressService: IProgressService) {
@@ -83,7 +83,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
private _resizeSash: Sash; private _resizeSash: Sash;
private searchTimeoutHandle: NodeJS.Timer; private searchTimeoutHandle: any;
constructor( constructor(
tableController: ITableController, tableController: ITableController,
+1 -8
View File
@@ -23,13 +23,6 @@
"sqltest/*": [ "sqltest/*": [
"./sqltest/*" "./sqltest/*"
] ]
}, }
"types": [
"keytar",
"mocha",
"semver",
"sinon",
"winreg"
]
} }
} }
+7
View File
@@ -11,6 +11,13 @@
"es5", "es5",
"es2015.iterable", "es2015.iterable",
"webworker" "webworker"
],
"types": [
"keytar",
"mocha",
"semver",
"sinon",
"winreg"
] ]
}, },
"include": [ "include": [
+148 -57
View File
@@ -207,47 +207,47 @@ declare module 'xterm' {
*/ */
export interface ITheme { export interface ITheme {
/** The default foreground color */ /** The default foreground color */
foreground?: string, foreground?: string;
/** The default background color */ /** The default background color */
background?: string, background?: string;
/** The cursor color */ /** The cursor color */
cursor?: string, cursor?: string;
/** The accent color of the cursor (fg color for a block cursor) */ /** The accent color of the cursor (fg color for a block cursor) */
cursorAccent?: string, cursorAccent?: string;
/** The selection background color (can be transparent) */ /** The selection background color (can be transparent) */
selection?: string, selection?: string;
/** ANSI black (eg. `\x1b[30m`) */ /** ANSI black (eg. `\x1b[30m`) */
black?: string, black?: string;
/** ANSI red (eg. `\x1b[31m`) */ /** ANSI red (eg. `\x1b[31m`) */
red?: string, red?: string;
/** ANSI green (eg. `\x1b[32m`) */ /** ANSI green (eg. `\x1b[32m`) */
green?: string, green?: string;
/** ANSI yellow (eg. `\x1b[33m`) */ /** ANSI yellow (eg. `\x1b[33m`) */
yellow?: string, yellow?: string;
/** ANSI blue (eg. `\x1b[34m`) */ /** ANSI blue (eg. `\x1b[34m`) */
blue?: string, blue?: string;
/** ANSI magenta (eg. `\x1b[35m`) */ /** ANSI magenta (eg. `\x1b[35m`) */
magenta?: string, magenta?: string;
/** ANSI cyan (eg. `\x1b[36m`) */ /** ANSI cyan (eg. `\x1b[36m`) */
cyan?: string, cyan?: string;
/** ANSI white (eg. `\x1b[37m`) */ /** ANSI white (eg. `\x1b[37m`) */
white?: string, white?: string;
/** ANSI bright black (eg. `\x1b[1;30m`) */ /** ANSI bright black (eg. `\x1b[1;30m`) */
brightBlack?: string, brightBlack?: string;
/** ANSI bright red (eg. `\x1b[1;31m`) */ /** ANSI bright red (eg. `\x1b[1;31m`) */
brightRed?: string, brightRed?: string;
/** ANSI bright green (eg. `\x1b[1;32m`) */ /** ANSI bright green (eg. `\x1b[1;32m`) */
brightGreen?: string, brightGreen?: string;
/** ANSI bright yellow (eg. `\x1b[1;33m`) */ /** ANSI bright yellow (eg. `\x1b[1;33m`) */
brightYellow?: string, brightYellow?: string;
/** ANSI bright blue (eg. `\x1b[1;34m`) */ /** ANSI bright blue (eg. `\x1b[1;34m`) */
brightBlue?: string, brightBlue?: string;
/** ANSI bright magenta (eg. `\x1b[1;35m`) */ /** ANSI bright magenta (eg. `\x1b[1;35m`) */
brightMagenta?: string, brightMagenta?: string;
/** ANSI bright cyan (eg. `\x1b[1;36m`) */ /** ANSI bright cyan (eg. `\x1b[1;36m`) */
brightCyan?: string, brightCyan?: string;
/** ANSI bright white (eg. `\x1b[1;37m`) */ /** ANSI bright white (eg. `\x1b[1;37m`) */
brightWhite?: string brightWhite?: string;
} }
/** /**
@@ -386,6 +386,12 @@ declare module 'xterm' {
*/ */
readonly markers: ReadonlyArray<IMarker>; 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. * Natural language strings that can be localized.
*/ */
@@ -500,32 +506,6 @@ declare module 'xterm' {
*/ */
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; 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 * (EXPERIMENTAL) Registers a link matcher, allowing custom link patterns to
* be matched and handled. * be matched and handled.
@@ -689,6 +669,12 @@ declare module 'xterm' {
*/ */
writeUtf8(data: Uint8Array): void; 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. * Retrieves an option's value from the terminal.
* @param key The option key. * @param key The option key.
@@ -804,18 +790,10 @@ declare module 'xterm' {
/** /**
* Perform a full reset (RIS, aka '\x1bc'). * Perform a full reset (RIS, aka '\x1bc').
*/ */
reset(): void reset(): void;
/** /**
* Applies an addon to the Terminal prototype, making it available to all * Loads an addon into this instance of xterm.js.
* 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.
* @param addon The addon to load. * @param addon The addon to load.
*/ */
loadAddon(addon: ITerminalAddon): void; loadAddon(addon: ITerminalAddon): void;
@@ -951,6 +929,119 @@ declare module 'xterm' {
*/ */
readonly width: number; 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;
}
} }
+3
View File
@@ -1202,5 +1202,8 @@ export function asDomUri(uri: URI): URI {
* returns url('...') * returns url('...')
*/ */
export function asCSSUrl(uri: URI): string { export function asCSSUrl(uri: URI): string {
if (!uri) {
return `url('')`;
}
return `url('${asDomUri(uri).toString(true).replace(/'/g, '%27')}')`; 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 { CharCode } from 'vs/base/common/charCode';
import { Iterator, IteratorResult, FIN } from './iterator'; 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<V = any>(set: Set<V>): V[];
export function values<K = any, V = any>(map: Map<K, 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[] { export function values<V>(forEachable: { forEach(callback: (value: V, ...more: any[]) => any): void }): V[] {
+20
View File
@@ -12,7 +12,11 @@ export function buildReplaceStringWithCasePreserved(matches: string[] | null, pa
} else if (matches[0].toLowerCase() === matches[0]) { } else if (matches[0].toLowerCase() === matches[0]) {
return pattern.toLowerCase(); return pattern.toLowerCase();
} else if (strings.containsUppercaseCharacter(matches[0][0])) { } else if (strings.containsUppercaseCharacter(matches[0][0])) {
if (validateSpecificSpecialCharacter(matches, pattern, '-')) {
return buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-');
} else {
return pattern[0].toUpperCase() + pattern.substr(1); return pattern[0].toUpperCase() + pattern.substr(1);
}
} else { } else {
// we don't understand its pattern yet. // we don't understand its pattern yet.
return pattern; return pattern;
@@ -21,3 +25,19 @@ export function buildReplaceStringWithCasePreserved(matches: string[] | null, pa
return pattern; 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
@@ -70,7 +70,7 @@ import { startsWith } from 'vs/base/common/strings';
import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService'; import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService';
import { IBackupMainService } from 'vs/platform/backup/common/backup'; import { IBackupMainService } from 'vs/platform/backup/common/backup';
import { HistoryMainService } from 'vs/platform/history/electron-main/historyMainService'; 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 { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
import { statSync } from 'fs'; import { statSync } from 'fs';
import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc'; 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 * A modifier to the `kind` which affect how the item
* is rendered, e.g. Deprecated is rendered with a strikeout * is rendered, e.g. Deprecated is rendered with a strikeout
*/ */
kindModifier?: CompletionItemKindModifier; kindModifier?: Set<CompletionItemKindModifier>;
/** /**
* A human-readable string with additional information * A human-readable string with additional information
* about this item, like type or symbol information. * about this item, like type or symbol information.
@@ -867,6 +867,9 @@ export const enum SymbolKind {
TypeParameter = 25 TypeParameter = 25
} }
export const enum SymbolKindTag {
Deprecated = 1,
}
/** /**
* @internal * @internal
@@ -910,6 +913,7 @@ export interface DocumentSymbol {
name: string; name: string;
detail: string; detail: string;
kind: SymbolKind; kind: SymbolKind;
kindTags: SymbolKindTag[];
containerName?: string; containerName?: string;
range: IRange; range: IRange;
selectionRange: IRange; selectionRange: IRange;
@@ -661,3 +661,7 @@ export enum SymbolKind {
Operator = 24, Operator = 24,
TypeParameter = 25 TypeParameter = 25
} }
export enum SymbolKindTag {
Deprecated = 1
}
@@ -20,6 +20,11 @@
color: var(--outline-element-color); 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 { .monaco-tree .monaco-tree-row.focused .outline-element .outline-element-detail {
visibility: inherit; visibility: inherit;
} }
@@ -12,7 +12,7 @@ import { createMatches, FuzzyScore } from 'vs/base/common/filters';
import 'vs/css!./media/outlineTree'; import 'vs/css!./media/outlineTree';
import 'vs/css!./media/symbol-icons'; import 'vs/css!./media/symbol-icons';
import { Range } from 'vs/editor/common/core/range'; 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 { OutlineElement, OutlineGroup, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; 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 // add styles for the icons
options.extraClasses.push(`outline-element-icon ${symbolKindToCssClass(element.symbol.kind, true)}`); 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); template.iconLabel.setLabel(element.symbol.name, element.symbol.detail, options);
this._renderMarkerInfo(element, template); this._renderMarkerInfo(element, template);
} }
@@ -76,6 +76,7 @@ suite('OutlineModel', function () {
name, name,
detail: 'fake', detail: 'fake',
kind: SymbolKind.Boolean, kind: SymbolKind.Boolean,
kindTags: [],
selectionRange: range, selectionRange: range,
range: range range: range
}; };
@@ -176,6 +176,13 @@ suite('Replace Pattern test', () => {
assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'Def'); assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'Def');
actual = ['aBC']; actual = ['aBC'];
assert.equal(buildReplaceStringWithCasePreserved(actual, replacePattern), 'Def'); 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', () => { test('preserve case', () => {
@@ -198,5 +205,17 @@ suite('Replace Pattern test', () => {
assert.equal(actual, 'Def'); assert.equal(actual, 'Def');
actual = replacePattern.buildReplaceString(['aBC'], true); actual = replacePattern.buildReplaceString(['aBC'], true);
assert.equal(actual, 'Def'); 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) { for (let entry of entries) {
bucket.push({ bucket.push({
kind: entry.kind, kind: entry.kind,
kindTags: [],
name: entry.name, name: entry.name,
detail: entry.detail, detail: entry.detail,
containerName: entry.containerName || overrideContainerLabel, containerName: entry.containerName || overrideContainerLabel,
@@ -97,10 +97,6 @@
font-weight: bold; font-weight: bold;
} }
.monaco-editor .suggest-widget-deprecated span {
text-decoration: line-through;
}
/** Icon styles **/ /** Icon styles **/
.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close, .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 { .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close {
background-image: url('./close-light.svg'); background-image: url('./close-light.svg');
position: absolute; position: absolute;
top: 0px; top: 0;
right: 0px; right: 0;
margin-right: 5px; margin-right: 5px;
} }
@@ -159,9 +155,16 @@
} }
/** Styles for each row in the list **/ /** 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 { .monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label::before {
height: 100%; height: 100%;
} }
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon { .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon {
@@ -257,7 +260,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
opacity: 0.7; opacity: 0.7;
word-break: break-all; word-break: break-all;
margin: 0px 24px 0 0; margin: 0 24px 0 0;
padding: 4px 0 12px 5px; padding: 4px 0 12px 5px;
} }
@@ -34,6 +34,8 @@ import { IdleValue } from 'vs/base/common/async';
import { isObject } from 'vs/base/common/types'; import { isObject } from 'vs/base/common/types';
import { CommitCharacterController } from './suggestCommitCharacters'; import { CommitCharacterController } from './suggestCommitCharacters';
const _sticky = false; // for development purposes only
export class SuggestController implements IEditorContribution { export class SuggestController implements IEditorContribution {
private static readonly ID: string = 'editor.contrib.suggestController'; private static readonly ID: string = 'editor.contrib.suggestController';
@@ -47,7 +49,6 @@ export class SuggestController implements IEditorContribution {
private readonly _alternatives: IdleValue<SuggestAlternatives>; private readonly _alternatives: IdleValue<SuggestAlternatives>;
private readonly _toDispose = new DisposableStore(); private readonly _toDispose = new DisposableStore();
private readonly _sticky = false; // for development purposes only
constructor( constructor(
private _editor: ICodeEditor, private _editor: ICodeEditor,
@@ -127,7 +128,7 @@ export class SuggestController implements IEditorContribution {
} }
})); }));
this._toDispose.add(this._editor.onDidBlurEditorWidget(() => { this._toDispose.add(this._editor.onDidBlurEditorWidget(() => {
if (!this._sticky) { if (!_sticky) {
this._model.cancel(); this._model.cancel();
this._model.clear(); this._model.clear();
} }
@@ -193,8 +193,9 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
]; ];
} }
if (suggestion.kindModifier && suggestion.kindModifier & CompletionItemKindModifier.Deprecated) { if (suggestion.kindModifier && suggestion.kindModifier.has(CompletionItemKindModifier.Deprecated)) {
labelOptions.extraClasses = (labelOptions.extraClasses || []).concat(['suggest-widget-deprecated']); labelOptions.extraClasses = (labelOptions.extraClasses || []).concat(['deprecated']);
labelOptions.matches = [];
} }
data.iconLabel.setLabel(suggestion.label, undefined, labelOptions); data.iconLabel.setLabel(suggestion.label, undefined, labelOptions);
@@ -565,6 +565,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages {
CompletionItemKindModifier: standaloneEnums.CompletionItemKindModifier, CompletionItemKindModifier: standaloneEnums.CompletionItemKindModifier,
CompletionItemInsertTextRule: standaloneEnums.CompletionItemInsertTextRule, CompletionItemInsertTextRule: standaloneEnums.CompletionItemInsertTextRule,
SymbolKind: standaloneEnums.SymbolKind, SymbolKind: standaloneEnums.SymbolKind,
SymbolKindTag: standaloneEnums.SymbolKindTag,
IndentAction: standaloneEnums.IndentAction, IndentAction: standaloneEnums.IndentAction,
CompletionTriggerKind: standaloneEnums.CompletionTriggerKind, CompletionTriggerKind: standaloneEnums.CompletionTriggerKind,
SignatureHelpTriggerKind: standaloneEnums.SignatureHelpTriggerKind, 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 * A modifier to the `kind` which affect how the item
* is rendered, e.g. Deprecated is rendered with a strikeout * is rendered, e.g. Deprecated is rendered with a strikeout
*/ */
kindModifier?: CompletionItemKindModifier; kindModifier?: Set<CompletionItemKindModifier>;
/** /**
* A human-readable string with additional information * A human-readable string with additional information
* about this item, like type or symbol information. * about this item, like type or symbol information.
@@ -5236,10 +5236,15 @@ declare namespace monaco.languages {
TypeParameter = 25 TypeParameter = 25
} }
export enum SymbolKindTag {
Deprecated = 1
}
export interface DocumentSymbol { export interface DocumentSymbol {
name: string; name: string;
detail: string; detail: string;
kind: SymbolKind; kind: SymbolKind;
kindTags: SymbolKindTag[];
containerName?: string; containerName?: string;
range: IRange; range: IRange;
selectionRange: IRange; selectionRange: IRange;
@@ -50,6 +50,7 @@ export interface IProgressOptions {
source?: string; source?: string;
total?: number; total?: number;
cancellable?: boolean; cancellable?: boolean;
buttons?: string[];
} }
export interface IProgressNotificationOptions extends IProgressOptions { 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 { RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { isPromiseCanceledError } from 'vs/base/common/errors'; import { isPromiseCanceledError } from 'vs/base/common/errors';
import { ISignService } from 'vs/platform/sign/common/sign'; import { ISignService } from 'vs/platform/sign/common/sign';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
export const enum ConnectionType { export const enum ConnectionType {
Management = 1, Management = 1,
@@ -245,9 +246,15 @@ export async function connectRemoteAgentTunnel(options: IConnectionOptions, tunn
return protocol; return protocol;
} }
function sleep(seconds: number): Promise<void> { function sleep(seconds: number): CancelablePromise<void> {
return new Promise<void>((resolve, reject) => { return createCancelablePromise(token => {
setTimeout(resolve, seconds * 1000); 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 { export class ReconnectionWaitEvent {
public readonly type = PersistentConnectionEventType.ReconnectionWait; public readonly type = PersistentConnectionEventType.ReconnectionWait;
constructor( constructor(
public readonly durationSeconds: number public readonly durationSeconds: number,
private readonly cancellableTimer: CancelablePromise<void>
) { } ) { }
public skipWait(): void {
this.cancellableTimer.cancel();
}
} }
export class ReconnectionRunningEvent { export class ReconnectionRunningEvent {
public readonly type = PersistentConnectionEventType.ReconnectionRunning; public readonly type = PersistentConnectionEventType.ReconnectionRunning;
@@ -330,8 +342,12 @@ abstract class PersistentConnection extends Disposable {
attempt++; attempt++;
const waitTime = (attempt < TIMES.length ? TIMES[attempt] : TIMES[TIMES.length - 1]); const waitTime = (attempt < TIMES.length ? TIMES[attempt] : TIMES[TIMES.length - 1]);
try { try {
this._onDidStateChange.fire(new ReconnectionWaitEvent(waitTime)); const sleepPromise = sleep(waitTime);
await 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 // connection was lost, let's try to re-establish it
this._onDidStateChange.fire(new ReconnectionRunningEvent()); 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. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable } from 'vs/base/common/lifecycle'; import { IDisposable } from 'vs/base/common/lifecycle';
export const IURLService = createDecorator<IURLService>('urlService'); export const IURLService = createDecorator<IURLService>('urlService');
@@ -14,8 +14,17 @@ export interface IURLHandler {
} }
export interface IURLService { 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>; open(url: URI): Promise<boolean>;
registerHandler(handler: IURLHandler): IDisposable; registerHandler(handler: IURLHandler): IDisposable;
} }
+6 -4
View File
@@ -4,18 +4,20 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; 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, toDisposable } from 'vs/base/common/lifecycle';
import { first } from 'vs/base/common/async';
import { values } from 'vs/base/common/map'; 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'; import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
export class URLService implements IURLService { export abstract class AbstractURLService extends Disposable implements IURLService {
_serviceBrand!: ServiceIdentifier<any>; _serviceBrand!: ServiceIdentifier<any>;
private handlers = new Set<IURLHandler>(); private handlers = new Set<IURLHandler>();
abstract create(options?: Partial<UriComponents>): URI;
open(uri: URI): Promise<boolean> { open(uri: URI): Promise<boolean> {
const handlers = values(this.handlers); const handlers = values(this.handlers);
return first(handlers.map(h => () => h.handleURL(uri)), undefined, false).then(val => val || false); 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 { 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 { IDisposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
@@ -39,6 +39,10 @@ export class URLServiceChannelClient implements IURLService {
registerHandler(handler: IURLHandler): IDisposable { registerHandler(handler: IURLHandler): IDisposable {
throw new Error('Not implemented.'); throw new Error('Not implemented.');
} }
create(_options?: Partial<UriComponents>): URI {
throw new Error('Method not implemented.');
}
} }
export class URLHandlerChannel implements IServerChannel { 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. * Whether to show collapse all action or not.
*/ */
showCollapseAll?: boolean; 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. * 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. * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification.
* ```typescript * ```typescript
* const writeEmitter = new vscode.EventEmitter<string>(); * const writeEmitter = new vscode.EventEmitter<string>();
@@ -899,7 +904,7 @@ declare module 'vscode' {
* }; * };
* vscode.window.createTerminal({ name: 'Exit example', pty }); * 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. * 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); 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 //#endregion
//#region CustomExecution //#region CustomExecution
@@ -1142,13 +1138,64 @@ declare module 'vscode' {
//#endregion //#endregion
//#region Deprecated support //#region Joh - CompletionItemKindModifier, https://github.com/microsoft/vscode/issues/23927
export enum CompletionItemKindModifier {
Deprecated = 1
}
export interface CompletionItem { 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 //#endregion
@@ -21,6 +21,7 @@ import { Selection } from 'vs/editor/common/core/selection';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { mixin } from 'vs/base/common/objects'; import { mixin } from 'vs/base/common/objects';
import { fromArray } from 'vs/base/common/map';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures) @extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape { export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
@@ -330,7 +331,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return { return {
label: data.a, label: data.a,
kind: data.b, kind: data.b,
kindModifier: data.n ? modes.CompletionItemKindModifier.Deprecated : undefined, kindModifier: data.n && fromArray(data.n),
detail: data.c, detail: data.c,
documentation: data.d, documentation: data.d,
sortText: data.e, 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 { ExtHostContext, IExtHostContext, MainContext, MainThreadUrlsShape, ExtHostUrlsShape } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from '../common/extHostCustomers'; import { extHostNamedCustomer } from '../common/extHostCustomers';
import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; 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 { IDisposable } from 'vs/base/common/lifecycle';
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler'; import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
@@ -68,6 +68,16 @@ export class MainThreadUrls implements MainThreadUrlsShape {
return Promise.resolve(undefined); 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 { dispose(): void {
this.handlers.forEach(({ disposable }) => disposable.dispose()); this.handlers.forEach(({ disposable }) => disposable.dispose());
this.handlers.clear(); this.handlers.clear();
+30 -24
View File
@@ -73,14 +73,6 @@ export interface IExtensionApiFactory {
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; (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 * 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> => { return extHostCommands.registerCommand(true, id, async (...args: any[]): Promise<any> => {
const activeTextEditor = extHostEditors.getActiveTextEditor(); const activeTextEditor = extHostEditors.getActiveTextEditor();
if (!activeTextEditor) { if (!activeTextEditor) {
@@ -219,7 +212,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const diff = await extHostEditors.getDiffInformation(activeTextEditor.id); const diff = await extHostEditors.getDiffInformation(activeTextEditor.id);
callback.apply(thisArg, [diff, ...args]); callback.apply(thisArg, [diff, ...args]);
}); });
}), },
executeCommand<T>(id: string, ...args: any[]): Thenable<T> { executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
return extHostCommands.executeCommand<T>(id, ...args); return extHostCommands.executeCommand<T>(id, ...args);
}, },
@@ -236,6 +229,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get appName() { return initData.environment.appName; }, get appName() { return initData.environment.appName; },
get appRoot() { return initData.environment.appRoot!.fsPath; }, get appRoot() { return initData.environment.appRoot!.fsPath; },
get uriScheme() { return initData.environment.appUriScheme; }, get uriScheme() { return initData.environment.appUriScheme; },
createAppUri(options?) {
checkProposedApiEnabled(extension);
return extHostUrls.createAppUri(extension.identifier, options);
},
get logLevel() { get logLevel() {
checkProposedApiEnabled(extension); checkProposedApiEnabled(extension);
return typeConverters.LogLevel.to(extHostLogService.getLevel()); return typeConverters.LogLevel.to(extHostLogService.getLevel());
@@ -531,9 +528,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => { registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
return extHostWebviews.registerWebviewPanelSerializer(viewType, serializer); return extHostWebviews.registerWebviewPanelSerializer(viewType, serializer);
}, },
registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider) => { registerDecorationProvider(provider: vscode.DecorationProvider) {
checkProposedApiEnabled(extension);
return extHostDecorations.registerDecorationProvider(provider, extension.identifier); return extHostDecorations.registerDecorationProvider(provider, extension.identifier);
}), },
registerUriHandler(handler: vscode.UriHandler) { registerUriHandler(handler: vscode.UriHandler) {
return extHostUrls.registerUriHandler(extension.identifier, handler); return extHostUrls.registerUriHandler(extension.identifier, handler);
}, },
@@ -548,6 +546,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// namespace: workspace // namespace: workspace
const workspace: typeof vscode.workspace = { const workspace: typeof vscode.workspace = {
get rootPath() { 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(); return extHostWorkspace.getPath();
}, },
set rootPath(value) { set rootPath(value) {
@@ -668,24 +667,30 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get fs() { get fs() {
return extHostFileSystem.fileSystem; return extHostFileSystem.fileSystem;
}, },
registerFileSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.FileSearchProvider) => { registerFileSearchProvider: (scheme: string, provider: vscode.FileSearchProvider) => {
checkProposedApiEnabled(extension);
return extHostSearch.registerFileSearchProvider(scheme, provider); 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); 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); return extensionService.registerRemoteAuthorityResolver(authorityPrefix, resolver);
}), },
registerResourceLabelFormatter: proposedApiFunction(extension, (formatter: vscode.ResourceLabelFormatter) => { registerResourceLabelFormatter: (formatter: vscode.ResourceLabelFormatter) => {
checkProposedApiEnabled(extension);
return extHostLabelService.$registerResourceLabelFormatter(formatter); 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); 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); return extHostFileSystemEvent.getOnWillRenameFileEvent(extension)(listener, thisArg, disposables);
}) }
}; };
// namespace: scm // namespace: scm
@@ -810,6 +815,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
CommentMode: extHostTypes.CommentMode, CommentMode: extHostTypes.CommentMode,
CompletionItem: extHostTypes.CompletionItem, CompletionItem: extHostTypes.CompletionItem,
CompletionItemKind: extHostTypes.CompletionItemKind, CompletionItemKind: extHostTypes.CompletionItemKind,
CompletionItemKindModifier: extHostTypes.CompletionItemKindModifier,
CompletionList: extHostTypes.CompletionList, CompletionList: extHostTypes.CompletionList,
CompletionTriggerKind: extHostTypes.CompletionTriggerKind, CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
ConfigurationTarget: extHostTypes.ConfigurationTarget, ConfigurationTarget: extHostTypes.ConfigurationTarget,
@@ -571,6 +571,7 @@ export interface ExtHostWebviewsShape {
export interface MainThreadUrlsShape extends IDisposable { export interface MainThreadUrlsShape extends IDisposable {
$registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise<void>; $registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise<void>;
$unregisterUriHandler(handle: number): Promise<void>; $unregisterUriHandler(handle: number): Promise<void>;
$createAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial<UriComponents> }): Promise<UriComponents>;
} }
export interface ExtHostUrlsShape { export interface ExtHostUrlsShape {
@@ -939,7 +940,7 @@ export interface ISuggestDataDto {
k/* commitCharacters */?: string[]; k/* commitCharacters */?: string[];
l/* additionalTextEdits */?: ISingleEditOperation[]; l/* additionalTextEdits */?: ISingleEditOperation[];
m/* command */?: modes.Command; m/* command */?: modes.Command;
n/* deprecated */?: boolean; n/* kindModifier */?: modes.CompletionItemKindModifier[];
// not-standard // not-standard
x?: ChainedCacheId; x?: ChainedCacheId;
} }
@@ -70,6 +70,7 @@ class DocumentSymbolAdapter {
const element = <modes.DocumentSymbol>{ const element = <modes.DocumentSymbol>{
name: info.name || '!!MISSING: name!!', name: info.name || '!!MISSING: name!!',
kind: typeConvert.SymbolKind.from(info.kind), kind: typeConvert.SymbolKind.from(info.kind),
kindTags: [],
detail: undefined!, // Strict null override — avoid changing behavior detail: undefined!, // Strict null override — avoid changing behavior
containerName: info.containerName, containerName: info.containerName,
range: typeConvert.Range.from(info.location.range), range: typeConvert.Range.from(info.location.range),
@@ -736,9 +737,14 @@ class SuggestAdapter {
k: item.commitCharacters, k: item.commitCharacters,
l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from), l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
m: this._commands.toInternal(item.command, disposables), 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 // 'insertText'-logic
if (item.textEdit) { if (item.textEdit) {
result.h = item.textEdit.newText; result.h = item.textEdit.newText;
@@ -198,7 +198,7 @@ export class ExtHostTreeView<T> extends Disposable {
private refreshPromise: Promise<void> = Promise.resolve(); private refreshPromise: Promise<void> = Promise.resolve();
private refreshQueue: 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(); super();
this.dataProvider = options.treeDataProvider; this.dataProvider = options.treeDataProvider;
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
@@ -582,7 +582,8 @@ export namespace DocumentSymbol {
detail: info.detail, detail: info.detail,
range: Range.from(info.range), range: Range.from(info.range),
selectionRange: Range.from(info.selectionRange), selectionRange: Range.from(info.selectionRange),
kind: SymbolKind.from(info.kind) kind: SymbolKind.from(info.kind),
kindTags: []
}; };
if (info.children) { if (info.children) {
result.children = info.children.map(from); 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 namespace CompletionItemKind {
export function from(kind: types.CompletionItemKind | undefined): modes.CompletionItemKind { export function from(kind: types.CompletionItemKind | undefined): modes.CompletionItemKind {
@@ -1308,11 +1308,16 @@ export enum CompletionItemKind {
TypeParameter = 24 TypeParameter = 24
} }
export enum CompletionItemKindModifier {
Deprecated = 1,
}
@es5ClassCompat @es5ClassCompat
export class CompletionItem implements vscode.CompletionItem { export class CompletionItem implements vscode.CompletionItem {
label: string; label: string;
kind?: CompletionItemKind; kind?: CompletionItemKind;
kind2?: CompletionItemKind | { base: CompletionItemKind, modifier: CompletionItemKindModifier[] };
detail?: string; detail?: string;
documentation?: string | MarkdownString; documentation?: string | MarkdownString;
sortText?: string; sortText?: string;
@@ -55,4 +55,8 @@ export class ExtHostUrls implements ExtHostUrlsShape {
return Promise.resolve(undefined); 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 // Attach the listeners
this._pty.onDidWrite(e => this._onProcessData.fire(e)); this._pty.onDidWrite(e => this._onProcessData.fire(e));
if (this._pty.onDidClose) { 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) { 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 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. // To properly reset line numbers we need to read the configuration for each editor respecting it's uri.
if (!lineNumbers && isCodeEditor(editor) && editor.hasModel()) { if (!lineNumbers && isCodeEditor(editor) && editor.hasModel()) {
const model = editor.getModel(); const model = editor.getModel();
this.configurationService.getValue('editor.lineNumbers', { resource: model.uri }); lineNumbers = this.configurationService.getValue('editor.lineNumbers', { resource: model.uri });
} else {
editor.updateOptions({ lineNumbers });
} }
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 // 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; this.disposed = true;
} }
} }
@@ -999,7 +999,7 @@ export class ChangeModeAction extends Action {
private configureFileAssociation(resource: URI): void { private configureFileAssociation(resource: URI): void {
const extension = extname(resource); const extension = extname(resource);
const base = basename(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 languages = this.modeService.getRegisteredLanguageNames();
const picks: IQuickPickItem[] = languages.sort().map((lang, index) => { const picks: IQuickPickItem[] = languages.sort().map((lang, index) => {
+17 -5
View File
@@ -6,7 +6,7 @@
import { mark } from 'vs/base/common/performance'; import { mark } from 'vs/base/common/performance';
import { domContentLoaded, addDisposableListener, EventType, addClass } from 'vs/base/browser/dom'; import { domContentLoaded, addDisposableListener, EventType, addClass } from 'vs/base/browser/dom';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; 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 { Disposable } from 'vs/base/common/lifecycle';
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
import { Workbench } from 'vs/workbench/browser/workbench'; 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 { BufferLogService } from 'vs/platform/log/common/bufferLog';
import { FileLogService } from 'vs/platform/log/common/fileLogService'; import { FileLogService } from 'vs/platform/log/common/fileLogService';
import { toLocalISOString } from 'vs/base/common/date'; 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 { class CodeRendererMain extends Disposable {
@@ -120,7 +121,7 @@ class CodeRendererMain extends Disposable {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Log // 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(); const logService = new BufferLogService();
serviceCollection.set(ILogService, logService); serviceCollection.set(ILogService, logService);
@@ -151,8 +152,19 @@ class CodeRendererMain extends Disposable {
serviceCollection.set(IFileService, fileService); serviceCollection.set(IFileService, fileService);
// Logger // Logger
fileService.registerProvider(INDEXEDDB_LOG_SCHEME, new IndexedDBLogProvider()); const indexedDBLogProvider = new IndexedDBLogProvider(logsPath.scheme);
logService.logger = new FileLogService('window', environmentService.logFile, logService.getLevel(), fileService); 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 // Static Extensions
const staticExtensions = new StaticExtensionsService(this.configuration.staticExtensions || []); 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 * as browser from 'vs/base/browser/browser';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { Event } from 'vs/base/common/event'; 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 { 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 { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IUpdateService, State } from 'vs/platform/update/common/update'; import { IUpdateService, State } from 'vs/platform/update/common/update';
import { IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IURIToOpen, IMessageBoxResult, IWindowsService, IOpenSettings, IWindowSettings } from 'vs/platform/windows/common/windows'; 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 { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { ITunnelService } from 'vs/platform/remote/common/tunnel'; 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 { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { addDisposableListener, EventType, windowOpenNoOpener } from 'vs/base/browser/dom'; import { addDisposableListener, EventType, windowOpenNoOpener } from 'vs/base/browser/dom';
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService'; 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 // tslint:disable-next-line: import-patterns
import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats'; 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 //#region Update
export class SimpleUpdateService implements IUpdateService { export class SimpleUpdateService implements IUpdateService {
@@ -95,24 +68,6 @@ registerSingleton(IUpdateService, SimpleUpdateService);
//#endregion //#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 //#region Window
export class SimpleWindowService extends Disposable implements IWindowService { export class SimpleWindowService extends Disposable implements IWindowService {
@@ -590,7 +590,12 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
constructor(private debugService: IDebugService) { } constructor(private debugService: IDebugService) { }
hasChildren(element: IDebugModel | CallStackItem): boolean { 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[]> { async getChildren(element: IDebugModel | CallStackItem): Promise<CallStackItem[]> {
@@ -236,16 +236,18 @@ export class Debugger implements IDebugger {
}; };
properties['preLaunchTask'] = { properties['preLaunchTask'] = {
anyOf: [taskSchema, { anyOf: [taskSchema, {
type: ['string', 'null'], type: ['string']
}], }],
default: '', default: '',
defaultSnippets: [{ body: { task: '', type: '' } }],
description: nls.localize('debugPrelaunchTask', "Task to run before debug session starts.") description: nls.localize('debugPrelaunchTask', "Task to run before debug session starts.")
}; };
properties['postDebugTask'] = { properties['postDebugTask'] = {
anyOf: [taskSchema, { anyOf: [taskSchema, {
type: ['string', 'null'], type: ['string'],
}], }],
default: '', default: '',
defaultSnippets: [{ body: { task: '', type: '' } }],
description: nls.localize('debugPostDebugTask', "Task to run after debug session ends.") description: nls.localize('debugPostDebugTask', "Task to run after debug session ends.")
}; };
properties['internalConsoleOptions'] = INTERNAL_CONSOLE_OPTIONS_SCHEMA; 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 { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { Emitter } from 'vs/base/common/event'; import { Emitter } from 'vs/base/common/event';
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test'; import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
import { URLService } from 'vs/platform/url/common/urlService'; import { URLService } from 'vs/platform/url/node/urlService';
import { IURLService } from 'vs/platform/url/common/url'; import { IURLService } from 'vs/platform/url/common/url';
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; 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 { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { ILogService, NullLogService } from 'vs/platform/log/common/log';
import { IWindowService } from 'vs/platform/windows/common/windows'; 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 { URI } from 'vs/base/common/uri';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; 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 { IModelService } from 'vs/editor/common/services/modelService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { INotificationService, Severity, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification'; 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 { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test'; import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; 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 { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { ILogService, NullLogService } from 'vs/platform/log/common/log';
import { IWindowService } from 'vs/platform/windows/common/windows'; 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 { URI } from 'vs/base/common/uri';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { SinonStub } from 'sinon'; 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 { IProgressService } from 'vs/platform/progress/common/progress';
import { ProgressService } from 'vs/workbench/services/progress/browser/progressService'; import { ProgressService } from 'vs/workbench/services/progress/browser/progressService';
import { INotificationService } from 'vs/platform/notification/common/notification'; 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 { URI } from 'vs/base/common/uri';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { ExtensionType } from 'vs/platform/extensions/common/extensions';
@@ -22,7 +22,7 @@ export class LogsDataCleaner extends Disposable {
} }
private cleanUpOldLogsSoon(): void { private cleanUpOldLogsSoon(): void {
let handle: NodeJS.Timeout | undefined = setTimeout(async () => { let handle: any = setTimeout(async () => {
handle = undefined; handle = undefined;
const logsPath = URI.file(this.environmentService.logsPath).with({ scheme: this.environmentService.logFile.scheme }); const logsPath = URI.file(this.environmentService.logsPath).with({ scheme: this.environmentService.logFile.scheme });
const stat = await this.fileService.resolve(dirname(logsPath)); const stat = await this.fileService.resolve(dirname(logsPath));
@@ -369,6 +369,10 @@
margin-top: -1px; margin-top: -1px;
z-index: 1; 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 { .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-text .setting-item-validation-message {
width: 500px; width: 500px;
@@ -224,8 +224,9 @@ interface ISettingComplexItemTemplate extends ISettingItemTemplate<void> {
button: Button; button: Button;
} }
interface ISettingListItemTemplate extends ISettingItemTemplate<void> { interface ISettingListItemTemplate extends ISettingItemTemplate<string[] | undefined> {
listWidget: ListSettingWidget; listWidget: ListSettingWidget;
validationErrorMessageElement: HTMLElement;
} }
interface ISettingExcludeItemTemplate extends ISettingItemTemplate<void> { interface ISettingExcludeItemTemplate extends ISettingItemTemplate<void> {
@@ -679,6 +680,9 @@ export class SettingArrayRenderer extends AbstractSettingRenderer implements ITr
renderTemplate(container: HTMLElement): ISettingListItemTemplate { renderTemplate(container: HTMLElement): ISettingListItemTemplate {
const common = this.renderCommonTemplate(null, container, 'list'); 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); const listWidget = this._instantiationService.createInstance(ListSettingWidget, common.controlElement);
listWidget.domNode.classList.add(AbstractSettingRenderer.CONTROL_CLASS); listWidget.domNode.classList.add(AbstractSettingRenderer.CONTROL_CLASS);
@@ -686,19 +690,40 @@ export class SettingArrayRenderer extends AbstractSettingRenderer implements ITr
const template: ISettingListItemTemplate = { const template: ISettingListItemTemplate = {
...common, ...common,
listWidget listWidget,
validationErrorMessageElement
}; };
this.addSettingElementFocusHandler(template); 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; 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) { if (template.context) {
let newValue: any[] = []; let newValue: string[] = [];
if (isArray(template.context.scopeValue)) { if (isArray(template.context.scopeValue)) {
newValue = [...template.context.scopeValue]; newValue = [...template.context.scopeValue];
} else if (isArray(template.context.value)) { } 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.length === newValue.length &&
template.context.defaultValue.join() === newValue.join() template.context.defaultValue.join() === newValue.join()
) { ) {
return this._onDidChangeSetting.fire({ return undefined;
key: template.context.setting.key,
value: undefined, // reset setting
type: template.context.valueType
});
} }
this._onDidChangeSetting.fire({ return newValue;
key: template.context.setting.key,
value: newValue,
type: template.context.valueType
});
} }
return undefined;
} }
renderElement(element: ITreeNode<SettingsTreeSettingElement, never>, index: number, templateData: ISettingListItemTemplate): void { renderElement(element: ITreeNode<SettingsTreeSettingElement, never>, index: number, templateData: ISettingListItemTemplate): void {
super.renderSettingElement(element, index, templateData); 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); const value = getListDisplayValue(dataElement);
template.listWidget.setValue(value); template.listWidget.setValue(value);
template.context = dataElement; 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'); 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 { function cleanRenderedMarkdown(element: Node): void {
for (let i = 0; i < element.childNodes.length; i++) { for (let i = 0; i < element.childNodes.length; i++) {
const child = element.childNodes.item(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 { IDiagnosticInfoOptions, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IProgressService, IProgress, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress'; 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 { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import Severity from 'vs/base/common/severity'; import Severity from 'vs/base/common/severity';
@@ -315,7 +315,58 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
if (connection) { if (connection) {
let currentProgressPromiseResolve: (() => void) | null = null; let currentProgressPromiseResolve: (() => void) | null = null;
let progressReporter: ProgressReporter | null = null; let progressReporter: ProgressReporter | null = null;
let lastLocation: ProgressLocation | null = null;
let currentTimer: ReconnectionTimer | 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) => { connection.onDidStateChange((e) => {
if (currentTimer) { if (currentTimer) {
@@ -325,31 +376,24 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
switch (e.type) { switch (e.type) {
case PersistentConnectionEventType.ConnectionLost: case PersistentConnectionEventType.ConnectionLost:
if (!currentProgressPromiseResolve) { if (!currentProgressPromiseResolve) {
let promise = new Promise<void>((resolve) => currentProgressPromiseResolve = resolve); showProgress(ProgressLocation.Dialog, [nls.localize('reconnectNow', "Reconnect Now")]);
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();
}
);
} }
progressReporter!.report(nls.localize('connectionLost', "Connection Lost")); progressReporter!.report(nls.localize('connectionLost', "Connection Lost"));
break; break;
case PersistentConnectionEventType.ReconnectionWait: case PersistentConnectionEventType.ReconnectionWait:
hideProgress();
reconnectWaitEvent = e;
showProgress(lastLocation || ProgressLocation.Notification, [nls.localize('reconnectNow', "Reconnect Now")]);
currentTimer = new ReconnectionTimer(progressReporter!, Date.now() + 1000 * e.durationSeconds); currentTimer = new ReconnectionTimer(progressReporter!, Date.now() + 1000 * e.durationSeconds);
break; break;
case PersistentConnectionEventType.ReconnectionRunning: case PersistentConnectionEventType.ReconnectionRunning:
hideProgress();
showProgress(lastLocation || ProgressLocation.Notification);
progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect...")); progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect..."));
break; break;
case PersistentConnectionEventType.ReconnectionPermanentFailure: case PersistentConnectionEventType.ReconnectionPermanentFailure:
currentProgressPromiseResolve!(); hideProgress();
currentProgressPromiseResolve = null;
progressReporter = null;
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 => { 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 // Reload the window
@@ -359,9 +403,7 @@ class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
}); });
break; break;
case PersistentConnectionEventType.ConnectionGain: case PersistentConnectionEventType.ConnectionGain:
currentProgressPromiseResolve!(); hideProgress();
currentProgressPromiseResolve = null;
progressReporter = null;
break; break;
} }
}); });
@@ -147,8 +147,10 @@ export class WorkspaceStats implements IWorkbenchContribution {
@ISharedProcessService private readonly sharedProcessService: ISharedProcessService, @ISharedProcessService private readonly sharedProcessService: ISharedProcessService,
@IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService @IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService
) { ) {
if (this.telemetryService.isOptedIn) {
this.report(); this.report();
} }
}
private report(): void { private report(): void {
@@ -44,6 +44,7 @@ import { Schemas } from 'vs/base/common/network';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { env as processEnv, cwd as processCwd } from 'vs/base/common/process';
interface TerminalData { interface TerminalData {
terminal: ITerminalInstance; terminal: ITerminalInstance;
@@ -339,7 +340,9 @@ export class TerminalTaskSystem implements ITaskSystem {
private async executeTask(task: Task, resolver: ITaskResolver, trigger: string): Promise<ITaskSummary> { private async executeTask(task: Task, resolver: ITaskResolver, trigger: string): Promise<ITaskSummary> {
let promises: Promise<ITaskSummary>[] = []; let promises: Promise<ITaskSummary>[] = [];
if (task.configurationProperties.dependsOn) { 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!); let dependencyTask = resolver.resolve(dependency.workspaceFolder, dependency.task!);
if (dependencyTask) { if (dependencyTask) {
let key = dependencyTask.getMapKey(); let key = dependencyTask.getMapKey();
@@ -1374,7 +1377,7 @@ export class TerminalTaskSystem implements ITaskSystem {
return command; return command;
} }
if (cwd === undefined) { if (cwd === undefined) {
cwd = process.cwd(); cwd = processCwd();
} }
const dir = path.dirname(command); const dir = path.dirname(command);
if (dir !== '.') { if (dir !== '.') {
@@ -1382,8 +1385,8 @@ export class TerminalTaskSystem implements ITaskSystem {
// to the current working directory. // to the current working directory.
return path.join(cwd, command); return path.join(cwd, command);
} }
if (paths === undefined && Types.isString(process.env.PATH)) { if (paths === undefined && Types.isString(processEnv.PATH)) {
paths = process.env.PATH.split(path.delimiter); paths = processEnv.PATH.split(path.delimiter);
} }
// No PATH environment. Make path absolute to the cwd. // No PATH environment. Make path absolute to the cwd.
if (paths === undefined || paths.length === 0) { if (paths === undefined || paths.length === 0) {
@@ -985,14 +985,15 @@ export namespace KeyedTaskIdentifier {
function sortedStringify(literal: any): string { function sortedStringify(literal: any): string {
const keys = Object.keys(literal).sort(); const keys = Object.keys(literal).sort();
let result: string = ''; let result: string = '';
for (const position of keys) { // {{SQL CARBON EDIT}} change to of for linting // tslint:disable-next-line: no-for-in-array
let stringified = literal[position]; for (let position in keys) {
let stringified = literal[keys[position]];
if (stringified instanceof Object) { if (stringified instanceof Object) {
stringified = sortedStringify(stringified); stringified = sortedStringify(stringified);
} else if (typeof stringified === 'string') { } else if (typeof stringified === 'string') {
stringified = stringified.replace(/,/g, ',,'); stringified = stringified.replace(/,/g, ',,');
} }
result += position + ',' + stringified + ','; result += keys[position] + ',' + stringified + ',';
} }
return result; return result;
} }
@@ -72,17 +72,17 @@ configurationRegistry.registerConfiguration({
type: 'object', type: 'object',
properties: { properties: {
'terminal.integrated.automationShell.linux': { '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'], type: ['string', 'null'],
default: null default: null
}, },
'terminal.integrated.automationShell.osx': { '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'], type: ['string', 'null'],
default: null default: null
}, },
'terminal.integrated.automationShell.windows': { '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'], type: ['string', 'null'],
default: null default: null
}, },
@@ -530,6 +530,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNe
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find next', category); }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find next', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, { actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, {
primary: KeyCode.F3, primary: KeyCode.F3,
secondary: [KeyMod.Shift | KeyCode.Enter],
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3, 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'); }, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find next');
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID_TERMINAL_FOCUS, FindPrevious.LABEL, { 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); }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find previous', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, { actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, {
primary: KeyMod.Shift | KeyCode.F3, primary: KeyMod.Shift | KeyCode.F3,
secondary: [KeyCode.Enter],
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3, 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'); }, 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 // 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 // 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. // 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(); this._onCursorMove();
return false; return false;
}); });
@@ -865,7 +865,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
return; return;
} }
this.focus(); this.focus();
this._xterm._core._coreService.triggerDataEvent(await this._clipboardService.readText(), true); this._xterm.paste(await this._clipboardService.readText());
} }
public write(text: string): void { 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. * 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; createInstance(container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance;
getInstanceFromId(terminalId: number): ITerminalInstance | undefined; getInstanceFromId(terminalId: number): ITerminalInstance | undefined;
getInstanceFromIndex(terminalIndex: number): ITerminalInstance; getInstanceFromIndex(terminalIndex: number): ITerminalInstance;
@@ -279,6 +280,7 @@ export interface ITerminalService {
selectDefaultWindowsShell(): Promise<void>; selectDefaultWindowsShell(): Promise<void>;
// tslint:disable-next-line: no-dom-globals
setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
manageWorkspaceShellPermissions(): void; manageWorkspaceShellPermissions(): void;
@@ -337,6 +339,7 @@ export interface ITerminalTab {
focusNextPane(): void; focusNextPane(): void;
resizePane(direction: Direction): void; resizePane(direction: Direction): void;
setActiveInstanceByIndex(index: number): void; setActiveInstanceByIndex(index: number): void;
// tslint:disable-next-line: no-dom-globals
attachToElement(element: HTMLElement): void; attachToElement(element: HTMLElement): void;
setVisible(visible: boolean): void; setVisible(visible: boolean): void;
layout(width: number, height: number): void; layout(width: number, height: number): void;
@@ -611,6 +614,7 @@ export interface ITerminalInstance {
* *
* @param container The element to attach the terminal instance to. * @param container The element to attach the terminal instance to.
*/ */
// tslint:disable-next-line: no-dom-globals
attachToElement(container: HTMLElement): void; attachToElement(container: HTMLElement): void;
/** /**
@@ -122,7 +122,9 @@ export abstract class TerminalService implements ITerminalService {
protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void; protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void;
public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
// tslint:disable-next-line: no-dom-globals
public abstract createInstance(container: HTMLElement, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; public abstract createInstance(container: HTMLElement, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance;
// tslint:disable-next-line: no-dom-globals
public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
public getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance { public getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance {
@@ -50,14 +50,17 @@ Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions).registe
localize('developer', 'Developer') 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 ( const configureTrustedDomainsHandler = async (
quickInputService: IQuickInputService, quickInputService: IQuickInputService,
storageService: IStorageService, storageService: IStorageService,
domainToConfigure?: string domainToConfigure?: string
) => { ) => {
let trustedDomains: string[] = [VSCODE_DOMAIN]; let trustedDomains: string[] = DEAFULT_TRUSTED_DOMAINS;
try { try {
const trustedDomainsSrc = storageService.get('http.trustedDomains', StorageScope.GLOBAL); const trustedDomainsSrc = storageService.get('http.trustedDomains', StorageScope.GLOBAL);
@@ -158,7 +161,7 @@ class OpenerValidatorContributions implements IWorkbenchContribution {
return true; return true;
} }
let trustedDomains: string[] = [VSCODE_DOMAIN]; let trustedDomains: string[] = DEAFULT_TRUSTED_DOMAINS;
try { try {
const trustedDomainsSrc = this._storageService.get('http.trustedDomains', StorageScope.GLOBAL); const trustedDomainsSrc = this._storageService.get('http.trustedDomains', StorageScope.GLOBAL);
if (trustedDomainsSrc) { 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) // 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 (!targetGroup) {
if ((options && options.revealIfOpened) || this.configurationService.getValue<boolean>('workbench.editor.revealIfOpen')) { 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) { for (const group of groupsByLastActive) {
if (group.isOpened(input) && group.isActive(input)) { if (group.isOpened(input)) {
targetGroup = group; if (!groupWithInputOpened) {
break; groupWithInputOpened = group;
} }
if (group.isOpened(input) && !targetGroup) {
targetGroup = group; if (!groupWithInputActive && group.isActive(input)) {
groupWithInputActive = 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 { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { MenuRegistry } from 'vs/platform/actions/common/actions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
// tslint:disable-next-line: import-patterns
import { commandsExtensionPoint } from 'vs/workbench/api/common/menusExtensionPoint'; import { commandsExtensionPoint } from 'vs/workbench/api/common/menusExtensionPoint';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { RunOnceScheduler } from 'vs/base/common/async'; import { RunOnceScheduler } from 'vs/base/common/async';
@@ -5,23 +5,21 @@
import { KeyValueLogProvider } from 'vs/workbench/services/log/common/keyValueLogProvider'; import { KeyValueLogProvider } from 'vs/workbench/services/log/common/keyValueLogProvider';
export const INDEXEDDB_LOG_SCHEME = 'vscode-logs-indexedbd'; export const INDEXEDDB_VSCODE_DB = 'vscode-web-db';
export const INDEXEDDB_LOGS_DB = 'vscode-logs-db';
export const INDEXEDDB_LOGS_OBJECT_STORE = 'vscode-logs-store'; export const INDEXEDDB_LOGS_OBJECT_STORE = 'vscode-logs-store';
export class IndexedDBLogProvider extends KeyValueLogProvider { export class IndexedDBLogProvider extends KeyValueLogProvider {
private readonly database: Promise<IDBDatabase>; readonly database: Promise<IDBDatabase>;
constructor( constructor(scheme: string) {
) { super(scheme);
super(INDEXEDDB_LOG_SCHEME);
this.database = this.openDatabase(1); this.database = this.openDatabase(1);
} }
private openDatabase(version: number): Promise<IDBDatabase> { private openDatabase(version: number): Promise<IDBDatabase> {
return new Promise((c, e) => { 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.onerror = (err) => e(request.error);
request.onsuccess = () => { request.onsuccess = () => {
const db = request.result; const db = request.result;
@@ -6,17 +6,10 @@
import { KeyValueLogProvider } from 'vs/workbench/services/log/common/keyValueLogProvider'; import { KeyValueLogProvider } from 'vs/workbench/services/log/common/keyValueLogProvider';
import { keys } from 'vs/base/common/map'; import { keys } from 'vs/base/common/map';
export const INMEMORY_LOG_SCHEME = 'vscode-logs-inmemory';
export class InMemoryLogProvider extends KeyValueLogProvider { export class InMemoryLogProvider extends KeyValueLogProvider {
private readonly logs: Map<string, string> = new Map<string, string>(); private readonly logs: Map<string, string> = new Map<string, string>();
constructor(
) {
super(INMEMORY_LOG_SCHEME);
}
protected async getAllKeys(): Promise<string[]> { protected async getAllKeys(): Promise<string[]> {
return keys(this.logs); return keys(this.logs);
} }
@@ -1028,6 +1028,67 @@ class SettingsContentBuilder {
} }
export function createValidator(prop: IConfigurationPropertySchema): (value: any) => (string | null) { 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 => { return value => {
let exclusiveMax: number | undefined; let exclusiveMax: number | undefined;
let exclusiveMin: number | undefined; let exclusiveMin: number | undefined;
@@ -250,4 +250,82 @@ suite('Preferences Model test', () => {
withMessage.rejects(' ').withMessage('always error!'); withMessage.rejects(' ').withMessage('always error!');
withMessage.rejects('1').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(); 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; const { location } = options;
if (typeof location === 'string') { if (typeof location === 'string') {
if (this.viewletService.getProgressIndicator(location)) { 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 toDispose = new DisposableStore();
const createNotification = (message: string | undefined, increment?: number): INotificationHandle | undefined => { 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 primaryActions = options.primaryActions ? Array.from(options.primaryActions) : [];
const secondaryActions = options.secondaryActions ? Array.from(options.secondaryActions) : []; 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) { if (options.cancellable) {
const cancelAction = new class extends Action { const cancelAction = new class extends Action {
constructor() { constructor() {
@@ -182,6 +205,10 @@ export class ProgressService extends Disposable implements IProgressService {
updateProgress(handle, increment); updateProgress(handle, increment);
Event.once(handle.onDidClose)(() => { Event.once(handle.onDidClose)(() => {
if (typeof onDidCancel === 'function') {
onDidCancel();
}
toDispose.dispose(); toDispose.dispose();
}); });
@@ -317,7 +344,7 @@ export class ProgressService extends Disposable implements IProgressService {
return promise; 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 disposables = new DisposableStore();
const allowableCommands = [ const allowableCommands = [
'workbench.action.quit', 'workbench.action.quit',
@@ -327,12 +354,17 @@ export class ProgressService extends Disposable implements IProgressService {
let dialog: Dialog; let dialog: Dialog;
const createDialog = (message: string) => { const createDialog = (message: string) => {
const buttons = options.buttons || [];
buttons.push(options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss"));
dialog = new Dialog( dialog = new Dialog(
this.layoutService.container, this.layoutService.container,
message, message,
[options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")], buttons,
{ {
type: 'pending', type: 'pending',
cancelId: buttons.length - 1,
keyEventProcessor: (event: StandardKeyboardEvent) => { keyEventProcessor: (event: StandardKeyboardEvent) => {
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container); const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
if (resolved && resolved.commandId) { if (resolved && resolved.commandId) {
@@ -347,9 +379,9 @@ export class ProgressService extends Disposable implements IProgressService {
disposables.add(dialog); disposables.add(dialog);
disposables.add(attachDialogStyler(dialog, this.themeService)); disposables.add(attachDialogStyler(dialog, this.themeService));
dialog.show().then(() => { dialog.show().then((dialogResult) => {
if (typeof onDidCancel === 'function') { if (typeof onDidCancel === 'function') {
onDidCancel(); onDidCancel(dialogResult.button);
} }
dispose(dialog); 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 { URI } from 'vs/base/common/uri';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/node/urlIpc'; 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 { IOpenerService } from 'vs/platform/opener/common/opener';
import product from 'vs/platform/product/node/product'; import product from 'vs/platform/product/node/product';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class RelayURLService extends URLService implements IURLHandler { export class RelayURLService extends URLService implements IURLHandler {
@@ -43,3 +44,5 @@ export class RelayURLService extends URLService implements IURLHandler {
return super.open(uri); return super.open(uri);
} }
} }
registerSingleton(IURLService, RelayURLService);
@@ -53,6 +53,7 @@ import 'vs/workbench/browser/parts/views/views';
//#region --- workbench services //#region --- workbench services
import 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler';
import 'vs/workbench/services/bulkEdit/browser/bulkEditService'; import 'vs/workbench/services/bulkEdit/browser/bulkEditService';
import 'vs/workbench/services/keybinding/common/keybindingEditing'; import 'vs/workbench/services/keybinding/common/keybindingEditing';
import 'vs/workbench/services/decorations/browser/decorationsService'; 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/integrity/node/integrityService';
import 'vs/workbench/services/textMate/electron-browser/textMateService'; import 'vs/workbench/services/textMate/electron-browser/textMateService';
import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService'; 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/search/node/searchService';
import 'vs/workbench/services/output/node/outputChannelModelService'; import 'vs/workbench/services/output/node/outputChannelModelService';
import 'vs/workbench/services/textfile/node/textFileService'; 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/remote/node/tunnelService';
import 'vs/workbench/services/backup/node/backupFileService'; import 'vs/workbench/services/backup/node/backupFileService';
import 'vs/workbench/services/credentials/node/credentialsService'; import 'vs/workbench/services/credentials/node/credentialsService';
import 'vs/workbench/services/url/electron-browser/urlService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; 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 { WorkspacesService } from 'vs/platform/workspaces/electron-browser/workspacesService';
import { IMenubarService } from 'vs/platform/menubar/node/menubar'; import { IMenubarService } from 'vs/platform/menubar/node/menubar';
import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService'; 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'; import { StaticExtensionsService, IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
registerSingleton(IClipboardService, ClipboardService, true); registerSingleton(IClipboardService, ClipboardService, true);
@@ -85,7 +83,6 @@ registerSingleton(IUpdateService, UpdateService);
registerSingleton(IIssueService, IssueService); registerSingleton(IIssueService, IssueService);
registerSingleton(IWorkspacesService, WorkspacesService); registerSingleton(IWorkspacesService, WorkspacesService);
registerSingleton(IMenubarService, MenubarService); registerSingleton(IMenubarService, MenubarService);
registerSingleton(IURLService, RelayURLService);
registerSingleton(IStaticExtensionsService, class extends StaticExtensionsService { constructor() { super([]); } }); registerSingleton(IStaticExtensionsService, class extends StaticExtensionsService { constructor() { super([]); } });
//#endregion //#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 { IWebSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory';
import { ICredentialsProvider } from 'vs/workbench/services/credentials/browser/credentialsService'; import { ICredentialsProvider } from 'vs/workbench/services/credentials/browser/credentialsService';
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { IURLCallbackProvider } from 'vs/workbench/services/url/browser/urlService';
export interface IWorkbenchConstructionOptions { export interface IWorkbenchConstructionOptions {
@@ -65,6 +66,11 @@ export interface IWorkbenchConstructionOptions {
* Experimental: Add static extensions that cannot be uninstalled but only be disabled. * Experimental: Add static extensions that cannot be uninstalled but only be disabled.
*/ */
staticExtensions?: { packageJSON: IExtensionManifest, extensionLocation: UriComponents }[]; 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/telemetry/browser/telemetryService';
import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
import 'vs/workbench/services/credentials/browser/credentialsService'; import 'vs/workbench/services/credentials/browser/credentialsService';
import 'vs/workbench/services/url/browser/urlService';
import 'vs/workbench/browser/web.simpleservices'; import 'vs/workbench/browser/web.simpleservices';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
+9 -4
View File
@@ -220,6 +220,11 @@
dependencies: dependencies:
commander "*" commander "*"
"@types/cookie@^0.3.3":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803"
integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==
"@types/d3@^3": "@types/d3@^3":
version "3.5.42" version "3.5.42"
resolved "https://registry.yarnpkg.com/@types/d3/-/d3-3.5.42.tgz#6a782b44bb7f5c48165cb166886b5d53cb84455f" resolved "https://registry.yarnpkg.com/@types/d3/-/d3-3.5.42.tgz#6a782b44bb7f5c48165cb166886b5d53cb84455f"
@@ -10338,10 +10343,10 @@ xterm-addon-web-links@0.1.0-beta10:
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23"
integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg==
xterm@3.15.0-beta99: xterm@3.15.0-beta101:
version "3.15.0-beta99" version "3.15.0-beta101"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta99.tgz#0010a7ea5d56cbb08a1e3a525b353c96a158e7a0" resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta101.tgz#38ffa0df5a3e9bdcb1818e74fe59b2f98b0fff69"
integrity sha512-Vm0ZWToWwO4uk/28Kqvqt9L92h5EU2z4WR9I6xcQaPIBmkJPINIARU4LWQnvaOfgFhRbpwBMveTfh8/jM97lPg== integrity sha512-HRa7+FDqQ8iWBTvb1Ni+uMGILnu6k9mF7JHMHRHfWxFoQlSoGYCyfdyXlJjk68YN8GsEQREmrII6cPLiQizdEQ==
y18n@^3.2.1: y18n@^3.2.1:
version "3.2.1" version "3.2.1"