mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
Merge remote-tracking branch 'upstream/master' into rebornix/browerkeybinding
This commit is contained in:
@@ -79,9 +79,9 @@ function extractDocumentLink(
|
||||
}
|
||||
|
||||
export default class LinkProvider implements vscode.DocumentLinkProvider {
|
||||
private readonly linkPattern = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|[^\]]*\])\(\s*)(([^\s\(\)]|\(\S*?\))+)\s*(".*?")?\)/g;
|
||||
private readonly referenceLinkPattern = /(\[([^\]]+)\]\[\s*?)([^\s\]]*?)\]/g;
|
||||
private readonly definitionPattern = /^([\t ]*\[([^\]]+)\]:\s*)(\S+)/gm;
|
||||
private readonly linkPattern = /(\[((!\[[^\]]*?\]\(\s*)([^\s\(\)]+?)\s*\)\]|(?:\\\]|[^\]])*\])\(\s*)(([^\s\(\)]|\(\S*?\))+)\s*(".*?")?\)/g;
|
||||
private readonly referenceLinkPattern = /(\[((?:\\\]|[^\]])+)\]\[\s*?)([^\s\]]*?)\]/g;
|
||||
private readonly definitionPattern = /^([\t ]*\[((?:\\\]|[^\]])+)\]:\s*)(\S+)/gm;
|
||||
|
||||
public provideDocumentLinks(
|
||||
document: vscode.TextDocument,
|
||||
|
||||
@@ -72,6 +72,14 @@ suite('markdown.DocumentLinkProvider', () => {
|
||||
assertRangeEqual(link.range, new vscode.Range(0, 6, 0, 25));
|
||||
});
|
||||
|
||||
// #35245
|
||||
test('Should handle links with escaped characters in name', () => {
|
||||
const links = getLinksForFile('a [b\\]](./file)');
|
||||
assert.strictEqual(links.length, 1);
|
||||
const [link] = links;
|
||||
assertRangeEqual(link.range, new vscode.Range(0, 8, 0, 14));
|
||||
});
|
||||
|
||||
|
||||
test('Should handle links with balanced parens', () => {
|
||||
{
|
||||
|
||||
@@ -208,7 +208,7 @@ export class DiagnosticsManager extends Disposable {
|
||||
|
||||
public configFileDiagnosticsReceived(
|
||||
file: vscode.Uri,
|
||||
diagnostics: vscode.Diagnostic[]
|
||||
diagnostics: ReadonlyArray<vscode.Diagnostic>
|
||||
): void {
|
||||
this._currentDiagnostics.set(file, diagnostics);
|
||||
}
|
||||
@@ -218,7 +218,7 @@ export class DiagnosticsManager extends Disposable {
|
||||
this._diagnostics.delete(resource);
|
||||
}
|
||||
|
||||
public getDiagnostics(file: vscode.Uri): vscode.Diagnostic[] {
|
||||
public getDiagnostics(file: vscode.Uri): ReadonlyArray<vscode.Diagnostic> {
|
||||
return this._currentDiagnostics.get(file) || [];
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.36.0",
|
||||
"distro": "060a874751adc68d68777085e88c99a8f04ba5da",
|
||||
"distro": "fa58edd879968b01e012f8cd56860787765aff8a",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
@@ -25,8 +25,8 @@
|
||||
"download-builtin-extensions": "node build/lib/builtInExtensions.js",
|
||||
"monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit",
|
||||
"strict-initialization-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictPropertyInitialization",
|
||||
"web": "node resources/server/bin-dev/code-web.js --port=9888",
|
||||
"web-selfhost": "node resources/server/bin-dev/code-web.js --port=9777 --selfhost --folder .",
|
||||
"web": "node resources/server/bin-dev/code-web.js --port 9888",
|
||||
"web-selfhost": "node resources/server/bin-dev/code-web.js --port 9777 --selfhost --folder .",
|
||||
"install-server": "git fetch distro && git checkout distro/distro -- src/vs/server resources/server && git reset HEAD src/vs/server resources/server"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -336,7 +336,9 @@ export function isFalsyOrEmpty(obj: any): boolean {
|
||||
/**
|
||||
* @returns True if the provided object is an array and has at least one element.
|
||||
*/
|
||||
export function isNonEmptyArray<T>(obj: ReadonlyArray<T> | undefined | null): obj is Array<T> {
|
||||
export function isNonEmptyArray<T>(obj: T[] | undefined | null): obj is T[];
|
||||
export function isNonEmptyArray<T>(obj: readonly T[] | undefined | null): obj is readonly T[];
|
||||
export function isNonEmptyArray<T>(obj: T[] | readonly T[] | undefined | null): obj is T[] | readonly T[] {
|
||||
return Array.isArray(obj) && obj.length > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ function markTracked<T extends IDisposable>(x: T): void {
|
||||
}
|
||||
}
|
||||
|
||||
function trackDisposable<T extends IDisposable>(x: T): void {
|
||||
function trackDisposable<T extends IDisposable>(x: T): T {
|
||||
if (!TRACK_DISPOSABLES) {
|
||||
return;
|
||||
return x;
|
||||
}
|
||||
|
||||
const stack = new Error().stack!;
|
||||
@@ -41,6 +41,7 @@ function trackDisposable<T extends IDisposable>(x: T): void {
|
||||
console.log(stack);
|
||||
}
|
||||
}, 3000);
|
||||
return x;
|
||||
}
|
||||
|
||||
export interface IDisposable {
|
||||
@@ -76,11 +77,11 @@ export function dispose<T extends IDisposable>(disposables: T | T[] | undefined)
|
||||
|
||||
export function combinedDisposable(...disposables: IDisposable[]): IDisposable {
|
||||
disposables.forEach(markTracked);
|
||||
return { dispose: () => dispose(disposables) };
|
||||
return trackDisposable({ dispose: () => dispose(disposables) });
|
||||
}
|
||||
|
||||
export function toDisposable(fn: () => void): IDisposable {
|
||||
return { dispose: fn };
|
||||
return trackDisposable({ dispose: fn });
|
||||
}
|
||||
|
||||
export class DisposableStore implements IDisposable {
|
||||
|
||||
@@ -96,10 +96,10 @@ export function getShellEnvironment(logService: ILogService, environmentService:
|
||||
logService.trace('getShellEnvironment: disable-user-env-probe set, skipping');
|
||||
_shellEnv = Promise.resolve({});
|
||||
} else if (isWindows) {
|
||||
logService.trace('getShellEnvironment: runing on windows, skipping');
|
||||
logService.trace('getShellEnvironment: running on Windows, skipping');
|
||||
_shellEnv = Promise.resolve({});
|
||||
} else if (process.env['VSCODE_CLI'] === '1') {
|
||||
logService.trace('getShellEnvironment: runing on CLI, skipping');
|
||||
logService.trace('getShellEnvironment: running on CLI, skipping');
|
||||
_shellEnv = Promise.resolve({});
|
||||
} else {
|
||||
logService.trace('getShellEnvironment: running on Unix');
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IPointerHandlerHelper, MouseHandler } from 'vs/editor/browser/controller/mouseHandler';
|
||||
import { IMouseTarget } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorMouseEvent } from 'vs/editor/browser/editorDom';
|
||||
@@ -195,11 +195,6 @@ class TouchHandler extends MouseHandler {
|
||||
this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e)));
|
||||
this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e)));
|
||||
this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Contextmenu, (e: MouseEvent) => this._onContextMenu(new EditorMouseEvent(e, this.viewHelper.viewDomNode), false)));
|
||||
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private onTap(event: GestureEvent): void {
|
||||
@@ -219,26 +214,23 @@ class TouchHandler extends MouseHandler {
|
||||
}
|
||||
}
|
||||
|
||||
export class PointerHandler implements IDisposable {
|
||||
export class PointerHandler extends Disposable {
|
||||
private readonly handler: MouseHandler;
|
||||
|
||||
constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {
|
||||
super();
|
||||
if (window.navigator.msPointerEnabled) {
|
||||
this.handler = new MsPointerHandler(context, viewController, viewHelper);
|
||||
this.handler = this._register(new MsPointerHandler(context, viewController, viewHelper));
|
||||
} else if ((<any>window).TouchEvent) {
|
||||
this.handler = new TouchHandler(context, viewController, viewHelper);
|
||||
this.handler = this._register(new TouchHandler(context, viewController, viewHelper));
|
||||
} else if (window.navigator.pointerEnabled || (<any>window).PointerEvent) {
|
||||
this.handler = new StandardPointerHandler(context, viewController, viewHelper);
|
||||
this.handler = this._register(new StandardPointerHandler(context, viewController, viewHelper));
|
||||
} else {
|
||||
this.handler = new MouseHandler(context, viewController, viewHelper);
|
||||
this.handler = this._register(new MouseHandler(context, viewController, viewHelper));
|
||||
}
|
||||
}
|
||||
|
||||
public getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null {
|
||||
return this.handler.getTargetAtClientPoint(clientX, clientY);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.handler.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,16 +13,16 @@ import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { TokenizationRegistry } from 'vs/editor/common/modes';
|
||||
|
||||
export interface IMarkdownRenderResult extends IDisposable {
|
||||
element: HTMLElement;
|
||||
}
|
||||
|
||||
export class MarkdownRenderer {
|
||||
export class MarkdownRenderer extends Disposable {
|
||||
|
||||
private _onDidRenderCodeBlock = new Emitter<void>();
|
||||
private _onDidRenderCodeBlock = this._register(new Emitter<void>());
|
||||
readonly onDidRenderCodeBlock: Event<void> = this._onDidRenderCodeBlock.event;
|
||||
|
||||
constructor(
|
||||
@@ -30,6 +30,7 @@ export class MarkdownRenderer {
|
||||
@IModeService private readonly _modeService: IModeService,
|
||||
@optional(IOpenerService) private readonly _openerService: IOpenerService | null = NullOpenerService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
private getOptions(disposeables: DisposableStore): RenderOptions {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { domEvent, stop } from 'vs/base/browser/event';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import 'vs/css!./parameterHints';
|
||||
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
@@ -31,7 +31,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
|
||||
|
||||
private readonly markdownRenderer: MarkdownRenderer;
|
||||
private readonly renderDisposeables = this._register(new DisposableStore());
|
||||
private model: ParameterHintsModel | null;
|
||||
private readonly model = this._register(new MutableDisposable<ParameterHintsModel>());
|
||||
private readonly keyVisible: IContextKey<boolean>;
|
||||
private readonly keyMultipleSignatures: IContextKey<boolean>;
|
||||
private element: HTMLElement;
|
||||
@@ -52,13 +52,13 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
|
||||
@IModeService modeService: IModeService,
|
||||
) {
|
||||
super();
|
||||
this.markdownRenderer = new MarkdownRenderer(editor, modeService, openerService);
|
||||
this.model = new ParameterHintsModel(editor);
|
||||
this.markdownRenderer = this._register(new MarkdownRenderer(editor, modeService, openerService));
|
||||
this.model.value = new ParameterHintsModel(editor);
|
||||
this.keyVisible = Context.Visible.bindTo(contextKeyService);
|
||||
this.keyMultipleSignatures = Context.MultipleSignatures.bindTo(contextKeyService);
|
||||
this.visible = false;
|
||||
|
||||
this._register(this.model.onChangedHints(newParameterHints => {
|
||||
this._register(this.model.value.onChangedHints(newParameterHints => {
|
||||
if (newParameterHints) {
|
||||
this.show();
|
||||
this.render(newParameterHints);
|
||||
@@ -282,22 +282,22 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
|
||||
}
|
||||
|
||||
next(): void {
|
||||
if (this.model) {
|
||||
if (this.model.value) {
|
||||
this.editor.focus();
|
||||
this.model.next();
|
||||
this.model.value.next();
|
||||
}
|
||||
}
|
||||
|
||||
previous(): void {
|
||||
if (this.model) {
|
||||
if (this.model.value) {
|
||||
this.editor.focus();
|
||||
this.model.previous();
|
||||
this.model.value.previous();
|
||||
}
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
if (this.model) {
|
||||
this.model.cancel();
|
||||
if (this.model.value) {
|
||||
this.model.value.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,8 +310,8 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
|
||||
}
|
||||
|
||||
trigger(context: TriggerContext): void {
|
||||
if (this.model) {
|
||||
this.model.trigger(context, 0);
|
||||
if (this.model.value) {
|
||||
this.model.value.trigger(context, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,15 +319,6 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget,
|
||||
const height = Math.max(this.editor.getLayoutInfo().height / 4, 250);
|
||||
this.element.style.maxHeight = `${height}px`;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
if (this.model) {
|
||||
this.model.dispose();
|
||||
this.model = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
|
||||
Vendored
+4
-4
@@ -4354,7 +4354,7 @@ declare module 'vscode' {
|
||||
* @param uri A resource identifier.
|
||||
* @param diagnostics Array of diagnostics or `undefined`
|
||||
*/
|
||||
set(uri: Uri, diagnostics: Diagnostic[] | undefined): void;
|
||||
set(uri: Uri, diagnostics: ReadonlyArray<Diagnostic> | undefined): void;
|
||||
|
||||
/**
|
||||
* Replace all entries in this collection.
|
||||
@@ -4366,7 +4366,7 @@ declare module 'vscode' {
|
||||
*
|
||||
* @param entries An array of tuples, like `[[file1, [d1, d2]], [file2, [d3, d4, d5]]]`, or `undefined`.
|
||||
*/
|
||||
set(entries: [Uri, Diagnostic[] | undefined][]): void;
|
||||
set(entries: ReadonlyArray<[Uri, ReadonlyArray<Diagnostic> | undefined]>): void;
|
||||
|
||||
/**
|
||||
* Remove all diagnostics from this collection that belong
|
||||
@@ -4388,7 +4388,7 @@ declare module 'vscode' {
|
||||
* @param callback Function to execute for each entry.
|
||||
* @param thisArg The `this` context used when invoking the handler function.
|
||||
*/
|
||||
forEach(callback: (uri: Uri, diagnostics: Diagnostic[], collection: DiagnosticCollection) => any, thisArg?: any): void;
|
||||
forEach(callback: (uri: Uri, diagnostics: ReadonlyArray<Diagnostic>, collection: DiagnosticCollection) => any, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* Get the diagnostics for a given resource. *Note* that you cannot
|
||||
@@ -4397,7 +4397,7 @@ declare module 'vscode' {
|
||||
* @param uri A resource identifier.
|
||||
* @returns An immutable array of [diagnostics](#Diagnostic) or `undefined`.
|
||||
*/
|
||||
get(uri: Uri): Diagnostic[] | undefined;
|
||||
get(uri: Uri): ReadonlyArray<Diagnostic> | undefined;
|
||||
|
||||
/**
|
||||
* Check if this collection contains diagnostics for a
|
||||
|
||||
@@ -339,7 +339,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
<head>
|
||||
<base href="https://code.visualstudio.com/raw/">
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; script-src 'none'; style-src vscode-core-resource: https: 'unsafe-inline'; child-src 'none'; frame-src 'none';">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; script-src 'none'; style-src vscode-resource: https: 'unsafe-inline'; child-src 'none'; frame-src 'none';">
|
||||
</head>
|
||||
<body>${localize('errorMessage', "An error occurred while restoring view:{0}", viewType)}</body>
|
||||
</html>`;
|
||||
|
||||
@@ -47,9 +47,9 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
set(uri: vscode.Uri, diagnostics: vscode.Diagnostic[]): void;
|
||||
set(entries: [vscode.Uri, vscode.Diagnostic[]][]): void;
|
||||
set(first: vscode.Uri | [vscode.Uri, vscode.Diagnostic[]][], diagnostics?: vscode.Diagnostic[]) {
|
||||
set(uri: vscode.Uri, diagnostics: ReadonlyArray<vscode.Diagnostic>): void;
|
||||
set(entries: ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]>): void;
|
||||
set(first: vscode.Uri | ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]>, diagnostics?: ReadonlyArray<vscode.Diagnostic>) {
|
||||
|
||||
if (!first) {
|
||||
// this set-call is a clear-call
|
||||
@@ -167,7 +167,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
this._proxy.$clear(this._owner);
|
||||
}
|
||||
|
||||
forEach(callback: (uri: URI, diagnostics: vscode.Diagnostic[], collection: DiagnosticCollection) => any, thisArg?: any): void {
|
||||
forEach(callback: (uri: URI, diagnostics: ReadonlyArray<vscode.Diagnostic>, collection: DiagnosticCollection) => any, thisArg?: any): void {
|
||||
this._checkDisposed();
|
||||
this._data.forEach((value, key) => {
|
||||
const uri = URI.parse(key);
|
||||
@@ -175,11 +175,11 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
});
|
||||
}
|
||||
|
||||
get(uri: URI): vscode.Diagnostic[] {
|
||||
get(uri: URI): ReadonlyArray<vscode.Diagnostic> {
|
||||
this._checkDisposed();
|
||||
const result = this._data.get(uri.toString());
|
||||
if (Array.isArray(result)) {
|
||||
return <vscode.Diagnostic[]>Object.freeze(result.slice(0));
|
||||
return <ReadonlyArray<vscode.Diagnostic>>Object.freeze(result.slice(0));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -278,10 +278,10 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
|
||||
return result;
|
||||
}
|
||||
|
||||
getDiagnostics(resource: vscode.Uri): vscode.Diagnostic[];
|
||||
getDiagnostics(): [vscode.Uri, vscode.Diagnostic[]][];
|
||||
getDiagnostics(resource?: vscode.Uri): vscode.Diagnostic[] | [vscode.Uri, vscode.Diagnostic[]][];
|
||||
getDiagnostics(resource?: vscode.Uri): vscode.Diagnostic[] | [vscode.Uri, vscode.Diagnostic[]][] {
|
||||
getDiagnostics(resource: vscode.Uri): ReadonlyArray<vscode.Diagnostic>;
|
||||
getDiagnostics(): ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]>;
|
||||
getDiagnostics(resource?: vscode.Uri): ReadonlyArray<vscode.Diagnostic> | ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]>;
|
||||
getDiagnostics(resource?: vscode.Uri): ReadonlyArray<vscode.Diagnostic> | ReadonlyArray<[vscode.Uri, ReadonlyArray<vscode.Diagnostic>]> {
|
||||
if (resource) {
|
||||
return this._getDiagnostics(resource);
|
||||
} else {
|
||||
@@ -302,7 +302,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
|
||||
}
|
||||
}
|
||||
|
||||
private _getDiagnostics(resource: vscode.Uri): vscode.Diagnostic[] {
|
||||
private _getDiagnostics(resource: vscode.Uri): ReadonlyArray<vscode.Diagnostic> {
|
||||
let res: vscode.Diagnostic[] = [];
|
||||
this._collections.forEach(collection => {
|
||||
if (collection.has(resource)) {
|
||||
|
||||
@@ -500,7 +500,10 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
variableResolver,
|
||||
isWorkspaceShellAllowed,
|
||||
pkg.version,
|
||||
terminalConfig.get<boolean>('setLocaleVariables', false)
|
||||
terminalConfig.get<boolean>('setLocaleVariables', false),
|
||||
// Always inherit the environment as we need to be running in a login shell, this may
|
||||
// change when macOS servers are supported
|
||||
process.env as platform.IProcessEnvironment
|
||||
);
|
||||
|
||||
// Fork the process and listen for messages
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./media/statusbarpart';
|
||||
import * as nls from 'vs/nls';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { dispose, IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { dispose, IDisposable, Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
@@ -636,10 +636,10 @@ class StatusbarEntryItem extends Disposable {
|
||||
private labelContainer: HTMLElement;
|
||||
private label: OcticonLabel;
|
||||
|
||||
private foregroundListener: IDisposable | undefined;
|
||||
private backgroundListener: IDisposable | undefined;
|
||||
private readonly foregroundListener = this._register(new MutableDisposable());
|
||||
private readonly backgroundListener = this._register(new MutableDisposable());
|
||||
|
||||
private commandListener: IDisposable | undefined;
|
||||
private readonly commandListener = this._register(new MutableDisposable());
|
||||
|
||||
constructor(
|
||||
private container: HTMLElement,
|
||||
@@ -692,11 +692,10 @@ class StatusbarEntryItem extends Disposable {
|
||||
|
||||
// Update: Command
|
||||
if (!this.entry || entry.command !== this.entry.command) {
|
||||
dispose(this.commandListener);
|
||||
this.commandListener = undefined;
|
||||
this.commandListener.clear();
|
||||
|
||||
if (entry.command) {
|
||||
this.commandListener = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(entry.command!, entry.arguments));
|
||||
this.commandListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(entry.command!, entry.arguments));
|
||||
|
||||
removeClass(this.labelContainer, 'disabled');
|
||||
} else {
|
||||
@@ -759,11 +758,9 @@ class StatusbarEntryItem extends Disposable {
|
||||
let colorResult: string | null = null;
|
||||
|
||||
if (isBackground) {
|
||||
dispose(this.backgroundListener);
|
||||
this.backgroundListener = undefined;
|
||||
this.backgroundListener.clear();
|
||||
} else {
|
||||
dispose(this.foregroundListener);
|
||||
this.foregroundListener = undefined;
|
||||
this.foregroundListener.clear();
|
||||
}
|
||||
|
||||
if (color) {
|
||||
@@ -781,9 +778,9 @@ class StatusbarEntryItem extends Disposable {
|
||||
});
|
||||
|
||||
if (isBackground) {
|
||||
this.backgroundListener = listener;
|
||||
this.backgroundListener.value = listener;
|
||||
} else {
|
||||
this.foregroundListener = listener;
|
||||
this.foregroundListener.value = listener;
|
||||
}
|
||||
} else {
|
||||
colorResult = color;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Cache, CacheResult } from 'vs/base/common/cache';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { IDisposable, dispose, toDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { append, $, addClass, removeClass, finalHandler, join, toggleClass, hide, show } from 'vs/base/browser/dom';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
@@ -51,14 +51,15 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
||||
import { getDefaultValue } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { isUndefined } from 'vs/base/common/types';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
function renderBody(body: string): string {
|
||||
const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-core-resource://');
|
||||
const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-resource://');
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; script-src 'none'; style-src vscode-core-resource:; child-src 'none'; frame-src 'none';">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; script-src 'none'; style-src vscode-resource:; child-src 'none'; frame-src 'none';">
|
||||
<link rel="stylesheet" type="text/css" href="${styleSheetPath}">
|
||||
</head>
|
||||
<body>
|
||||
@@ -176,9 +177,8 @@ export class ExtensionEditor extends BaseEditor {
|
||||
private extensionManifest: Cache<IExtensionManifest | null> | null;
|
||||
|
||||
private layoutParticipants: ILayoutParticipant[] = [];
|
||||
private contentDisposables: IDisposable[] = [];
|
||||
private transientDisposables: IDisposable[] = [];
|
||||
private disposables: IDisposable[];
|
||||
private readonly contentDisposables = this._register(new DisposableStore());
|
||||
private readonly transientDisposables = this._register(new DisposableStore());
|
||||
private activeElement: IActiveElement | null;
|
||||
private editorLoadComplete: boolean = false;
|
||||
|
||||
@@ -198,7 +198,6 @@ export class ExtensionEditor extends BaseEditor {
|
||||
|
||||
) {
|
||||
super(ExtensionEditor.ID, telemetryService, themeService, storageService);
|
||||
this.disposables = [];
|
||||
this.extensionReadme = null;
|
||||
this.extensionChangelog = null;
|
||||
this.extensionManifest = null;
|
||||
@@ -256,18 +255,18 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.subtext = append(this.subtextContainer, $('.subtext'));
|
||||
this.ignoreActionbar = new ActionBar(this.subtextContainer, { animated: false });
|
||||
|
||||
this.disposables.push(this.extensionActionBar);
|
||||
this.disposables.push(this.ignoreActionbar);
|
||||
this._register(this.extensionActionBar);
|
||||
this._register(this.ignoreActionbar);
|
||||
|
||||
Event.chain(this.extensionActionBar.onDidRun)
|
||||
this._register(Event.chain(this.extensionActionBar.onDidRun)
|
||||
.map(({ error }) => error)
|
||||
.filter(error => !!error)
|
||||
.on(this.onError, this, this.disposables);
|
||||
.on(this.onError, this));
|
||||
|
||||
Event.chain(this.ignoreActionbar.onDidRun)
|
||||
this._register(Event.chain(this.ignoreActionbar.onDidRun)
|
||||
.map(({ error }) => error)
|
||||
.filter(error => !!error)
|
||||
.on(this.onError, this, this.disposables);
|
||||
.on(this.onError, this));
|
||||
|
||||
const body = append(root, $('.body'));
|
||||
this.navbar = new NavBar(body);
|
||||
@@ -284,7 +283,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.editorLoadComplete = false;
|
||||
const extension = input.extension;
|
||||
|
||||
this.transientDisposables = dispose(this.transientDisposables);
|
||||
this.transientDisposables.clear();
|
||||
|
||||
this.extensionReadme = new Cache(() => createCancelablePromise(token => extension.getReadme(token)));
|
||||
this.extensionChangelog = new Cache(() => createCancelablePromise(token => extension.getChangelog(token)));
|
||||
@@ -383,7 +382,9 @@ export class ExtensionEditor extends BaseEditor {
|
||||
|
||||
this.extensionActionBar.clear();
|
||||
this.extensionActionBar.push(actions, { icon: true, label: true });
|
||||
this.transientDisposables.push(...[...actions, ...widgets, extensionContainers]);
|
||||
for (const disposable of [...actions, ...widgets, extensionContainers]) {
|
||||
this.transientDisposables.add(disposable);
|
||||
}
|
||||
|
||||
this.setSubText(extension, reloadAction);
|
||||
this.content.innerHTML = ''; // Clear content before setting navbar actions.
|
||||
@@ -430,7 +431,8 @@ export class ExtensionEditor extends BaseEditor {
|
||||
|
||||
this.ignoreActionbar.clear();
|
||||
this.ignoreActionbar.push([ignoreAction, undoIgnoreAction], { icon: true, label: true });
|
||||
this.transientDisposables.push(ignoreAction, undoIgnoreAction);
|
||||
this.transientDisposables.add(ignoreAction);
|
||||
this.transientDisposables.add(undoIgnoreAction);
|
||||
|
||||
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
|
||||
if (extRecommendations[extension.identifier.id.toLowerCase()]) {
|
||||
@@ -463,7 +465,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
}
|
||||
});
|
||||
|
||||
this.transientDisposables.push(reloadAction.onDidChange(e => {
|
||||
this.transientDisposables.add(reloadAction.onDidChange(e => {
|
||||
if (e.tooltip) {
|
||||
this.subtext.textContent = reloadAction.tooltip;
|
||||
show(this.subtextContainer);
|
||||
@@ -504,7 +506,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.telemetryService.publicLog('extensionEditor:navbarChange', assign(extension.telemetryData, { navItem: id }));
|
||||
}
|
||||
|
||||
this.contentDisposables = dispose(this.contentDisposables);
|
||||
this.contentDisposables.clear();
|
||||
this.content.innerHTML = '';
|
||||
this.activeElement = null;
|
||||
this.open(id, extension)
|
||||
@@ -538,15 +540,18 @@ export class ExtensionEditor extends BaseEditor {
|
||||
enableFindWidget: true,
|
||||
},
|
||||
{
|
||||
svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders
|
||||
svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders,
|
||||
localResourceRoots: [
|
||||
URI.parse(require.toUrl('./media'))
|
||||
]
|
||||
});
|
||||
webviewElement.mountTo(this.content);
|
||||
this.contentDisposables.push(webviewElement.onDidFocus(() => this.fireOnDidFocus()));
|
||||
this.contentDisposables.add(webviewElement.onDidFocus(() => this.fireOnDidFocus()));
|
||||
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, webviewElement);
|
||||
this.contentDisposables.push(toDisposable(removeLayoutParticipant));
|
||||
this.contentDisposables.add(toDisposable(removeLayoutParticipant));
|
||||
webviewElement.html = body;
|
||||
|
||||
this.contentDisposables.push(webviewElement.onDidClickLink(link => {
|
||||
this.contentDisposables.add(webviewElement.onDidClickLink(link => {
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
@@ -555,7 +560,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.openerService.open(link);
|
||||
}
|
||||
}, null, this.contentDisposables));
|
||||
this.contentDisposables.push(webviewElement);
|
||||
this.contentDisposables.add(webviewElement);
|
||||
return webviewElement;
|
||||
})
|
||||
.then(undefined, () => {
|
||||
@@ -585,7 +590,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
|
||||
const layout = () => scrollableContent.scanDomNode();
|
||||
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, { layout });
|
||||
this.contentDisposables.push(toDisposable(removeLayoutParticipant));
|
||||
this.contentDisposables.add(toDisposable(removeLayoutParticipant));
|
||||
|
||||
const renders = [
|
||||
this.renderSettings(content, manifest, layout),
|
||||
@@ -609,7 +614,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
append(this.content, content);
|
||||
} else {
|
||||
append(this.content, scrollableContent.getDomNode());
|
||||
this.contentDisposables.push(scrollableContent);
|
||||
this.contentDisposables.add(scrollableContent);
|
||||
}
|
||||
return content;
|
||||
}, () => {
|
||||
@@ -628,7 +633,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
const content = $('div', { class: 'subcontent' });
|
||||
const scrollableContent = new DomScrollableElement(content, {});
|
||||
append(this.content, scrollableContent.getDomNode());
|
||||
this.contentDisposables.push(scrollableContent);
|
||||
this.contentDisposables.add(scrollableContent);
|
||||
|
||||
const dependenciesTree = this.instantiationService.createInstance(ExtensionsTree, new ExtensionData(extension, null, extension => extension.dependencies || [], this.extensionsWorkbenchService), content);
|
||||
const layout = () => {
|
||||
@@ -637,9 +642,9 @@ export class ExtensionEditor extends BaseEditor {
|
||||
dependenciesTree.layout(scrollDimensions.height);
|
||||
};
|
||||
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, { layout });
|
||||
this.contentDisposables.push(toDisposable(removeLayoutParticipant));
|
||||
this.contentDisposables.add(toDisposable(removeLayoutParticipant));
|
||||
|
||||
this.contentDisposables.push(dependenciesTree);
|
||||
this.contentDisposables.add(dependenciesTree);
|
||||
scrollableContent.scanDomNode();
|
||||
return Promise.resolve({ focus() { dependenciesTree.domFocus(); } });
|
||||
}
|
||||
@@ -648,7 +653,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
const content = $('div', { class: 'subcontent' });
|
||||
const scrollableContent = new DomScrollableElement(content, {});
|
||||
append(this.content, scrollableContent.getDomNode());
|
||||
this.contentDisposables.push(scrollableContent);
|
||||
this.contentDisposables.add(scrollableContent);
|
||||
|
||||
const extensionsPackTree = this.instantiationService.createInstance(ExtensionsTree, new ExtensionData(extension, null, extension => extension.extensionPack || [], this.extensionsWorkbenchService), content);
|
||||
const layout = () => {
|
||||
@@ -657,9 +662,9 @@ export class ExtensionEditor extends BaseEditor {
|
||||
extensionsPackTree.layout(scrollDimensions.height);
|
||||
};
|
||||
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, { layout });
|
||||
this.contentDisposables.push(toDisposable(removeLayoutParticipant));
|
||||
this.contentDisposables.add(toDisposable(removeLayoutParticipant));
|
||||
|
||||
this.contentDisposables.push(extensionsPackTree);
|
||||
this.contentDisposables.add(extensionsPackTree);
|
||||
scrollableContent.scanDomNode();
|
||||
return Promise.resolve({ focus() { extensionsPackTree.domFocus(); } });
|
||||
}
|
||||
@@ -1074,7 +1079,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
const onDone = () => removeClass(this.content, 'loading');
|
||||
result.promise.then(onDone, onDone);
|
||||
|
||||
this.contentDisposables.push(toDisposable(() => result.dispose()));
|
||||
this.contentDisposables.add(toDisposable(() => result.dispose()));
|
||||
|
||||
return result.promise;
|
||||
}
|
||||
@@ -1090,12 +1095,6 @@ export class ExtensionEditor extends BaseEditor {
|
||||
|
||||
this.notificationService.error(err);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.transientDisposables = dispose(this.transientDisposables);
|
||||
this.disposables = dispose(this.disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class ShowExtensionEditorFindCommand extends Command {
|
||||
|
||||
@@ -228,6 +228,11 @@ configurationRegistry.registerConfiguration({
|
||||
},
|
||||
default: []
|
||||
},
|
||||
'terminal.integrated.inheritEnv': {
|
||||
markdownDescription: nls.localize('terminal.integrated.inheritEnv', "Whether new shells should inherit their environment from VS Code."),
|
||||
type: 'boolean',
|
||||
default: true
|
||||
},
|
||||
'terminal.integrated.env.osx': {
|
||||
markdownDescription: nls.localize('terminal.integrated.env.osx', "Object with environment variables that will be added to the VS Code process to be used by the terminal on macOS. Set to `null` to delete the environment variable."),
|
||||
type: 'object',
|
||||
|
||||
@@ -26,6 +26,7 @@ export interface ITerminalInstanceService {
|
||||
createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper;
|
||||
createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess;
|
||||
getDefaultShell(p: Platform): string;
|
||||
getMainProcessParentEnv(): Promise<IProcessEnvironment>;
|
||||
}
|
||||
|
||||
export interface IBrowserTerminalConfigHelper extends ITerminalConfigHelper {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { IWindowsShellHelper, ITerminalChildProcess } from 'vs/workbench/contrib
|
||||
import { Terminal as XTermTerminal } from 'xterm';
|
||||
import { WebLinksAddon as XTermWebLinksAddon } from 'xterm-addon-web-links';
|
||||
import { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
|
||||
let Terminal: typeof XTermTerminal;
|
||||
let WebLinksAddon: typeof XTermWebLinksAddon;
|
||||
@@ -50,4 +51,8 @@ export class TerminalInstanceService implements ITerminalInstanceService {
|
||||
public getDefaultShell(): string {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public async getMainProcessParentEnv(): Promise<IProcessEnvironment> {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -96,11 +96,11 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
}
|
||||
}
|
||||
|
||||
public createProcess(
|
||||
public async createProcess(
|
||||
shellLaunchConfig: IShellLaunchConfig,
|
||||
cols: number,
|
||||
rows: number
|
||||
): void {
|
||||
): Promise<void> {
|
||||
const forceExtHostProcess = (this._configHelper.config as any).extHostProcess;
|
||||
if (shellLaunchConfig.cwd && typeof shellLaunchConfig.cwd === 'object') {
|
||||
this.remoteAuthority = getRemoteAuthority(shellLaunchConfig.cwd);
|
||||
@@ -126,7 +126,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot();
|
||||
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, this._configHelper);
|
||||
} else {
|
||||
this._process = this._launchProcess(shellLaunchConfig, cols, rows);
|
||||
this._process = await this._launchProcess(shellLaunchConfig, cols, rows);
|
||||
}
|
||||
this.processState = ProcessState.LAUNCHING;
|
||||
|
||||
@@ -159,7 +159,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
}, LAUNCHING_DURATION);
|
||||
}
|
||||
|
||||
private _launchProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): ITerminalChildProcess {
|
||||
private async _launchProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): Promise<ITerminalChildProcess> {
|
||||
if (!shellLaunchConfig.executable) {
|
||||
this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig, this._terminalInstanceService.getDefaultShell(platform.platform));
|
||||
}
|
||||
@@ -171,7 +171,8 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
const lastActiveWorkspace = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : null;
|
||||
const envFromConfigValue = this._workspaceConfigurationService.inspect<ITerminalEnvironment | undefined>(`terminal.integrated.env.${platformKey}`);
|
||||
const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions();
|
||||
const env = terminalEnvironment.createTerminalEnvironment(shellLaunchConfig, lastActiveWorkspace, envFromConfigValue, this._configurationResolverService, isWorkspaceShellAllowed, this._productService.version, this._configHelper.config.setLocaleVariables);
|
||||
const baseEnv = this._configHelper.config.inheritEnv ? process.env as platform.IProcessEnvironment : await this._terminalInstanceService.getMainProcessParentEnv();
|
||||
const env = terminalEnvironment.createTerminalEnvironment(shellLaunchConfig, lastActiveWorkspace, envFromConfigValue, this._configurationResolverService, isWorkspaceShellAllowed, this._productService.version, this._configHelper.config.setLocaleVariables, baseEnv);
|
||||
|
||||
const useConpty = this._configHelper.config.windowsEnableConpty;
|
||||
return this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, useConpty);
|
||||
|
||||
@@ -94,6 +94,7 @@ export interface ITerminalConfiguration {
|
||||
cwd: string;
|
||||
confirmOnExit: boolean;
|
||||
enableBell: boolean;
|
||||
inheritEnv: boolean;
|
||||
env: {
|
||||
linux: { [key: string]: string };
|
||||
osx: { [key: string]: string };
|
||||
@@ -689,7 +690,7 @@ export interface ITerminalProcessManager extends IDisposable {
|
||||
readonly onProcessExit: Event<number>;
|
||||
|
||||
dispose(immediate?: boolean): void;
|
||||
createProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): void;
|
||||
createProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): Promise<void>;
|
||||
write(data: string): void;
|
||||
setDimensions(cols: number, rows: number): void;
|
||||
|
||||
|
||||
@@ -198,7 +198,8 @@ export function createTerminalEnvironment(
|
||||
configurationResolverService: IConfigurationResolverService | undefined,
|
||||
isWorkspaceShellAllowed: boolean,
|
||||
version: string | undefined,
|
||||
setLocaleVariables: boolean
|
||||
setLocaleVariables: boolean,
|
||||
baseEnv: platform.IProcessEnvironment
|
||||
): platform.IProcessEnvironment {
|
||||
// Create a terminal environment based on settings, launch config and permissions
|
||||
let env: platform.IProcessEnvironment = {};
|
||||
@@ -207,7 +208,7 @@ export function createTerminalEnvironment(
|
||||
mergeNonNullKeys(env, shellLaunchConfig.env);
|
||||
} else {
|
||||
// Merge process env with the env from config and from shellLaunchConfig
|
||||
mergeNonNullKeys(env, process.env);
|
||||
mergeNonNullKeys(env, baseEnv);
|
||||
|
||||
// const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||
// const envFromConfigValue = this._workspaceConfigurationService.inspect<ITerminalEnvironment | undefined>(`terminal.integrated.env.${platformKey}`);
|
||||
|
||||
@@ -7,12 +7,14 @@ import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/
|
||||
import { ITerminalInstance, IWindowsShellHelper, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProcessEnvironment, Platform } from 'vs/base/common/platform';
|
||||
import { IProcessEnvironment, Platform, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
||||
import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { Terminal as XTermTerminal } from 'xterm';
|
||||
import { WebLinksAddon as XTermWebLinksAddon } from 'xterm-addon-web-links';
|
||||
import { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
|
||||
import { readFile } from 'vs/base/node/pfs';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
|
||||
let Terminal: typeof XTermTerminal;
|
||||
let WebLinksAddon: typeof XTermWebLinksAddon;
|
||||
@@ -21,6 +23,8 @@ let SearchAddon: typeof XTermSearchAddon;
|
||||
export class TerminalInstanceService implements ITerminalInstanceService {
|
||||
public _serviceBrand: any;
|
||||
|
||||
private _mainProcessParentEnv: IProcessEnvironment | undefined;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
) {
|
||||
@@ -58,4 +62,73 @@ export class TerminalInstanceService implements ITerminalInstanceService {
|
||||
public getDefaultShell(p: Platform): string {
|
||||
return getDefaultShell(p);
|
||||
}
|
||||
|
||||
public async getMainProcessParentEnv(): Promise<IProcessEnvironment> {
|
||||
if (this._mainProcessParentEnv) {
|
||||
return this._mainProcessParentEnv;
|
||||
}
|
||||
|
||||
// For Linux use /proc/<pid>/status to get the parent of the main process and then fetch its
|
||||
// env using /proc/<pid>/environ.
|
||||
if (isLinux) {
|
||||
const mainProcessId = process.ppid;
|
||||
const codeProcessName = basename(process.argv[0]);
|
||||
let pid: number = 0;
|
||||
let ppid: number = mainProcessId;
|
||||
let name: string = codeProcessName;
|
||||
do {
|
||||
pid = ppid;
|
||||
const status = await readFile(`/proc/${pid}/status`, 'utf8');
|
||||
const splitByLine = status.split('\n');
|
||||
splitByLine.forEach(line => {
|
||||
if (line.indexOf('Name:') === 0) {
|
||||
name = line.replace(/^Name:\s+/, '');
|
||||
}
|
||||
if (line.indexOf('PPid:') === 0) {
|
||||
ppid = parseInt(line.replace(/^PPid:\s+/, ''));
|
||||
}
|
||||
});
|
||||
} while (name === codeProcessName);
|
||||
const rawEnv = await readFile(`/proc/${pid}/environ`, 'utf8');
|
||||
const env = {};
|
||||
rawEnv.split('\0').forEach(e => {
|
||||
const i = e.indexOf('=');
|
||||
env[e.substr(0, i)] = e.substr(i + 1);
|
||||
});
|
||||
this._mainProcessParentEnv = env;
|
||||
}
|
||||
|
||||
// For macOS we want the "root" environment as shells by default run as login shells. It
|
||||
// doesn't appear to be possible to get the "root" environment as `ps eww -o command` for
|
||||
// PID 1 (the parent of the main process when launched from the dock/finder) returns no
|
||||
// environment, because of this we will fill in the root environment using a whitelist of
|
||||
// environment variables that we have.
|
||||
if (isMacintosh) {
|
||||
this._mainProcessParentEnv = {};
|
||||
// This list was generated by diffing launching a terminal with {} and the system
|
||||
// terminal launched from finder.
|
||||
const rootEnvVars = [
|
||||
'SHELL',
|
||||
'SSH_AUTH_SOCK',
|
||||
'Apple_PubSub_Socket_Render',
|
||||
'XPC_FLAGS',
|
||||
'XPC_SERVICE_NAME',
|
||||
'HOME',
|
||||
'LOGNAME',
|
||||
'TMPDIR'
|
||||
];
|
||||
rootEnvVars.forEach(k => {
|
||||
if (process.env[k]) {
|
||||
this._mainProcessParentEnv![k] = process.env[k]!;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Windows should return a fresh environment block, might need native code?
|
||||
if (isWindows) {
|
||||
this._mainProcessParentEnv = process.env as IProcessEnvironment;
|
||||
}
|
||||
|
||||
return this._mainProcessParentEnv!;
|
||||
}
|
||||
}
|
||||
@@ -49,8 +49,9 @@ class MockTerminalInstanceService implements ITerminalInstanceService {
|
||||
getDefaultShell(p: Platform): string {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
|
||||
getMainProcessParentEnv(): any {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
interface LinkFormatInfo {
|
||||
|
||||
@@ -32,13 +32,13 @@ function renderBody(
|
||||
body: string,
|
||||
css: string
|
||||
): string {
|
||||
const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-core-resource://');
|
||||
const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-resource://');
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<base href="https://code.visualstudio.com/raw/">
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; script-src 'none'; style-src vscode-core-resource: https: 'unsafe-inline'; child-src 'none'; frame-src 'none';">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; script-src 'none'; style-src vscode-resource: https: 'unsafe-inline'; child-src 'none'; frame-src 'none';">
|
||||
<link rel="stylesheet" type="text/css" href="${styleSheetPath}">
|
||||
<style>${css}</style>
|
||||
</head>
|
||||
@@ -95,7 +95,13 @@ export class ReleaseNotesManager {
|
||||
'releaseNotes',
|
||||
title,
|
||||
{ group: ACTIVE_GROUP, preserveFocus: false },
|
||||
{ tryRestoreScrollPosition: true, enableFindWidget: true },
|
||||
{
|
||||
tryRestoreScrollPosition: true,
|
||||
enableFindWidget: true,
|
||||
localResourceRoots: [
|
||||
URI.parse(require.toUrl('./media'))
|
||||
]
|
||||
},
|
||||
undefined, {
|
||||
onDidClickLink: uri => this.onDidClickLink(uri),
|
||||
onDispose: () => { this._currentReleaseNotes = undefined; }
|
||||
|
||||
@@ -30,6 +30,8 @@ export interface IWebviewService {
|
||||
): Webview;
|
||||
}
|
||||
|
||||
export const WebviewResourceScheme = 'vscode-resource';
|
||||
|
||||
export interface WebviewOptions {
|
||||
readonly allowSvgs?: boolean;
|
||||
readonly extension?: {
|
||||
|
||||
@@ -21,8 +21,8 @@ import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { registerFileProtocol, WebviewProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols';
|
||||
import { Webview, WebviewContentOptions, WebviewOptions, WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { registerFileProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols';
|
||||
import { areWebviewInputOptionsEqual } from '../browser/webviewEditorService';
|
||||
import { WebviewFindWidget } from '../browser/webviewFindWidget';
|
||||
import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing';
|
||||
@@ -116,7 +116,6 @@ class WebviewProtocolProvider extends Disposable {
|
||||
webview: Electron.WebviewTag,
|
||||
private readonly _extensionLocation: URI | undefined,
|
||||
private readonly _getLocalResourceRoots: () => ReadonlyArray<URI>,
|
||||
private readonly _environmentService: IEnvironmentService,
|
||||
private readonly _fileService: IFileService,
|
||||
) {
|
||||
super();
|
||||
@@ -134,13 +133,7 @@ class WebviewProtocolProvider extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
const appRootUri = URI.file(this._environmentService.appRoot);
|
||||
|
||||
registerFileProtocol(contents, WebviewProtocol.CoreResource, this._fileService, undefined, () => [
|
||||
appRootUri
|
||||
]);
|
||||
|
||||
registerFileProtocol(contents, WebviewProtocol.VsCodeResource, this._fileService, this._extensionLocation, () =>
|
||||
registerFileProtocol(contents, WebviewResourceScheme, this._fileService, this._extensionLocation, () =>
|
||||
this._getLocalResourceRoots()
|
||||
);
|
||||
}
|
||||
@@ -420,7 +413,6 @@ export class WebviewElement extends Disposable implements Webview {
|
||||
this._webview,
|
||||
this._options.extension ? this._options.extension.location : undefined,
|
||||
() => (this.content.options.localResourceRoots || []),
|
||||
environmentService,
|
||||
fileService));
|
||||
|
||||
this._register(new WebviewPortMappingProvider(
|
||||
|
||||
@@ -12,10 +12,6 @@ import { getWebviewContentMimeType } from 'vs/workbench/contrib/webview/common/m
|
||||
|
||||
type BufferProtocolCallback = (buffer?: Buffer | electron.MimeTypedBuffer | { error: number }) => void;
|
||||
|
||||
export const enum WebviewProtocol {
|
||||
CoreResource = 'vscode-core-resource',
|
||||
VsCodeResource = 'vscode-resource',
|
||||
}
|
||||
|
||||
function resolveContent(fileService: IFileService, resource: URI, mime: string, callback: BufferProtocolCallback): void {
|
||||
fileService.readFile(resource).then(contents => {
|
||||
@@ -31,7 +27,7 @@ function resolveContent(fileService: IFileService, resource: URI, mime: string,
|
||||
|
||||
export function registerFileProtocol(
|
||||
contents: electron.WebContents,
|
||||
protocol: WebviewProtocol,
|
||||
protocol: string,
|
||||
fileService: IFileService,
|
||||
extensionLocation: URI | undefined,
|
||||
getRoots: () => ReadonlyArray<URI>
|
||||
|
||||
@@ -44,6 +44,7 @@ import { parse } from 'vs/base/common/json';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { IKeymapService } from 'vs/workbench/services/keybinding/common/keymapService';
|
||||
import { getDispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig';
|
||||
import { isArray } from 'vs/base/common/types';
|
||||
|
||||
interface ContributedKeyBinding {
|
||||
command: string;
|
||||
@@ -505,7 +506,8 @@ class UserKeybindings extends Disposable {
|
||||
const existing = this._keybindings;
|
||||
try {
|
||||
const content = await this.fileService.readFile(this.keybindingsResource);
|
||||
this._keybindings = parse(content.value.toString());
|
||||
const value = parse(content.value.toString());
|
||||
this._keybindings = isArray(value) ? value : [];
|
||||
} catch (e) {
|
||||
this._keybindings = [];
|
||||
}
|
||||
|
||||
@@ -91,18 +91,18 @@ suite('ExtHostDiagnostics', () => {
|
||||
new Diagnostic(new Range(0, 0, 1, 1), 'message-2')
|
||||
]);
|
||||
|
||||
let array = collection.get(URI.parse('foo:bar'));
|
||||
let array = collection.get(URI.parse('foo:bar')) as Diagnostic[];
|
||||
assert.throws(() => array.length = 0);
|
||||
assert.throws(() => array.pop());
|
||||
assert.throws(() => array[0] = new Diagnostic(new Range(0, 0, 0, 0), 'evil'));
|
||||
|
||||
collection.forEach((uri, array) => {
|
||||
collection.forEach((uri, array: Diagnostic[]) => {
|
||||
assert.throws(() => array.length = 0);
|
||||
assert.throws(() => array.pop());
|
||||
assert.throws(() => array[0] = new Diagnostic(new Range(0, 0, 0, 0), 'evil'));
|
||||
});
|
||||
|
||||
array = collection.get(URI.parse('foo:bar'));
|
||||
array = collection.get(URI.parse('foo:bar')) as Diagnostic[];
|
||||
assert.equal(array.length, 2);
|
||||
|
||||
collection.dispose();
|
||||
|
||||
Reference in New Issue
Block a user