mirror of
https://github.com/coder/code-server.git
synced 2026-05-19 02:37:27 +02:00
chore(vscode): update to 1.56.0
This commit is contained in:
@@ -72,7 +72,7 @@ export class Client extends IPCClient implements IDisposable {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.protocol.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ class ProtocolReader extends Disposable {
|
||||
return this._incomingData.read(this._incomingData.byteLength);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
this._isDisposed = true;
|
||||
super.dispose();
|
||||
}
|
||||
@@ -412,7 +412,7 @@ export class Client<TContext = string> extends IPCClient<TContext> {
|
||||
super(protocol, id, ipcLogger);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
const socket = this.protocol.getSocket();
|
||||
this.protocol.sendDisconnect();
|
||||
|
||||
@@ -32,7 +32,7 @@ export class Client extends IPCClient implements IDisposable {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.protocol.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ export class WebSocketNodeSocket extends Disposable implements ISocket {
|
||||
this._register(this.socket.onClose(() => this._onClose.fire()));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
if (this._zlibDeflateFlushWaitingCount > 0) {
|
||||
// Wait for any outstanding writes to finish before disposing
|
||||
this._register(this._onDidZlibFlush.event(() => {
|
||||
@@ -581,7 +581,7 @@ export class Server extends IPCServer {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
if (this.server) {
|
||||
this.server.close();
|
||||
|
||||
@@ -66,7 +66,7 @@ class TestIPCClient extends IPCClient<string> {
|
||||
super(protocol, id);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this._onDidDisconnect.fire();
|
||||
super.dispose();
|
||||
}
|
||||
@@ -253,7 +253,7 @@ suite('Base IPC', function () {
|
||||
|
||||
test('call success', async function () {
|
||||
const r = await ipcService.marco();
|
||||
return assert.equal(r, 'polo');
|
||||
return assert.strictEqual(r, 'polo');
|
||||
});
|
||||
|
||||
test('call error', async function () {
|
||||
@@ -261,7 +261,7 @@ suite('Base IPC', function () {
|
||||
await ipcService.error('nice error');
|
||||
return assert.fail('should not reach here');
|
||||
} catch (err) {
|
||||
return assert.equal(err.message, 'nice error');
|
||||
return assert.strictEqual(err.message, 'nice error');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -304,20 +304,20 @@ suite('Base IPC', function () {
|
||||
ipcService.onPong(msg => messages.push(msg));
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, []);
|
||||
assert.deepStrictEqual(messages, []);
|
||||
service.ping('hello');
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, ['hello']);
|
||||
assert.deepStrictEqual(messages, ['hello']);
|
||||
service.ping('world');
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, ['hello', 'world']);
|
||||
assert.deepStrictEqual(messages, ['hello', 'world']);
|
||||
});
|
||||
|
||||
test('buffers in arrays', async function () {
|
||||
const r = await ipcService.buffersLength([VSBuffer.alloc(2), VSBuffer.alloc(3)]);
|
||||
return assert.equal(r, 5);
|
||||
return assert.strictEqual(r, 5);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -345,7 +345,7 @@ suite('Base IPC', function () {
|
||||
|
||||
test('call success', async function () {
|
||||
const r = await ipcService.marco();
|
||||
return assert.equal(r, 'polo');
|
||||
return assert.strictEqual(r, 'polo');
|
||||
});
|
||||
|
||||
test('call error', async function () {
|
||||
@@ -353,7 +353,7 @@ suite('Base IPC', function () {
|
||||
await ipcService.error('nice error');
|
||||
return assert.fail('should not reach here');
|
||||
} catch (err) {
|
||||
return assert.equal(err.message, 'nice error');
|
||||
return assert.strictEqual(err.message, 'nice error');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -363,15 +363,15 @@ suite('Base IPC', function () {
|
||||
ipcService.onPong(msg => messages.push(msg));
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, []);
|
||||
assert.deepStrictEqual(messages, []);
|
||||
service.ping('hello');
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, ['hello']);
|
||||
assert.deepStrictEqual(messages, ['hello']);
|
||||
service.ping('world');
|
||||
await timeout(0);
|
||||
|
||||
assert.deepEqual(messages, ['hello', 'world']);
|
||||
assert.deepStrictEqual(messages, ['hello', 'world']);
|
||||
});
|
||||
|
||||
test('marshalling uri', async function () {
|
||||
@@ -383,7 +383,7 @@ suite('Base IPC', function () {
|
||||
|
||||
test('buffers in arrays', async function () {
|
||||
const r = await ipcService.buffersLength([VSBuffer.alloc(2), VSBuffer.alloc(3)]);
|
||||
return assert.equal(r, 5);
|
||||
return assert.strictEqual(r, 5);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -411,7 +411,7 @@ suite('Base IPC', function () {
|
||||
|
||||
test('call extra context', async function () {
|
||||
const r = await ipcService.context();
|
||||
return assert.equal(r, 'Super Context');
|
||||
return assert.strictEqual(r, 'Super Context');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -461,7 +461,7 @@ suite('Base IPC', function () {
|
||||
clientService1.ping('hello 1');
|
||||
|
||||
await timeout(1);
|
||||
assert.deepEqual(pings, ['hello 1']);
|
||||
assert.deepStrictEqual(pings, ['hello 1']);
|
||||
|
||||
const client2 = server.createConnection('client2');
|
||||
const clientService2 = new TestService();
|
||||
@@ -472,19 +472,19 @@ suite('Base IPC', function () {
|
||||
clientService2.ping('hello 2');
|
||||
|
||||
await timeout(1);
|
||||
assert.deepEqual(pings, ['hello 1', 'hello 2']);
|
||||
assert.deepStrictEqual(pings, ['hello 1', 'hello 2']);
|
||||
|
||||
client1.dispose();
|
||||
clientService1.ping('hello 1');
|
||||
|
||||
await timeout(1);
|
||||
assert.deepEqual(pings, ['hello 1', 'hello 2']);
|
||||
assert.deepStrictEqual(pings, ['hello 1', 'hello 2']);
|
||||
|
||||
await timeout(1);
|
||||
clientService2.ping('hello again 2');
|
||||
|
||||
await timeout(1);
|
||||
assert.deepEqual(pings, ['hello 1', 'hello 2', 'hello again 2']);
|
||||
assert.deepStrictEqual(pings, ['hello 1', 'hello 2', 'hello again 2']);
|
||||
|
||||
client2.dispose();
|
||||
server.dispose();
|
||||
|
||||
@@ -22,8 +22,8 @@ suite('IPC, Child Process', () => {
|
||||
const service = new TestServiceClient(channel);
|
||||
|
||||
const result = service.pong('ping').then(r => {
|
||||
assert.equal(r.incoming, 'ping');
|
||||
assert.equal(r.outgoing, 'pong');
|
||||
assert.strictEqual(r.incoming, 'ping');
|
||||
assert.strictEqual(r.outgoing, 'pong');
|
||||
});
|
||||
|
||||
return result.finally(() => client.dispose());
|
||||
@@ -37,7 +37,7 @@ suite('IPC, Child Process', () => {
|
||||
const event = new Promise((c, e) => {
|
||||
service.onMarco(({ answer }) => {
|
||||
try {
|
||||
assert.equal(answer, 'polo');
|
||||
assert.strictEqual(answer, 'polo');
|
||||
c(undefined);
|
||||
} catch (err) {
|
||||
e(err);
|
||||
@@ -60,17 +60,17 @@ suite('IPC, Child Process', () => {
|
||||
const disposable = service.onMarco(() => count++);
|
||||
|
||||
const result = service.marco().then(async answer => {
|
||||
assert.equal(answer, 'polo');
|
||||
assert.equal(count, 1);
|
||||
assert.strictEqual(answer, 'polo');
|
||||
assert.strictEqual(count, 1);
|
||||
|
||||
const answer_1 = await service.marco();
|
||||
assert.equal(answer_1, 'polo');
|
||||
assert.equal(count, 2);
|
||||
assert.strictEqual(answer_1, 'polo');
|
||||
assert.strictEqual(count, 2);
|
||||
disposable.dispose();
|
||||
|
||||
const answer_2 = await service.marco();
|
||||
assert.equal(answer_2, 'polo');
|
||||
assert.equal(count, 2);
|
||||
assert.strictEqual(answer_2, 'polo');
|
||||
assert.strictEqual(count, 2);
|
||||
});
|
||||
|
||||
return result.finally(() => client.dispose());
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
.quick-input-titlebar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.quick-input-left-action-bar {
|
||||
@@ -22,10 +23,6 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.quick-input-left-action-bar.monaco-action-bar .actions-container {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.quick-input-title {
|
||||
padding: 3px 0px;
|
||||
text-align: center;
|
||||
@@ -37,12 +34,14 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.quick-input-right-action-bar > .actions-container {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.quick-input-titlebar .monaco-action-bar .action-label.codicon {
|
||||
margin: 0;
|
||||
width: 19px;
|
||||
height: 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.quick-input-description {
|
||||
@@ -260,10 +259,8 @@
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar .action-label.codicon {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
padding: 0 2px;
|
||||
vertical-align: middle;
|
||||
margin-right: 4px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar {
|
||||
@@ -274,10 +271,6 @@
|
||||
margin-right: 4px; /* separate from scrollbar */
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar .action-label.codicon {
|
||||
margin-right: 4px; /* separate actions */
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry .quick-input-list-entry-action-bar .action-label.always-visible,
|
||||
.quick-input-list .quick-input-list-entry:hover .quick-input-list-entry-action-bar .action-label,
|
||||
.quick-input-list .monaco-list-row.focused .quick-input-list-entry-action-bar .action-label {
|
||||
|
||||
@@ -32,6 +32,7 @@ import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
|
||||
import { isString } from 'vs/base/common/types';
|
||||
import { IKeybindingLabelStyles } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
|
||||
|
||||
export interface IQuickInputOptions {
|
||||
idPrefix: string;
|
||||
@@ -57,6 +58,7 @@ export interface IQuickInputStyles {
|
||||
countBadge: ICountBadgetyles;
|
||||
button: IButtonStyles;
|
||||
progressBar: IProgressBarStyles;
|
||||
keybindingLabel: IKeybindingLabelStyles;
|
||||
list: IListStyles & { pickerGroupBorder?: Color; pickerGroupForeground?: Color; };
|
||||
}
|
||||
|
||||
@@ -410,7 +412,7 @@ class QuickInput extends Disposable implements IQuickInput {
|
||||
|
||||
readonly onDispose = this.onDisposeEmitter.event;
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.hide();
|
||||
this.onDisposeEmitter.fire();
|
||||
|
||||
@@ -694,7 +696,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
}
|
||||
}
|
||||
|
||||
show() {
|
||||
override show() {
|
||||
if (!this.visible) {
|
||||
this.visibleDisposables.add(
|
||||
this.ui.inputBox.onDidChange(value => {
|
||||
@@ -884,20 +886,11 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
});
|
||||
}
|
||||
|
||||
protected update() {
|
||||
protected override update() {
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
let hideInput = false;
|
||||
let inputShownJustForScreenReader = false;
|
||||
if (!!this._hideInput && this._items.length > 0) {
|
||||
if (this.ui.isScreenReaderOptimized()) {
|
||||
// Always show input if screen reader attached https://github.com/microsoft/vscode/issues/94360
|
||||
inputShownJustForScreenReader = true;
|
||||
} else {
|
||||
hideInput = true;
|
||||
}
|
||||
}
|
||||
const hideInput = !!this._hideInput && this._items.length > 0;
|
||||
this.ui.container.classList.toggle('hidden-input', hideInput && !this.description);
|
||||
const visibilities: Visibilities = {
|
||||
title: !!this.title || !!this.step || !!this.buttons.length,
|
||||
@@ -925,13 +918,9 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
if (this.ui.inputBox.placeholder !== (this.placeholder || '')) {
|
||||
this.ui.inputBox.placeholder = (this.placeholder || '');
|
||||
}
|
||||
if (inputShownJustForScreenReader) {
|
||||
this.ui.inputBox.ariaLabel = '';
|
||||
} else {
|
||||
const ariaLabel = this.ariaLabel || this.placeholder || QuickPick.DEFAULT_ARIA_LABEL;
|
||||
if (this.ui.inputBox.ariaLabel !== ariaLabel) {
|
||||
this.ui.inputBox.ariaLabel = ariaLabel;
|
||||
}
|
||||
const ariaLabel = this.ariaLabel || this.placeholder || QuickPick.DEFAULT_ARIA_LABEL;
|
||||
if (this.ui.inputBox.ariaLabel !== ariaLabel) {
|
||||
this.ui.inputBox.ariaLabel = ariaLabel;
|
||||
}
|
||||
this.ui.list.matchOnDescription = this.matchOnDescription;
|
||||
this.ui.list.matchOnDetail = this.matchOnDetail;
|
||||
@@ -1063,7 +1052,7 @@ class InputBox extends QuickInput implements IInputBox {
|
||||
|
||||
readonly onDidAccept = this.onDidAcceptEmitter.event;
|
||||
|
||||
show() {
|
||||
override show() {
|
||||
if (!this.visible) {
|
||||
this.visibleDisposables.add(
|
||||
this.ui.inputBox.onDidChange(value => {
|
||||
@@ -1079,7 +1068,7 @@ class InputBox extends QuickInput implements IInputBox {
|
||||
super.show();
|
||||
}
|
||||
|
||||
protected update() {
|
||||
protected override update() {
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
@@ -1388,8 +1377,12 @@ export class QuickInputController extends Disposable {
|
||||
const index = input.items.indexOf(event.item);
|
||||
if (index !== -1) {
|
||||
const items = input.items.slice();
|
||||
items.splice(index, 1);
|
||||
const removed = items.splice(index, 1);
|
||||
const activeItems = input.activeItems.filter((ai) => ai !== removed[0]);
|
||||
input.items = items;
|
||||
if (activeItems) {
|
||||
input.activeItems = activeItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
})),
|
||||
@@ -1729,6 +1722,34 @@ export class QuickInputController extends Disposable {
|
||||
if (this.styles.list.pickerGroupForeground) {
|
||||
content.push(`.quick-input-list .quick-input-list-separator { color: ${this.styles.list.pickerGroupForeground}; }`);
|
||||
}
|
||||
|
||||
if (
|
||||
this.styles.keybindingLabel.keybindingLabelBackground ||
|
||||
this.styles.keybindingLabel.keybindingLabelBorder ||
|
||||
this.styles.keybindingLabel.keybindingLabelBottomBorder ||
|
||||
this.styles.keybindingLabel.keybindingLabelShadow ||
|
||||
this.styles.keybindingLabel.keybindingLabelForeground
|
||||
) {
|
||||
content.push('.quick-input-list .monaco-keybinding > .monaco-keybinding-key {');
|
||||
if (this.styles.keybindingLabel.keybindingLabelBackground) {
|
||||
content.push(`background-color: ${this.styles.keybindingLabel.keybindingLabelBackground};`);
|
||||
}
|
||||
if (this.styles.keybindingLabel.keybindingLabelBorder) {
|
||||
// Order matters here. `border-color` must come before `border-bottom-color`.
|
||||
content.push(`border-color: ${this.styles.keybindingLabel.keybindingLabelBorder};`);
|
||||
}
|
||||
if (this.styles.keybindingLabel.keybindingLabelBottomBorder) {
|
||||
content.push(`border-bottom-color: ${this.styles.keybindingLabel.keybindingLabelBottomBorder};`);
|
||||
}
|
||||
if (this.styles.keybindingLabel.keybindingLabelShadow) {
|
||||
content.push(`box-shadow: inset 0 -1px 0 ${this.styles.keybindingLabel.keybindingLabelShadow};`);
|
||||
}
|
||||
if (this.styles.keybindingLabel.keybindingLabelForeground) {
|
||||
content.push(`color: ${this.styles.keybindingLabel.keybindingLabelForeground};`);
|
||||
}
|
||||
content.push('}');
|
||||
}
|
||||
|
||||
const newStyles = content.join('\n');
|
||||
if (newStyles !== this.ui.styleSheet.textContent) {
|
||||
this.ui.styleSheet.textContent = newStyles;
|
||||
|
||||
@@ -27,6 +27,7 @@ import { IQuickInputOptions } from 'vs/base/parts/quickinput/browser/quickInput'
|
||||
import { IListOptions, List, IListStyles, IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { getCodiconAriaLabel } from 'vs/base/common/codicons';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -427,7 +428,7 @@ export class QuickInputList {
|
||||
const saneDescription = item.description && item.description.replace(/\r?\n/g, ' ');
|
||||
const saneDetail = item.detail && item.detail.replace(/\r?\n/g, ' ');
|
||||
const saneAriaLabel = item.ariaLabel || [saneLabel, saneDescription, saneDetail]
|
||||
.map(s => s && parseLabelWithIcons(s).text)
|
||||
.map(s => getCodiconAriaLabel(s))
|
||||
.filter(s => !!s)
|
||||
.join(', ');
|
||||
|
||||
@@ -603,6 +604,7 @@ export class QuickInputList {
|
||||
|
||||
// Filter by value (since we support icons in labels, use $(..) aware fuzzy matching)
|
||||
else {
|
||||
let currentSeparator: IQuickPickSeparator | undefined;
|
||||
this.elements.forEach(element => {
|
||||
const labelHighlights = this.matchOnLabel ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneLabel))) : undefined;
|
||||
const descriptionHighlights = this.matchOnDescription ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneDescription || ''))) : undefined;
|
||||
@@ -621,6 +623,16 @@ export class QuickInputList {
|
||||
element.hidden = !element.item.alwaysShow;
|
||||
}
|
||||
element.separator = undefined;
|
||||
|
||||
// we can show the separator unless the list gets sorted by match
|
||||
if (!this.sortByLabel) {
|
||||
const previous = element.index && this.inputElements[element.index - 1];
|
||||
currentSeparator = previous && previous.type === 'separator' ? previous : currentSeparator;
|
||||
if (currentSeparator && !element.hidden) {
|
||||
element.separator = currentSeparator;
|
||||
currentSeparator = undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ export interface IQuickPickItemButtonContext<T extends IQuickPickItem> extends I
|
||||
export type QuickPickInput<T = IQuickPickItem> = T | IQuickPickSeparator;
|
||||
|
||||
|
||||
//region Fuzzy Scorer Support
|
||||
//#region Fuzzy Scorer Support
|
||||
|
||||
export type IQuickPickItemWithResource = IQuickPickItem & { resource?: URI };
|
||||
|
||||
|
||||
52
lib/vscode/src/vs/base/parts/sandbox/common/sandboxTypes.ts
Normal file
52
lib/vscode/src/vs/base/parts/sandbox/common/sandboxTypes.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { IProductConfiguration } from 'vs/base/common/product';
|
||||
|
||||
|
||||
// #######################################################################
|
||||
// ### ###
|
||||
// ### Types we need in a common layer for reuse ###
|
||||
// ### ###
|
||||
// #######################################################################
|
||||
|
||||
|
||||
/**
|
||||
* The common properties required for any sandboxed
|
||||
* renderer to function.
|
||||
*/
|
||||
export interface ISandboxConfiguration {
|
||||
|
||||
/**
|
||||
* Identifier of the sandboxed renderer.
|
||||
*/
|
||||
windowId: number;
|
||||
|
||||
/**
|
||||
* Absolute installation path.
|
||||
*/
|
||||
appRoot: string;
|
||||
|
||||
/**
|
||||
* Per window process environment.
|
||||
*/
|
||||
userEnv: IProcessEnvironment;
|
||||
|
||||
/**
|
||||
* Product configuration.
|
||||
*/
|
||||
product: IProductConfiguration;
|
||||
|
||||
/**
|
||||
* Configured zoom level.
|
||||
*/
|
||||
zoomLevel?: number;
|
||||
|
||||
/**
|
||||
* @deprecated to be removed soon
|
||||
*/
|
||||
nodeCachedDataDir?: string;
|
||||
}
|
||||
@@ -9,6 +9,122 @@
|
||||
|
||||
const { ipcRenderer, webFrame, crashReporter, contextBridge } = require('electron');
|
||||
|
||||
//#region Utilities
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @returns {true | never}
|
||||
*/
|
||||
function validateIPC(channel) {
|
||||
if (!channel || !channel.startsWith('vscode:')) {
|
||||
throw new Error(`Unsupported event IPC channel '${channel}'`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type
|
||||
* @returns {type is 'uncaughtException'}
|
||||
*/
|
||||
function validateProcessEventType(type) {
|
||||
if (type !== 'uncaughtException') {
|
||||
throw new Error(`Unsupported process event '${type}'`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key the name of the process argument to parse
|
||||
* @returns {string | undefined}
|
||||
*/
|
||||
function parseArgv(key) {
|
||||
for (const arg of process.argv) {
|
||||
if (arg.indexOf(`--${key}=`) === 0) {
|
||||
return arg.split('=')[1];
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Resolve Configuration
|
||||
|
||||
/**
|
||||
* @typedef {import('../common/sandboxTypes').ISandboxConfiguration} ISandboxConfiguration
|
||||
*/
|
||||
|
||||
/** @type {ISandboxConfiguration | undefined} */
|
||||
let configuration = undefined;
|
||||
|
||||
/** @type {Promise<ISandboxConfiguration>} */
|
||||
const resolveConfiguration = (async () => {
|
||||
const windowConfigIpcChannel = parseArgv('vscode-window-config');
|
||||
if (!windowConfigIpcChannel) {
|
||||
throw new Error('Preload: did not find expected vscode-window-config in renderer process arguments list.');
|
||||
}
|
||||
|
||||
try {
|
||||
if (validateIPC(windowConfigIpcChannel)) {
|
||||
|
||||
// Resolve configuration from electron-main
|
||||
configuration = await ipcRenderer.invoke(windowConfigIpcChannel);
|
||||
|
||||
// Apply `userEnv` directly
|
||||
Object.assign(process.env, configuration.userEnv);
|
||||
|
||||
// Apply zoom level early before even building the
|
||||
// window DOM elements to avoid UI flicker. We always
|
||||
// have to set the zoom level from within the window
|
||||
// because Chrome has it's own way of remembering zoom
|
||||
// settings per origin (if vscode-file:// is used) and
|
||||
// we want to ensure that the user configuration wins.
|
||||
webFrame.setZoomLevel(configuration.zoomLevel ?? 0);
|
||||
|
||||
return configuration;
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`Preload: unable to fetch vscode-window-config: ${error}`);
|
||||
}
|
||||
})();
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Resolve Shell Environment
|
||||
|
||||
/**
|
||||
* If VSCode is not run from a terminal, we should resolve additional
|
||||
* shell specific environment from the OS shell to ensure we are seeing
|
||||
* all development related environment variables. We do this from the
|
||||
* main process because it may involve spawning a shell.
|
||||
*
|
||||
* @type {Promise<typeof process.env>}
|
||||
*/
|
||||
const resolveShellEnv = (async () => {
|
||||
|
||||
// Resolve `userEnv` from configuration and
|
||||
// `shellEnv` from the main side
|
||||
const [userEnv, shellEnv] = await Promise.all([
|
||||
(async () => (await resolveConfiguration).userEnv)(),
|
||||
ipcRenderer.invoke('vscode:fetchShellEnv')
|
||||
]);
|
||||
|
||||
if (!process.env['VSCODE_SKIP_PROCESS_ENV_PATCHING'] /* TODO@bpasero for https://github.com/microsoft/vscode/issues/108804 */) {
|
||||
// Assign all keys of the shell environment to our process environment
|
||||
// But make sure that the user environment wins in the end over shell environment
|
||||
Object.assign(process.env, shellEnv, userEnv);
|
||||
}
|
||||
|
||||
return { ...process.env, ...shellEnv, ...userEnv };
|
||||
})();
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Globals Definition
|
||||
|
||||
// #######################################################################
|
||||
// ### ###
|
||||
// ### !!! DO NOT USE GET/SET PROPERTIES ANYWHERE HERE !!! ###
|
||||
@@ -17,14 +133,21 @@
|
||||
// ### ###
|
||||
// #######################################################################
|
||||
|
||||
/**
|
||||
* @type {import('../electron-sandbox/globals')}
|
||||
*/
|
||||
const globals = {
|
||||
|
||||
/**
|
||||
* A minimal set of methods exposed from Electron's `ipcRenderer`
|
||||
* to support communication to main process.
|
||||
*
|
||||
* @type {import('../electron-sandbox/electronTypes').IpcRenderer}
|
||||
* @typedef {import('../electron-sandbox/electronTypes').IpcRenderer} IpcRenderer
|
||||
* @typedef {import('electron').IpcRendererEvent} IpcRendererEvent
|
||||
*
|
||||
* @type {IpcRenderer}
|
||||
*/
|
||||
|
||||
ipcRenderer: {
|
||||
|
||||
/**
|
||||
@@ -50,8 +173,8 @@
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @param {(event: import('electron').IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {import('../electron-sandbox/electronTypes').IpcRenderer}
|
||||
* @param {(event: IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {IpcRenderer}
|
||||
*/
|
||||
on(channel, listener) {
|
||||
if (validateIPC(channel)) {
|
||||
@@ -63,8 +186,8 @@
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @param {(event: import('electron').IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {import('../electron-sandbox/electronTypes').IpcRenderer}
|
||||
* @param {(event: IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {IpcRenderer}
|
||||
*/
|
||||
once(channel, listener) {
|
||||
if (validateIPC(channel)) {
|
||||
@@ -76,8 +199,8 @@
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @param {(event: import('electron').IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {import('../electron-sandbox/electronTypes').IpcRenderer}
|
||||
* @param {(event: IpcRendererEvent, ...args: any[]) => void} listener
|
||||
* @returns {IpcRenderer}
|
||||
*/
|
||||
removeListener(channel, listener) {
|
||||
if (validateIPC(channel)) {
|
||||
@@ -100,7 +223,7 @@
|
||||
*/
|
||||
connect(channelRequest, channelResponse, requestNonce) {
|
||||
if (validateIPC(channelRequest) && validateIPC(channelResponse)) {
|
||||
const responseListener = (/** @type {import('electron').IpcRendererEvent} */ e, /** @type {string} */ responseNonce) => {
|
||||
const responseListener = (/** @type {IpcRendererEvent} */ e, /** @type {string} */ responseNonce) => {
|
||||
// validate that the nonce from the response is the same
|
||||
// as when requested. and if so, use `postMessage` to
|
||||
// send the `MessagePort` safely over, even when context
|
||||
@@ -157,7 +280,9 @@
|
||||
* Note: when `sandbox` is enabled, the only properties available
|
||||
* are https://github.com/electron/electron/blob/master/docs/api/process.md#sandbox
|
||||
*
|
||||
* @type {import('../electron-sandbox/globals').ISandboxNodeProcess}
|
||||
* @typedef {import('../electron-sandbox/globals').ISandboxNodeProcess} ISandboxNodeProcess
|
||||
*
|
||||
* @type {ISandboxNodeProcess}
|
||||
*/
|
||||
process: {
|
||||
get platform() { return process.platform; },
|
||||
@@ -178,16 +303,8 @@
|
||||
/**
|
||||
* @returns {Promise<typeof process.env>}
|
||||
*/
|
||||
getShellEnv() {
|
||||
return shellEnv;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {{[key: string]: string}} userEnv
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
resolveEnv(userEnv) {
|
||||
return resolveEnv(userEnv);
|
||||
shellEnv() {
|
||||
return resolveShellEnv;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -200,7 +317,7 @@
|
||||
/**
|
||||
* @param {string} type
|
||||
* @param {Function} callback
|
||||
* @returns {import('../electron-sandbox/globals').ISandboxNodeProcess}
|
||||
* @returns {ISandboxNodeProcess}
|
||||
*/
|
||||
on(type, callback) {
|
||||
if (validateProcessEventType(type)) {
|
||||
@@ -210,6 +327,37 @@
|
||||
return this;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Some information about the context we are running in.
|
||||
*
|
||||
* @type {import('../electron-sandbox/globals').ISandboxContext}
|
||||
*/
|
||||
context: {
|
||||
|
||||
/**
|
||||
* A configuration object made accessible from the main side
|
||||
* to configure the sandbox browser window.
|
||||
*
|
||||
* Note: intentionally not using a getter here because the
|
||||
* actual value will be set after `resolveConfiguration`
|
||||
* has finished.
|
||||
*
|
||||
* @returns {ISandboxConfiguration | undefined}
|
||||
*/
|
||||
configuration() {
|
||||
return configuration;
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows to await the resolution of the configuration object.
|
||||
*
|
||||
* @returns {Promise<ISandboxConfiguration>}
|
||||
*/
|
||||
async resolveConfiguration() {
|
||||
return resolveConfiguration;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -231,69 +379,4 @@
|
||||
// @ts-ignore
|
||||
window.vscode = globals;
|
||||
}
|
||||
|
||||
//#region Utilities
|
||||
|
||||
/**
|
||||
* @param {string} channel
|
||||
* @returns {true | never}
|
||||
*/
|
||||
function validateIPC(channel) {
|
||||
if (!channel || !channel.startsWith('vscode:')) {
|
||||
throw new Error(`Unsupported event IPC channel '${channel}'`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type
|
||||
* @returns {type is 'uncaughtException'}
|
||||
*/
|
||||
function validateProcessEventType(type) {
|
||||
if (type !== 'uncaughtException') {
|
||||
throw new Error(`Unsupported process event '${type}'`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @type {Promise<typeof process.env> | undefined} */
|
||||
let shellEnv = undefined;
|
||||
|
||||
/**
|
||||
* If VSCode is not run from a terminal, we should resolve additional
|
||||
* shell specific environment from the OS shell to ensure we are seeing
|
||||
* all development related environment variables. We do this from the
|
||||
* main process because it may involve spawning a shell.
|
||||
*
|
||||
* @param {{[key: string]: string}} userEnv
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function resolveEnv(userEnv) {
|
||||
if (!shellEnv) {
|
||||
|
||||
// Apply `userEnv` directly
|
||||
Object.assign(process.env, userEnv);
|
||||
|
||||
// Resolve `shellEnv` from the main side
|
||||
shellEnv = new Promise(function (resolve) {
|
||||
ipcRenderer.once('vscode:acceptShellEnv', function (event, shellEnvResult) {
|
||||
if (!process.env['VSCODE_SKIP_PROCESS_ENV_PATCHING'] /* TODO@bpasero for https://github.com/microsoft/vscode/issues/108804 */) {
|
||||
// Assign all keys of the shell environment to our process environment
|
||||
// But make sure that the user environment wins in the end over shell environment
|
||||
Object.assign(process.env, shellEnvResult, userEnv);
|
||||
}
|
||||
|
||||
resolve({ ...process.env, ...shellEnvResult, ...userEnv });
|
||||
});
|
||||
|
||||
ipcRenderer.send('vscode:fetchShellEnv');
|
||||
});
|
||||
}
|
||||
|
||||
await shellEnv;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}());
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { globals, INodeProcess, IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { ISandboxConfiguration } from 'vs/base/parts/sandbox/common/sandboxTypes';
|
||||
import { ProcessMemoryInfo, CrashReporter, IpcRenderer, WebFrame } from 'vs/base/parts/sandbox/electron-sandbox/electronTypes';
|
||||
|
||||
/**
|
||||
@@ -74,8 +75,8 @@ export interface ISandboxNodeProcess extends INodeProcess {
|
||||
getProcessMemoryInfo: () => Promise<ProcessMemoryInfo>;
|
||||
|
||||
/**
|
||||
* A custom method we add to `process`: Resolve the true process environment to use and
|
||||
* apply it to `process.env`.
|
||||
* Returns a process environment that includes all shell environment variables even if
|
||||
* the application was not started from a shell / terminal / console.
|
||||
*
|
||||
* There are different layers of environment that will apply:
|
||||
* - `process.env`: this is the actual environment of the process before this method
|
||||
@@ -86,17 +87,8 @@ export interface ISandboxNodeProcess extends INodeProcess {
|
||||
* from a terminal and changed certain variables
|
||||
*
|
||||
* The order of overwrites is `process.env` < `shellEnv` < `userEnv`.
|
||||
*
|
||||
* It is critical that every process awaits this method early on startup to get the right
|
||||
* set of environment in `process.env`.
|
||||
*/
|
||||
resolveEnv(userEnv: IProcessEnvironment): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns a process environment that includes any shell environment even if the application
|
||||
* was not started from a shell / terminal / console.
|
||||
*/
|
||||
getShellEnv(): Promise<IProcessEnvironment>;
|
||||
shellEnv(): Promise<IProcessEnvironment>;
|
||||
}
|
||||
|
||||
export interface IpcMessagePort {
|
||||
@@ -114,8 +106,24 @@ export interface IpcMessagePort {
|
||||
connect(channelRequest: string, channelResponse: string, requestNonce: string): void;
|
||||
}
|
||||
|
||||
export interface ISandboxContext {
|
||||
|
||||
/**
|
||||
* A configuration object made accessible from the main side
|
||||
* to configure the sandbox browser window. Will be `undefined`
|
||||
* for as long as `resolveConfiguration` is not awaited.
|
||||
*/
|
||||
configuration(): ISandboxConfiguration | undefined;
|
||||
|
||||
/**
|
||||
* Allows to await the resolution of the configuration object.
|
||||
*/
|
||||
resolveConfiguration(): Promise<ISandboxConfiguration>;
|
||||
}
|
||||
|
||||
export const ipcRenderer: IpcRenderer = globals.vscode.ipcRenderer;
|
||||
export const ipcMessagePort: IpcMessagePort = globals.vscode.ipcMessagePort;
|
||||
export const webFrame: WebFrame = globals.vscode.webFrame;
|
||||
export const crashReporter: CrashReporter = globals.vscode.crashReporter;
|
||||
export const process: ISandboxNodeProcess = globals.vscode.process;
|
||||
export const context: ISandboxContext = globals.vscode.context;
|
||||
|
||||
@@ -4,13 +4,17 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ipcRenderer, crashReporter, webFrame, process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { ipcRenderer, crashReporter, webFrame, context, process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
|
||||
suite('Sandbox', () => {
|
||||
test('globals', () => {
|
||||
test('globals', async () => {
|
||||
assert.ok(typeof ipcRenderer.send === 'function');
|
||||
assert.ok(typeof crashReporter.addExtraParameter === 'function');
|
||||
assert.ok(typeof webFrame.setZoomLevel === 'function');
|
||||
assert.ok(typeof process.platform === 'string');
|
||||
|
||||
const config = await context.resolveConfiguration();
|
||||
assert.ok(config);
|
||||
assert.ok(context.configuration());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -320,7 +320,7 @@ export class Storage extends Disposable implements IStorage {
|
||||
return new Promise(resolve => this.whenFlushedCallbacks.push(resolve));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this.flushDelayer.cancel(); // workaround https://github.com/microsoft/vscode/issues/116777
|
||||
this.flushDelayer.dispose();
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ flakySuite('Storage Library', function () {
|
||||
|
||||
class TestSQLiteStorageDatabase extends SQLiteStorageDatabase {
|
||||
private readonly _onDidChangeItemsExternal = new Emitter<IStorageItemsChangeEvent>();
|
||||
get onDidChangeItemsExternal(): Event<IStorageItemsChangeEvent> { return this._onDidChangeItemsExternal.event; }
|
||||
override get onDidChangeItemsExternal(): Event<IStorageItemsChangeEvent> { return this._onDidChangeItemsExternal.event; }
|
||||
|
||||
fireDidChangeItemsExternal(event: IStorageItemsChangeEvent): void {
|
||||
this._onDidChangeItemsExternal.fire(event);
|
||||
|
||||
Reference in New Issue
Block a user