Archived
Merge from vscode 3a6dcb42008d509900b3a3b2d695564eeb4dbdac (#5098)
This commit is contained in:
@@ -2,5 +2,5 @@
|
|||||||
setlocal
|
setlocal
|
||||||
set VSCODE_DEV=
|
set VSCODE_DEV=
|
||||||
set ELECTRON_RUN_AS_NODE=1
|
set ELECTRON_RUN_AS_NODE=1
|
||||||
call "%~dp0..\@@NAME@@.exe" "%~dp0..\resources\app\out\cli.js" %*
|
"%~dp0..\@@NAME@@.exe" "%~dp0..\resources\app\out\cli.js" %*
|
||||||
endlocal
|
endlocal
|
||||||
@@ -18,15 +18,20 @@ export const UTF16be_BOM = [0xFE, 0xFF];
|
|||||||
export const UTF16le_BOM = [0xFF, 0xFE];
|
export const UTF16le_BOM = [0xFF, 0xFE];
|
||||||
export const UTF8_BOM = [0xEF, 0xBB, 0xBF];
|
export const UTF8_BOM = [0xEF, 0xBB, 0xBF];
|
||||||
|
|
||||||
|
const ZERO_BYTE_DETECTION_BUFFER_MAX_LEN = 512; // number of bytes to look at to decide about a file being binary or not
|
||||||
|
const NO_GUESS_BUFFER_MAX_LEN = 512; // when not auto guessing the encoding, small number of bytes are enough
|
||||||
|
const AUTO_GUESS_BUFFER_MAX_LEN = 512 * 8; // with auto guessing we want a lot more content to be read for guessing
|
||||||
|
|
||||||
export interface IDecodeStreamOptions {
|
export interface IDecodeStreamOptions {
|
||||||
guessEncoding?: boolean;
|
guessEncoding: boolean;
|
||||||
minBytesRequiredForDetection?: number;
|
minBytesRequiredForDetection?: number;
|
||||||
overwriteEncoding?(detectedEncoding: string | null): string;
|
|
||||||
|
overwriteEncoding(detectedEncoding: string | null): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDecodeStreamResult {
|
export interface IDecodeStreamResult {
|
||||||
detected: IDetectedEncodingResult;
|
|
||||||
stream: NodeJS.ReadableStream;
|
stream: NodeJS.ReadableStream;
|
||||||
|
detected: IDetectedEncodingResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions): Promise<IDecodeStreamResult> {
|
export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions): Promise<IDecodeStreamResult> {
|
||||||
@@ -34,78 +39,82 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions
|
|||||||
options.minBytesRequiredForDetection = options.guessEncoding ? AUTO_GUESS_BUFFER_MAX_LEN : NO_GUESS_BUFFER_MAX_LEN;
|
options.minBytesRequiredForDetection = options.guessEncoding ? AUTO_GUESS_BUFFER_MAX_LEN : NO_GUESS_BUFFER_MAX_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.overwriteEncoding) {
|
|
||||||
options.overwriteEncoding = detected => detected || UTF8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise<IDecodeStreamResult>((resolve, reject) => {
|
return new Promise<IDecodeStreamResult>((resolve, reject) => {
|
||||||
const writer = new class extends Writable {
|
const writer = new class extends Writable {
|
||||||
private decodeStream: NodeJS.ReadWriteStream;
|
private decodeStream: NodeJS.ReadWriteStream;
|
||||||
private decodeStreamConstruction: Promise<void>;
|
private decodeStreamPromise: Promise<void>;
|
||||||
private buffer: Buffer[] = [];
|
|
||||||
|
private bufferedChunks: Buffer[] = [];
|
||||||
private bytesBuffered = 0;
|
private bytesBuffered = 0;
|
||||||
|
|
||||||
_write(chunk: any, encoding: string, callback: Function): void {
|
_write(chunk: Buffer, encoding: string, callback: (error: Error | null) => void): void {
|
||||||
if (!Buffer.isBuffer(chunk)) {
|
if (!Buffer.isBuffer(chunk)) {
|
||||||
callback(new Error('data must be a buffer'));
|
return callback(new Error('toDecodeStream(): data must be a buffer'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the decode stream is ready, we just write directly
|
||||||
if (this.decodeStream) {
|
if (this.decodeStream) {
|
||||||
this.decodeStream.write(chunk, callback); // just a forwarder now
|
this.decodeStream.write(chunk, callback);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buffer.push(chunk);
|
// otherwise we need to buffer the data until the stream is ready
|
||||||
this.bytesBuffered += chunk.length;
|
this.bufferedChunks.push(chunk);
|
||||||
|
this.bytesBuffered += chunk.byteLength;
|
||||||
|
|
||||||
// waiting for the decoder to be ready
|
// waiting for the decoder to be ready
|
||||||
if (this.decodeStreamConstruction) {
|
if (this.decodeStreamPromise) {
|
||||||
this.decodeStreamConstruction.then(() => callback(), err => callback(err));
|
this.decodeStreamPromise.then(() => callback(null), error => callback(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffered enough data, create stream and forward data
|
// buffered enough data for encoding detection, create stream and forward data
|
||||||
else if (typeof options.minBytesRequiredForDetection === 'number' && this.bytesBuffered >= options.minBytesRequiredForDetection) {
|
else if (typeof options.minBytesRequiredForDetection === 'number' && this.bytesBuffered >= options.minBytesRequiredForDetection) {
|
||||||
this._startDecodeStream(callback);
|
this._startDecodeStream(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// only buffering
|
// only buffering until enough data for encoding detection is there
|
||||||
else {
|
else {
|
||||||
callback();
|
callback(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_startDecodeStream(callback: Function): void {
|
_startDecodeStream(callback: (error: Error | null) => void): void {
|
||||||
this.decodeStreamConstruction = Promise.resolve(detectEncodingFromBuffer({
|
|
||||||
buffer: Buffer.concat(this.buffer),
|
// detect encoding from buffer
|
||||||
|
this.decodeStreamPromise = Promise.resolve(detectEncodingFromBuffer({
|
||||||
|
buffer: Buffer.concat(this.bufferedChunks),
|
||||||
bytesRead: this.bytesBuffered
|
bytesRead: this.bytesBuffered
|
||||||
}, options.guessEncoding)).then(detected => {
|
}, options.guessEncoding)).then(detected => {
|
||||||
if (options.overwriteEncoding) {
|
|
||||||
|
// ensure to respect overwrite of encoding
|
||||||
detected.encoding = options.overwriteEncoding(detected.encoding);
|
detected.encoding = options.overwriteEncoding(detected.encoding);
|
||||||
}
|
|
||||||
|
|
||||||
|
// decode and write buffer
|
||||||
this.decodeStream = decodeStream(detected.encoding);
|
this.decodeStream = decodeStream(detected.encoding);
|
||||||
|
this.decodeStream.write(Buffer.concat(this.bufferedChunks), callback);
|
||||||
|
this.bufferedChunks.length = 0;
|
||||||
|
|
||||||
for (const buffer of this.buffer) {
|
// signal to the outside our detected encoding
|
||||||
this.decodeStream.write(buffer);
|
// and final decoder stream
|
||||||
}
|
|
||||||
|
|
||||||
callback();
|
|
||||||
resolve({ detected, stream: this.decodeStream });
|
resolve({ detected, stream: this.decodeStream });
|
||||||
}, err => {
|
}, error => {
|
||||||
this.emit('error', err);
|
this.emit('error', error);
|
||||||
callback(err);
|
|
||||||
|
callback(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_final(callback: (err?: any) => any) {
|
_final(callback: (error: Error | null) => void) {
|
||||||
|
|
||||||
// normal finish
|
// normal finish
|
||||||
if (this.decodeStream) {
|
if (this.decodeStream) {
|
||||||
this.decodeStream.end(callback);
|
this.decodeStream.end(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we were still waiting for data...
|
// we were still waiting for data to do the encoding
|
||||||
|
// detection. thus, wrap up starting the stream even
|
||||||
|
// without all the data to get things going
|
||||||
else {
|
else {
|
||||||
this._startDecodeStream(() => this.decodeStream.end(callback));
|
this._startDecodeStream(() => this.decodeStream.end(callback));
|
||||||
}
|
}
|
||||||
@@ -149,7 +158,7 @@ function toNodeEncoding(enc: string | null): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null, bytesRead: number): string | null {
|
export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null, bytesRead: number): string | null {
|
||||||
if (!buffer || bytesRead < 2) {
|
if (!buffer || bytesRead < UTF16be_BOM.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +175,7 @@ export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null,
|
|||||||
return UTF16le;
|
return UTF16le;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytesRead < 3) {
|
if (bytesRead < UTF8_BOM.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,10 +265,6 @@ export function toCanonicalName(enc: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ZERO_BYTE_DETECTION_BUFFER_MAX_LEN = 512; // number of bytes to look at to decide about a file being binary or not
|
|
||||||
const NO_GUESS_BUFFER_MAX_LEN = 512; // when not auto guessing the encoding, small number of bytes are enough
|
|
||||||
const AUTO_GUESS_BUFFER_MAX_LEN = 512 * 8; // with auto guessing we want a lot more content to be read for guessing
|
|
||||||
|
|
||||||
export interface IDetectedEncodingResult {
|
export interface IDetectedEncodingResult {
|
||||||
encoding: string | null;
|
encoding: string | null;
|
||||||
seemsBinary: boolean;
|
seemsBinary: boolean;
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ export function registerContextMenuListener(): void {
|
|||||||
y: options ? options.y : undefined,
|
y: options ? options.y : undefined,
|
||||||
positioningItem: options ? options.positioningItem : undefined,
|
positioningItem: options ? options.positioningItem : undefined,
|
||||||
callback: () => {
|
callback: () => {
|
||||||
|
if (menu) {
|
||||||
event.sender.send(CONTEXT_MENU_CLOSE_CHANNEL, contextMenuId);
|
event.sender.send(CONTEXT_MENU_CLOSE_CHANNEL, contextMenuId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ const enum ProtocolMessageType {
|
|||||||
Regular = 1,
|
Regular = 1,
|
||||||
Control = 2,
|
Control = 2,
|
||||||
Ack = 3,
|
Ack = 3,
|
||||||
KeepAlive = 4
|
KeepAlive = 4,
|
||||||
|
Disconnect = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum ProtocolConstants {
|
export const enum ProtocolConstants {
|
||||||
@@ -373,6 +374,10 @@ export class Protocol extends Disposable implements IMessagePassingProtocol {
|
|||||||
return this._socket;
|
return this._socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendDisconnect(): void {
|
||||||
|
// Nothing to do...
|
||||||
|
}
|
||||||
|
|
||||||
send(buffer: VSBuffer): void {
|
send(buffer: VSBuffer): void {
|
||||||
this._socketWriter.write(new ProtocolMessage(ProtocolMessageType.Regular, 0, 0, buffer));
|
this._socketWriter.write(new ProtocolMessage(ProtocolMessageType.Regular, 0, 0, buffer));
|
||||||
}
|
}
|
||||||
@@ -393,6 +398,7 @@ export class Client<TContext = string> extends IPCClient<TContext> {
|
|||||||
dispose(): void {
|
dispose(): void {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
const socket = this.protocol.getSocket();
|
const socket = this.protocol.getSocket();
|
||||||
|
this.protocol.sendDisconnect();
|
||||||
this.protocol.dispose();
|
this.protocol.dispose();
|
||||||
socket.end();
|
socket.end();
|
||||||
}
|
}
|
||||||
@@ -572,7 +578,6 @@ export class PersistentProtocol {
|
|||||||
this._socketDisposables.push(this._socketReader);
|
this._socketDisposables.push(this._socketReader);
|
||||||
this._socketDisposables.push(this._socketReader.onMessage(msg => this._receiveMessage(msg)));
|
this._socketDisposables.push(this._socketReader.onMessage(msg => this._receiveMessage(msg)));
|
||||||
this._socketDisposables.push(this._socket.onClose(() => this._onSocketClose.fire()));
|
this._socketDisposables.push(this._socket.onClose(() => this._onSocketClose.fire()));
|
||||||
this._socketDisposables.push(this._socket.onEnd(() => this._onClose.fire()));
|
|
||||||
if (initialChunk) {
|
if (initialChunk) {
|
||||||
this._socketReader.acceptChunk(initialChunk);
|
this._socketReader.acceptChunk(initialChunk);
|
||||||
}
|
}
|
||||||
@@ -601,6 +606,12 @@ export class PersistentProtocol {
|
|||||||
this._socketDisposables = dispose(this._socketDisposables);
|
this._socketDisposables = dispose(this._socketDisposables);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendDisconnect(): void {
|
||||||
|
const msg = new ProtocolMessage(ProtocolMessageType.Disconnect, 0, 0, getEmptyBuffer());
|
||||||
|
this._socketWriter.write(msg);
|
||||||
|
this._socketWriter.flush();
|
||||||
|
}
|
||||||
|
|
||||||
private _sendKeepAliveCheck(): void {
|
private _sendKeepAliveCheck(): void {
|
||||||
if (this._outgoingKeepAliveTimeout) {
|
if (this._outgoingKeepAliveTimeout) {
|
||||||
// there will be a check in the near future
|
// there will be a check in the near future
|
||||||
@@ -659,7 +670,6 @@ export class PersistentProtocol {
|
|||||||
this._socketDisposables.push(this._socketReader);
|
this._socketDisposables.push(this._socketReader);
|
||||||
this._socketDisposables.push(this._socketReader.onMessage(msg => this._receiveMessage(msg)));
|
this._socketDisposables.push(this._socketReader.onMessage(msg => this._receiveMessage(msg)));
|
||||||
this._socketDisposables.push(this._socket.onClose(() => this._onSocketClose.fire()));
|
this._socketDisposables.push(this._socket.onClose(() => this._onSocketClose.fire()));
|
||||||
this._socketDisposables.push(this._socket.onEnd(() => this._onClose.fire()));
|
|
||||||
this._socketReader.acceptChunk(initialDataChunk);
|
this._socketReader.acceptChunk(initialDataChunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,6 +713,8 @@ export class PersistentProtocol {
|
|||||||
}
|
}
|
||||||
} else if (msg.type === ProtocolMessageType.Control) {
|
} else if (msg.type === ProtocolMessageType.Control) {
|
||||||
this._onControlMessage.fire(msg.data);
|
this._onControlMessage.fire(msg.data);
|
||||||
|
} else if (msg.type === ProtocolMessageType.Disconnect) {
|
||||||
|
this._onClose.fire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ suite('Encoding', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let { detected, stream } = await encoding.toDecodeStream(source, { minBytesRequiredForDetection: 4 });
|
let { detected, stream } = await encoding.toDecodeStream(source, { minBytesRequiredForDetection: 4, guessEncoding: false, overwriteEncoding: detected => detected || encoding.UTF8 });
|
||||||
|
|
||||||
assert.ok(detected);
|
assert.ok(detected);
|
||||||
assert.ok(stream);
|
assert.ok(stream);
|
||||||
@@ -260,7 +260,7 @@ suite('Encoding', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let { detected, stream } = await encoding.toDecodeStream(source, { minBytesRequiredForDetection: 64 });
|
let { detected, stream } = await encoding.toDecodeStream(source, { minBytesRequiredForDetection: 64, guessEncoding: false, overwriteEncoding: detected => detected || encoding.UTF8 });
|
||||||
|
|
||||||
assert.ok(detected);
|
assert.ok(detected);
|
||||||
assert.ok(stream);
|
assert.ok(stream);
|
||||||
@@ -277,7 +277,7 @@ suite('Encoding', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let { detected, stream } = await encoding.toDecodeStream(source, { minBytesRequiredForDetection: 512 });
|
let { detected, stream } = await encoding.toDecodeStream(source, { minBytesRequiredForDetection: 512, guessEncoding: false, overwriteEncoding: detected => detected || encoding.UTF8 });
|
||||||
|
|
||||||
assert.ok(detected);
|
assert.ok(detected);
|
||||||
assert.ok(stream);
|
assert.ok(stream);
|
||||||
@@ -292,7 +292,7 @@ suite('Encoding', () => {
|
|||||||
let path = getPathFromAmdModule(require, './fixtures/some_utf16be.css');
|
let path = getPathFromAmdModule(require, './fixtures/some_utf16be.css');
|
||||||
let source = fs.createReadStream(path);
|
let source = fs.createReadStream(path);
|
||||||
|
|
||||||
let { detected, stream } = await encoding.toDecodeStream(source, { minBytesRequiredForDetection: 64 });
|
let { detected, stream } = await encoding.toDecodeStream(source, { minBytesRequiredForDetection: 64, guessEncoding: false, overwriteEncoding: detected => detected || encoding.UTF8 });
|
||||||
|
|
||||||
assert.equal(detected.encoding, 'utf16be');
|
assert.equal(detected.encoding, 'utf16be');
|
||||||
assert.equal(detected.seemsBinary, false);
|
assert.equal(detected.seemsBinary, false);
|
||||||
@@ -307,7 +307,7 @@ suite('Encoding', () => {
|
|||||||
|
|
||||||
let path = getPathFromAmdModule(require, './fixtures/empty.txt');
|
let path = getPathFromAmdModule(require, './fixtures/empty.txt');
|
||||||
let source = fs.createReadStream(path);
|
let source = fs.createReadStream(path);
|
||||||
let { detected, stream } = await encoding.toDecodeStream(source, {});
|
let { detected, stream } = await encoding.toDecodeStream(source, { guessEncoding: false, overwriteEncoding: detected => detected || encoding.UTF8 });
|
||||||
|
|
||||||
let expected = await readAndDecodeFromDisk(path, detected.encoding);
|
let expected = await readAndDecodeFromDisk(path, detected.encoding);
|
||||||
let actual = await readAllAsString(stream);
|
let actual = await readAllAsString(stream);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
|
|||||||
import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporterUtil';
|
import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporterUtil';
|
||||||
import { Button } from 'vs/base/browser/ui/button/button';
|
import { Button } from 'vs/base/browser/ui/button/button';
|
||||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||||
import { SystemInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
import { SystemInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||||
|
|
||||||
const MAX_URL_LENGTH = platform.isWindows ? 2081 : 5400;
|
const MAX_URL_LENGTH = platform.isWindows ? 2081 : 5400;
|
||||||
|
|
||||||
@@ -940,6 +940,14 @@ export class IssueReporter extends Disposable {
|
|||||||
</table>`;
|
</table>`;
|
||||||
|
|
||||||
systemInfo.remoteData.forEach(remote => {
|
systemInfo.remoteData.forEach(remote => {
|
||||||
|
if (isRemoteDiagnosticError(remote)) {
|
||||||
|
renderedData += `
|
||||||
|
<hr>
|
||||||
|
<table>
|
||||||
|
<tr><td>Remote</td><td>${remote.hostName}</td></tr>
|
||||||
|
<tr><td></td><td>${remote.errorMessage}</td></tr>
|
||||||
|
</table>`;
|
||||||
|
} else {
|
||||||
renderedData += `
|
renderedData += `
|
||||||
<hr>
|
<hr>
|
||||||
<table>
|
<table>
|
||||||
@@ -949,6 +957,7 @@ export class IssueReporter extends Disposable {
|
|||||||
<tr><td>Memory (System)</td><td>${remote.machineInfo.memory}</td></tr>
|
<tr><td>Memory (System)</td><td>${remote.machineInfo.memory}</td></tr>
|
||||||
<tr><td>VM</td><td>${remote.machineInfo.vmHint}</td></tr>
|
<tr><td>VM</td><td>${remote.machineInfo.vmHint}</td></tr>
|
||||||
</table>`;
|
</table>`;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
target.innerHTML = renderedData;
|
target.innerHTML = renderedData;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { assign } from 'vs/base/common/objects';
|
import { assign } from 'vs/base/common/objects';
|
||||||
import { IssueType, ISettingSearchResult, IssueReporterExtensionData } from 'vs/platform/issue/common/issue';
|
import { IssueType, ISettingSearchResult, IssueReporterExtensionData } from 'vs/platform/issue/common/issue';
|
||||||
import { SystemInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
import { SystemInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||||
|
|
||||||
export interface IssueReporterData {
|
export interface IssueReporterData {
|
||||||
issueType: IssueType;
|
issueType: IssueType;
|
||||||
@@ -76,7 +76,8 @@ ${this.getInfos()}
|
|||||||
|
|
||||||
private getRemoteOSes(): string {
|
private getRemoteOSes(): string {
|
||||||
if (this._data.systemInfo && this._data.systemInfo.remoteData.length) {
|
if (this._data.systemInfo && this._data.systemInfo.remoteData.length) {
|
||||||
return this._data.systemInfo.remoteData.map(remote => `Remote OS version: ${remote.machineInfo.os}`).join('\n') + '\n';
|
return this._data.systemInfo.remoteData
|
||||||
|
.map(remote => isRemoteDiagnosticError(remote) ? remote.errorMessage : `Remote OS version: ${remote.machineInfo.os}`).join('\n') + '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
@@ -169,6 +170,9 @@ ${this.getInfos()}
|
|||||||
|VM|${this._data.systemInfo.vmHint}|`;
|
|VM|${this._data.systemInfo.vmHint}|`;
|
||||||
|
|
||||||
this._data.systemInfo.remoteData.forEach(remote => {
|
this._data.systemInfo.remoteData.forEach(remote => {
|
||||||
|
if (isRemoteDiagnosticError(remote)) {
|
||||||
|
md += `\n\n${remote.errorMessage}`;
|
||||||
|
} else {
|
||||||
md += `
|
md += `
|
||||||
|
|
||||||
|Item|Value|
|
|Item|Value|
|
||||||
@@ -178,6 +182,7 @@ ${this.getInfos()}
|
|||||||
|CPUs|${remote.machineInfo.cpus}|
|
|CPUs|${remote.machineInfo.cpus}|
|
||||||
|Memory (System)|${remote.machineInfo.memory}|
|
|Memory (System)|${remote.machineInfo.memory}|
|
||||||
|VM|${remote.machineInfo.vmHint}|`;
|
|VM|${remote.machineInfo.vmHint}|`;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<!-- // {{SQL CARBON EDIT}}
|
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: vscode-remote:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https: vscode-remote:;">
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: vscode-remote:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
|
|
||||||
-->
|
|
||||||
</head>
|
</head>
|
||||||
<body class="vs-dark" aria-label="">
|
<body class="vs-dark" aria-label="">
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1190,46 +1190,62 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we are not asked to open a workspace or folder that is already opened
|
if (!Array.isArray(extensionDevelopmentPath)) {
|
||||||
if (cliArgs.length && cliArgs.some(path => !!findWindowOnWorkspaceOrFolderUri(WindowsManager.WINDOWS, URI.file(path)))) {
|
extensionDevelopmentPath = [extensionDevelopmentPath];
|
||||||
cliArgs = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (folderUris.length && folderUris.some(uri => !!findWindowOnWorkspaceOrFolderUri(WindowsManager.WINDOWS, this.argToUri(uri)))) {
|
let authority = '';
|
||||||
folderUris = [];
|
for (let p of extensionDevelopmentPath) {
|
||||||
|
if (p.match(/^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/)) {
|
||||||
|
const url = URI.parse(p);
|
||||||
|
if (url.scheme === Schemas.vscodeRemote) {
|
||||||
|
if (authority) {
|
||||||
|
if (url.authority !== authority) {
|
||||||
|
this.logService.error('more than one extension development path authority');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authority = url.authority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileUris.length && fileUris.some(uri => !!findWindowOnWorkspaceOrFolderUri(WindowsManager.WINDOWS, this.argToUri(uri)))) {
|
// Make sure that we do not try to open:
|
||||||
fileUris = [];
|
// - a workspace or folder that is already opened
|
||||||
|
// - a workspace or file that has a different authority as the extension development.
|
||||||
|
|
||||||
|
cliArgs = cliArgs.filter(path => {
|
||||||
|
const uri = URI.file(path);
|
||||||
|
if (!!findWindowOnWorkspaceOrFolderUri(WindowsManager.WINDOWS, uri)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return uri.authority === authority;
|
||||||
|
});
|
||||||
|
|
||||||
|
folderUris = folderUris.filter(uri => {
|
||||||
|
const u = this.argToUri(uri);
|
||||||
|
if (!!findWindowOnWorkspaceOrFolderUri(WindowsManager.WINDOWS, u)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return u ? u.authority === authority : false;
|
||||||
|
});
|
||||||
|
|
||||||
|
fileUris = fileUris.filter(uri => {
|
||||||
|
const u = this.argToUri(uri);
|
||||||
|
if (!!findWindowOnWorkspaceOrFolderUri(WindowsManager.WINDOWS, u)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return u ? u.authority === authority : false;
|
||||||
|
});
|
||||||
|
|
||||||
openConfig.cli._ = cliArgs;
|
openConfig.cli._ = cliArgs;
|
||||||
openConfig.cli['folder-uri'] = folderUris;
|
openConfig.cli['folder-uri'] = folderUris;
|
||||||
openConfig.cli['file-uri'] = fileUris;
|
openConfig.cli['file-uri'] = fileUris;
|
||||||
|
|
||||||
if (Array.isArray(extensionDevelopmentPath)) {
|
// if there are no files or folders cli args left, use the "remote" cli argument
|
||||||
let authority: string | undefined = undefined;
|
if (!cliArgs.length && !folderUris.length && !fileUris.length) {
|
||||||
for (let p of extensionDevelopmentPath) {
|
|
||||||
const match = p.match(/^vscode-remote:\/\/([^\/]+)/);
|
|
||||||
if (match) {
|
|
||||||
const auth = URI.parse(p).authority;
|
|
||||||
if (authority) {
|
if (authority) {
|
||||||
if (auth !== authority) {
|
openConfig.cli.remote = authority;
|
||||||
console.log('more than one authority');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
authority = auth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (authority) {
|
|
||||||
openConfig.cli['remote'] = authority;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
const match = extensionDevelopmentPath.match(/^vscode-remote:\/\/([^\/]+)/);
|
|
||||||
if (match) {
|
|
||||||
openConfig.cli['remote'] = URI.parse(extensionDevelopmentPath).authority;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1581,7 +1597,8 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
cli = { ...cli, remote };
|
cli = { ...cli, remote };
|
||||||
}
|
}
|
||||||
const forceReuseWindow = options && options.reuseWindow;
|
const forceReuseWindow = options && options.reuseWindow;
|
||||||
return this.open({ context, cli, forceEmpty: true, forceReuseWindow });
|
const forceNewWindow = !forceReuseWindow;
|
||||||
|
return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow });
|
||||||
}
|
}
|
||||||
|
|
||||||
openNewTabbedWindow(context: OpenContext): ICodeWindow[] {
|
openNewTabbedWindow(context: OpenContext): ICodeWindow[] {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export class OpenerService implements IOpenerService {
|
|||||||
|
|
||||||
if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https) || equalsIgnoreCase(scheme, Schemas.mailto)) {
|
if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https) || equalsIgnoreCase(scheme, Schemas.mailto)) {
|
||||||
// open http or default mail application
|
// open http or default mail application
|
||||||
dom.windowOpenNoOpener(resource.toString(true));
|
dom.windowOpenNoOpener(encodeURI(resource.toString(true)));
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
|
|
||||||
} else if (equalsIgnoreCase(scheme, Schemas.command)) {
|
} else if (equalsIgnoreCase(scheme, Schemas.command)) {
|
||||||
|
|||||||
@@ -1288,6 +1288,7 @@ export interface CommentThread2 {
|
|||||||
onDidChangeRange: Event<IRange>;
|
onDidChangeRange: Event<IRange>;
|
||||||
onDidChangeLabel: Event<string>;
|
onDidChangeLabel: Event<string>;
|
||||||
onDidChangeCollasibleState: Event<CommentThreadCollapsibleState | undefined>;
|
onDidChangeCollasibleState: Event<CommentThreadCollapsibleState | undefined>;
|
||||||
|
isDisposed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1312,6 +1313,7 @@ export interface CommentThread {
|
|||||||
comments: Comment[] | undefined;
|
comments: Comment[] | undefined;
|
||||||
collapsibleState?: CommentThreadCollapsibleState;
|
collapsibleState?: CommentThreadCollapsibleState;
|
||||||
reply?: Command;
|
reply?: Command;
|
||||||
|
isDisposed?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ export abstract class BaseEditorSimpleWorker {
|
|||||||
|
|
||||||
// ---- BEGIN minimal edits ---------------------------------------------------------------
|
// ---- BEGIN minimal edits ---------------------------------------------------------------
|
||||||
|
|
||||||
private static readonly _diffLimit = 10000;
|
private static readonly _diffLimit = 100000;
|
||||||
|
|
||||||
public computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): Promise<TextEdit[]> {
|
public computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): Promise<TextEdit[]> {
|
||||||
const model = this._getModel(modelUrl);
|
const model = this._getModel(modelUrl);
|
||||||
@@ -432,7 +432,7 @@ export abstract class BaseEditorSimpleWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const original = model.getValueInRange(range);
|
const original = model.getValueInRange(range);
|
||||||
text = text!.replace(/\r\n|\n|\r/g, model.eol);
|
text = text.replace(/\r\n|\n|\r/g, model.eol);
|
||||||
|
|
||||||
if (original === text) {
|
if (original === text) {
|
||||||
// noop
|
// noop
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import { IModelService } from 'vs/editor/common/services/modelService';
|
|||||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||||
import { regExpFlags } from 'vs/base/common/strings';
|
import { regExpFlags } from 'vs/base/common/strings';
|
||||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||||
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
|
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop syncing a model to the worker if it was not needed for 1 min.
|
* Stop syncing a model to the worker if it was not needed for 1 min.
|
||||||
@@ -48,14 +50,16 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker
|
|||||||
|
|
||||||
private readonly _modelService: IModelService;
|
private readonly _modelService: IModelService;
|
||||||
private readonly _workerManager: WorkerManager;
|
private readonly _workerManager: WorkerManager;
|
||||||
|
private readonly _logService: ILogService;
|
||||||
constructor(
|
constructor(
|
||||||
@IModelService modelService: IModelService,
|
@IModelService modelService: IModelService,
|
||||||
@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService
|
@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService,
|
||||||
|
@ILogService logService: ILogService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._modelService = modelService;
|
this._modelService = modelService;
|
||||||
this._workerManager = this._register(new WorkerManager(this._modelService));
|
this._workerManager = this._register(new WorkerManager(this._modelService));
|
||||||
|
this._logService = logService;
|
||||||
|
|
||||||
// todo@joh make sure this happens only once
|
// todo@joh make sure this happens only once
|
||||||
this._register(modes.LinkProviderRegistry.register('*', {
|
this._register(modes.LinkProviderRegistry.register('*', {
|
||||||
@@ -96,7 +100,10 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker
|
|||||||
if (!canSyncModel(this._modelService, resource)) {
|
if (!canSyncModel(this._modelService, resource)) {
|
||||||
return Promise.resolve(edits); // File too large
|
return Promise.resolve(edits); // File too large
|
||||||
}
|
}
|
||||||
return this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits));
|
const sw = StopWatch.create(true);
|
||||||
|
const result = this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits));
|
||||||
|
result.finally(() => this._logService.trace('FORMAT#computeMoreMinimalEdits', resource.toString(true), sw.elapsed()));
|
||||||
|
return result;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
|
|||||||
@@ -145,8 +145,6 @@ export module StaticServices {
|
|||||||
|
|
||||||
export const markerDecorationsService = define(IMarkerDecorationsService, (o) => new MarkerDecorationsService(modelService.get(o), markerService.get(o)));
|
export const markerDecorationsService = define(IMarkerDecorationsService, (o) => new MarkerDecorationsService(modelService.get(o), markerService.get(o)));
|
||||||
|
|
||||||
export const editorWorkerService = define(IEditorWorkerService, (o) => new EditorWorkerServiceImpl(modelService.get(o), resourceConfigurationService.get(o)));
|
|
||||||
|
|
||||||
export const standaloneThemeService = define(IStandaloneThemeService, () => new StandaloneThemeServiceImpl());
|
export const standaloneThemeService = define(IStandaloneThemeService, () => new StandaloneThemeServiceImpl());
|
||||||
|
|
||||||
export const codeEditorService = define(ICodeEditorService, (o) => new StandaloneCodeEditorServiceImpl(standaloneThemeService.get(o)));
|
export const codeEditorService = define(ICodeEditorService, (o) => new StandaloneCodeEditorServiceImpl(standaloneThemeService.get(o)));
|
||||||
@@ -157,6 +155,8 @@ export module StaticServices {
|
|||||||
|
|
||||||
export const logService = define(ILogService, () => new NullLogService());
|
export const logService = define(ILogService, () => new NullLogService());
|
||||||
|
|
||||||
|
export const editorWorkerService = define(IEditorWorkerService, (o) => new EditorWorkerServiceImpl(modelService.get(o), resourceConfigurationService.get(o), logService.get(o)));
|
||||||
|
|
||||||
export const suggestMemoryService = define(ISuggestMemoryService, (o) => new SuggestMemoryService(storageService.get(o), configurationService.get(o)));
|
export const suggestMemoryService = define(ISuggestMemoryService, (o) => new SuggestMemoryService(storageService.get(o), configurationService.get(o)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export interface SystemInfo extends IMachineInfo {
|
|||||||
processArgs: string;
|
processArgs: string;
|
||||||
gpuStatus: any;
|
gpuStatus: any;
|
||||||
screenReader: string;
|
screenReader: string;
|
||||||
remoteData: IRemoteDiagnosticInfo[];
|
remoteData: (IRemoteDiagnosticInfo | IRemoteDiagnosticError)[];
|
||||||
load?: string;
|
load?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,8 @@ import product from 'vs/platform/product/node/product';
|
|||||||
|
|
||||||
export function isUIExtension(manifest: IExtensionManifest, uiContributions: string[], configurationService: IConfigurationService): boolean {
|
export function isUIExtension(manifest: IExtensionManifest, uiContributions: string[], configurationService: IConfigurationService): boolean {
|
||||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||||
const { ui, workspace } = configurationService.getValue<{ ui: string[], workspace: string[] }>('extensions.extensionKind') || { ui: [], workspace: [] };
|
const extensionKind = getExtensionKind(manifest, configurationService);
|
||||||
if (isNonEmptyArray(workspace) && workspace.some(id => areSameExtensions({ id }, { id: extensionId }))) {
|
switch (extensionKind) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isNonEmptyArray(ui) && ui.some(id => areSameExtensions({ id }, { id: extensionId }))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
switch (manifest.extensionKind) {
|
|
||||||
case 'ui': return true;
|
case 'ui': return true;
|
||||||
case 'workspace': return false;
|
case 'workspace': return false;
|
||||||
default: {
|
default: {
|
||||||
@@ -38,3 +32,14 @@ export function isUIExtension(manifest: IExtensionManifest, uiContributions: str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getExtensionKind(manifest: IExtensionManifest, configurationService: IConfigurationService): string | undefined {
|
||||||
|
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||||
|
const configuredExtensionKinds = configurationService.getValue<{ [key: string]: string }>('remote.extensionKind') || {};
|
||||||
|
for (const id of Object.keys(configuredExtensionKinds)) {
|
||||||
|
if (areSameExtensions({ id: extensionId }, { id })) {
|
||||||
|
return configuredExtensionKinds[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return manifest.extensionKind;
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,8 +34,9 @@ export function resolveCommonProperties(commit: string | undefined, version: str
|
|||||||
result['common.nodePlatform'] = process.platform;
|
result['common.nodePlatform'] = process.platform;
|
||||||
// __GDPR__COMMON__ "common.nodeArch" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
// __GDPR__COMMON__ "common.nodeArch" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||||
result['common.nodeArch'] = process.arch;
|
result['common.nodeArch'] = process.arch;
|
||||||
|
// __GDPR__COMMON__ "common.product" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
|
result['common.product'] = product.nameShort || 'desktop';
|
||||||
result['common.application.name'] = product.nameLong;
|
result['common.application.name'] = product.nameLong;
|
||||||
|
|
||||||
// dynamic properties which value differs on each call
|
// dynamic properties which value differs on each call
|
||||||
|
|||||||
Vendored
+39
@@ -1371,4 +1371,43 @@ declare module 'vscode' {
|
|||||||
group?: string;
|
group?: string;
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region Workspace URI Ben
|
||||||
|
|
||||||
|
export namespace workspace {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of the workspace file, for example:
|
||||||
|
*
|
||||||
|
* `file:///Users/name/Development/myProject.code-workspace`
|
||||||
|
*
|
||||||
|
* or
|
||||||
|
*
|
||||||
|
* `untitled:1555503116870`
|
||||||
|
*
|
||||||
|
* for a workspace that is untitled and not yet saved.
|
||||||
|
*
|
||||||
|
* Depending on the workspace that is opened, the value will be:
|
||||||
|
* * `undefined` when no workspace or a single folder is opened
|
||||||
|
* * the path of the workspace file as `Uri` otherwise. if the workspace
|
||||||
|
* is untitled, the returned URI will use the `untitled:` scheme
|
||||||
|
*
|
||||||
|
* The location can e.g. be used with the `vscode.openFolder` command to
|
||||||
|
* open the workspace again after it has been closed.
|
||||||
|
*
|
||||||
|
* **Example:**
|
||||||
|
* ```typescript
|
||||||
|
* vscode.commands.executeCommand('vscode.openFolder', uriOfWorkspace);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* **Note:** it is not advised to use `workspace.workspaceFile` to write
|
||||||
|
* configuration data into the file. You can use `workspace.getConfiguration().update()`
|
||||||
|
* for that purpose which will work both when a single folder is opened as
|
||||||
|
* well as an untitled or saved workspace.
|
||||||
|
*/
|
||||||
|
export const workspaceFile: Uri | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,6 +184,12 @@ export class MainThreadCommentThread implements modes.CommentThread2 {
|
|||||||
private _onDidChangeCollasibleState = new Emitter<modes.CommentThreadCollapsibleState | undefined>();
|
private _onDidChangeCollasibleState = new Emitter<modes.CommentThreadCollapsibleState | undefined>();
|
||||||
public onDidChangeCollasibleState = this._onDidChangeCollasibleState.event;
|
public onDidChangeCollasibleState = this._onDidChangeCollasibleState.event;
|
||||||
|
|
||||||
|
private _isDisposed: boolean;
|
||||||
|
|
||||||
|
get isDisposed(): boolean {
|
||||||
|
return this._isDisposed;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public commentThreadHandle: number,
|
public commentThreadHandle: number,
|
||||||
public controller: MainThreadCommentController,
|
public controller: MainThreadCommentController,
|
||||||
@@ -191,7 +197,9 @@ export class MainThreadCommentThread implements modes.CommentThread2 {
|
|||||||
public threadId: string,
|
public threadId: string,
|
||||||
public resource: string,
|
public resource: string,
|
||||||
private _range: IRange
|
private _range: IRange
|
||||||
) { }
|
) {
|
||||||
|
this._isDisposed = false;
|
||||||
|
}
|
||||||
|
|
||||||
batchUpdate(
|
batchUpdate(
|
||||||
range: IRange,
|
range: IRange,
|
||||||
@@ -210,7 +218,16 @@ export class MainThreadCommentThread implements modes.CommentThread2 {
|
|||||||
this._collapsibleState = collapsibleState;
|
this._collapsibleState = collapsibleState;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() { }
|
dispose() {
|
||||||
|
this._isDisposed = true;
|
||||||
|
this._onDidChangeAcceptInputCommand.dispose();
|
||||||
|
this._onDidChangeAdditionalCommands.dispose();
|
||||||
|
this._onDidChangeCollasibleState.dispose();
|
||||||
|
this._onDidChangeComments.dispose();
|
||||||
|
this._onDidChangeInput.dispose();
|
||||||
|
this._onDidChangeLabel.dispose();
|
||||||
|
this._onDidChangeRange.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
toJSON(): any {
|
toJSON(): any {
|
||||||
return {
|
return {
|
||||||
@@ -493,6 +510,8 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('createCommentThread', commentThreadHandle);
|
||||||
|
|
||||||
return provider.createCommentThread(commentThreadHandle, threadId, resource, range);
|
return provider.createCommentThread(commentThreadHandle, threadId, resource, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,23 +46,20 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async $openUri(uriComponent: UriComponents, options: IOpenUriOptions): Promise<boolean> {
|
async $openUri(uriComponent: UriComponents, options: IOpenUriOptions): Promise<boolean> {
|
||||||
const uri = URI.revive(uriComponent);
|
let uri = URI.revive(uriComponent);
|
||||||
if (options.allowTunneling && !!this.environmentService.configuration.remoteAuthority) {
|
if (options.allowTunneling && !!this.environmentService.configuration.remoteAuthority) {
|
||||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||||
const port = this.getLocalhostPort(uri);
|
const port = this.getLocalhostPort(uri);
|
||||||
if (typeof port === 'number') {
|
if (typeof port === 'number') {
|
||||||
const tunnel = await this.getOrCreateTunnel(port);
|
const tunnel = await this.getOrCreateTunnel(port);
|
||||||
if (tunnel) {
|
if (tunnel) {
|
||||||
const tunneledUrl = uri.toString().replace(
|
uri = uri.with({ authority: `localhost:${tunnel.tunnelLocalPort}` });
|
||||||
new RegExp(`^${uri.scheme}://localhost:${port}/`),
|
|
||||||
`${uri.scheme}://localhost:${tunnel.tunnelLocalPort}/`);
|
|
||||||
return this.windowsService.openExternal(tunneledUrl);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.windowsService.openExternal(uri.toString(true));
|
return this.windowsService.openExternal(encodeURI(uri.toString(true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLocalhostPort(uri: URI): number | undefined {
|
private getLocalhostPort(uri: URI): number | undefined {
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
|||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||||
import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape, IWorkspaceData, ITextSearchComplete } from '../common/extHost.protocol';
|
import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape, IWorkspaceData, ITextSearchComplete } from '../common/extHost.protocol';
|
||||||
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
import { isEqualOrParent } from 'vs/base/common/resources';
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadWorkspace)
|
@extHostNamedCustomer(MainContext.MainThreadWorkspace)
|
||||||
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||||
@@ -40,7 +42,8 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
|||||||
@IStatusbarService private readonly _statusbarService: IStatusbarService,
|
@IStatusbarService private readonly _statusbarService: IStatusbarService,
|
||||||
@IWindowService private readonly _windowService: IWindowService,
|
@IWindowService private readonly _windowService: IWindowService,
|
||||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||||
@ILabelService private readonly _labelService: ILabelService
|
@ILabelService private readonly _labelService: ILabelService,
|
||||||
|
@IEnvironmentService private readonly _environmentService: IEnvironmentService
|
||||||
) {
|
) {
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace);
|
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace);
|
||||||
this._contextService.getCompleteWorkspace().then(workspace => this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace)));
|
this._contextService.getCompleteWorkspace().then(workspace => this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace)));
|
||||||
@@ -110,6 +113,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
configuration: workspace.configuration || undefined,
|
configuration: workspace.configuration || undefined,
|
||||||
|
isUntitled: workspace.configuration ? isEqualOrParent(workspace.configuration, this._environmentService.untitledWorkspacesHome) : false,
|
||||||
folders: workspace.folders,
|
folders: workspace.folders,
|
||||||
id: workspace.id,
|
id: workspace.id,
|
||||||
name: this._labelService.getWorkspaceLabel(workspace)
|
name: this._labelService.getWorkspaceLabel(workspace)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { IWindowsService, IOpenSettings, IURIToOpen } from 'vs/platform/windows/
|
|||||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||||
import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
|
import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
|
||||||
import { IRecent } from 'vs/platform/history/common/history';
|
import { IRecent } from 'vs/platform/history/common/history';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
// The following commands are registered on both sides separately.
|
// The following commands are registered on both sides separately.
|
||||||
@@ -51,7 +52,7 @@ export class OpenFolderAPICommand {
|
|||||||
}
|
}
|
||||||
const options: IOpenSettings = { forceNewWindow: arg.forceNewWindow, noRecentEntry: arg.noRecentEntry };
|
const options: IOpenSettings = { forceNewWindow: arg.forceNewWindow, noRecentEntry: arg.noRecentEntry };
|
||||||
uri = URI.revive(uri);
|
uri = URI.revive(uri);
|
||||||
const uriToOpen: IURIToOpen = hasWorkspaceFileExtension(uri.path) ? { workspaceUri: uri } : { folderUri: uri };
|
const uriToOpen: IURIToOpen = (hasWorkspaceFileExtension(uri.path) || uri.scheme === Schemas.untitled) ? { workspaceUri: uri } : { folderUri: uri };
|
||||||
return executor.executeCommand('_files.windowOpen', [uriToOpen], options);
|
return executor.executeCommand('_files.windowOpen', [uriToOpen], options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export interface IStaticWorkspaceData {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
configuration?: UriComponents | null;
|
configuration?: UriComponents | null;
|
||||||
|
isUntitled?: boolean | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IWorkspaceData extends IStaticWorkspaceData {
|
export interface IWorkspaceData extends IStaticWorkspaceData {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
|||||||
import { TernarySearchTree } from 'vs/base/common/map';
|
import { TernarySearchTree } from 'vs/base/common/map';
|
||||||
import { Counter } from 'vs/base/common/numbers';
|
import { Counter } from 'vs/base/common/numbers';
|
||||||
import { isLinux } from 'vs/base/common/platform';
|
import { isLinux } from 'vs/base/common/platform';
|
||||||
import { basenameOrAuthority, dirname, isEqual, relativePath } from 'vs/base/common/resources';
|
import { basenameOrAuthority, dirname, isEqual, relativePath, basename } from 'vs/base/common/resources';
|
||||||
import { compare } from 'vs/base/common/strings';
|
import { compare } from 'vs/base/common/strings';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
@@ -24,6 +24,7 @@ import * as vscode from 'vscode';
|
|||||||
import { ExtHostWorkspaceShape, IWorkspaceData, MainThreadMessageServiceShape, MainThreadWorkspaceShape, IMainContext, MainContext, IStaticWorkspaceData } from './extHost.protocol';
|
import { ExtHostWorkspaceShape, IWorkspaceData, MainThreadMessageServiceShape, MainThreadWorkspaceShape, IMainContext, MainContext, IStaticWorkspaceData } from './extHost.protocol';
|
||||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { Barrier } from 'vs/base/common/async';
|
import { Barrier } from 'vs/base/common/async';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
export interface IExtHostWorkspaceProvider {
|
export interface IExtHostWorkspaceProvider {
|
||||||
getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise<vscode.WorkspaceFolder | undefined>;
|
getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise<vscode.WorkspaceFolder | undefined>;
|
||||||
@@ -67,7 +68,7 @@ class ExtHostWorkspaceImpl extends Workspace {
|
|||||||
return { workspace: null, added: [], removed: [] };
|
return { workspace: null, added: [], removed: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id, name, folders } = data;
|
const { id, name, folders, configuration, isUntitled } = data;
|
||||||
const newWorkspaceFolders: vscode.WorkspaceFolder[] = [];
|
const newWorkspaceFolders: vscode.WorkspaceFolder[] = [];
|
||||||
|
|
||||||
// If we have an existing workspace, we try to find the folders that match our
|
// If we have an existing workspace, we try to find the folders that match our
|
||||||
@@ -95,7 +96,7 @@ class ExtHostWorkspaceImpl extends Workspace {
|
|||||||
// make sure to restore sort order based on index
|
// make sure to restore sort order based on index
|
||||||
newWorkspaceFolders.sort((f1, f2) => f1.index < f2.index ? -1 : 1);
|
newWorkspaceFolders.sort((f1, f2) => f1.index < f2.index ? -1 : 1);
|
||||||
|
|
||||||
const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders);
|
const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders, configuration ? URI.revive(configuration) : null, !!isUntitled);
|
||||||
const { added, removed } = delta(oldWorkspace ? oldWorkspace.workspaceFolders : [], workspace.workspaceFolders, compareWorkspaceFolderByUri);
|
const { added, removed } = delta(oldWorkspace ? oldWorkspace.workspaceFolders : [], workspace.workspaceFolders, compareWorkspaceFolderByUri);
|
||||||
|
|
||||||
return { workspace, added, removed };
|
return { workspace, added, removed };
|
||||||
@@ -115,8 +116,8 @@ class ExtHostWorkspaceImpl extends Workspace {
|
|||||||
private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
|
private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
|
||||||
private readonly _structure = TernarySearchTree.forPaths<vscode.WorkspaceFolder>();
|
private readonly _structure = TernarySearchTree.forPaths<vscode.WorkspaceFolder>();
|
||||||
|
|
||||||
constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[]) {
|
constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[], configuration: URI | null, private _isUntitled: boolean) {
|
||||||
super(id, folders.map(f => new WorkspaceFolder(f)));
|
super(id, folders.map(f => new WorkspaceFolder(f)), configuration);
|
||||||
|
|
||||||
// setup the workspace folder data structure
|
// setup the workspace folder data structure
|
||||||
folders.forEach(folder => {
|
folders.forEach(folder => {
|
||||||
@@ -129,6 +130,10 @@ class ExtHostWorkspaceImpl extends Workspace {
|
|||||||
return this._name;
|
return this._name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isUntitled(): boolean {
|
||||||
|
return this._isUntitled;
|
||||||
|
}
|
||||||
|
|
||||||
get workspaceFolders(): vscode.WorkspaceFolder[] {
|
get workspaceFolders(): vscode.WorkspaceFolder[] {
|
||||||
return this._workspaceFolders.slice(0);
|
return this._workspaceFolders.slice(0);
|
||||||
}
|
}
|
||||||
@@ -175,7 +180,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
|
|||||||
|
|
||||||
this._proxy = mainContext.getProxy(MainContext.MainThreadWorkspace);
|
this._proxy = mainContext.getProxy(MainContext.MainThreadWorkspace);
|
||||||
this._messageService = mainContext.getProxy(MainContext.MainThreadMessageService);
|
this._messageService = mainContext.getProxy(MainContext.MainThreadMessageService);
|
||||||
this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, []) : undefined;
|
this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, [], data.configuration ? URI.revive(data.configuration) : null, !!data.isUntitled) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
$initializeWorkspace(data: IWorkspaceData): void {
|
$initializeWorkspace(data: IWorkspaceData): void {
|
||||||
@@ -197,6 +202,20 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
|
|||||||
return this._actualWorkspace ? this._actualWorkspace.name : undefined;
|
return this._actualWorkspace ? this._actualWorkspace.name : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get workspaceFile(): vscode.Uri | undefined {
|
||||||
|
if (this._actualWorkspace) {
|
||||||
|
if (this._actualWorkspace.configuration) {
|
||||||
|
if (this._actualWorkspace.isUntitled) {
|
||||||
|
return URI.from({ scheme: Schemas.untitled, path: basename(dirname(this._actualWorkspace.configuration)) }); // Untitled Worspace: return untitled URI
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._actualWorkspace.configuration; // Workspace: return the configuration location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
private get _actualWorkspace(): ExtHostWorkspaceImpl | undefined {
|
private get _actualWorkspace(): ExtHostWorkspaceImpl | undefined {
|
||||||
return this._unconfirmedWorkspace || this._confirmedWorkspace;
|
return this._unconfirmedWorkspace || this._confirmedWorkspace;
|
||||||
}
|
}
|
||||||
@@ -365,7 +384,8 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
|
|||||||
id: this._actualWorkspace.id,
|
id: this._actualWorkspace.id,
|
||||||
name: this._actualWorkspace.name,
|
name: this._actualWorkspace.name,
|
||||||
configuration: this._actualWorkspace.configuration,
|
configuration: this._actualWorkspace.configuration,
|
||||||
folders
|
folders,
|
||||||
|
isUntitled: this._actualWorkspace.isUntitled
|
||||||
} as IWorkspaceData, this._actualWorkspace).workspace || undefined;
|
} as IWorkspaceData, this._actualWorkspace).workspace || undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export function createApiFactory(
|
|||||||
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
|
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
|
||||||
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostDocumentsAndEditors));
|
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostDocumentsAndEditors));
|
||||||
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
|
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
|
||||||
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol, extHostConfiguration, extHostLogService));
|
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol, extHostConfiguration, extHostWorkspace, extHostDocumentsAndEditors, extHostLogService));
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
// const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService, extHostCommands));
|
// const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService, extHostCommands));
|
||||||
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
|
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
|
||||||
@@ -539,6 +539,12 @@ export function createApiFactory(
|
|||||||
set name(value) {
|
set name(value) {
|
||||||
throw errors.readonly();
|
throw errors.readonly();
|
||||||
},
|
},
|
||||||
|
get workspaceFile() {
|
||||||
|
return extHostWorkspace.workspaceFile;
|
||||||
|
},
|
||||||
|
set workspaceFile(value) {
|
||||||
|
throw errors.readonly();
|
||||||
|
},
|
||||||
updateWorkspaceFolders: (index, deleteCount, ...workspaceFoldersToAdd) => {
|
updateWorkspaceFolders: (index, deleteCount, ...workspaceFoldersToAdd) => {
|
||||||
return extHostWorkspace.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd);
|
return extHostWorkspace.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
|||||||
private readonly _mainThreadExtensionsProxy: MainThreadExtensionServiceShape;
|
private readonly _mainThreadExtensionsProxy: MainThreadExtensionServiceShape;
|
||||||
|
|
||||||
private readonly _almostReadyToRunExtensions: Barrier;
|
private readonly _almostReadyToRunExtensions: Barrier;
|
||||||
|
private readonly _readyToStartExtensionHost: Barrier;
|
||||||
private readonly _readyToRunExtensions: Barrier;
|
private readonly _readyToRunExtensions: Barrier;
|
||||||
private readonly _registry: ExtensionDescriptionRegistry;
|
private readonly _registry: ExtensionDescriptionRegistry;
|
||||||
private readonly _storage: ExtHostStorage;
|
private readonly _storage: ExtHostStorage;
|
||||||
@@ -101,6 +102,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
|||||||
this._mainThreadExtensionsProxy = this._extHostContext.getProxy(MainContext.MainThreadExtensionService);
|
this._mainThreadExtensionsProxy = this._extHostContext.getProxy(MainContext.MainThreadExtensionService);
|
||||||
|
|
||||||
this._almostReadyToRunExtensions = new Barrier();
|
this._almostReadyToRunExtensions = new Barrier();
|
||||||
|
this._readyToStartExtensionHost = new Barrier();
|
||||||
this._readyToRunExtensions = new Barrier();
|
this._readyToRunExtensions = new Barrier();
|
||||||
this._registry = new ExtensionDescriptionRegistry(initData.extensions);
|
this._registry = new ExtensionDescriptionRegistry(initData.extensions);
|
||||||
this._storage = new ExtHostStorage(this._extHostContext);
|
this._storage = new ExtHostStorage(this._extHostContext);
|
||||||
@@ -171,7 +173,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
|||||||
this._almostReadyToRunExtensions.open();
|
this._almostReadyToRunExtensions.open();
|
||||||
|
|
||||||
await this._extHostWorkspace.waitForInitializeCall();
|
await this._extHostWorkspace.waitForInitializeCall();
|
||||||
this._readyToRunExtensions.open();
|
this._readyToStartExtensionHost.open();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
errors.onUnexpectedError(err);
|
errors.onUnexpectedError(err);
|
||||||
}
|
}
|
||||||
@@ -581,7 +583,8 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
|||||||
}
|
}
|
||||||
this._started = true;
|
this._started = true;
|
||||||
|
|
||||||
return this._readyToRunExtensions.wait()
|
return this._readyToStartExtensionHost.wait()
|
||||||
|
.then(() => this._readyToRunExtensions.open())
|
||||||
.then(() => this._handleEagerExtensions())
|
.then(() => this._handleEagerExtensions())
|
||||||
.then(() => this._handleExtensionTests())
|
.then(() => this._handleExtensionTests())
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -13,10 +13,14 @@ import { Event, Emitter } from 'vs/base/common/event';
|
|||||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto } from 'vs/workbench/api/common/extHost.protocol';
|
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal';
|
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||||
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
||||||
import { timeout } from 'vs/base/common/async';
|
import { timeout } from 'vs/base/common/async';
|
||||||
import { sanitizeProcessEnvironment } from 'vs/base/common/processes';
|
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||||
|
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
|
// {{SQL CARBON EDIT}}
|
||||||
|
// import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
|
||||||
|
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||||
|
|
||||||
const RENDERER_NO_PROCESS_ID = -1;
|
const RENDERER_NO_PROCESS_ID = -1;
|
||||||
|
|
||||||
@@ -288,6 +292,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||||||
constructor(
|
constructor(
|
||||||
mainContext: IMainContext,
|
mainContext: IMainContext,
|
||||||
private _extHostConfiguration: ExtHostConfiguration,
|
private _extHostConfiguration: ExtHostConfiguration,
|
||||||
|
private _extHostWorkspace: ExtHostWorkspace,
|
||||||
|
private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
|
||||||
private _logService: ILogService,
|
private _logService: ILogService,
|
||||||
) {
|
) {
|
||||||
this._proxy = mainContext.getProxy(MainContext.MainThreadTerminalService);
|
this._proxy = mainContext.getProxy(MainContext.MainThreadTerminalService);
|
||||||
@@ -436,6 +442,16 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _apiInspectConfigToPlain<T>(
|
||||||
|
config: { key: string; defaultValue?: T; globalValue?: T; workspaceValue?: T, workspaceFolderValue?: T } | undefined
|
||||||
|
): { user: T | undefined, value: T | undefined, default: T | undefined } {
|
||||||
|
return {
|
||||||
|
user: config ? config.globalValue : undefined,
|
||||||
|
value: config ? config.workspaceValue : undefined,
|
||||||
|
default: config ? config.defaultValue : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public async $createProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
|
public async $createProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
|
||||||
const shellLaunchConfig: IShellLaunchConfig = {
|
const shellLaunchConfig: IShellLaunchConfig = {
|
||||||
name: shellLaunchConfigDto.name,
|
name: shellLaunchConfigDto.name,
|
||||||
@@ -447,57 +463,54 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||||||
|
|
||||||
// Merge in shell and args from settings
|
// Merge in shell and args from settings
|
||||||
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||||
|
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||||
if (!shellLaunchConfig.executable) {
|
if (!shellLaunchConfig.executable) {
|
||||||
const fetchSetting = (key: string) => {
|
const fetchSetting = (key: string) => {
|
||||||
const setting = configProvider
|
const setting = configProvider
|
||||||
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
||||||
.inspect<string | string[]>(key.substr(key.lastIndexOf('.') + 1));
|
.inspect<string | string[]>(key.substr(key.lastIndexOf('.') + 1));
|
||||||
return {
|
return this._apiInspectConfigToPlain<string | string[]>(setting);
|
||||||
user: setting ? setting.globalValue : undefined,
|
|
||||||
value: setting ? setting.workspaceValue : undefined,
|
|
||||||
default: setting ? setting.defaultValue : undefined,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
terminalEnvironment.mergeDefaultShellPathAndArgs(shellLaunchConfig, fetchSetting, isWorkspaceShellAllowed || false);
|
terminalEnvironment.mergeDefaultShellPathAndArgs(shellLaunchConfig, fetchSetting, isWorkspaceShellAllowed || false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the initial cwd
|
// Get the initial cwd
|
||||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
|
||||||
const terminalConfig = configProvider.getConfiguration('terminal.integrated');
|
const terminalConfig = configProvider.getConfiguration('terminal.integrated');
|
||||||
const activeWorkspaceRootUri = URI.revive(activeWorkspaceRootUriComponents);
|
const activeWorkspaceRootUri = URI.revive(activeWorkspaceRootUriComponents);
|
||||||
const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, os.homedir(), activeWorkspaceRootUri, terminalConfig.cwd);
|
const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, os.homedir(), activeWorkspaceRootUri, terminalConfig.cwd);
|
||||||
|
|
||||||
// TODO: Pull in and resolve config settings
|
// Get the environment
|
||||||
// // Resolve env vars from config and shell
|
const apiLastActiveWorkspace = await this._extHostWorkspace.getWorkspaceFolder(activeWorkspaceRootUri);
|
||||||
// const lastActiveWorkspaceRoot = this._workspaceContextService.getWorkspaceFolder(lastActiveWorkspaceRootUri);
|
const lastActiveWorkspace = apiLastActiveWorkspace ? {
|
||||||
// const envFromConfig = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...terminalConfig.env[platformKey] }, lastActiveWorkspaceRoot);
|
uri: apiLastActiveWorkspace.uri,
|
||||||
const envFromConfig = { ...terminalConfig.env[platformKey] };
|
name: apiLastActiveWorkspace.name,
|
||||||
// const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot);
|
index: apiLastActiveWorkspace.index,
|
||||||
|
toResource: () => {
|
||||||
// Merge process env with the env from config
|
throw new Error('Not implemented');
|
||||||
const env = { ...process.env };
|
}
|
||||||
Object.keys(env).filter(k => env[k] === undefined).forEach(k => {
|
} as IWorkspaceFolder : null;
|
||||||
delete env[k];
|
const envFromConfig = this._apiInspectConfigToPlain(configProvider.getConfiguration('terminal.integrated').inspect<ITerminalEnvironment>(`env.${platformKey}`));
|
||||||
});
|
const workspaceFolders = await this._extHostWorkspace.getWorkspaceFolders2();
|
||||||
const castedEnv = env as platform.IProcessEnvironment;
|
// {{SQL CARBON EDIT}}
|
||||||
terminalEnvironment.mergeEnvironments(castedEnv, envFromConfig);
|
// const variableResolver = workspaceFolders ? new ExtHostVariableResolverService(workspaceFolders, this._extHostDocumentsAndEditors, configProvider) : undefined;
|
||||||
terminalEnvironment.mergeEnvironments(castedEnv, shellLaunchConfig.env);
|
const variableResolver = undefined;
|
||||||
|
const env = terminalEnvironment.createTerminalEnvironment(
|
||||||
// Sanitize the environment, removing any undesirable VS Code and Electron environment
|
shellLaunchConfig,
|
||||||
// variables
|
lastActiveWorkspace,
|
||||||
sanitizeProcessEnvironment(castedEnv, 'VSCODE_IPC_HOOK_CLI');
|
envFromConfig,
|
||||||
|
variableResolver,
|
||||||
// Continue env initialization, merging in the env from the launch
|
isWorkspaceShellAllowed,
|
||||||
// config and adding keys that are needed to create the process
|
pkg.version,
|
||||||
terminalEnvironment.addTerminalEnvironmentKeys(castedEnv, pkg.version, platform.locale, terminalConfig.get('setLocaleVariables') as boolean);
|
terminalConfig.get<boolean>('setLocaleVariables', false)
|
||||||
|
);
|
||||||
|
|
||||||
// Fork the process and listen for messages
|
// Fork the process and listen for messages
|
||||||
this._logService.debug(`Terminal process launching on ext host`, shellLaunchConfig, initialCwd, cols, rows, castedEnv);
|
this._logService.debug(`Terminal process launching on ext host`, shellLaunchConfig, initialCwd, cols, rows, env);
|
||||||
const p = new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, castedEnv, terminalConfig.get('windowsEnableConpty') as boolean);
|
const p = new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, terminalConfig.get('windowsEnableConpty') as boolean);
|
||||||
p.onProcessIdReady(pid => this._proxy.$sendProcessPid(id, pid));
|
p.onProcessIdReady(pid => this._proxy.$sendProcessPid(id, pid));
|
||||||
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
|
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
|
||||||
p.onProcessData(data => this._proxy.$sendProcessData(id, data));
|
p.onProcessData(data => this._proxy.$sendProcessData(id, data));
|
||||||
p.onProcessExit((exitCode) => this._onProcessExit(id, exitCode));
|
p.onProcessExit(exitCode => this._onProcessExit(id, exitCode));
|
||||||
this._terminalProcesses[id] = p;
|
this._terminalProcesses[id] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,7 +554,6 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||||||
|
|
||||||
// Send exit event to main side
|
// Send exit event to main side
|
||||||
this._proxy.$sendProcessExit(id, exitCode);
|
this._proxy.$sendProcessExit(id, exitCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal> {
|
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal> {
|
||||||
|
|||||||
@@ -145,13 +145,14 @@ export class NoTabsTitleControl extends TitleControl {
|
|||||||
this.redraw();
|
this.redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEditorLabel(editor?: IEditorInput): void {
|
updateEditorLabel(editor: IEditorInput): void {
|
||||||
if (!editor) {
|
|
||||||
editor = withNullAsUndefined(this.group.activeEditor);
|
|
||||||
}
|
|
||||||
if (editor) {
|
|
||||||
this.ifEditorIsActive(editor, () => this.redraw());
|
this.ifEditorIsActive(editor, () => this.redraw());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateEditorLabels(): void {
|
||||||
|
if (this.group.activeEditor) {
|
||||||
|
this.updateEditorLabel(this.group.activeEditor); // we only have the active one to update
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEditorDirty(editor: IEditorInput): void {
|
updateEditorDirty(editor: IEditorInput): void {
|
||||||
|
|||||||
@@ -371,6 +371,12 @@ export class TabsTitleControl extends TitleControl {
|
|||||||
|
|
||||||
updateEditorLabel(editor: IEditorInput): void {
|
updateEditorLabel(editor: IEditorInput): void {
|
||||||
|
|
||||||
|
// Update all labels to account for changes to tab labels
|
||||||
|
this.updateEditorLabels();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateEditorLabels(): void {
|
||||||
|
|
||||||
// A change to a label requires to recompute all labels
|
// A change to a label requires to recompute all labels
|
||||||
this.computeTabLabels();
|
this.computeTabLabels();
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export abstract class TitleControl extends Themable {
|
|||||||
|
|
||||||
private registerListeners(): void {
|
private registerListeners(): void {
|
||||||
this._register(this.extensionService.onDidRegisterExtensions(() => this.updateEditorActionsToolbar()));
|
this._register(this.extensionService.onDidRegisterExtensions(() => this.updateEditorActionsToolbar()));
|
||||||
this._register(this.labelService.onDidChangeFormatters(() => this.updateEditorLabel()));
|
this._register(this.labelService.onDidChangeFormatters(() => this.updateEditorLabels()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract create(parent: HTMLElement): void;
|
protected abstract create(parent: HTMLElement): void;
|
||||||
@@ -343,7 +343,9 @@ export abstract class TitleControl extends Themable {
|
|||||||
|
|
||||||
abstract setActive(isActive: boolean): void;
|
abstract setActive(isActive: boolean): void;
|
||||||
|
|
||||||
abstract updateEditorLabel(editor?: IEditorInput): void;
|
abstract updateEditorLabel(editor: IEditorInput): void;
|
||||||
|
|
||||||
|
abstract updateEditorLabels(): void;
|
||||||
|
|
||||||
abstract updateEditorDirty(editor: IEditorInput): void;
|
abstract updateEditorDirty(editor: IEditorInput): void;
|
||||||
|
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ class NotificationMessageRenderer {
|
|||||||
|
|
||||||
const anchor = document.createElement('a');
|
const anchor = document.createElement('a');
|
||||||
anchor.textContent = link.name;
|
anchor.textContent = link.name;
|
||||||
anchor.title = link.href;
|
anchor.title = link.title;
|
||||||
anchor.href = link.href;
|
anchor.href = link.href;
|
||||||
|
|
||||||
if (actionHandler) {
|
if (actionHandler) {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
|||||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||||
import { Action } from 'vs/base/common/actions';
|
import { Action } from 'vs/base/common/actions';
|
||||||
import { isErrorWithActions } from 'vs/base/common/errorsWithActions';
|
import { isErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||||
|
import { startsWith } from 'vs/base/common/strings';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
|
||||||
export interface INotificationsModel {
|
export interface INotificationsModel {
|
||||||
|
|
||||||
@@ -306,8 +308,9 @@ export class NotificationViewItemProgress extends Disposable implements INotific
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessageLink {
|
export interface IMessageLink {
|
||||||
name: string;
|
|
||||||
href: string;
|
href: string;
|
||||||
|
name: string;
|
||||||
|
title: string;
|
||||||
offset: number;
|
offset: number;
|
||||||
length: number;
|
length: number;
|
||||||
}
|
}
|
||||||
@@ -325,7 +328,7 @@ export class NotificationViewItem extends Disposable implements INotificationVie
|
|||||||
|
|
||||||
// Example link: "Some message with [link text](http://link.href)."
|
// Example link: "Some message with [link text](http://link.href)."
|
||||||
// RegEx: [, anything not ], ], (, http://|https://|command:, no whitespace)
|
// RegEx: [, anything not ], ], (, http://|https://|command:, no whitespace)
|
||||||
private static LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)\)/gi;
|
private static LINK_REGEX = /\[([^\]]+)\]\(((?:https?:\/\/|command:)[^\)\s]+)(?: "([^"]+)")?\)/gi;
|
||||||
|
|
||||||
private _expanded: boolean;
|
private _expanded: boolean;
|
||||||
|
|
||||||
@@ -392,8 +395,17 @@ export class NotificationViewItem extends Disposable implements INotificationVie
|
|||||||
|
|
||||||
// Parse Links
|
// Parse Links
|
||||||
const links: IMessageLink[] = [];
|
const links: IMessageLink[] = [];
|
||||||
message.replace(NotificationViewItem.LINK_REGEX, (matchString: string, name: string, href: string, offset: number) => {
|
message.replace(NotificationViewItem.LINK_REGEX, (matchString: string, name: string, href: string, title: string, offset: number) => {
|
||||||
links.push({ name, href, offset, length: matchString.length });
|
let massagedTitle: string;
|
||||||
|
if (title && title.length > 0) {
|
||||||
|
massagedTitle = title;
|
||||||
|
} else if (startsWith(href, 'command:')) {
|
||||||
|
massagedTitle = localize('executeCommand', "Click to execute command '{0}'", href.substr('command:'.length));
|
||||||
|
} else {
|
||||||
|
massagedTitle = href;
|
||||||
|
}
|
||||||
|
|
||||||
|
links.push({ name, href, title: massagedTitle, offset, length: matchString.length });
|
||||||
|
|
||||||
return matchString;
|
return matchString;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -738,6 +738,7 @@ export class ReviewController implements IEditorContribution {
|
|||||||
|
|
||||||
this._commentInfos.forEach(info => {
|
this._commentInfos.forEach(info => {
|
||||||
let providerCacheStore = this._pendingCommentCache[info.owner];
|
let providerCacheStore = this._pendingCommentCache[info.owner];
|
||||||
|
info.threads = info.threads.filter(thread => !thread.isDisposed);
|
||||||
info.threads.forEach(thread => {
|
info.threads.forEach(thread => {
|
||||||
let pendingComment: string | null = null;
|
let pendingComment: string | null = null;
|
||||||
if (providerCacheStore) {
|
if (providerCacheStore) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, IReplElementSource,
|
ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, IReplElementSource,
|
||||||
IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IReplElement, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State
|
IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IReplElement, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State
|
||||||
} from 'vs/workbench/contrib/debug/common/debug';
|
} from 'vs/workbench/contrib/debug/common/debug';
|
||||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
import { Source, UNKNOWN_SOURCE_LABEL } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||||
import { commonSuffixLength } from 'vs/base/common/strings';
|
import { commonSuffixLength } from 'vs/base/common/strings';
|
||||||
import { posix } from 'vs/base/common/path';
|
import { posix } from 'vs/base/common/path';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
@@ -381,7 +381,10 @@ export class StackFrame implements IStackFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return `${this.name} (${this.source.inMemory ? this.source.name : this.source.uri.fsPath}:${this.range.startLineNumber})`;
|
const lineNumberToString = typeof this.range.startLineNumber === 'number' ? `:${this.range.startLineNumber}` : '';
|
||||||
|
const sourceToString = `${this.source.inMemory ? this.source.name : this.source.uri.fsPath}${lineNumberToString}`;
|
||||||
|
|
||||||
|
return sourceToString === UNKNOWN_SOURCE_LABEL ? this.name : `${this.name} (${sourceToString})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise<any> {
|
openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise<any> {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/
|
|||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
|
import { isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||||
|
|
||||||
const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source");
|
export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug URI format
|
* Debug URI format
|
||||||
|
|||||||
@@ -394,6 +394,22 @@ suite('Debug - Model', () => {
|
|||||||
assert.equal(secondStackFrame.getSpecificSourceName(), '.../x/c/d/internalModule.js');
|
assert.equal(secondStackFrame.getSpecificSourceName(), '.../x/c/d/internalModule.js');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('stack frame toString()', () => {
|
||||||
|
const session = createMockSession(model);
|
||||||
|
const thread = new Thread(session, 'mockthread', 1);
|
||||||
|
const firstSource = new Source({
|
||||||
|
name: 'internalModule.js',
|
||||||
|
path: 'a/b/c/d/internalModule.js',
|
||||||
|
sourceReference: 10,
|
||||||
|
}, 'aDebugSessionId');
|
||||||
|
const stackFrame = new StackFrame(thread, 1, firstSource, 'app', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 10 }, 1);
|
||||||
|
assert.equal(stackFrame.toString(), 'app (internalModule.js:1)');
|
||||||
|
|
||||||
|
const secondSource = new Source(undefined, 'aDebugSessionId');
|
||||||
|
const stackFrame2 = new StackFrame(thread, 2, secondSource, 'module', 'normal', { startLineNumber: undefined!, startColumn: undefined!, endLineNumber: undefined!, endColumn: undefined! }, 2);
|
||||||
|
assert.equal(stackFrame2.toString(), 'module');
|
||||||
|
});
|
||||||
|
|
||||||
test('debug child sessions are added in correct order', () => {
|
test('debug child sessions are added in correct order', () => {
|
||||||
const session = createMockSession(model);
|
const session = createMockSession(model);
|
||||||
model.addSession(session);
|
model.addSession(session);
|
||||||
|
|||||||
@@ -252,35 +252,6 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
|||||||
scope: ConfigurationScope.APPLICATION,
|
scope: ConfigurationScope.APPLICATION,
|
||||||
default: ExtensionsPolicy.allowAll
|
default: ExtensionsPolicy.allowAll
|
||||||
},
|
},
|
||||||
'extensions.extensionKind': {
|
|
||||||
type: 'object',
|
|
||||||
description: localize('extensions.extensionKind', "Configure ui or workspace extensions and allow them to run locally or remotely in a remote window."),
|
|
||||||
properties: {
|
|
||||||
'ui': {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
pattern: '^([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'workspace': {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
pattern: '^([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
default: {
|
|
||||||
ui: [],
|
|
||||||
workspace: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'extensions.showInstalledExtensionsByDefault': {
|
|
||||||
type: 'boolean',
|
|
||||||
description: localize('extensions.showInstalledExtensionsByDefault', "When enabled, extensions view shows installed extensions view by default."),
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IE
|
|||||||
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
|
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
|
||||||
import { IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionRecommendation, IGalleryExtension, IExtensionsConfigContent, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/platform/extensionManagement/common/extensionManagement';
|
import { IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionRecommendation, IGalleryExtension, IExtensionsConfigContent, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||||
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
import { ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
||||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||||
@@ -176,14 +176,17 @@ export class InstallAction extends ExtensionAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(): void {
|
update(): void {
|
||||||
if (!this.extension || this.extension.type === ExtensionType.System) {
|
if (!this.extension || this.extension.type === ExtensionType.System || this.extension.state === ExtensionState.Installed) {
|
||||||
this.enabled = false;
|
this.enabled = false;
|
||||||
this.class = InstallAction.Class;
|
this.class = InstallAction.Class;
|
||||||
this.label = InstallAction.INSTALL_LABEL;
|
this.label = InstallAction.INSTALL_LABEL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.enabled = false;
|
||||||
this.enabled = this.extensionsWorkbenchService.canInstall(this.extension) && !this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, this.extension.identifier));
|
if (this.extensionsWorkbenchService.canInstall(this.extension)) {
|
||||||
|
const local = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
|
||||||
|
this.enabled = !local || (!!local.local && isLanguagePackExtension(local.local.manifest));
|
||||||
|
}
|
||||||
this.class = this.extension.state === ExtensionState.Installing ? InstallAction.InstallingClass : InstallAction.Class;
|
this.class = this.extension.state === ExtensionState.Installing ? InstallAction.InstallingClass : InstallAction.Class;
|
||||||
this.updateLabel();
|
this.updateLabel();
|
||||||
}
|
}
|
||||||
@@ -2590,6 +2593,9 @@ export class DisabledLabelAction extends ExtensionAction {
|
|||||||
this.class = `${DisabledLabelAction.Class} hide`;
|
this.class = `${DisabledLabelAction.Class} hide`;
|
||||||
this.label = '';
|
this.label = '';
|
||||||
this.enabled = false;
|
this.enabled = false;
|
||||||
|
if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.warningAction.enabled) {
|
if (this.warningAction.enabled) {
|
||||||
this.enabled = true;
|
this.enabled = true;
|
||||||
this.class = DisabledLabelAction.Class;
|
this.class = DisabledLabelAction.Class;
|
||||||
@@ -2649,6 +2655,9 @@ export class SystemDisabledWarningAction extends ExtensionAction {
|
|||||||
this.enabled = false;
|
this.enabled = false;
|
||||||
this.class = `${SystemDisabledWarningAction.Class} hide`;
|
this.class = `${SystemDisabledWarningAction.Class} hide`;
|
||||||
this.tooltip = '';
|
this.tooltip = '';
|
||||||
|
if (this.extension && this.extension.local && isLanguagePackExtension(this.extension.local.manifest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.extension && this.extension.local && this.extension.server && this._runningExtensions && this.workbenchEnvironmentService.configuration.remoteAuthority && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
if (this.extension && this.extension.local && this.extension.server && this._runningExtensions && this.workbenchEnvironmentService.configuration.remoteAuthority && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||||
const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
|
const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier))[0];
|
||||||
const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null;
|
const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteB
|
|||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
import { IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
|
import { isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||||
|
|
||||||
export interface IExtensionsViewState {
|
export interface IExtensionsViewState {
|
||||||
onFocus: Event<IExtension>;
|
onFocus: Event<IExtension>;
|
||||||
@@ -154,7 +155,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||||||
|
|
||||||
const updateEnablement = async () => {
|
const updateEnablement = async () => {
|
||||||
const runningExtensions = await this.extensionService.getExtensions();
|
const runningExtensions = await this.extensionService.getExtensions();
|
||||||
if (extension.local) {
|
if (extension.local && !isLanguagePackExtension(extension.local.manifest)) {
|
||||||
const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, extension.identifier))[0];
|
const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value }, extension.identifier))[0];
|
||||||
const isSameExtensionRunning = runningExtension && extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation);
|
const isSameExtensionRunning = runningExtension && extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation);
|
||||||
toggleClass(data.root, 'disabled', !isSameExtensionRunning);
|
toggleClass(data.root, 'disabled', !isSameExtensionRunning);
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
|
|||||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||||
|
import { RemoteAuthorityContext } from 'vs/workbench/common/contextkeys';
|
||||||
|
|
||||||
interface SearchInputEvent extends Event {
|
interface SearchInputEvent extends Event {
|
||||||
target: HTMLInputElement;
|
target: HTMLInputElement;
|
||||||
@@ -139,7 +140,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
|||||||
id,
|
id,
|
||||||
name: viewIdNameMappings[id],
|
name: viewIdNameMappings[id],
|
||||||
ctorDescriptor: { ctor: EnabledExtensionsView },
|
ctorDescriptor: { ctor: EnabledExtensionsView },
|
||||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), ContextKeyExpr.not('config.extensions.showInstalledExtensionsByDefault')),
|
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')),
|
||||||
weight: 40,
|
weight: 40,
|
||||||
canToggleVisibility: true,
|
canToggleVisibility: true,
|
||||||
order: 1
|
order: 1
|
||||||
@@ -154,7 +155,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
|||||||
id,
|
id,
|
||||||
name: viewIdNameMappings[id],
|
name: viewIdNameMappings[id],
|
||||||
ctorDescriptor: { ctor: DisabledExtensionsView },
|
ctorDescriptor: { ctor: DisabledExtensionsView },
|
||||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), ContextKeyExpr.not('config.extensions.showInstalledExtensionsByDefault')),
|
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')),
|
||||||
weight: 10,
|
weight: 10,
|
||||||
canToggleVisibility: true,
|
canToggleVisibility: true,
|
||||||
order: 3,
|
order: 3,
|
||||||
@@ -195,7 +196,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio
|
|||||||
id: `extensions.${server.authority}.default`,
|
id: `extensions.${server.authority}.default`,
|
||||||
name: localize('installed', "Installed"),
|
name: localize('installed', "Installed"),
|
||||||
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server] },
|
||||||
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), ContextKeyExpr.has('config.extensions.showInstalledExtensionsByDefault')),
|
when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.notEqualsTo('')),
|
||||||
weight: 40,
|
weight: 40,
|
||||||
order: 1
|
order: 1
|
||||||
}];
|
}];
|
||||||
@@ -512,7 +513,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||||||
|
|
||||||
private doSearch(): Promise<void> {
|
private doSearch(): Promise<void> {
|
||||||
const value = this.normalizedQuery();
|
const value = this.normalizedQuery();
|
||||||
this.defaultViewsContextKey.set(!value);
|
|
||||||
const isRecommendedExtensionsQuery = ExtensionsListView.isRecommendedExtensionsQuery(value);
|
const isRecommendedExtensionsQuery = ExtensionsListView.isRecommendedExtensionsQuery(value);
|
||||||
this.searchInstalledExtensionsContextKey.set(ExtensionsListView.isInstalledExtensionsQuery(value));
|
this.searchInstalledExtensionsContextKey.set(ExtensionsListView.isInstalledExtensionsQuery(value));
|
||||||
this.searchOutdatedExtensionsContextKey.set(ExtensionsListView.isOutdatedExtensionsQuery(value));
|
this.searchOutdatedExtensionsContextKey.set(ExtensionsListView.isOutdatedExtensionsQuery(value));
|
||||||
@@ -522,6 +522,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||||||
this.recommendedExtensionsContextKey.set(isRecommendedExtensionsQuery);
|
this.recommendedExtensionsContextKey.set(isRecommendedExtensionsQuery);
|
||||||
this.searchMarketplaceExtensionsContextKey.set(!!value && !ExtensionsListView.isLocalExtensionsQuery(value) && !isRecommendedExtensionsQuery);
|
this.searchMarketplaceExtensionsContextKey.set(!!value && !ExtensionsListView.isLocalExtensionsQuery(value) && !isRecommendedExtensionsQuery);
|
||||||
this.nonEmptyWorkspaceContextKey.set(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY);
|
this.nonEmptyWorkspaceContextKey.set(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY);
|
||||||
|
this.defaultViewsContextKey.set(!value);
|
||||||
|
|
||||||
return this.progress(Promise.all(this.panels.map(view =>
|
return this.progress(Promise.all(this.panels.map(view =>
|
||||||
(<ExtensionsListView>view).show(this.normalizedQuery())
|
(<ExtensionsListView>view).show(this.normalizedQuery())
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
|
|||||||
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { IAction } from 'vs/base/common/actions';
|
import { IAction } from 'vs/base/common/actions';
|
||||||
import { ExtensionType, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import product from 'vs/platform/product/node/product';
|
import product from 'vs/platform/product/node/product';
|
||||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||||
@@ -343,6 +343,11 @@ export class ExtensionsListView extends ViewletPanel {
|
|||||||
if ((isE1Running && isE2Running) || (!isE1Running && !isE2Running)) {
|
if ((isE1Running && isE2Running) || (!isE1Running && !isE2Running)) {
|
||||||
return e1.displayName.localeCompare(e2.displayName);
|
return e1.displayName.localeCompare(e2.displayName);
|
||||||
}
|
}
|
||||||
|
const isE1LanguagePackExtension = e1.local && isLanguagePackExtension(e1.local.manifest);
|
||||||
|
const isE2LanguagePackExtension = e2.local && isLanguagePackExtension(e2.local.manifest);
|
||||||
|
if ((isE1Running && isE2LanguagePackExtension) || (isE2Running && isE1LanguagePackExtension)) {
|
||||||
|
return e1.displayName.localeCompare(e2.displayName);
|
||||||
|
}
|
||||||
return isE1Running ? -1 : 1;
|
return isE1Running ? -1 : 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
|||||||
import { VIEWLET_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
import { VIEWLET_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IFileService, AutoSaveConfiguration } from 'vs/platform/files/common/files';
|
import { IFileService, AutoSaveConfiguration } from 'vs/platform/files/common/files';
|
||||||
import { toResource, ITextEditor, SideBySideEditor } from 'vs/workbench/common/editor';
|
import { toResource, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||||
import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet';
|
import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet';
|
||||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||||
@@ -356,64 +356,6 @@ function containsBothDirectoryAndFile(distinctElements: ExplorerItem[]): boolean
|
|||||||
return directories.length > 0 && files.length > 0;
|
return directories.length > 0 && files.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pasteShouldMove = false;
|
|
||||||
// Paste File/Folder
|
|
||||||
class PasteFileAction extends Action {
|
|
||||||
|
|
||||||
public static readonly ID = 'filesExplorer.paste';
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private element: ExplorerItem,
|
|
||||||
@IFileService private fileService: IFileService,
|
|
||||||
@INotificationService private notificationService: INotificationService,
|
|
||||||
@IEditorService private readonly editorService: IEditorService,
|
|
||||||
@IExplorerService private readonly explorerService: IExplorerService
|
|
||||||
) {
|
|
||||||
super(PasteFileAction.ID, PASTE_FILE_LABEL);
|
|
||||||
|
|
||||||
if (!this.element) {
|
|
||||||
this.element = this.explorerService.roots[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public run(fileToPaste: URI): Promise<any> {
|
|
||||||
|
|
||||||
// Check if target is ancestor of pasted folder
|
|
||||||
if (this.element.resource.toString() !== fileToPaste.toString() && resources.isEqualOrParent(this.element.resource, fileToPaste, !isLinux /* ignorecase */)) {
|
|
||||||
throw new Error(nls.localize('fileIsAncestor', "File to paste is an ancestor of the destination folder"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.fileService.resolve(fileToPaste).then(fileToPasteStat => {
|
|
||||||
|
|
||||||
// Find target
|
|
||||||
let target: ExplorerItem;
|
|
||||||
if (this.element.resource.toString() === fileToPaste.toString()) {
|
|
||||||
target = this.element.parent!;
|
|
||||||
} else {
|
|
||||||
target = this.element.isDirectory ? this.element : this.element.parent!;
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetFile = findValidPasteFileTarget(target, { resource: fileToPaste, isDirectory: fileToPasteStat.isDirectory, allowOverwirte: pasteShouldMove });
|
|
||||||
|
|
||||||
// Copy File
|
|
||||||
const promise = pasteShouldMove ? this.fileService.move(fileToPaste, targetFile) : this.fileService.copy(fileToPaste, targetFile);
|
|
||||||
return promise.then<ITextEditor | undefined>(stat => {
|
|
||||||
if (pasteShouldMove) {
|
|
||||||
// Cut is done. Make sure to clear cut state.
|
|
||||||
this.explorerService.setToCopy([], false);
|
|
||||||
}
|
|
||||||
if (!stat.isDirectory) {
|
|
||||||
return this.editorService.openEditor({ resource: stat.resource, options: { pinned: true, preserveFocus: true } })
|
|
||||||
.then(types.withNullAsUndefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}, e => onError(this.notificationService, e));
|
|
||||||
}, error => {
|
|
||||||
onError(this.notificationService, new Error(nls.localize('fileDeleted', "File to paste was deleted or moved meanwhile")));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function findValidPasteFileTarget(targetFolder: ExplorerItem, fileToPaste: { resource: URI, isDirectory?: boolean, allowOverwirte: boolean }): URI {
|
export function findValidPasteFileTarget(targetFolder: ExplorerItem, fileToPaste: { resource: URI, isDirectory?: boolean, allowOverwirte: boolean }): URI {
|
||||||
let name = resources.basenameOrAuthority(fileToPaste.resource);
|
let name = resources.basenameOrAuthority(fileToPaste.resource);
|
||||||
@@ -1083,6 +1025,7 @@ export const deleteFileHandler = (accessor: ServicesAccessor) => {
|
|||||||
return deleteFiles(accessor, stats, false);
|
return deleteFiles(accessor, stats, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let pasteShouldMove = false;
|
||||||
export const copyFileHandler = (accessor: ServicesAccessor) => {
|
export const copyFileHandler = (accessor: ServicesAccessor) => {
|
||||||
const listService = accessor.get(IListService);
|
const listService = accessor.get(IListService);
|
||||||
if (!listService.lastFocusedList) {
|
if (!listService.lastFocusedList) {
|
||||||
@@ -1112,16 +1055,50 @@ export const cutFileHandler = (accessor: ServicesAccessor) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const pasteFileHandler = (accessor: ServicesAccessor) => {
|
export const pasteFileHandler = (accessor: ServicesAccessor) => {
|
||||||
const instantiationService = accessor.get(IInstantiationService);
|
|
||||||
const listService = accessor.get(IListService);
|
const listService = accessor.get(IListService);
|
||||||
const clipboardService = accessor.get(IClipboardService);
|
const clipboardService = accessor.get(IClipboardService);
|
||||||
if (!listService.lastFocusedList) {
|
const explorerService = accessor.get(IExplorerService);
|
||||||
return Promise.resolve();
|
const fileService = accessor.get(IFileService);
|
||||||
}
|
const notificationService = accessor.get(INotificationService);
|
||||||
const explorerContext = getContext(listService.lastFocusedList);
|
const editorService = accessor.get(IEditorService);
|
||||||
|
|
||||||
return sequence(resources.distinctParents(clipboardService.readResources(), r => r).map(toCopy => {
|
if (listService.lastFocusedList) {
|
||||||
const pasteFileAction = instantiationService.createInstance(PasteFileAction, explorerContext.stat);
|
const explorerContext = getContext(listService.lastFocusedList);
|
||||||
return () => pasteFileAction.run(toCopy);
|
const toPaste = resources.distinctParents(clipboardService.readResources(), r => r);
|
||||||
}));
|
const element = explorerContext.stat || explorerService.roots[0];
|
||||||
|
|
||||||
|
// Check if target is ancestor of pasted folder
|
||||||
|
sequence(toPaste.map(fileToPaste => () => {
|
||||||
|
|
||||||
|
if (element.resource.toString() !== fileToPaste.toString() && resources.isEqualOrParent(element.resource, fileToPaste, !isLinux /* ignorecase */)) {
|
||||||
|
throw new Error(nls.localize('fileIsAncestor', "File to paste is an ancestor of the destination folder"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileService.resolve(fileToPaste).then(fileToPasteStat => {
|
||||||
|
|
||||||
|
// Find target
|
||||||
|
let target: ExplorerItem;
|
||||||
|
if (element.resource.toString() === fileToPaste.toString()) {
|
||||||
|
target = element.parent!;
|
||||||
|
} else {
|
||||||
|
target = element.isDirectory ? element : element.parent!;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetFile = findValidPasteFileTarget(target, { resource: fileToPaste, isDirectory: fileToPasteStat.isDirectory, allowOverwirte: pasteShouldMove });
|
||||||
|
|
||||||
|
// Copy File
|
||||||
|
return pasteShouldMove ? fileService.move(fileToPaste, targetFile) : fileService.copy(fileToPaste, targetFile);
|
||||||
|
}, error => {
|
||||||
|
onError(notificationService, new Error(nls.localize('fileDeleted', "File to paste was deleted or moved meanwhile")));
|
||||||
|
});
|
||||||
|
})).then((stat) => {
|
||||||
|
if (pasteShouldMove) {
|
||||||
|
// Cut is done. Make sure to clear cut state.
|
||||||
|
explorerService.setToCopy([], false);
|
||||||
|
}
|
||||||
|
if (stat.length === 1 && !stat[0].isDirectory) {
|
||||||
|
editorService.openEditor({ resource: stat[0].resource, options: { pinned: true, preserveFocus: true } }).then(undefined, onUnexpectedError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
// {{SQL CARBON EDIT}} - Import EditorInput
|
// {{SQL CARBON EDIT}} import EditorInput
|
||||||
import { toResource, IEditorCommandsContext, EditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
import { toResource, IEditorCommandsContext, SideBySideEditor, EditorInput } from 'vs/workbench/common/editor';
|
||||||
import { IWindowsService, IWindowService, IURIToOpen, IOpenSettings, INewWindowOptions } from 'vs/platform/windows/common/windows';
|
import { IWindowsService, IWindowService, IURIToOpen, IOpenSettings, INewWindowOptions, isWorkspaceToOpen } from 'vs/platform/windows/common/windows';
|
||||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||||
@@ -35,14 +35,15 @@ import { getMultiSelectedEditorContexts } from 'vs/workbench/browser/parts/edito
|
|||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||||
// {{SQL CARBON EDIT}} - Import EditorInput
|
|
||||||
import { IEditorService, SIDE_GROUP, IResourceEditorReplacement } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService, SIDE_GROUP, IResourceEditorReplacement } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
import { ILabelService } from 'vs/platform/label/common/label';
|
import { ILabelService } from 'vs/platform/label/common/label';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { basename, toLocalResource } from 'vs/base/common/resources';
|
import { basename, toLocalResource, joinPath } from 'vs/base/common/resources';
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
import { UNTITLED_WORKSPACE_NAME } from 'vs/platform/workspaces/common/workspaces';
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
||||||
@@ -86,6 +87,19 @@ export const REMOVE_ROOT_FOLDER_LABEL = nls.localize('removeFolderFromWorkspace'
|
|||||||
export const openWindowCommand = (accessor: ServicesAccessor, urisToOpen: IURIToOpen[], options?: IOpenSettings) => {
|
export const openWindowCommand = (accessor: ServicesAccessor, urisToOpen: IURIToOpen[], options?: IOpenSettings) => {
|
||||||
if (Array.isArray(urisToOpen)) {
|
if (Array.isArray(urisToOpen)) {
|
||||||
const windowService = accessor.get(IWindowService);
|
const windowService = accessor.get(IWindowService);
|
||||||
|
const environmentService = accessor.get(IEnvironmentService);
|
||||||
|
|
||||||
|
// rewrite untitled: workspace URIs to the absolute path on disk
|
||||||
|
urisToOpen = urisToOpen.map(uriToOpen => {
|
||||||
|
if (isWorkspaceToOpen(uriToOpen) && uriToOpen.workspaceUri.scheme === Schemas.untitled) {
|
||||||
|
return {
|
||||||
|
workspaceUri: joinPath(environmentService.untitledWorkspacesHome, uriToOpen.workspaceUri.path, UNTITLED_WORKSPACE_NAME)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return uriToOpen;
|
||||||
|
});
|
||||||
|
|
||||||
windowService.openWindow(urisToOpen, options);
|
windowService.openWindow(urisToOpen, options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -228,6 +228,10 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
|
|||||||
return this.setting.scope === ConfigurationScope.WINDOW || this.setting.scope === ConfigurationScope.RESOURCE;
|
return this.setting.scope === ConfigurationScope.WINDOW || this.setting.scope === ConfigurationScope.RESOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configTarget === ConfigurationTarget.USER_REMOTE) {
|
||||||
|
return this.setting.scope === ConfigurationScope.MACHINE || this.setting.scope === ConfigurationScope.WINDOW || this.setting.scope === ConfigurationScope.RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
|
|||||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { REMOTE_HOST_SCHEME, getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
|
import { REMOTE_HOST_SCHEME, getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
|
||||||
import { sanitizeProcessEnvironment } from 'vs/base/common/processes';
|
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
import { IProductService } from 'vs/platform/product/common/product';
|
||||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
|
|
||||||
/** The amount of time to consider terminal errors to be related to the launch */
|
/** The amount of time to consider terminal errors to be related to the launch */
|
||||||
const LAUNCHING_DURATION = 500;
|
const LAUNCHING_DURATION = 500;
|
||||||
@@ -173,53 +171,20 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
|||||||
if (!shellLaunchConfig.executable) {
|
if (!shellLaunchConfig.executable) {
|
||||||
this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig);
|
this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file);
|
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file);
|
||||||
const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, this._environmentService.userHome, activeWorkspaceRootUri, this._configHelper.config.cwd);
|
const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, this._environmentService.userHome, activeWorkspaceRootUri, this._configHelper.config.cwd);
|
||||||
const env = this._createEnvironment(shellLaunchConfig, activeWorkspaceRootUri);
|
|
||||||
|
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||||
|
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);
|
||||||
|
|
||||||
this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env);
|
this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env);
|
||||||
return this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, this._configHelper.config.windowsEnableConpty);
|
return this._terminalInstanceService.createTerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, this._configHelper.config.windowsEnableConpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createEnvironment(shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI | undefined): platform.IProcessEnvironment {
|
|
||||||
// Create a terminal environment based on settings, launch config and permissions
|
|
||||||
let env: platform.IProcessEnvironment = {};
|
|
||||||
if (shellLaunchConfig.strictEnv) {
|
|
||||||
// strictEnv is true, only use the requested env (ignoring null entries)
|
|
||||||
terminalEnvironment.mergeNonNullKeys(env, shellLaunchConfig.env);
|
|
||||||
} else {
|
|
||||||
// Merge process env with the env from config and from shellLaunchConfig
|
|
||||||
terminalEnvironment.mergeNonNullKeys(env, process.env);
|
|
||||||
|
|
||||||
// Determine config env based on workspace shell permissions
|
|
||||||
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : null;
|
|
||||||
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
|
||||||
const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions();
|
|
||||||
const envFromConfigValue = this._workspaceConfigurationService.inspect<ITerminalEnvironment | undefined>(`terminal.integrated.env.${platformKey}`);
|
|
||||||
const allowedEnvFromConfig = { ...(isWorkspaceShellAllowed ? envFromConfigValue.value : envFromConfigValue.user) };
|
|
||||||
|
|
||||||
// Resolve env vars from config and shell
|
|
||||||
if (allowedEnvFromConfig) {
|
|
||||||
terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, allowedEnvFromConfig, lastActiveWorkspaceRoot);
|
|
||||||
}
|
|
||||||
if (shellLaunchConfig.env) {
|
|
||||||
terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, shellLaunchConfig.env, lastActiveWorkspaceRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge config (settings) and ShellLaunchConfig environments
|
|
||||||
terminalEnvironment.mergeEnvironments(env, allowedEnvFromConfig);
|
|
||||||
terminalEnvironment.mergeEnvironments(env, shellLaunchConfig.env);
|
|
||||||
|
|
||||||
// Sanitize the environment, removing any undesirable VS Code and Electron environment
|
|
||||||
// variables
|
|
||||||
sanitizeProcessEnvironment(env, 'VSCODE_IPC_HOOK_CLI');
|
|
||||||
|
|
||||||
// Adding other env keys necessary to create the process
|
|
||||||
terminalEnvironment.addTerminalEnvironmentKeys(env, this._productService.version, platform.locale, this._configHelper.config.setLocaleVariables);
|
|
||||||
}
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setDimensions(cols: number, rows: number): void {
|
public setDimensions(cols: number, rows: number): void {
|
||||||
if (!this._process) {
|
if (!this._process) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { URI as Uri } from 'vs/base/common/uri';
|
|||||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
|
import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||||
|
import { sanitizeProcessEnvironment } from 'vs/base/common/processes';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This module contains utility functions related to the environment, cwd and paths.
|
* This module contains utility functions related to the environment, cwd and paths.
|
||||||
@@ -59,7 +60,7 @@ export function addTerminalEnvironmentKeys(env: platform.IProcessEnvironment, ve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mergeNonNullKeys(env: platform.IProcessEnvironment, other: ITerminalEnvironment | NodeJS.ProcessEnv | undefined) {
|
function mergeNonNullKeys(env: platform.IProcessEnvironment, other: ITerminalEnvironment | NodeJS.ProcessEnv | undefined) {
|
||||||
if (!other) {
|
if (!other) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -71,7 +72,7 @@ export function mergeNonNullKeys(env: platform.IProcessEnvironment, other: ITerm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveConfigurationVariables(configurationResolverService: IConfigurationResolverService, env: ITerminalEnvironment, lastActiveWorkspaceRoot: IWorkspaceFolder | null): ITerminalEnvironment {
|
function resolveConfigurationVariables(configurationResolverService: IConfigurationResolverService, env: ITerminalEnvironment, lastActiveWorkspaceRoot: IWorkspaceFolder | null): ITerminalEnvironment {
|
||||||
Object.keys(env).forEach((key) => {
|
Object.keys(env).forEach((key) => {
|
||||||
const value = env[key];
|
const value = env[key];
|
||||||
if (typeof value === 'string' && lastActiveWorkspaceRoot !== null) {
|
if (typeof value === 'string' && lastActiveWorkspaceRoot !== null) {
|
||||||
@@ -189,3 +190,49 @@ export function mergeDefaultShellPathAndArgs(
|
|||||||
shell.executable = shell.executable.replace(/\//g, '\\');
|
shell.executable = shell.executable.replace(/\//g, '\\');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createTerminalEnvironment(
|
||||||
|
shellLaunchConfig: IShellLaunchConfig,
|
||||||
|
lastActiveWorkspace: IWorkspaceFolder | null,
|
||||||
|
envFromConfig: { user: ITerminalEnvironment | undefined, value: ITerminalEnvironment | undefined, default: ITerminalEnvironment | undefined },
|
||||||
|
configurationResolverService: IConfigurationResolverService | undefined,
|
||||||
|
isWorkspaceShellAllowed: boolean,
|
||||||
|
version: string | undefined,
|
||||||
|
setLocaleVariables: boolean
|
||||||
|
): platform.IProcessEnvironment {
|
||||||
|
// Create a terminal environment based on settings, launch config and permissions
|
||||||
|
let env: platform.IProcessEnvironment = {};
|
||||||
|
if (shellLaunchConfig.strictEnv) {
|
||||||
|
// strictEnv is true, only use the requested env (ignoring null entries)
|
||||||
|
mergeNonNullKeys(env, shellLaunchConfig.env);
|
||||||
|
} else {
|
||||||
|
// Merge process env with the env from config and from shellLaunchConfig
|
||||||
|
mergeNonNullKeys(env, process.env);
|
||||||
|
|
||||||
|
// const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||||
|
// const envFromConfigValue = this._workspaceConfigurationService.inspect<ITerminalEnvironment | undefined>(`terminal.integrated.env.${platformKey}`);
|
||||||
|
const allowedEnvFromConfig = { ...(isWorkspaceShellAllowed ? envFromConfig.value : envFromConfig.user) };
|
||||||
|
|
||||||
|
// Resolve env vars from config and shell
|
||||||
|
if (configurationResolverService) {
|
||||||
|
if (allowedEnvFromConfig) {
|
||||||
|
resolveConfigurationVariables(configurationResolverService, allowedEnvFromConfig, lastActiveWorkspace);
|
||||||
|
}
|
||||||
|
if (shellLaunchConfig.env) {
|
||||||
|
resolveConfigurationVariables(configurationResolverService, shellLaunchConfig.env, lastActiveWorkspace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge config (settings) and ShellLaunchConfig environments
|
||||||
|
mergeEnvironments(env, allowedEnvFromConfig);
|
||||||
|
mergeEnvironments(env, shellLaunchConfig.env);
|
||||||
|
|
||||||
|
// Sanitize the environment, removing any undesirable VS Code and Electron environment
|
||||||
|
// variables
|
||||||
|
sanitizeProcessEnvironment(env, 'VSCODE_IPC_HOOK_CLI');
|
||||||
|
|
||||||
|
// Adding other env keys necessary to create the process
|
||||||
|
addTerminalEnvironmentKeys(env, version, platform.locale, setLocaleVariables);
|
||||||
|
}
|
||||||
|
return env;
|
||||||
|
}
|
||||||
@@ -38,6 +38,7 @@ import { parseExtensionDevOptions } from '../common/extensionDevOptions';
|
|||||||
import { VSBuffer } from 'vs/base/common/buffer';
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug';
|
import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug';
|
||||||
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
|
import { isEqualOrParent } from 'vs/base/common/resources';
|
||||||
|
|
||||||
export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||||
|
|
||||||
@@ -400,7 +401,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
|||||||
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : {
|
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : {
|
||||||
configuration: withNullAsUndefined(workspace.configuration),
|
configuration: withNullAsUndefined(workspace.configuration),
|
||||||
id: workspace.id,
|
id: workspace.id,
|
||||||
name: this._labelService.getWorkspaceLabel(workspace)
|
name: this._labelService.getWorkspaceLabel(workspace),
|
||||||
|
isUntitled: workspace.configuration ? isEqualOrParent(workspace.configuration, this._environmentService.untitledWorkspacesHome) : false
|
||||||
},
|
},
|
||||||
resolvedExtensions: [],
|
resolvedExtensions: [],
|
||||||
hostExtensions: [],
|
hostExtensions: [],
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
IExtensionManagementService, ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata,
|
IExtensionManagementService, ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata,
|
||||||
IExtensionManagementServerService, IExtensionManagementServer, IExtensionGalleryService
|
IExtensionManagementServerService, IExtensionManagementServer, IExtensionGalleryService
|
||||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
import { flatten } from 'vs/base/common/arrays';
|
|
||||||
import { ExtensionType, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionType, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
@@ -46,8 +45,10 @@ export class MultiExtensionManagementService extends Disposable implements IExte
|
|||||||
}
|
}
|
||||||
|
|
||||||
getInstalled(type?: ExtensionType): Promise<ILocalExtension[]> {
|
getInstalled(type?: ExtensionType): Promise<ILocalExtension[]> {
|
||||||
return Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.getInstalled(type)))
|
const installedExtensions: ILocalExtension[] = [];
|
||||||
.then(result => flatten(result));
|
return Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.getInstalled(type).then(extensions => installedExtensions.push(...extensions))))
|
||||||
|
.then(_ => installedExtensions)
|
||||||
|
.catch(e => installedExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
async uninstall(extension: ILocalExtension, force?: boolean): Promise<void> {
|
async uninstall(extension: ILocalExtension, force?: boolean): Promise<void> {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
|||||||
import { VSBuffer, VSBufferReadable, readableToBuffer, bufferToReadable, streamToBuffer, bufferToStream, VSBufferReadableStream, writeableBufferStream, VSBufferWriteableStream } from 'vs/base/common/buffer';
|
import { VSBuffer, VSBufferReadable, readableToBuffer, bufferToReadable, streamToBuffer, bufferToStream, VSBufferReadableStream, writeableBufferStream, VSBufferWriteableStream } from 'vs/base/common/buffer';
|
||||||
import { Queue } from 'vs/base/common/async';
|
import { Queue } from 'vs/base/common/async';
|
||||||
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
export class FileService extends Disposable implements IFileService {
|
export class FileService extends Disposable implements IFileService {
|
||||||
|
|
||||||
@@ -101,7 +102,7 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
|
|
||||||
// Assert path is absolute
|
// Assert path is absolute
|
||||||
if (!isAbsolutePath(resource)) {
|
if (!isAbsolutePath(resource)) {
|
||||||
throw new FileOperationError(localize('invalidPath', "The path of resource '{0}' must be absolute", resource.toString(true)), FileOperationResult.FILE_INVALID_PATH);
|
throw new FileOperationError(localize('invalidPath', "The path of resource '{0}' must be absolute", this.resourceForError(resource)), FileOperationResult.FILE_INVALID_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate provider
|
// Activate provider
|
||||||
@@ -110,11 +111,11 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
// Assert provider
|
// Assert provider
|
||||||
const provider = this.provider.get(resource.scheme);
|
const provider = this.provider.get(resource.scheme);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
const err = new Error();
|
const error = new Error();
|
||||||
err.name = 'ENOPRO';
|
error.name = 'ENOPRO';
|
||||||
err.message = `No provider found for ${resource.toString()}`;
|
error.message = localize('noProviderFound', "No file system provider found for {0}", resource.toString());
|
||||||
|
|
||||||
throw err;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider;
|
return provider;
|
||||||
@@ -150,7 +151,7 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
// Specially handle file not found case as file operation result
|
// Specially handle file not found case as file operation result
|
||||||
if (toFileSystemProviderErrorCode(error) === FileSystemProviderErrorCode.FileNotFound) {
|
if (toFileSystemProviderErrorCode(error) === FileSystemProviderErrorCode.FileNotFound) {
|
||||||
throw new FileOperationError(
|
throw new FileOperationError(
|
||||||
localize('fileNotFoundError', "File not found ({0})", resource.toString(true)),
|
localize('fileNotFoundError', "File not found ({0})", this.resourceForError(resource)),
|
||||||
FileOperationResult.FILE_NOT_FOUND
|
FileOperationResult.FILE_NOT_FOUND
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -270,7 +271,7 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
// validate overwrite
|
// validate overwrite
|
||||||
const overwrite = !!(options && options.overwrite);
|
const overwrite = !!(options && options.overwrite);
|
||||||
if (!overwrite && await this.exists(resource)) {
|
if (!overwrite && await this.exists(resource)) {
|
||||||
throw new FileOperationError(localize('fileExists', "File to create already exists ({0})", resource.toString(true)), FileOperationResult.FILE_MODIFIED_SINCE, options);
|
throw new FileOperationError(localize('fileExists', "File to create already exists ({0})", this.resourceForError(resource)), FileOperationResult.FILE_MODIFIED_SINCE, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do write into file (this will create it too)
|
// do write into file (this will create it too)
|
||||||
@@ -305,7 +306,7 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
await this.doWriteUnbuffered(provider, resource, bufferOrReadable);
|
await this.doWriteUnbuffered(provider, resource, bufferOrReadable);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new FileOperationError(localize('err.write', "Failed to write file {0}", resource.toString(false)), toFileOperationResult(error), options);
|
throw new FileOperationError(localize('err.write', "Unable to write file ({0})", error.toString()), toFileOperationResult(error), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.resolve(resource, { resolveMetadata: true });
|
return this.resolve(resource, { resolveMetadata: true });
|
||||||
@@ -321,7 +322,7 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
|
|
||||||
// file cannot be directory
|
// file cannot be directory
|
||||||
if ((stat.type & FileType.Directory) !== 0) {
|
if ((stat.type & FileType.Directory) !== 0) {
|
||||||
throw new FileOperationError(localize('fileIsDirectoryError', "Expected file {0} is actually a directory", resource.toString()), FileOperationResult.FILE_IS_DIRECTORY, options);
|
throw new FileOperationError(localize('fileIsDirectoryError', "Expected file {0} is actually a directory", this.resourceForError(resource)), FileOperationResult.FILE_IS_DIRECTORY, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dirty write prevention: if the file on disk has been changed and does not match our expected
|
// Dirty write prevention: if the file on disk has been changed and does not match our expected
|
||||||
@@ -397,7 +398,7 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
value: fileStream
|
value: fileStream
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new FileOperationError(localize('err.read', "Failed to read file {0}", resource.toString(false)), toFileOperationResult(error), options);
|
throw new FileOperationError(localize('err.read', "Unable to read file ({0})", error.toString()), toFileOperationResult(error), options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,7 +489,7 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
|
|
||||||
// Return early if resource is a directory
|
// Return early if resource is a directory
|
||||||
if (stat.isDirectory) {
|
if (stat.isDirectory) {
|
||||||
throw new FileOperationError(localize('fileIsDirectoryError', "Expected file {0} is actually a directory", resource.toString()), FileOperationResult.FILE_IS_DIRECTORY, options);
|
throw new FileOperationError(localize('fileIsDirectoryError', "Expected file {0} is actually a directory", this.resourceForError(resource)), FileOperationResult.FILE_IS_DIRECTORY, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return early if file not modified since
|
// Return early if file not modified since
|
||||||
@@ -692,7 +693,7 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
try {
|
try {
|
||||||
const stat = await provider.stat(directory);
|
const stat = await provider.stat(directory);
|
||||||
if ((stat.type & FileType.Directory) === 0) {
|
if ((stat.type & FileType.Directory) === 0) {
|
||||||
throw new Error(localize('mkdirExistsError', "{0} exists, but is not a directory", directory.toString()));
|
throw new Error(localize('mkdirExistsError', "{0} exists, but is not a directory", this.resourceForError(directory)));
|
||||||
}
|
}
|
||||||
|
|
||||||
break; // we have hit a directory that exists -> good
|
break; // we have hit a directory that exists -> good
|
||||||
@@ -732,7 +733,7 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
if (!recursive && await this.exists(resource)) {
|
if (!recursive && await this.exists(resource)) {
|
||||||
const stat = await this.resolve(resource);
|
const stat = await this.resolve(resource);
|
||||||
if (stat.isDirectory && Array.isArray(stat.children) && stat.children.length > 0) {
|
if (stat.isDirectory && Array.isArray(stat.children) && stat.children.length > 0) {
|
||||||
throw new Error(localize('deleteFailed', "Failed to delete non-empty folder '{0}'.", resource.toString()));
|
throw new Error(localize('deleteFailed', "Unable to delete non-empty folder '{0}'.", this.resourceForError(resource)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1006,5 +1007,13 @@ export class FileService extends Disposable implements IFileService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private resourceForError(resource: URI): string {
|
||||||
|
if (resource.scheme === Schemas.file) {
|
||||||
|
return resource.fsPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource.toString(true);
|
||||||
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { FileChangeType } from 'vs/platform/files/common/files';
|
|||||||
import { ThrottledDelayer } from 'vs/base/common/async';
|
import { ThrottledDelayer } from 'vs/base/common/async';
|
||||||
import { normalizeNFC } from 'vs/base/common/normalization';
|
import { normalizeNFC } from 'vs/base/common/normalization';
|
||||||
import { realcaseSync } from 'vs/base/node/extpath';
|
import { realcaseSync } from 'vs/base/node/extpath';
|
||||||
import { isMacintosh } from 'vs/base/common/platform';
|
import { isMacintosh, isLinux } from 'vs/base/common/platform';
|
||||||
import { IDiskFileChange, normalizeFileChanges } from 'vs/workbench/services/files/node/watcher/watcher';
|
import { IDiskFileChange, normalizeFileChanges } from 'vs/workbench/services/files/node/watcher/watcher';
|
||||||
import { IWatcherRequest, IWatcherService, IWatcherOptions, IWatchError } from 'vs/workbench/services/files/node/watcher/unix/watcher';
|
import { IWatcherRequest, IWatcherService, IWatcherOptions, IWatchError } from 'vs/workbench/services/files/node/watcher/unix/watcher';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
@@ -114,12 +114,21 @@ export class ChokidarWatcherService implements IWatcherService {
|
|||||||
disableGlobbing: true // fix https://github.com/Microsoft/vscode/issues/4586
|
disableGlobbing: true // fix https://github.com/Microsoft/vscode/issues/4586
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const excludes: string[] = [];
|
||||||
// if there's only one request, use the built-in ignore-filterering
|
// if there's only one request, use the built-in ignore-filterering
|
||||||
const isSingleFolder = requests.length === 1;
|
const isSingleFolder = requests.length === 1;
|
||||||
if (isSingleFolder) {
|
if (isSingleFolder) {
|
||||||
watcherOpts.ignored = requests[0].excludes;
|
excludes.push(...requests[0].excludes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((isMacintosh || isLinux) && (basePath.length === 0 || basePath === '/')) {
|
||||||
|
excludes.push('/dev/**');
|
||||||
|
if (isLinux) {
|
||||||
|
excludes.push('/proc/**', '/sys/**');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watcherOpts.ignored = excludes;
|
||||||
|
|
||||||
// Chokidar fails when the basePath does not match case-identical to the path on disk
|
// Chokidar fails when the basePath does not match case-identical to the path on disk
|
||||||
// so we have to find the real casing of the path and do some path massaging to fix this
|
// so we have to find the real casing of the path and do some path massaging to fix this
|
||||||
// see https://github.com/paulmillr/chokidar/issues/418
|
// see https://github.com/paulmillr/chokidar/issues/418
|
||||||
|
|||||||
@@ -1382,6 +1382,10 @@ suite('Disk File Service', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('watch - file - multiple writes', done => {
|
test('watch - file - multiple writes', done => {
|
||||||
|
if (isWindows) {
|
||||||
|
return done(); // not happy
|
||||||
|
}
|
||||||
|
|
||||||
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
|
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
|
||||||
writeFileSync(toWatch.fsPath, 'Init');
|
writeFileSync(toWatch.fsPath, 'Init');
|
||||||
|
|
||||||
@@ -1487,7 +1491,7 @@ suite('Disk File Service', () => {
|
|||||||
setTimeout(() => mkdirSync(folder.fsPath), 50);
|
setTimeout(() => mkdirSync(folder.fsPath), 50);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('watch - folder (non recursive) - delete folder', done => {
|
test.skip('watch - folder (non recursive) - delete folder', done => {
|
||||||
const watchDir = URI.file(join(testDir, 'watch7'));
|
const watchDir = URI.file(join(testDir, 'watch7'));
|
||||||
mkdirSync(watchDir.fsPath);
|
mkdirSync(watchDir.fsPath);
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export class LabelService implements ILabelService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWorkspace), options?: { verbose: boolean }): string {
|
getWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IWorkspace), options?: { verbose: boolean }): string {
|
||||||
if (!isWorkspaceIdentifier(workspace) && !isSingleFolderWorkspaceIdentifier(workspace)) {
|
if (IWorkspace.isIWorkspace(workspace)) {
|
||||||
const identifier = toWorkspaceIdentifier(workspace);
|
const identifier = toWorkspaceIdentifier(workspace);
|
||||||
if (!identifier) {
|
if (!identifier) {
|
||||||
return '';
|
return '';
|
||||||
@@ -176,6 +176,7 @@ export class LabelService implements ILabelService {
|
|||||||
return this.appendWorkspaceSuffix(label, workspace);
|
return this.appendWorkspaceSuffix(label, workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isWorkspaceIdentifier(workspace)) {
|
||||||
// Workspace: Untitled
|
// Workspace: Untitled
|
||||||
if (isEqualOrParent(workspace.configPath, this.environmentService.untitledWorkspacesHome)) {
|
if (isEqualOrParent(workspace.configPath, this.environmentService.untitledWorkspacesHome)) {
|
||||||
return localize('untitledWorkspace', "Untitled (Workspace)");
|
return localize('untitledWorkspace', "Untitled (Workspace)");
|
||||||
@@ -194,6 +195,9 @@ export class LabelService implements ILabelService {
|
|||||||
}
|
}
|
||||||
return this.appendWorkspaceSuffix(label, workspace.configPath);
|
return this.appendWorkspaceSuffix(label, workspace.configPath);
|
||||||
}
|
}
|
||||||
|
return '';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
getSeparator(scheme: string, authority?: string): '/' | '\\' {
|
getSeparator(scheme: string, authority?: string): '/' | '\\' {
|
||||||
const formatter = this.findFormatting(URI.from({ scheme, authority }));
|
const formatter = this.findFormatting(URI.from({ scheme, authority }));
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||||||
// Model does not exist
|
// Model does not exist
|
||||||
else {
|
else {
|
||||||
const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined);
|
const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined);
|
||||||
model = newModel;
|
|
||||||
modelPromise = model.load(options);
|
modelPromise = model.load(options);
|
||||||
|
|
||||||
// Install state change listener
|
// Install state change listener
|
||||||
@@ -192,24 +191,24 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
|||||||
this.mapResourceToPendingModelLoaders.set(resource, modelPromise);
|
this.mapResourceToPendingModelLoaders.set(resource, modelPromise);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const model = await modelPromise;
|
const resolvedModel = await modelPromise;
|
||||||
|
|
||||||
// Make known to manager (if not already known)
|
// Make known to manager (if not already known)
|
||||||
this.add(resource, model);
|
this.add(resource, resolvedModel);
|
||||||
|
|
||||||
// Model can be dirty if a backup was restored, so we make sure to have this event delivered
|
// Model can be dirty if a backup was restored, so we make sure to have this event delivered
|
||||||
if (model.isDirty()) {
|
if (resolvedModel.isDirty()) {
|
||||||
this._onModelDirty.fire(new TextFileModelChangeEvent(model, StateChange.DIRTY));
|
this._onModelDirty.fire(new TextFileModelChangeEvent(resolvedModel, StateChange.DIRTY));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from pending loads
|
// Remove from pending loads
|
||||||
this.mapResourceToPendingModelLoaders.delete(resource);
|
this.mapResourceToPendingModelLoaders.delete(resource);
|
||||||
|
|
||||||
return model;
|
return resolvedModel;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
// Free resources of this invalid model
|
// Free resources of this invalid model
|
||||||
if (model && typeof model.dispose === 'function') { // workaround for https://github.com/Microsoft/vscode/issues/72404
|
if (model) {
|
||||||
model.dispose();
|
model.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import { coalesce } from 'vs/base/common/arrays';
|
|||||||
import { trim } from 'vs/base/common/strings';
|
import { trim } from 'vs/base/common/strings';
|
||||||
import { VSBuffer } from 'vs/base/common/buffer';
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { ITextSnapshot } from 'vs/editor/common/model';
|
import { ITextSnapshot } from 'vs/editor/common/model';
|
||||||
|
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The workbench file service implementation implements the raw file service spec and adds additional methods on top.
|
* The workbench file service implementation implements the raw file service spec and adds additional methods on top.
|
||||||
@@ -85,7 +86,8 @@ export abstract class TextFileService extends Disposable implements ITextFileSer
|
|||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
@IDialogService private readonly dialogService: IDialogService,
|
@IDialogService private readonly dialogService: IDialogService,
|
||||||
@IFileDialogService private readonly fileDialogService: IFileDialogService,
|
@IFileDialogService private readonly fileDialogService: IFileDialogService,
|
||||||
@IEditorService private readonly editorService: IEditorService
|
@IEditorService private readonly editorService: IEditorService,
|
||||||
|
@ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { isMacintosh, isLinux } from 'vs/base/common/platform';
|
|||||||
import product from 'vs/platform/product/node/product';
|
import product from 'vs/platform/product/node/product';
|
||||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||||
import { UTF8, UTF8_with_bom, UTF16be, UTF16le, encodingExists, IDetectedEncodingResult, encodeStream, UTF8_BOM, UTF16be_BOM, UTF16le_BOM, toDecodeStream, IDecodeStreamResult, detectEncodingByBOMFromBuffer } from 'vs/base/node/encoding';
|
import { UTF8, UTF8_with_bom, UTF16be, UTF16le, encodingExists, encodeStream, UTF8_BOM, UTF16be_BOM, UTF16le_BOM, toDecodeStream, IDecodeStreamResult, detectEncodingByBOMFromBuffer } from 'vs/base/node/encoding';
|
||||||
import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces';
|
import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces';
|
||||||
import { joinPath, extname, isEqualOrParent } from 'vs/base/common/resources';
|
import { joinPath, extname, isEqualOrParent } from 'vs/base/common/resources';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
@@ -70,8 +70,8 @@ export class NodeTextFileService extends TextFileService {
|
|||||||
|
|
||||||
// read through encoding library
|
// read through encoding library
|
||||||
const decoder = await toDecodeStream(this.streamToNodeReadable(bufferStream.value), {
|
const decoder = await toDecodeStream(this.streamToNodeReadable(bufferStream.value), {
|
||||||
guessEncoding: options && options.autoGuessEncoding,
|
guessEncoding: (options && options.autoGuessEncoding) || this.textResourceConfigurationService.getValue(resource, 'files.autoGuessEncoding'),
|
||||||
overwriteEncoding: detected => this.encoding.getReadEncoding(resource, options, { encoding: detected, seemsBinary: false })
|
overwriteEncoding: detectedEncoding => this.encoding.getReadEncoding(resource, options, detectedEncoding)
|
||||||
});
|
});
|
||||||
|
|
||||||
// validate binary
|
// validate binary
|
||||||
@@ -417,7 +417,7 @@ export class EncodingOracle extends Disposable implements IResourceEncodings {
|
|||||||
const overwriteEncoding = options && options.overwriteEncoding;
|
const overwriteEncoding = options && options.overwriteEncoding;
|
||||||
if (!overwriteEncoding && encoding === UTF8) {
|
if (!overwriteEncoding && encoding === UTF8) {
|
||||||
try {
|
try {
|
||||||
const buffer = (await this.fileService.readFile(resource, { length: 3 })).value;
|
const buffer = (await this.fileService.readFile(resource, { length: UTF8_BOM.length })).value;
|
||||||
if (detectEncodingByBOMFromBuffer(buffer, buffer.byteLength) === UTF8) {
|
if (detectEncodingByBOMFromBuffer(buffer, buffer.byteLength) === UTF8) {
|
||||||
return { encoding, addBOM: true };
|
return { encoding, addBOM: true };
|
||||||
}
|
}
|
||||||
@@ -438,12 +438,12 @@ export class EncodingOracle extends Disposable implements IResourceEncodings {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getReadEncoding(resource: URI, options: IReadTextFileOptions | undefined, detected: IDetectedEncodingResult): string {
|
getReadEncoding(resource: URI, options: IReadTextFileOptions | undefined, detectedEncoding: string | null): string {
|
||||||
let preferredEncoding: string | undefined;
|
let preferredEncoding: string | undefined;
|
||||||
|
|
||||||
// Encoding passed in as option
|
// Encoding passed in as option
|
||||||
if (options && options.encoding) {
|
if (options && options.encoding) {
|
||||||
if (detected.encoding === UTF8 && options.encoding === UTF8) {
|
if (detectedEncoding === UTF8 && options.encoding === UTF8) {
|
||||||
preferredEncoding = UTF8_with_bom; // indicate the file has BOM if we are to resolve with UTF 8
|
preferredEncoding = UTF8_with_bom; // indicate the file has BOM if we are to resolve with UTF 8
|
||||||
} else {
|
} else {
|
||||||
preferredEncoding = options.encoding; // give passed in encoding highest priority
|
preferredEncoding = options.encoding; // give passed in encoding highest priority
|
||||||
@@ -451,11 +451,11 @@ export class EncodingOracle extends Disposable implements IResourceEncodings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encoding detected
|
// Encoding detected
|
||||||
else if (detected.encoding) {
|
else if (detectedEncoding) {
|
||||||
if (detected.encoding === UTF8) {
|
if (detectedEncoding === UTF8) {
|
||||||
preferredEncoding = UTF8_with_bom; // if we detected UTF-8, it can only be because of a BOM
|
preferredEncoding = UTF8_with_bom; // if we detected UTF-8, it can only be because of a BOM
|
||||||
} else {
|
} else {
|
||||||
preferredEncoding = detected.encoding;
|
preferredEncoding = detectedEncoding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -570,6 +570,13 @@ suite('Files - TextFileService i/o', () => {
|
|||||||
assert.equal(result.encoding, 'utf16be');
|
assert.equal(result.encoding, 'utf16be');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('readStream - autoguessEncoding', async () => {
|
||||||
|
const resource = URI.file(join(testDir, 'some_cp1252.txt'));
|
||||||
|
|
||||||
|
const result = await service.readStream(resource, { autoGuessEncoding: true });
|
||||||
|
assert.equal(result.encoding, 'windows1252');
|
||||||
|
});
|
||||||
|
|
||||||
test('readStream - FILE_IS_BINARY', async () => {
|
test('readStream - FILE_IS_BINARY', async () => {
|
||||||
const resource = URI.file(join(testDir, 'binary.txt'));
|
const resource = URI.file(join(testDir, 'binary.txt'));
|
||||||
|
|
||||||
@@ -586,4 +593,21 @@ suite('Files - TextFileService i/o', () => {
|
|||||||
const result = await service.readStream(URI.file(join(testDir, 'small.txt')), { acceptTextOnly: true });
|
const result = await service.readStream(URI.file(join(testDir, 'small.txt')), { acceptTextOnly: true });
|
||||||
assert.equal(result.name, 'small.txt');
|
assert.equal(result.name, 'small.txt');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('read - FILE_IS_BINARY', async () => {
|
||||||
|
const resource = URI.file(join(testDir, 'binary.txt'));
|
||||||
|
|
||||||
|
let error: TextFileOperationError | undefined = undefined;
|
||||||
|
try {
|
||||||
|
await service.read(resource, { acceptTextOnly: true });
|
||||||
|
} catch (err) {
|
||||||
|
error = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.ok(error);
|
||||||
|
assert.equal(error!.textFileOperationResult, TextFileOperationResult.FILE_IS_BINARY);
|
||||||
|
|
||||||
|
const result = await service.read(URI.file(join(testDir, 'small.txt')), { acceptTextOnly: true });
|
||||||
|
assert.equal(result.name, 'small.txt');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,19 +6,19 @@
|
|||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, DETECT_HC_SETTING, HC_THEME_ID } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, DETECT_HC_SETTING, HC_THEME_ID, IColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import * as errors from 'vs/base/common/errors';
|
import * as errors from 'vs/base/common/errors';
|
||||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry';
|
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { ColorThemeData } from './colorThemeData';
|
import { ColorThemeData } from 'vs/workbench/services/themes/common/colorThemeData';
|
||||||
import { ITheme, Extensions as ThemingExtensions, IThemingRegistry } from 'vs/platform/theme/common/themeService';
|
import { ITheme, Extensions as ThemingExtensions, IThemingRegistry } from 'vs/platform/theme/common/themeService';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { registerFileIconThemeSchemas } from 'vs/workbench/services/themes/common/fileIconThemeSchema';
|
import { registerFileIconThemeSchemas } from 'vs/workbench/services/themes/common/fileIconThemeSchema';
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { ColorThemeStore } from 'vs/workbench/services/themes/browser/colorThemeStore';
|
import { ColorThemeStore } from 'vs/workbench/services/themes/common/colorThemeStore';
|
||||||
import { FileIconThemeStore } from 'vs/workbench/services/themes/common/fileIconThemeStore';
|
import { FileIconThemeStore } from 'vs/workbench/services/themes/common/fileIconThemeStore';
|
||||||
import { FileIconThemeData } from 'vs/workbench/services/themes/common/fileIconThemeData';
|
import { FileIconThemeData } from 'vs/workbench/services/themes/common/fileIconThemeData';
|
||||||
import { removeClasses, addClasses } from 'vs/base/browser/dom';
|
import { removeClasses, addClasses } from 'vs/base/browser/dom';
|
||||||
@@ -64,10 +64,6 @@ function validateThemeId(theme: string): string {
|
|||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IColorCustomizations {
|
|
||||||
[colorIdOrThemeSettingsId: string]: string | IColorCustomizations;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WorkbenchThemeService implements IWorkbenchThemeService {
|
export class WorkbenchThemeService implements IWorkbenchThemeService {
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -6,8 +6,8 @@
|
|||||||
import { basename } from 'vs/base/common/path';
|
import { basename } from 'vs/base/common/path';
|
||||||
import * as Json from 'vs/base/common/json';
|
import * as Json from 'vs/base/common/json';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
import { ExtensionData, ITokenColorCustomizations, ITokenColorizationRule, IColorTheme, IColorMap, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { ExtensionData, ITokenColorCustomizations, ITokenColorizationRule, IColorTheme, IColorMap, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME, IColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { convertSettings } from 'vs/workbench/services/themes/browser/themeCompatibility';
|
import { convertSettings } from 'vs/workbench/services/themes/common/themeCompatibility';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
import * as objects from 'vs/base/common/objects';
|
import * as objects from 'vs/base/common/objects';
|
||||||
@@ -15,7 +15,6 @@ import * as resources from 'vs/base/common/resources';
|
|||||||
import { Extensions, IColorRegistry, ColorIdentifier, editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry';
|
import { Extensions, IColorRegistry, ColorIdentifier, editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { ThemeType } from 'vs/platform/theme/common/themeService';
|
import { ThemeType } from 'vs/platform/theme/common/themeService';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { IColorCustomizations } from 'vs/workbench/services/themes/browser/workbenchThemeService';
|
|
||||||
import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages';
|
import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
+1
-1
@@ -9,7 +9,7 @@ import * as types from 'vs/base/common/types';
|
|||||||
import * as resources from 'vs/base/common/resources';
|
import * as resources from 'vs/base/common/resources';
|
||||||
import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||||
import { ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { ColorThemeData } from 'vs/workbench/services/themes/browser/colorThemeData';
|
import { ColorThemeData } from 'vs/workbench/services/themes/common/colorThemeData';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
@@ -64,6 +64,10 @@ export interface IWorkbenchThemeService extends IThemeService {
|
|||||||
onDidFileIconThemeChange: Event<IFileIconTheme>;
|
onDidFileIconThemeChange: Event<IFileIconTheme>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IColorCustomizations {
|
||||||
|
[colorIdOrThemeSettingsId: string]: string | IColorCustomizations;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ITokenColorCustomizations {
|
export interface ITokenColorCustomizations {
|
||||||
comments?: string | ITokenColorizationSetting;
|
comments?: string | ITokenColorizationSetting;
|
||||||
strings?: string | ITokenColorizationSetting;
|
strings?: string | ITokenColorizationSetting;
|
||||||
|
|||||||
@@ -106,19 +106,27 @@ suite('Notifications', () => {
|
|||||||
assert.equal(item6.actions.primary!.length, 1);
|
assert.equal(item6.actions.primary!.length, 1);
|
||||||
|
|
||||||
// Links
|
// Links
|
||||||
let item7 = NotificationViewItem.create({ severity: Severity.Info, message: 'Unable to [Link 1](http://link1.com) open [Link 2](https://link2.com) and [Invalid Link3](ftp://link3.com)' })!;
|
let item7 = NotificationViewItem.create({ severity: Severity.Info, message: 'Unable to [Link 1](http://link1.com) open [Link 2](command:open.me "Open This") and [Link 3](command:without.title) and [Invalid Link4](ftp://link4.com)' })!;
|
||||||
|
|
||||||
const links = item7.message.links;
|
const links = item7.message.links;
|
||||||
assert.equal(links.length, 2);
|
assert.equal(links.length, 3);
|
||||||
assert.equal(links[0].name, 'Link 1');
|
assert.equal(links[0].name, 'Link 1');
|
||||||
assert.equal(links[0].href, 'http://link1.com');
|
assert.equal(links[0].href, 'http://link1.com');
|
||||||
|
assert.equal(links[0].title, 'http://link1.com');
|
||||||
assert.equal(links[0].length, '[Link 1](http://link1.com)'.length);
|
assert.equal(links[0].length, '[Link 1](http://link1.com)'.length);
|
||||||
assert.equal(links[0].offset, 'Unable to '.length);
|
assert.equal(links[0].offset, 'Unable to '.length);
|
||||||
|
|
||||||
assert.equal(links[1].name, 'Link 2');
|
assert.equal(links[1].name, 'Link 2');
|
||||||
assert.equal(links[1].href, 'https://link2.com');
|
assert.equal(links[1].href, 'command:open.me');
|
||||||
assert.equal(links[1].length, '[Link 2](https://link2.com)'.length);
|
assert.equal(links[1].title, 'Open This');
|
||||||
|
assert.equal(links[1].length, '[Link 2](command:open.me "Open This")'.length);
|
||||||
assert.equal(links[1].offset, 'Unable to [Link 1](http://link1.com) open '.length);
|
assert.equal(links[1].offset, 'Unable to [Link 1](http://link1.com) open '.length);
|
||||||
|
|
||||||
|
assert.equal(links[2].name, 'Link 3');
|
||||||
|
assert.equal(links[2].href, 'command:without.title');
|
||||||
|
assert.equal(links[2].title, 'Click to execute command \'without.title\'');
|
||||||
|
assert.equal(links[2].length, '[Link 3](command:without.title)'.length);
|
||||||
|
assert.equal(links[2].offset, 'Unable to [Link 1](http://link1.com) open [Link 2](command:open.me "Open This") and '.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Model', () => {
|
test('Model', () => {
|
||||||
|
|||||||
@@ -200,7 +200,8 @@ export class TestTextFileService extends BrowserTextFileService {
|
|||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
@IDialogService dialogService: IDialogService,
|
@IDialogService dialogService: IDialogService,
|
||||||
@IFileDialogService fileDialogService: IFileDialogService,
|
@IFileDialogService fileDialogService: IFileDialogService,
|
||||||
@IEditorService editorService: IEditorService
|
@IEditorService editorService: IEditorService,
|
||||||
|
@ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
contextService,
|
contextService,
|
||||||
@@ -219,7 +220,8 @@ export class TestTextFileService extends BrowserTextFileService {
|
|||||||
contextKeyService,
|
contextKeyService,
|
||||||
dialogService,
|
dialogService,
|
||||||
fileDialogService,
|
fileDialogService,
|
||||||
editorService
|
editorService,
|
||||||
|
textResourceConfigurationService
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user