mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-04-06 20:10:30 -04:00
Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd (#5074)
* Merge from vscode 05fc61ffb1aee9fd19173c32113daed079f9b7bd * fix tests
This commit is contained in:
@@ -90,8 +90,6 @@ const vscodeResources = [
|
|||||||
'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md',
|
'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md',
|
||||||
'out-build/vs/workbench/services/files/**/*.exe',
|
'out-build/vs/workbench/services/files/**/*.exe',
|
||||||
'out-build/vs/workbench/services/files/**/*.md',
|
'out-build/vs/workbench/services/files/**/*.md',
|
||||||
'out-build/vs/workbench/services/files2/**/*.exe',
|
|
||||||
'out-build/vs/workbench/services/files2/**/*.md',
|
|
||||||
'out-build/vs/code/electron-browser/workbench/**',
|
'out-build/vs/code/electron-browser/workbench/**',
|
||||||
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
|
'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js',
|
||||||
'out-build/vs/code/electron-browser/issue/issueReporter.js',
|
'out-build/vs/code/electron-browser/issue/issueReporter.js',
|
||||||
|
|||||||
@@ -222,10 +222,6 @@
|
|||||||
"name": "vs/workbench/services/files",
|
"name": "vs/workbench/services/files",
|
||||||
"project": "vscode-workbench"
|
"project": "vscode-workbench"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "vs/workbench/services/files2",
|
|
||||||
"project": "vscode-workbench"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "vs/workbench/services/integrity",
|
"name": "vs/workbench/services/integrity",
|
||||||
"project": "vscode-workbench"
|
"project": "vscode-workbench"
|
||||||
|
|||||||
@@ -71,8 +71,9 @@
|
|||||||
"scope": [
|
"scope": [
|
||||||
"keyword.control",
|
"keyword.control",
|
||||||
"keyword.operator.new.cpp",
|
"keyword.operator.new.cpp",
|
||||||
"keyword.operator.delete.cpp",
|
"keyword.operator.delete",
|
||||||
"keyword.other.using"
|
"keyword.other.using",
|
||||||
|
"keyword.other.operator"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"foreground": "#C586C0"
|
"foreground": "#C586C0"
|
||||||
|
|||||||
@@ -69,7 +69,8 @@
|
|||||||
"keyword.control",
|
"keyword.control",
|
||||||
"keyword.operator.new.cpp",
|
"keyword.operator.new.cpp",
|
||||||
"keyword.operator.delete.cpp",
|
"keyword.operator.delete.cpp",
|
||||||
"keyword.other.using"
|
"keyword.other.using",
|
||||||
|
"keyword.other.operator"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"foreground": "#C586C0"
|
"foreground": "#C586C0"
|
||||||
|
|||||||
@@ -72,7 +72,8 @@
|
|||||||
"keyword.control",
|
"keyword.control",
|
||||||
"keyword.operator.new.cpp",
|
"keyword.operator.new.cpp",
|
||||||
"keyword.operator.delete.cpp",
|
"keyword.operator.delete.cpp",
|
||||||
"keyword.other.using"
|
"keyword.other.using",
|
||||||
|
"keyword.other.operator"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"foreground": "#AF00DB"
|
"foreground": "#AF00DB"
|
||||||
|
|||||||
@@ -116,7 +116,8 @@
|
|||||||
"keyword.control",
|
"keyword.control",
|
||||||
"keyword.operator.new.cpp",
|
"keyword.operator.new.cpp",
|
||||||
"keyword.operator.delete.cpp",
|
"keyword.operator.delete.cpp",
|
||||||
"keyword.other.using"
|
"keyword.other.using",
|
||||||
|
"keyword.other.operator"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"foreground": "#98676a"
|
"foreground": "#98676a"
|
||||||
|
|||||||
@@ -259,7 +259,8 @@
|
|||||||
"keyword.control",
|
"keyword.control",
|
||||||
"keyword.operator.new.cpp",
|
"keyword.operator.new.cpp",
|
||||||
"keyword.operator.delete.cpp",
|
"keyword.operator.delete.cpp",
|
||||||
"keyword.other.using"
|
"keyword.other.using",
|
||||||
|
"keyword.other.operator"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"fontStyle": "",
|
"fontStyle": "",
|
||||||
|
|||||||
@@ -191,4 +191,4 @@
|
|||||||
"natives": "1.1.6",
|
"natives": "1.1.6",
|
||||||
"@types/node": "10.12.12"
|
"@types/node": "10.12.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,19 +7,18 @@ APP_NAME="@@APPNAME@@"
|
|||||||
QUALITY="@@QUALITY@@"
|
QUALITY="@@QUALITY@@"
|
||||||
NAME="@@NAME@@"
|
NAME="@@NAME@@"
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if grep -qi Microsoft /proc/version; then
|
if grep -qi Microsoft /proc/version; then
|
||||||
# in a wsl shell
|
# in a wsl shell
|
||||||
WIN_CODE_CMD=$(wslpath -w "$(dirname "$(realpath "$0")")/$APP_NAME.cmd")
|
WIN_CODE_CMD=$(wslpath -w "$(dirname "$(realpath "$0")")/$APP_NAME.cmd")
|
||||||
|
if ! [ -z "$WIN_CODE_CMD" ]; then
|
||||||
WSL_EXT_ID="ms-vscode.remote-wsl"
|
WSL_EXT_ID="ms-vscode.remote-wsl"
|
||||||
WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CMD" --locate-extension $WSL_EXT_ID)
|
WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CMD" --locate-extension $WSL_EXT_ID)
|
||||||
if ! [ -z "$WSL_EXT_WLOC" ]; then
|
if ! [ -z "$WSL_EXT_WLOC" ]; then
|
||||||
# replace \r\n with \n in WSL_EXT_WLOC, get linux path for
|
# replace \r\n with \n in WSL_EXT_WLOC, get linux path for
|
||||||
WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh
|
WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh
|
||||||
$WSL_CODE $COMMIT $QUALITY "$WIN_CODE_CMD" "$APP_NAME" "$@"
|
$WSL_CODE $COMMIT $QUALITY "$WIN_CODE_CMD" "$APP_NAME" "$@"
|
||||||
exit $?
|
exit $?
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import * as path from 'vs/base/common/path';
|
|||||||
import * as pfs from 'vs/base/node/pfs';
|
import * as pfs from 'vs/base/node/pfs';
|
||||||
|
|
||||||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||||
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
import { Workspace, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
|
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
|
||||||
import { TestContextService } from 'vs/workbench/test/workbenchTestServices';
|
import { TestContextService } from 'vs/workbench/test/workbenchTestServices';
|
||||||
import { IExtensionHostDebugParams, IDebugParams, ParsedArgs } from 'vs/platform/environment/common/environment';
|
import { IExtensionHostDebugParams, IDebugParams, ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||||
@@ -113,7 +113,7 @@ suite('Insights Utils tests', function () {
|
|||||||
const contextService = new TestContextService(
|
const contextService = new TestContextService(
|
||||||
new Workspace(
|
new Workspace(
|
||||||
'TestWorkspace',
|
'TestWorkspace',
|
||||||
toWorkspaceFolders([{ path: queryFileDir }])
|
[toWorkspaceFolder(URI.file(queryFileDir))]
|
||||||
));
|
));
|
||||||
const configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
undefined,
|
undefined,
|
||||||
@@ -133,8 +133,8 @@ suite('Insights Utils tests', function () {
|
|||||||
const contextService = new TestContextService(
|
const contextService = new TestContextService(
|
||||||
new Workspace(
|
new Workspace(
|
||||||
'TestWorkspace',
|
'TestWorkspace',
|
||||||
toWorkspaceFolders([{ path: os.tmpdir() }])
|
[toWorkspaceFolder(URI.file(os.tmpdir()))])
|
||||||
));
|
);
|
||||||
const configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
undefined,
|
undefined,
|
||||||
new TestEnvironmentService({}),
|
new TestEnvironmentService({}),
|
||||||
@@ -194,7 +194,7 @@ suite('Insights Utils tests', function () {
|
|||||||
|
|
||||||
test('resolveQueryFilePath resolves path correctly with env var and non-empty workspace', async () => {
|
test('resolveQueryFilePath resolves path correctly with env var and non-empty workspace', async () => {
|
||||||
const contextService = new TestContextService(
|
const contextService = new TestContextService(
|
||||||
new Workspace('TestWorkspace', toWorkspaceFolders([{ path: os.tmpdir() }])));
|
new Workspace('TestWorkspace', [toWorkspaceFolder(URI.file(os.tmpdir()))]));
|
||||||
|
|
||||||
// Create mock window service with env variable containing test folder for resolution
|
// Create mock window service with env variable containing test folder for resolution
|
||||||
const configurationResolverService = new ConfigurationResolverService(
|
const configurationResolverService = new ConfigurationResolverService(
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ export class InputBox extends Widget {
|
|||||||
return errorMsg ? errorMsg.type !== MessageType.ERROR : true;
|
return errorMsg ? errorMsg.type !== MessageType.ERROR : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private stylesForType(type: MessageType | undefined): { border: Color | undefined; background: Color | undefined; foreground: Color | undefined } {
|
public stylesForType(type: MessageType | undefined): { border: Color | undefined; background: Color | undefined; foreground: Color | undefined } {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MessageType.INFO: return { border: this.inputValidationInfoBorder, background: this.inputValidationInfoBackground, foreground: this.inputValidationInfoForeground };
|
case MessageType.INFO: return { border: this.inputValidationInfoBorder, background: this.inputValidationInfoBackground, foreground: this.inputValidationInfoForeground };
|
||||||
case MessageType.WARNING: return { border: this.inputValidationWarningBorder, background: this.inputValidationWarningBackground, foreground: this.inputValidationWarningForeground };
|
case MessageType.WARNING: return { border: this.inputValidationWarningBorder, background: this.inputValidationWarningBackground, foreground: this.inputValidationWarningForeground };
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ let textDecoder: TextDecoder | null;
|
|||||||
|
|
||||||
export class VSBuffer {
|
export class VSBuffer {
|
||||||
|
|
||||||
public static alloc(byteLength: number): VSBuffer {
|
static alloc(byteLength: number): VSBuffer {
|
||||||
if (hasBuffer) {
|
if (hasBuffer) {
|
||||||
return new VSBuffer(Buffer.allocUnsafe(byteLength));
|
return new VSBuffer(Buffer.allocUnsafe(byteLength));
|
||||||
} else {
|
} else {
|
||||||
@@ -19,7 +19,7 @@ export class VSBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static wrap(actual: Uint8Array): VSBuffer {
|
static wrap(actual: Uint8Array): VSBuffer {
|
||||||
if (hasBuffer && !(Buffer.isBuffer(actual))) {
|
if (hasBuffer && !(Buffer.isBuffer(actual))) {
|
||||||
// https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length
|
// https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length
|
||||||
// Create a zero-copy Buffer wrapper around the ArrayBuffer pointed to by the Uint8Array
|
// Create a zero-copy Buffer wrapper around the ArrayBuffer pointed to by the Uint8Array
|
||||||
@@ -28,7 +28,7 @@ export class VSBuffer {
|
|||||||
return new VSBuffer(actual);
|
return new VSBuffer(actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromString(source: string): VSBuffer {
|
static fromString(source: string): VSBuffer {
|
||||||
if (hasBuffer) {
|
if (hasBuffer) {
|
||||||
return new VSBuffer(Buffer.from(source));
|
return new VSBuffer(Buffer.from(source));
|
||||||
} else {
|
} else {
|
||||||
@@ -39,7 +39,7 @@ export class VSBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static concat(buffers: VSBuffer[], totalLength?: number): VSBuffer {
|
static concat(buffers: VSBuffer[], totalLength?: number): VSBuffer {
|
||||||
if (typeof totalLength === 'undefined') {
|
if (typeof totalLength === 'undefined') {
|
||||||
totalLength = 0;
|
totalLength = 0;
|
||||||
for (let i = 0, len = buffers.length; i < len; i++) {
|
for (let i = 0, len = buffers.length; i < len; i++) {
|
||||||
@@ -58,15 +58,15 @@ export class VSBuffer {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly buffer: Uint8Array;
|
readonly buffer: Uint8Array;
|
||||||
public readonly byteLength: number;
|
readonly byteLength: number;
|
||||||
|
|
||||||
private constructor(buffer: Uint8Array) {
|
private constructor(buffer: Uint8Array) {
|
||||||
this.buffer = buffer;
|
this.buffer = buffer;
|
||||||
this.byteLength = this.buffer.byteLength;
|
this.byteLength = this.buffer.byteLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toString(): string {
|
toString(): string {
|
||||||
if (hasBuffer) {
|
if (hasBuffer) {
|
||||||
return this.buffer.toString();
|
return this.buffer.toString();
|
||||||
} else {
|
} else {
|
||||||
@@ -77,33 +77,32 @@ export class VSBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public slice(start?: number, end?: number): VSBuffer {
|
slice(start?: number, end?: number): VSBuffer {
|
||||||
return new VSBuffer(this.buffer.slice(start, end));
|
return new VSBuffer(this.buffer.slice(start, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
public set(array: VSBuffer, offset?: number): void {
|
set(array: VSBuffer, offset?: number): void {
|
||||||
this.buffer.set(array.buffer, offset);
|
this.buffer.set(array.buffer, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readUint32BE(offset: number): number {
|
readUInt32BE(offset: number): number {
|
||||||
return readUint32BE(this.buffer, offset);
|
return readUInt32BE(this.buffer, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public writeUint32BE(value: number, offset: number): void {
|
writeUInt32BE(value: number, offset: number): void {
|
||||||
writeUint32BE(this.buffer, value, offset);
|
writeUInt32BE(this.buffer, value, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readUint8(offset: number): number {
|
readUInt8(offset: number): number {
|
||||||
return readUint8(this.buffer, offset);
|
return readUInt8(this.buffer, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public writeUint8(value: number, offset: number): void {
|
writeUInt8(value: number, offset: number): void {
|
||||||
writeUint8(this.buffer, value, offset);
|
writeUInt8(this.buffer, value, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function readUint32BE(source: Uint8Array, offset: number): number {
|
function readUInt32BE(source: Uint8Array, offset: number): number {
|
||||||
return (
|
return (
|
||||||
source[offset] * 2 ** 24
|
source[offset] * 2 ** 24
|
||||||
+ source[offset + 1] * 2 ** 16
|
+ source[offset + 1] * 2 ** 16
|
||||||
@@ -112,7 +111,7 @@ function readUint32BE(source: Uint8Array, offset: number): number {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeUint32BE(destination: Uint8Array, value: number, offset: number): void {
|
function writeUInt32BE(destination: Uint8Array, value: number, offset: number): void {
|
||||||
destination[offset + 3] = value;
|
destination[offset + 3] = value;
|
||||||
value = value >>> 8;
|
value = value >>> 8;
|
||||||
destination[offset + 2] = value;
|
destination[offset + 2] = value;
|
||||||
@@ -122,11 +121,11 @@ function writeUint32BE(destination: Uint8Array, value: number, offset: number):
|
|||||||
destination[offset] = value;
|
destination[offset] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readUint8(source: Uint8Array, offset: number): number {
|
function readUInt8(source: Uint8Array, offset: number): number {
|
||||||
return source[offset];
|
return source[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeUint8(destination: Uint8Array, value: number, offset: number): void {
|
function writeUInt8(destination: Uint8Array, value: number, offset: number): void {
|
||||||
destination[offset] = value;
|
destination[offset] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,6 +138,47 @@ export interface VSBufferReadable {
|
|||||||
read(): VSBuffer | null;
|
read(): VSBuffer | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffer readable stream emits data to listeners. The stream
|
||||||
|
* will only start emitting when the first data listener has
|
||||||
|
* been added or the resume() method has been called.
|
||||||
|
*/
|
||||||
|
export interface VSBufferReadableStream {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 'data' event is emitted whenever the stream is
|
||||||
|
* relinquishing ownership of a chunk of data to a consumer.
|
||||||
|
*/
|
||||||
|
on(event: 'data', callback: (chunk: VSBuffer) => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when any error occurs.
|
||||||
|
*/
|
||||||
|
on(event: 'error', callback: (err: any) => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 'end' event is emitted when there is no more data
|
||||||
|
* to be consumed from the stream. The 'end' event will
|
||||||
|
* not be emitted unless the data is completely consumed.
|
||||||
|
*/
|
||||||
|
on(event: 'end', callback: () => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops emitting any events until resume() is called.
|
||||||
|
*/
|
||||||
|
pause(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts emitting events again after pause() was called.
|
||||||
|
*/
|
||||||
|
resume(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the stream and stops emitting any event.
|
||||||
|
*/
|
||||||
|
destroy(): void;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to fully read a VSBuffer readable into a single buffer.
|
* Helper to fully read a VSBuffer readable into a single buffer.
|
||||||
*/
|
*/
|
||||||
@@ -158,6 +198,7 @@ export function readableToBuffer(readable: VSBufferReadable): VSBuffer {
|
|||||||
*/
|
*/
|
||||||
export function bufferToReadable(buffer: VSBuffer): VSBufferReadable {
|
export function bufferToReadable(buffer: VSBuffer): VSBufferReadable {
|
||||||
let done = false;
|
let done = false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
read: () => {
|
read: () => {
|
||||||
if (done) {
|
if (done) {
|
||||||
@@ -169,4 +210,231 @@ export function bufferToReadable(buffer: VSBuffer): VSBufferReadable {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to fully read a VSBuffer stream into a single buffer.
|
||||||
|
*/
|
||||||
|
export function streamToBuffer(stream: VSBufferReadableStream): Promise<VSBuffer> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const chunks: VSBuffer[] = [];
|
||||||
|
|
||||||
|
stream.on('data', chunk => chunks.push(chunk));
|
||||||
|
stream.on('error', error => reject(error));
|
||||||
|
stream.on('end', () => resolve(VSBuffer.concat(chunks)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to create a VSBufferStream from an existing VSBuffer.
|
||||||
|
*/
|
||||||
|
export function bufferToStream(buffer: VSBuffer): VSBufferReadableStream {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
stream.end(buffer);
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to create a VSBufferStream that can be pushed
|
||||||
|
* buffers to. Will only start to emit data when a listener
|
||||||
|
* is added.
|
||||||
|
*/
|
||||||
|
export function writeableBufferStream(): VSBufferWriteableStream {
|
||||||
|
return new VSBufferWriteableStreamImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VSBufferWriteableStream extends VSBufferReadableStream {
|
||||||
|
write(chunk: VSBuffer): void;
|
||||||
|
error(error: Error): void;
|
||||||
|
end(result?: VSBuffer | Error): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class VSBufferWriteableStreamImpl implements VSBufferWriteableStream {
|
||||||
|
|
||||||
|
private readonly state = {
|
||||||
|
flowing: false,
|
||||||
|
ended: false,
|
||||||
|
destroyed: false
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly buffer = {
|
||||||
|
data: [] as VSBuffer[],
|
||||||
|
error: [] as Error[]
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly listeners = {
|
||||||
|
data: [] as { (chunk: VSBuffer): void }[],
|
||||||
|
error: [] as { (error: Error): void }[],
|
||||||
|
end: [] as { (): void }[]
|
||||||
|
};
|
||||||
|
|
||||||
|
pause(): void {
|
||||||
|
if (this.state.destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.flowing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
resume(): void {
|
||||||
|
if (this.state.destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.state.flowing) {
|
||||||
|
this.state.flowing = true;
|
||||||
|
|
||||||
|
// emit buffered events
|
||||||
|
this.flowData();
|
||||||
|
this.flowErrors();
|
||||||
|
this.flowEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write(chunk: VSBuffer): void {
|
||||||
|
if (this.state.destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flowing: directly send the data to listeners
|
||||||
|
if (this.state.flowing) {
|
||||||
|
this.listeners.data.forEach(listener => listener(chunk));
|
||||||
|
}
|
||||||
|
|
||||||
|
// not yet flowing: buffer data until flowing
|
||||||
|
else {
|
||||||
|
this.buffer.data.push(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error(error: Error): void {
|
||||||
|
if (this.state.destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// flowing: directly send the error to listeners
|
||||||
|
if (this.state.flowing) {
|
||||||
|
this.listeners.error.forEach(listener => listener(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
// not yet flowing: buffer errors until flowing
|
||||||
|
else {
|
||||||
|
this.buffer.error.push(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end(result?: VSBuffer | Error): void {
|
||||||
|
if (this.state.destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// end with data or error if provided
|
||||||
|
if (result instanceof Error) {
|
||||||
|
this.error(result);
|
||||||
|
} else if (result) {
|
||||||
|
this.write(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// flowing: send end event to listeners
|
||||||
|
if (this.state.flowing) {
|
||||||
|
this.listeners.end.forEach(listener => listener());
|
||||||
|
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// not yet flowing: remember state
|
||||||
|
else {
|
||||||
|
this.state.ended = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
on(event: 'data', callback: (chunk: VSBuffer) => void): void;
|
||||||
|
on(event: 'error', callback: (err: any) => void): void;
|
||||||
|
on(event: 'end', callback: () => void): void;
|
||||||
|
on(event: 'data' | 'error' | 'end', callback: (arg0?: any) => void): void {
|
||||||
|
if (this.state.destroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case 'data':
|
||||||
|
this.listeners.data.push(callback);
|
||||||
|
|
||||||
|
// switch into flowing mode as soon as the first 'data'
|
||||||
|
// listener is added and we are not yet in flowing mode
|
||||||
|
this.resume();
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'end':
|
||||||
|
this.listeners.end.push(callback);
|
||||||
|
|
||||||
|
// emit 'end' event directly if we are flowing
|
||||||
|
// and the end has already been reached
|
||||||
|
//
|
||||||
|
// finish() when it went through
|
||||||
|
if (this.state.flowing && this.flowEnd()) {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'error':
|
||||||
|
this.listeners.error.push(callback);
|
||||||
|
|
||||||
|
// emit buffered 'error' events unless done already
|
||||||
|
// now that we know that we have at least one listener
|
||||||
|
if (this.state.flowing) {
|
||||||
|
this.flowErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private flowData(): void {
|
||||||
|
if (this.buffer.data.length > 0) {
|
||||||
|
const fullDataBuffer = VSBuffer.concat(this.buffer.data);
|
||||||
|
|
||||||
|
this.listeners.data.forEach(listener => listener(fullDataBuffer));
|
||||||
|
|
||||||
|
this.buffer.data.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private flowErrors(): void {
|
||||||
|
if (this.listeners.error.length > 0) {
|
||||||
|
for (const error of this.buffer.error) {
|
||||||
|
this.listeners.error.forEach(listener => listener(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buffer.error.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private flowEnd(): boolean {
|
||||||
|
if (this.state.ended) {
|
||||||
|
this.listeners.end.forEach(listener => listener());
|
||||||
|
|
||||||
|
return this.listeners.end.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
if (!this.state.destroyed) {
|
||||||
|
this.state.destroyed = true;
|
||||||
|
this.state.ended = true;
|
||||||
|
|
||||||
|
this.buffer.data.length = 0;
|
||||||
|
this.buffer.error.length = 0;
|
||||||
|
|
||||||
|
this.listeners.data.length = 0;
|
||||||
|
this.listeners.error.length = 0;
|
||||||
|
this.listeners.end.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as stream from 'vs/base/node/stream';
|
|
||||||
import * as iconv from 'iconv-lite';
|
import * as iconv from 'iconv-lite';
|
||||||
import { isLinux, isMacintosh } from 'vs/base/common/platform';
|
import { isLinux, isMacintosh } from 'vs/base/common/platform';
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
import { Readable, Writable } from 'stream';
|
import { Readable, Writable } from 'stream';
|
||||||
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
|
|
||||||
export const UTF8 = 'utf8';
|
export const UTF8 = 'utf8';
|
||||||
export const UTF8_with_bom = 'utf8bom';
|
export const UTF8_with_bom = 'utf8bom';
|
||||||
@@ -24,7 +24,12 @@ export interface IDecodeStreamOptions {
|
|||||||
overwriteEncoding?(detectedEncoding: string | null): string;
|
overwriteEncoding?(detectedEncoding: string | null): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions): Promise<{ detected: IDetectedEncodingResult, stream: NodeJS.ReadableStream }> {
|
export interface IDecodeStreamResult {
|
||||||
|
detected: IDetectedEncodingResult;
|
||||||
|
stream: NodeJS.ReadableStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions): Promise<IDecodeStreamResult> {
|
||||||
if (!options.minBytesRequiredForDetection) {
|
if (!options.minBytesRequiredForDetection) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -33,90 +38,88 @@ export function toDecodeStream(readable: Readable, options: IDecodeStreamOptions
|
|||||||
options.overwriteEncoding = detected => detected || UTF8;
|
options.overwriteEncoding = detected => detected || UTF8;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<{ detected: IDetectedEncodingResult, stream: NodeJS.ReadableStream }>((resolve, reject) => {
|
return new Promise<IDecodeStreamResult>((resolve, reject) => {
|
||||||
|
const writer = new class extends Writable {
|
||||||
readable.on('error', reject);
|
private decodeStream: NodeJS.ReadWriteStream;
|
||||||
|
private decodeStreamConstruction: Promise<void>;
|
||||||
readable.pipe(new class extends Writable {
|
private buffer: Buffer[] = [];
|
||||||
|
private bytesBuffered = 0;
|
||||||
private _decodeStream: NodeJS.ReadWriteStream;
|
|
||||||
private _decodeStreamConstruction: Promise<void>;
|
|
||||||
private _buffer: Buffer[] = [];
|
|
||||||
private _bytesBuffered = 0;
|
|
||||||
|
|
||||||
_write(chunk: any, encoding: string, callback: Function): void {
|
_write(chunk: any, encoding: string, callback: Function): void {
|
||||||
if (!Buffer.isBuffer(chunk)) {
|
if (!Buffer.isBuffer(chunk)) {
|
||||||
callback(new Error('data must be a buffer'));
|
callback(new Error('data must be a buffer'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._decodeStream) {
|
if (this.decodeStream) {
|
||||||
// just a forwarder now
|
this.decodeStream.write(chunk, callback); // just a forwarder now
|
||||||
this._decodeStream.write(chunk, callback);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._buffer.push(chunk);
|
this.buffer.push(chunk);
|
||||||
this._bytesBuffered += chunk.length;
|
this.bytesBuffered += chunk.length;
|
||||||
|
|
||||||
if (this._decodeStreamConstruction) {
|
// waiting for the decoder to be ready
|
||||||
// waiting for the decoder to be ready
|
if (this.decodeStreamConstruction) {
|
||||||
this._decodeStreamConstruction.then(_ => callback(), err => callback(err));
|
this.decodeStreamConstruction.then(() => callback(), err => callback(err));
|
||||||
|
}
|
||||||
|
|
||||||
} else if (typeof options.minBytesRequiredForDetection === 'number' && this._bytesBuffered >= options.minBytesRequiredForDetection) {
|
// buffered enough data, create stream and forward data
|
||||||
// buffered enough data, create stream and forward data
|
else if (typeof options.minBytesRequiredForDetection === 'number' && this.bytesBuffered >= options.minBytesRequiredForDetection) {
|
||||||
this._startDecodeStream(callback);
|
this._startDecodeStream(callback);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
// only buffering
|
||||||
// only buffering
|
else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_startDecodeStream(callback: Function): void {
|
_startDecodeStream(callback: Function): void {
|
||||||
|
this.decodeStreamConstruction = Promise.resolve(detectEncodingFromBuffer({
|
||||||
this._decodeStreamConstruction = Promise.resolve(detectEncodingFromBuffer({
|
buffer: Buffer.concat(this.buffer),
|
||||||
buffer: Buffer.concat(this._buffer), bytesRead: this._bytesBuffered
|
bytesRead: this.bytesBuffered
|
||||||
}, options.guessEncoding)).then(detected => {
|
}, options.guessEncoding)).then(detected => {
|
||||||
if (options.overwriteEncoding) {
|
if (options.overwriteEncoding) {
|
||||||
detected.encoding = options.overwriteEncoding(detected.encoding);
|
detected.encoding = options.overwriteEncoding(detected.encoding);
|
||||||
}
|
}
|
||||||
this._decodeStream = decodeStream(detected.encoding);
|
|
||||||
for (const buffer of this._buffer) {
|
|
||||||
this._decodeStream.write(buffer);
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
resolve({ detected, stream: this._decodeStream });
|
|
||||||
|
|
||||||
|
this.decodeStream = decodeStream(detected.encoding);
|
||||||
|
|
||||||
|
for (const buffer of this.buffer) {
|
||||||
|
this.decodeStream.write(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
resolve({ detected, stream: this.decodeStream });
|
||||||
}, err => {
|
}, err => {
|
||||||
this.emit('error', err);
|
this.emit('error', err);
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_final(callback: (err?: any) => any) {
|
_final(callback: (err?: any) => any) {
|
||||||
if (this._decodeStream) {
|
|
||||||
// normal finish
|
// normal finish
|
||||||
this._decodeStream.end(callback);
|
if (this.decodeStream) {
|
||||||
} else {
|
this.decodeStream.end(callback);
|
||||||
// we were still waiting for data...
|
}
|
||||||
this._startDecodeStream(() => this._decodeStream.end(callback));
|
|
||||||
|
// we were still waiting for data...
|
||||||
|
else {
|
||||||
|
this._startDecodeStream(() => this.decodeStream.end(callback));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// errors
|
||||||
|
readable.on('error', reject);
|
||||||
|
|
||||||
|
// pipe through
|
||||||
|
readable.pipe(writer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bomLength(encoding: string): number {
|
|
||||||
switch (encoding) {
|
|
||||||
case UTF8:
|
|
||||||
return 3;
|
|
||||||
case UTF16be:
|
|
||||||
case UTF16le:
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function decode(buffer: Buffer, encoding: string): string {
|
export function decode(buffer: Buffer, encoding: string): string {
|
||||||
return iconv.decode(buffer, toNodeEncoding(encoding));
|
return iconv.decode(buffer, toNodeEncoding(encoding));
|
||||||
}
|
}
|
||||||
@@ -129,7 +132,7 @@ export function encodingExists(encoding: string): boolean {
|
|||||||
return iconv.encodingExists(toNodeEncoding(encoding));
|
return iconv.encodingExists(toNodeEncoding(encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decodeStream(encoding: string | null): NodeJS.ReadWriteStream {
|
function decodeStream(encoding: string | null): NodeJS.ReadWriteStream {
|
||||||
return iconv.decodeStream(toNodeEncoding(encoding));
|
return iconv.decodeStream(toNodeEncoding(encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +148,7 @@ function toNodeEncoding(enc: string | null): string {
|
|||||||
return enc;
|
return enc;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function detectEncodingByBOMFromBuffer(buffer: Buffer | null, bytesRead: number): string | null {
|
export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null, bytesRead: number): string | null {
|
||||||
if (!buffer || bytesRead < 2) {
|
if (!buffer || bytesRead < 2) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -177,39 +180,31 @@ export function detectEncodingByBOMFromBuffer(buffer: Buffer | null, bytesRead:
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Detects the Byte Order Mark in a given file.
|
|
||||||
* If no BOM is detected, null will be passed to callback.
|
|
||||||
*/
|
|
||||||
export function detectEncodingByBOM(file: string): Promise<string | null> {
|
|
||||||
return stream.readExactlyByFile(file, 3).then(({ buffer, bytesRead }) => detectEncodingByBOMFromBuffer(buffer, bytesRead), error => null);
|
|
||||||
}
|
|
||||||
|
|
||||||
const MINIMUM_THRESHOLD = 0.2;
|
const MINIMUM_THRESHOLD = 0.2;
|
||||||
const IGNORE_ENCODINGS = ['ascii', 'utf-8', 'utf-16', 'utf-32'];
|
const IGNORE_ENCODINGS = ['ascii', 'utf-8', 'utf-16', 'utf-32'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Guesses the encoding from buffer.
|
* Guesses the encoding from buffer.
|
||||||
*/
|
*/
|
||||||
export function guessEncodingByBuffer(buffer: Buffer): Promise<string | null> {
|
async function guessEncodingByBuffer(buffer: Buffer): Promise<string | null> {
|
||||||
return import('jschardet').then(jschardet => {
|
const jschardet = await import('jschardet');
|
||||||
jschardet.Constants.MINIMUM_THRESHOLD = MINIMUM_THRESHOLD;
|
|
||||||
|
|
||||||
const guessed = jschardet.detect(buffer);
|
jschardet.Constants.MINIMUM_THRESHOLD = MINIMUM_THRESHOLD;
|
||||||
if (!guessed || !guessed.encoding) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const enc = guessed.encoding.toLowerCase();
|
const guessed = jschardet.detect(buffer);
|
||||||
|
if (!guessed || !guessed.encoding) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore encodings that cannot guess correctly
|
const enc = guessed.encoding.toLowerCase();
|
||||||
// (http://chardet.readthedocs.io/en/latest/supported-encodings.html)
|
|
||||||
if (0 <= IGNORE_ENCODINGS.indexOf(enc)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return toIconvLiteEncoding(guessed.encoding);
|
// Ignore encodings that cannot guess correctly
|
||||||
});
|
// (http://chardet.readthedocs.io/en/latest/supported-encodings.html)
|
||||||
|
if (0 <= IGNORE_ENCODINGS.indexOf(enc)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return toIconvLiteEncoding(guessed.encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
const JSCHARDET_TO_ICONV_ENCODINGS: { [name: string]: string } = {
|
const JSCHARDET_TO_ICONV_ENCODINGS: { [name: string]: string } = {
|
||||||
@@ -270,9 +265,14 @@ export interface IDetectedEncodingResult {
|
|||||||
seemsBinary: boolean;
|
seemsBinary: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function detectEncodingFromBuffer(readResult: stream.ReadResult, autoGuessEncoding?: false): IDetectedEncodingResult;
|
export interface IReadResult {
|
||||||
export function detectEncodingFromBuffer(readResult: stream.ReadResult, autoGuessEncoding?: boolean): Promise<IDetectedEncodingResult>;
|
buffer: Buffer | null;
|
||||||
export function detectEncodingFromBuffer({ buffer, bytesRead }: stream.ReadResult, autoGuessEncoding?: boolean): Promise<IDetectedEncodingResult> | IDetectedEncodingResult {
|
bytesRead: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function detectEncodingFromBuffer(readResult: IReadResult, autoGuessEncoding?: false): IDetectedEncodingResult;
|
||||||
|
export function detectEncodingFromBuffer(readResult: IReadResult, autoGuessEncoding?: boolean): Promise<IDetectedEncodingResult>;
|
||||||
|
export function detectEncodingFromBuffer({ buffer, bytesRead }: IReadResult, autoGuessEncoding?: boolean): Promise<IDetectedEncodingResult> | IDetectedEncodingResult {
|
||||||
|
|
||||||
// Always first check for BOM to find out about encoding
|
// Always first check for BOM to find out about encoding
|
||||||
let encoding = detectEncodingByBOMFromBuffer(buffer, bytesRead);
|
let encoding = detectEncodingByBOMFromBuffer(buffer, bytesRead);
|
||||||
@@ -357,7 +357,7 @@ const windowsTerminalEncodings = {
|
|||||||
'1252': 'cp1252' // West European Latin
|
'1252': 'cp1252' // West European Latin
|
||||||
};
|
};
|
||||||
|
|
||||||
export function resolveTerminalEncoding(verbose?: boolean): Promise<string> {
|
export async function resolveTerminalEncoding(verbose?: boolean): Promise<string> {
|
||||||
let rawEncodingPromise: Promise<string>;
|
let rawEncodingPromise: Promise<string>;
|
||||||
|
|
||||||
// Support a global environment variable to win over other mechanics
|
// Support a global environment variable to win over other mechanics
|
||||||
@@ -403,24 +403,23 @@ export function resolveTerminalEncoding(verbose?: boolean): Promise<string> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return rawEncodingPromise.then(rawEncoding => {
|
const rawEncoding = await rawEncodingPromise;
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
console.log(`Detected raw terminal encoding: ${rawEncoding}`);
|
console.log(`Detected raw terminal encoding: ${rawEncoding}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rawEncoding || rawEncoding.toLowerCase() === 'utf-8' || rawEncoding.toLowerCase() === UTF8) {
|
|
||||||
return UTF8;
|
|
||||||
}
|
|
||||||
|
|
||||||
const iconvEncoding = toIconvLiteEncoding(rawEncoding);
|
|
||||||
if (iconv.encodingExists(iconvEncoding)) {
|
|
||||||
return iconvEncoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
console.log('Unsupported terminal encoding, falling back to UTF-8.');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!rawEncoding || rawEncoding.toLowerCase() === 'utf-8' || rawEncoding.toLowerCase() === UTF8) {
|
||||||
return UTF8;
|
return UTF8;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
const iconvEncoding = toIconvLiteEncoding(rawEncoding);
|
||||||
|
if (iconv.encodingExists(iconvEncoding)) {
|
||||||
|
return iconvEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
console.log('Unsupported terminal encoding, falling back to UTF-8.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return UTF8;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,63 +5,6 @@
|
|||||||
|
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
export interface ReadResult {
|
|
||||||
buffer: Buffer | null;
|
|
||||||
bytesRead: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads totalBytes from the provided file.
|
|
||||||
*/
|
|
||||||
export function readExactlyByFile(file: string, totalBytes: number): Promise<ReadResult> {
|
|
||||||
return new Promise<ReadResult>((resolve, reject) => {
|
|
||||||
fs.open(file, 'r', null, (err, fd) => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
function end(err: Error | null, resultBuffer: Buffer | null, bytesRead: number): void {
|
|
||||||
fs.close(fd, closeError => {
|
|
||||||
if (closeError) {
|
|
||||||
return reject(closeError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err && (<any>err).code === 'EISDIR') {
|
|
||||||
return reject(err); // we want to bubble this error up (file is actually a folder)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolve({ buffer: resultBuffer, bytesRead });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const buffer = Buffer.allocUnsafe(totalBytes);
|
|
||||||
let offset = 0;
|
|
||||||
|
|
||||||
function readChunk(): void {
|
|
||||||
fs.read(fd, buffer, offset, totalBytes - offset, null, (err, bytesRead) => {
|
|
||||||
if (err) {
|
|
||||||
return end(err, null, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytesRead === 0) {
|
|
||||||
return end(null, buffer, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += bytesRead;
|
|
||||||
|
|
||||||
if (offset === totalBytes) {
|
|
||||||
return end(null, buffer, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return readChunk();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
readChunk();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a file until a matching string is found.
|
* Reads a file until a matching string is found.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -216,10 +216,10 @@ class ProtocolReader extends Disposable {
|
|||||||
|
|
||||||
// save new state => next time will read the body
|
// save new state => next time will read the body
|
||||||
this._state.readHead = false;
|
this._state.readHead = false;
|
||||||
this._state.readLen = buff.readUint32BE(9);
|
this._state.readLen = buff.readUInt32BE(9);
|
||||||
this._state.messageType = <ProtocolMessageType>buff.readUint8(0);
|
this._state.messageType = <ProtocolMessageType>buff.readUInt8(0);
|
||||||
this._state.id = buff.readUint32BE(1);
|
this._state.id = buff.readUInt32BE(1);
|
||||||
this._state.ack = buff.readUint32BE(5);
|
this._state.ack = buff.readUInt32BE(5);
|
||||||
} else {
|
} else {
|
||||||
// buff is the body
|
// buff is the body
|
||||||
const messageType = this._state.messageType;
|
const messageType = this._state.messageType;
|
||||||
@@ -288,10 +288,10 @@ class ProtocolWriter {
|
|||||||
msg.writtenTime = Date.now();
|
msg.writtenTime = Date.now();
|
||||||
this.lastWriteTime = Date.now();
|
this.lastWriteTime = Date.now();
|
||||||
const header = VSBuffer.alloc(ProtocolConstants.HeaderLength);
|
const header = VSBuffer.alloc(ProtocolConstants.HeaderLength);
|
||||||
header.writeUint8(msg.type, 0);
|
header.writeUInt8(msg.type, 0);
|
||||||
header.writeUint32BE(msg.id, 1);
|
header.writeUInt32BE(msg.id, 1);
|
||||||
header.writeUint32BE(msg.ack, 5);
|
header.writeUInt32BE(msg.ack, 5);
|
||||||
header.writeUint32BE(msg.data.byteLength, 9);
|
header.writeUInt32BE(msg.data.byteLength, 9);
|
||||||
this._writeSoon(header, msg.data);
|
this._writeSoon(header, msg.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,17 +166,17 @@ enum DataType {
|
|||||||
|
|
||||||
function createSizeBuffer(size: number): VSBuffer {
|
function createSizeBuffer(size: number): VSBuffer {
|
||||||
const result = VSBuffer.alloc(4);
|
const result = VSBuffer.alloc(4);
|
||||||
result.writeUint32BE(size, 0);
|
result.writeUInt32BE(size, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readSizeBuffer(reader: IReader): number {
|
function readSizeBuffer(reader: IReader): number {
|
||||||
return reader.read(4).readUint32BE(0);
|
return reader.read(4).readUInt32BE(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createOneByteBuffer(value: number): VSBuffer {
|
function createOneByteBuffer(value: number): VSBuffer {
|
||||||
const result = VSBuffer.alloc(1);
|
const result = VSBuffer.alloc(1);
|
||||||
result.writeUint8(value, 0);
|
result.writeUInt8(value, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ function serialize(writer: IWriter, data: any): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deserialize(reader: IReader): any {
|
function deserialize(reader: IReader): any {
|
||||||
const type = reader.read(1).readUint8(0);
|
const type = reader.read(1).readUInt8(0);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DataType.Undefined: return undefined;
|
case DataType.Undefined: return undefined;
|
||||||
|
|||||||
@@ -136,10 +136,10 @@ suite('IPC, Socket Protocol', () => {
|
|||||||
assert.equal(msg1.toString(), 'foobarfarboo');
|
assert.equal(msg1.toString(), 'foobarfarboo');
|
||||||
|
|
||||||
const buffer = VSBuffer.alloc(1);
|
const buffer = VSBuffer.alloc(1);
|
||||||
buffer.writeUint8(123, 0);
|
buffer.writeUInt8(123, 0);
|
||||||
a.send(buffer);
|
a.send(buffer);
|
||||||
const msg2 = await bMessages.waitForOne();
|
const msg2 = await bMessages.waitForOne();
|
||||||
assert.equal(msg2.readUint8(0), 123);
|
assert.equal(msg2.readUInt8(0), 123);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,18 +3,365 @@
|
|||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { hasBuffer, VSBuffer } from 'vs/base/common/buffer';
|
import { VSBuffer, bufferToReadable, readableToBuffer, bufferToStream, streamToBuffer, writeableBufferStream } from 'vs/base/common/buffer';
|
||||||
|
import { timeout } from 'vs/base/common/async';
|
||||||
|
|
||||||
suite('Buffer', () => {
|
suite('Buffer', () => {
|
||||||
|
|
||||||
if (hasBuffer) {
|
test('issue #71993 - VSBuffer#toString returns numbers', () => {
|
||||||
test('issue #71993 - VSBuffer#toString returns numbers', () => {
|
const data = new Uint8Array([1, 2, 3, 'h'.charCodeAt(0), 'i'.charCodeAt(0), 4, 5]).buffer;
|
||||||
const data = new Uint8Array([1, 2, 3, 'h'.charCodeAt(0), 'i'.charCodeAt(0), 4, 5]).buffer;
|
const buffer = VSBuffer.wrap(new Uint8Array(data, 3, 2));
|
||||||
const buffer = VSBuffer.wrap(new Uint8Array(data, 3, 2));
|
assert.deepEqual(buffer.toString(), 'hi');
|
||||||
assert.deepEqual(buffer.toString(), 'hi');
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
test('bufferToReadable / readableToBuffer', () => {
|
||||||
|
const content = 'Hello World';
|
||||||
|
const readable = bufferToReadable(VSBuffer.fromString(content));
|
||||||
|
|
||||||
|
assert.equal(readableToBuffer(readable).toString(), content);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferToStream / streamToBuffer', async () => {
|
||||||
|
const content = 'Hello World';
|
||||||
|
const stream = bufferToStream(VSBuffer.fromString(content));
|
||||||
|
|
||||||
|
assert.equal((await streamToBuffer(stream)).toString(), content);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - basics (no error)', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let ended = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
ended = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let errors: Error[] = [];
|
||||||
|
stream.on('error', error => {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(VSBuffer.fromString('World'));
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 2);
|
||||||
|
assert.equal(chunks[0].toString(), 'Hello');
|
||||||
|
assert.equal(chunks[1].toString(), 'World');
|
||||||
|
assert.equal(ended, true);
|
||||||
|
assert.equal(errors.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - basics (error)', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let ended = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
ended = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let errors: Error[] = [];
|
||||||
|
stream.on('error', error => {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(new Error());
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 1);
|
||||||
|
assert.equal(chunks[0].toString(), 'Hello');
|
||||||
|
assert.equal(ended, true);
|
||||||
|
assert.equal(errors.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - buffers data when no listener', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(VSBuffer.fromString('World'));
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let ended = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
ended = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let errors: Error[] = [];
|
||||||
|
stream.on('error', error => {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 1);
|
||||||
|
assert.equal(chunks[0].toString(), 'HelloWorld');
|
||||||
|
assert.equal(ended, true);
|
||||||
|
assert.equal(errors.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - buffers errors when no listener', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.error(new Error());
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let errors: Error[] = [];
|
||||||
|
stream.on('error', error => {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
let ended = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
ended = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.end();
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 1);
|
||||||
|
assert.equal(chunks[0].toString(), 'Hello');
|
||||||
|
assert.equal(ended, true);
|
||||||
|
assert.equal(errors.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - buffers end when no listener', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(VSBuffer.fromString('World'));
|
||||||
|
|
||||||
|
let ended = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
ended = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let errors: Error[] = [];
|
||||||
|
stream.on('error', error => {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 1);
|
||||||
|
assert.equal(chunks[0].toString(), 'HelloWorld');
|
||||||
|
assert.equal(ended, true);
|
||||||
|
assert.equal(errors.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - nothing happens after end()', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(VSBuffer.fromString('World'));
|
||||||
|
|
||||||
|
let dataCalledAfterEnd = false;
|
||||||
|
stream.on('data', data => {
|
||||||
|
dataCalledAfterEnd = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let errorCalledAfterEnd = false;
|
||||||
|
stream.on('error', error => {
|
||||||
|
errorCalledAfterEnd = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let endCalledAfterEnd = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
endCalledAfterEnd = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.error(new Error());
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(VSBuffer.fromString('World'));
|
||||||
|
|
||||||
|
assert.equal(dataCalledAfterEnd, false);
|
||||||
|
assert.equal(errorCalledAfterEnd, false);
|
||||||
|
assert.equal(endCalledAfterEnd, false);
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 2);
|
||||||
|
assert.equal(chunks[0].toString(), 'Hello');
|
||||||
|
assert.equal(chunks[1].toString(), 'World');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - pause/resume (simple)', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let ended = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
ended = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let errors: Error[] = [];
|
||||||
|
stream.on('error', error => {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.pause();
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(VSBuffer.fromString('World'));
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 0);
|
||||||
|
assert.equal(errors.length, 0);
|
||||||
|
assert.equal(ended, false);
|
||||||
|
|
||||||
|
stream.resume();
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 1);
|
||||||
|
assert.equal(chunks[0].toString(), 'HelloWorld');
|
||||||
|
assert.equal(ended, true);
|
||||||
|
assert.equal(errors.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - pause/resume (pause after first write)', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let ended = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
ended = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let errors: Error[] = [];
|
||||||
|
stream.on('error', error => {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
|
||||||
|
stream.pause();
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(VSBuffer.fromString('World'));
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 1);
|
||||||
|
assert.equal(chunks[0].toString(), 'Hello');
|
||||||
|
assert.equal(errors.length, 0);
|
||||||
|
assert.equal(ended, false);
|
||||||
|
|
||||||
|
stream.resume();
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 2);
|
||||||
|
assert.equal(chunks[0].toString(), 'Hello');
|
||||||
|
assert.equal(chunks[1].toString(), 'World');
|
||||||
|
assert.equal(ended, true);
|
||||||
|
assert.equal(errors.length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - pause/resume (error)', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let ended = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
ended = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let errors: Error[] = [];
|
||||||
|
stream.on('error', error => {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.pause();
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(new Error());
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 0);
|
||||||
|
assert.equal(ended, false);
|
||||||
|
assert.equal(errors.length, 0);
|
||||||
|
|
||||||
|
stream.resume();
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 1);
|
||||||
|
assert.equal(chunks[0].toString(), 'Hello');
|
||||||
|
assert.equal(ended, true);
|
||||||
|
assert.equal(errors.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bufferWriteableStream - destroy', async () => {
|
||||||
|
const stream = writeableBufferStream();
|
||||||
|
|
||||||
|
let chunks: VSBuffer[] = [];
|
||||||
|
stream.on('data', data => {
|
||||||
|
chunks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let ended = false;
|
||||||
|
stream.on('end', () => {
|
||||||
|
ended = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let errors: Error[] = [];
|
||||||
|
stream.on('error', error => {
|
||||||
|
errors.push(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.destroy();
|
||||||
|
|
||||||
|
await timeout(0);
|
||||||
|
stream.write(VSBuffer.fromString('Hello'));
|
||||||
|
await timeout(0);
|
||||||
|
stream.end(VSBuffer.fromString('World'));
|
||||||
|
|
||||||
|
assert.equal(chunks.length, 0);
|
||||||
|
assert.equal(ended, false);
|
||||||
|
assert.equal(errors.length, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,51 +6,114 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as encoding from 'vs/base/node/encoding';
|
import * as encoding from 'vs/base/node/encoding';
|
||||||
import { readExactlyByFile } from 'vs/base/node/stream';
|
|
||||||
import { Readable } from 'stream';
|
import { Readable } from 'stream';
|
||||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||||
|
|
||||||
|
export async function detectEncodingByBOM(file: string): Promise<string | null> {
|
||||||
|
try {
|
||||||
|
const { buffer, bytesRead } = await readExactlyByFile(file, 3);
|
||||||
|
|
||||||
|
return encoding.detectEncodingByBOMFromBuffer(buffer, bytesRead);
|
||||||
|
} catch (error) {
|
||||||
|
return null; // ignore errors (like file not found)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadResult {
|
||||||
|
buffer: Buffer | null;
|
||||||
|
bytesRead: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readExactlyByFile(file: string, totalBytes: number): Promise<ReadResult> {
|
||||||
|
return new Promise<ReadResult>((resolve, reject) => {
|
||||||
|
fs.open(file, 'r', null, (err, fd) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
function end(err: Error | null, resultBuffer: Buffer | null, bytesRead: number): void {
|
||||||
|
fs.close(fd, closeError => {
|
||||||
|
if (closeError) {
|
||||||
|
return reject(closeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err && (<any>err).code === 'EISDIR') {
|
||||||
|
return reject(err); // we want to bubble this error up (file is actually a folder)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve({ buffer: resultBuffer, bytesRead });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = Buffer.allocUnsafe(totalBytes);
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
function readChunk(): void {
|
||||||
|
fs.read(fd, buffer, offset, totalBytes - offset, null, (err, bytesRead) => {
|
||||||
|
if (err) {
|
||||||
|
return end(err, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytesRead === 0) {
|
||||||
|
return end(null, buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += bytesRead;
|
||||||
|
|
||||||
|
if (offset === totalBytes) {
|
||||||
|
return end(null, buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return readChunk();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
readChunk();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
suite('Encoding', () => {
|
suite('Encoding', () => {
|
||||||
|
|
||||||
test('detectBOM does not return error for non existing file', async () => {
|
test('detectBOM does not return error for non existing file', async () => {
|
||||||
const file = getPathFromAmdModule(require, './fixtures/not-exist.css');
|
const file = getPathFromAmdModule(require, './fixtures/not-exist.css');
|
||||||
|
|
||||||
const detectedEncoding = await encoding.detectEncodingByBOM(file);
|
const detectedEncoding = await detectEncodingByBOM(file);
|
||||||
assert.equal(detectedEncoding, null);
|
assert.equal(detectedEncoding, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('detectBOM UTF-8', async () => {
|
test('detectBOM UTF-8', async () => {
|
||||||
const file = getPathFromAmdModule(require, './fixtures/some_utf8.css');
|
const file = getPathFromAmdModule(require, './fixtures/some_utf8.css');
|
||||||
|
|
||||||
const detectedEncoding = await encoding.detectEncodingByBOM(file);
|
const detectedEncoding = await detectEncodingByBOM(file);
|
||||||
assert.equal(detectedEncoding, 'utf8');
|
assert.equal(detectedEncoding, 'utf8');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('detectBOM UTF-16 LE', async () => {
|
test('detectBOM UTF-16 LE', async () => {
|
||||||
const file = getPathFromAmdModule(require, './fixtures/some_utf16le.css');
|
const file = getPathFromAmdModule(require, './fixtures/some_utf16le.css');
|
||||||
|
|
||||||
const detectedEncoding = await encoding.detectEncodingByBOM(file);
|
const detectedEncoding = await detectEncodingByBOM(file);
|
||||||
assert.equal(detectedEncoding, 'utf16le');
|
assert.equal(detectedEncoding, 'utf16le');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('detectBOM UTF-16 BE', async () => {
|
test('detectBOM UTF-16 BE', async () => {
|
||||||
const file = getPathFromAmdModule(require, './fixtures/some_utf16be.css');
|
const file = getPathFromAmdModule(require, './fixtures/some_utf16be.css');
|
||||||
|
|
||||||
const detectedEncoding = await encoding.detectEncodingByBOM(file);
|
const detectedEncoding = await detectEncodingByBOM(file);
|
||||||
assert.equal(detectedEncoding, 'utf16be');
|
assert.equal(detectedEncoding, 'utf16be');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('detectBOM ANSI', async function () {
|
test('detectBOM ANSI', async function () {
|
||||||
const file = getPathFromAmdModule(require, './fixtures/some_ansi.css');
|
const file = getPathFromAmdModule(require, './fixtures/some_ansi.css');
|
||||||
|
|
||||||
const detectedEncoding = await encoding.detectEncodingByBOM(file);
|
const detectedEncoding = await detectEncodingByBOM(file);
|
||||||
assert.equal(detectedEncoding, null);
|
assert.equal(detectedEncoding, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('detectBOM ANSI', async function () {
|
test('detectBOM ANSI', async function () {
|
||||||
const file = getPathFromAmdModule(require, './fixtures/empty.txt');
|
const file = getPathFromAmdModule(require, './fixtures/empty.txt');
|
||||||
|
|
||||||
const detectedEncoding = await encoding.detectEncodingByBOM(file);
|
const detectedEncoding = await detectEncodingByBOM(file);
|
||||||
assert.equal(detectedEncoding, null);
|
assert.equal(detectedEncoding, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -9,23 +9,6 @@ import * as stream from 'vs/base/node/stream';
|
|||||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||||
|
|
||||||
suite('Stream', () => {
|
suite('Stream', () => {
|
||||||
test('readExactlyByFile - ANSI', function () {
|
|
||||||
const file = getPathFromAmdModule(require, './fixtures/file.css');
|
|
||||||
|
|
||||||
return stream.readExactlyByFile(file, 10).then(({ buffer, bytesRead }) => {
|
|
||||||
assert.equal(bytesRead, 10);
|
|
||||||
assert.equal(buffer!.toString(), '/*--------');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('readExactlyByFile - empty', function () {
|
|
||||||
const file = getPathFromAmdModule(require, './fixtures/empty.txt');
|
|
||||||
|
|
||||||
return stream.readExactlyByFile(file, 10).then(({ bytesRead }) => {
|
|
||||||
assert.equal(bytesRead, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('readToMatchingString - ANSI', function () {
|
test('readToMatchingString - ANSI', function () {
|
||||||
const file = getPathFromAmdModule(require, './fixtures/file.css');
|
const file = getPathFromAmdModule(require, './fixtures/file.css');
|
||||||
|
|
||||||
|
|||||||
@@ -1580,8 +1580,8 @@ export class WindowsManager implements IWindowsMainService {
|
|||||||
if (cli && (cli.remote !== remote)) {
|
if (cli && (cli.remote !== remote)) {
|
||||||
cli = { ...cli, remote };
|
cli = { ...cli, remote };
|
||||||
}
|
}
|
||||||
const forceNewWindow = !(options && options.reuseWindow);
|
const forceReuseWindow = options && options.reuseWindow;
|
||||||
return this.open({ context, cli, forceNewWindow, forceEmpty: true });
|
return this.open({ context, cli, forceEmpty: true, forceReuseWindow });
|
||||||
}
|
}
|
||||||
|
|
||||||
openNewTabbedWindow(context: OpenContext): ICodeWindow[] {
|
openNewTabbedWindow(context: OpenContext): ICodeWindow[] {
|
||||||
|
|||||||
@@ -18,13 +18,15 @@ const testWorkspace: IWorkspaceIdentifier = {
|
|||||||
configPath: URI.file(path.join(fixturesFolder, 'workspaces.json'))
|
configPath: URI.file(path.join(fixturesFolder, 'workspaces.json'))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const testWorkspaceFolders = toWorkspaceFolders([{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }], testWorkspace.configPath);
|
||||||
|
|
||||||
function options(custom?: Partial<IBestWindowOrFolderOptions<ISimpleWindow>>): IBestWindowOrFolderOptions<ISimpleWindow> {
|
function options(custom?: Partial<IBestWindowOrFolderOptions<ISimpleWindow>>): IBestWindowOrFolderOptions<ISimpleWindow> {
|
||||||
return {
|
return {
|
||||||
windows: [],
|
windows: [],
|
||||||
newWindow: false,
|
newWindow: false,
|
||||||
context: OpenContext.CLI,
|
context: OpenContext.CLI,
|
||||||
codeSettingsFolder: '_vscode',
|
codeSettingsFolder: '_vscode',
|
||||||
localWorkspaceResolver: workspace => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: toWorkspaceFolders([{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }]) } : null!; },
|
localWorkspaceResolver: workspace => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: testWorkspaceFolders } : null; },
|
||||||
...custom
|
...custom
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { Selection } from 'vs/editor/common/core/selection';
|
|||||||
import { IModelContentChange, IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent, ModelRawContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
import { IModelContentChange, IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent, ModelRawContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||||
import { SearchData } from 'vs/editor/common/model/textModelSearch';
|
import { SearchData } from 'vs/editor/common/model/textModelSearch';
|
||||||
import { LanguageId, LanguageIdentifier, FormattingOptions } from 'vs/editor/common/modes';
|
import { LanguageId, LanguageIdentifier, FormattingOptions } from 'vs/editor/common/modes';
|
||||||
import { ITextSnapshot } from 'vs/platform/files/common/files';
|
|
||||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -460,6 +459,17 @@ export interface IActiveIndentGuideInfo {
|
|||||||
indent: number;
|
indent: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text snapshot that works like an iterator.
|
||||||
|
* Will try to return chunks of roughly ~64KB size.
|
||||||
|
* Will return null when finished.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export interface ITextSnapshot {
|
||||||
|
read(): string | null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A model.
|
* A model.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -6,10 +6,9 @@
|
|||||||
import { CharCode } from 'vs/base/common/charCode';
|
import { CharCode } from 'vs/base/common/charCode';
|
||||||
import { Position } from 'vs/editor/common/core/position';
|
import { Position } from 'vs/editor/common/core/position';
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import { FindMatch } from 'vs/editor/common/model';
|
import { FindMatch, ITextSnapshot } from 'vs/editor/common/model';
|
||||||
import { NodeColor, SENTINEL, TreeNode, fixInsert, leftest, rbDelete, righttest, updateTreeMetadata } from 'vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase';
|
import { NodeColor, SENTINEL, TreeNode, fixInsert, leftest, rbDelete, righttest, updateTreeMetadata } from 'vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase';
|
||||||
import { SearchData, Searcher, createFindMatch, isValidMatch } from 'vs/editor/common/model/textModelSearch';
|
import { SearchData, Searcher, createFindMatch, isValidMatch } from 'vs/editor/common/model/textModelSearch';
|
||||||
import { ITextSnapshot } from 'vs/platform/files/common/files';
|
|
||||||
|
|
||||||
// const lfRegex = new RegExp(/\r\n|\r|\n/g);
|
// const lfRegex = new RegExp(/\r\n|\r|\n/g);
|
||||||
export const AverageBufferSize = 65535;
|
export const AverageBufferSize = 65535;
|
||||||
|
|||||||
@@ -6,10 +6,9 @@
|
|||||||
import * as strings from 'vs/base/common/strings';
|
import * as strings from 'vs/base/common/strings';
|
||||||
import { Position } from 'vs/editor/common/core/position';
|
import { Position } from 'vs/editor/common/core/position';
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import { ApplyEditsResult, EndOfLinePreference, FindMatch, IIdentifiedSingleEditOperation, IInternalModelContentChange, ISingleEditOperationIdentifier, ITextBuffer } from 'vs/editor/common/model';
|
import { ApplyEditsResult, EndOfLinePreference, FindMatch, IIdentifiedSingleEditOperation, IInternalModelContentChange, ISingleEditOperationIdentifier, ITextBuffer, ITextSnapshot } from 'vs/editor/common/model';
|
||||||
import { PieceTreeBase, StringBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';
|
import { PieceTreeBase, StringBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';
|
||||||
import { SearchData } from 'vs/editor/common/model/textModelSearch';
|
import { SearchData } from 'vs/editor/common/model/textModelSearch';
|
||||||
import { ITextSnapshot } from 'vs/platform/files/common/files';
|
|
||||||
|
|
||||||
export interface IValidatedEditOperation {
|
export interface IValidatedEditOperation {
|
||||||
sortIndex: number;
|
sortIndex: number;
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageCo
|
|||||||
import { NULL_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/nullMode';
|
import { NULL_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/nullMode';
|
||||||
import { ignoreBracketsInToken } from 'vs/editor/common/modes/supports';
|
import { ignoreBracketsInToken } from 'vs/editor/common/modes/supports';
|
||||||
import { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';
|
import { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets';
|
||||||
import { IStringStream, ITextSnapshot } from 'vs/platform/files/common/files';
|
|
||||||
import { ITheme, ThemeColor } from 'vs/platform/theme/common/themeService';
|
import { ITheme, ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||||
|
import { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer';
|
||||||
|
|
||||||
const CHEAP_TOKENIZATION_LENGTH_LIMIT = 2048;
|
const CHEAP_TOKENIZATION_LENGTH_LIMIT = 2048;
|
||||||
|
|
||||||
@@ -46,36 +46,54 @@ export function createTextBufferFactory(text: string): model.ITextBufferFactory
|
|||||||
return builder.finish();
|
return builder.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTextBufferFactoryFromStream(stream: IStringStream, filter?: (chunk: string) => string): Promise<model.ITextBufferFactory> {
|
interface ITextStream {
|
||||||
return new Promise<model.ITextBufferFactory>((c, e) => {
|
on(event: 'data', callback: (data: string) => void): void;
|
||||||
let done = false;
|
on(event: 'error', callback: (err: Error) => void): void;
|
||||||
let builder = createTextBufferBuilder();
|
on(event: 'end', callback: () => void): void;
|
||||||
|
on(event: string, callback: any): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTextBufferFactoryFromStream(stream: ITextStream, filter?: (chunk: string) => string, validator?: (chunk: string) => Error | undefined): Promise<model.ITextBufferFactory>;
|
||||||
|
export function createTextBufferFactoryFromStream(stream: VSBufferReadableStream, filter?: (chunk: VSBuffer) => VSBuffer, validator?: (chunk: VSBuffer) => Error | undefined): Promise<model.ITextBufferFactory>;
|
||||||
|
export function createTextBufferFactoryFromStream(stream: ITextStream | VSBufferReadableStream, filter?: (chunk: any) => string | VSBuffer, validator?: (chunk: any) => Error | undefined): Promise<model.ITextBufferFactory> {
|
||||||
|
return new Promise<model.ITextBufferFactory>((resolve, reject) => {
|
||||||
|
const builder = createTextBufferBuilder();
|
||||||
|
|
||||||
|
let done = false;
|
||||||
|
|
||||||
|
stream.on('data', (chunk: string | VSBuffer) => {
|
||||||
|
if (validator) {
|
||||||
|
const error = validator(chunk);
|
||||||
|
if (error) {
|
||||||
|
done = true;
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stream.on('data', (chunk) => {
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
chunk = filter(chunk);
|
chunk = filter(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.acceptChunk(chunk);
|
builder.acceptChunk((typeof chunk === 'string') ? chunk : chunk.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
stream.on('error', (error) => {
|
stream.on('error', (error) => {
|
||||||
if (!done) {
|
if (!done) {
|
||||||
done = true;
|
done = true;
|
||||||
e(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
stream.on('end', () => {
|
stream.on('end', () => {
|
||||||
if (!done) {
|
if (!done) {
|
||||||
done = true;
|
done = true;
|
||||||
c(builder.finish());
|
resolve(builder.finish());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTextBufferFactoryFromSnapshot(snapshot: ITextSnapshot): model.ITextBufferFactory {
|
export function createTextBufferFactoryFromSnapshot(snapshot: model.ITextSnapshot): model.ITextBufferFactory {
|
||||||
let builder = createTextBufferBuilder();
|
let builder = createTextBufferBuilder();
|
||||||
|
|
||||||
let chunk: string | null;
|
let chunk: string | null;
|
||||||
@@ -111,12 +129,12 @@ function singleLetter(result: number): string {
|
|||||||
const LIMIT_FIND_COUNT = 999;
|
const LIMIT_FIND_COUNT = 999;
|
||||||
export const LONG_LINE_BOUNDARY = 10000;
|
export const LONG_LINE_BOUNDARY = 10000;
|
||||||
|
|
||||||
class TextModelSnapshot implements ITextSnapshot {
|
class TextModelSnapshot implements model.ITextSnapshot {
|
||||||
|
|
||||||
private readonly _source: ITextSnapshot;
|
private readonly _source: model.ITextSnapshot;
|
||||||
private _eos: boolean;
|
private _eos: boolean;
|
||||||
|
|
||||||
constructor(source: ITextSnapshot) {
|
constructor(source: model.ITextSnapshot) {
|
||||||
this._source = source;
|
this._source = source;
|
||||||
this._eos = false;
|
this._eos = false;
|
||||||
}
|
}
|
||||||
@@ -731,7 +749,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
return fullModelValue;
|
return fullModelValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createSnapshot(preserveBOM: boolean = false): ITextSnapshot {
|
public createSnapshot(preserveBOM: boolean = false): model.ITextSnapshot {
|
||||||
return new TextModelSnapshot(this._buffer.createSnapshot(preserveBOM));
|
return new TextModelSnapshot(this._buffer.createSnapshot(preserveBOM));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { SelectionBasedVariableResolver, CompositeSnippetVariableResolver, Model
|
|||||||
import { SnippetParser, Variable, VariableResolver } from 'vs/editor/contrib/snippet/snippetParser';
|
import { SnippetParser, Variable, VariableResolver } from 'vs/editor/contrib/snippet/snippetParser';
|
||||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { Workspace, toWorkspaceFolders, IWorkspace, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
import { Workspace, toWorkspaceFolders, IWorkspace, IWorkspaceContextService, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
|
|
||||||
suite('Snippet Variables Resolver', function () {
|
suite('Snippet Variables Resolver', function () {
|
||||||
|
|
||||||
@@ -328,11 +328,12 @@ suite('Snippet Variables Resolver', function () {
|
|||||||
assertVariableResolve(resolver, 'WORKSPACE_NAME', undefined);
|
assertVariableResolve(resolver, 'WORKSPACE_NAME', undefined);
|
||||||
|
|
||||||
// single folder workspace without config
|
// single folder workspace without config
|
||||||
workspace = new Workspace('', toWorkspaceFolders([{ path: '/folderName' }]));
|
workspace = new Workspace('', [toWorkspaceFolder(URI.file('/folderName'))]);
|
||||||
assertVariableResolve(resolver, 'WORKSPACE_NAME', 'folderName');
|
assertVariableResolve(resolver, 'WORKSPACE_NAME', 'folderName');
|
||||||
|
|
||||||
// workspace with config
|
// workspace with config
|
||||||
workspace = new Workspace('', toWorkspaceFolders([{ path: 'folderName' }]), URI.file('testWorkspace.code-workspace'));
|
const workspaceConfigPath = URI.file('testWorkspace.code-workspace');
|
||||||
|
workspace = new Workspace('', toWorkspaceFolders([{ path: 'folderName' }], workspaceConfigPath), workspaceConfigPath);
|
||||||
assertVariableResolve(resolver, 'WORKSPACE_NAME', 'testWorkspace');
|
assertVariableResolve(resolver, 'WORKSPACE_NAME', 'testWorkspace');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -7,14 +7,13 @@ import * as assert from 'assert';
|
|||||||
import { WordCharacterClassifier } from 'vs/editor/common/controller/wordCharacterClassifier';
|
import { WordCharacterClassifier } from 'vs/editor/common/controller/wordCharacterClassifier';
|
||||||
import { Position } from 'vs/editor/common/core/position';
|
import { Position } from 'vs/editor/common/core/position';
|
||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import { DefaultEndOfLine } from 'vs/editor/common/model';
|
import { DefaultEndOfLine, ITextSnapshot } from 'vs/editor/common/model';
|
||||||
import { PieceTreeBase } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';
|
import { PieceTreeBase } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';
|
||||||
import { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';
|
import { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';
|
||||||
import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder';
|
import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder';
|
||||||
import { NodeColor, SENTINEL, TreeNode } from 'vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase';
|
import { NodeColor, SENTINEL, TreeNode } from 'vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase';
|
||||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||||
import { SearchData } from 'vs/editor/common/model/textModelSearch';
|
import { SearchData } from 'vs/editor/common/model/textModelSearch';
|
||||||
import { ITextSnapshot } from 'vs/platform/files/common/files';
|
|
||||||
|
|
||||||
const alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n';
|
const alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n';
|
||||||
|
|
||||||
|
|||||||
@@ -362,13 +362,6 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
|||||||
return Promise.reject(new ExtensionManagementError(nls.localize('notFoundCompatibleDependency', "Unable to install because, the extension '{0}' compatible with current version '{1}' of VS Code is not found.", extension.identifier.id, pkg.version), INSTALL_ERROR_INCOMPATIBLE));
|
return Promise.reject(new ExtensionManagementError(nls.localize('notFoundCompatibleDependency', "Unable to install because, the extension '{0}' compatible with current version '{1}' of VS Code is not found.", extension.identifier.id, pkg.version), INSTALL_ERROR_INCOMPATIBLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.remote) {
|
|
||||||
const manifest = await this.galleryService.getManifest(extension, CancellationToken.None);
|
|
||||||
if (manifest && isUIExtension(manifest, [], this.configurationService) && !isLanguagePackExtension(manifest)) {
|
|
||||||
return Promise.reject(new Error(nls.localize('notSupportedUIExtension', "Can't install extension {0} since UI Extensions are not supported", extension.identifier.id)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return compatibleExtension;
|
return compatibleExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ 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 configuredUIExtensions = configurationService.getValue<string[]>('_workbench.uiExtensions') || [];
|
const { ui, workspace } = configurationService.getValue<{ ui: string[], workspace: string[] }>('extensions.extensionKind') || { ui: [], workspace: [] };
|
||||||
if (configuredUIExtensions.some(id => areSameExtensions({ id }, { id: extensionId }))) {
|
if (isNonEmptyArray(workspace) && workspace.some(id => areSameExtensions({ id }, { id: extensionId }))) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (configuredUIExtensions.some(id => areSameExtensions({ id }, { id: `-${extensionId}` }))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isNonEmptyArray(ui) && ui.some(id => areSameExtensions({ id }, { id: extensionId }))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
switch (manifest.extensionKind) {
|
switch (manifest.extensionKind) {
|
||||||
case 'ui': return true;
|
case 'ui': return true;
|
||||||
case 'workspace': return false;
|
case 'workspace': return false;
|
||||||
|
|||||||
@@ -13,25 +13,14 @@ import { startsWithIgnoreCase } from 'vs/base/common/strings';
|
|||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { isEqualOrParent, isEqual } from 'vs/base/common/resources';
|
import { isEqualOrParent, isEqual } from 'vs/base/common/resources';
|
||||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||||
import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer';
|
import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from 'vs/base/common/buffer';
|
||||||
|
|
||||||
export const IFileService = createDecorator<IFileService>('fileService');
|
export const IFileService = createDecorator<IFileService>('fileService');
|
||||||
|
|
||||||
export interface IResourceEncodings {
|
|
||||||
getWriteEncoding(resource: URI, preferredEncoding?: string): IResourceEncoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IResourceEncoding {
|
|
||||||
encoding: string;
|
|
||||||
hasBOM: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IFileService {
|
export interface IFileService {
|
||||||
|
|
||||||
_serviceBrand: ServiceIdentifier<any>;
|
_serviceBrand: ServiceIdentifier<any>;
|
||||||
|
|
||||||
//#region File System Provider
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event that is fired when a file system provider is added or removed
|
* An event that is fired when a file system provider is added or removed
|
||||||
*/
|
*/
|
||||||
@@ -63,13 +52,6 @@ export interface IFileService {
|
|||||||
*/
|
*/
|
||||||
hasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean;
|
hasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean;
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to determine read/write encoding for resources.
|
|
||||||
*/
|
|
||||||
encoding: IResourceEncodings;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows to listen for file changes. The event will fire for every file within the opened workspace
|
* Allows to listen for file changes. The event will fire for every file within the opened workspace
|
||||||
* (if any) as well as all files that have been watched explicitly using the #watch() API.
|
* (if any) as well as all files that have been watched explicitly using the #watch() API.
|
||||||
@@ -111,18 +93,14 @@ export interface IFileService {
|
|||||||
exists(resource: URI): Promise<boolean>;
|
exists(resource: URI): Promise<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the contents of a file identified by the resource.
|
* Read the contents of the provided resource unbuffered.
|
||||||
*
|
|
||||||
* The returned object contains properties of the file and the full value as string.
|
|
||||||
*/
|
*/
|
||||||
resolveContent(resource: URI, options?: IResolveContentOptions): Promise<IContent>;
|
readFile(resource: URI, options?: IReadFileOptions): Promise<IFileContent>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the contents of a file identified by the resource.
|
* Read the contents of the provided resource buffered as stream.
|
||||||
*
|
|
||||||
* The returned object contains properties of the file and the value as a readable stream.
|
|
||||||
*/
|
*/
|
||||||
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
readFileStream(resource: URI, options?: IReadFileOptions): Promise<IFileStreamContent>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the content replacing its previous value.
|
* Updates the content replacing its previous value.
|
||||||
@@ -228,11 +206,11 @@ export const enum FileSystemProviderCapabilities {
|
|||||||
export interface IFileSystemProvider {
|
export interface IFileSystemProvider {
|
||||||
|
|
||||||
readonly capabilities: FileSystemProviderCapabilities;
|
readonly capabilities: FileSystemProviderCapabilities;
|
||||||
onDidChangeCapabilities: Event<void>;
|
readonly onDidChangeCapabilities: Event<void>;
|
||||||
|
|
||||||
onDidErrorOccur?: Event<Error>; // TODO@ben remove once file watchers are solid
|
readonly onDidErrorOccur?: Event<Error>; // TODO@ben remove once file watchers are solid
|
||||||
|
|
||||||
onDidChangeFile: Event<IFileChange[]>;
|
readonly onDidChangeFile: Event<IFileChange[]>;
|
||||||
watch(resource: URI, opts: IWatchOptions): IDisposable;
|
watch(resource: URI, opts: IWatchOptions): IDisposable;
|
||||||
|
|
||||||
stat(resource: URI): Promise<IStat>;
|
stat(resource: URI): Promise<IStat>;
|
||||||
@@ -337,6 +315,13 @@ export function toFileSystemProviderErrorCode(error: Error): FileSystemProviderE
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function toFileOperationResult(error: Error): FileOperationResult {
|
export function toFileOperationResult(error: Error): FileOperationResult {
|
||||||
|
|
||||||
|
// FileSystemProviderError comes with the result already
|
||||||
|
if (error instanceof FileOperationError) {
|
||||||
|
return error.fileOperationResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise try to find from code
|
||||||
switch (toFileSystemProviderErrorCode(error)) {
|
switch (toFileSystemProviderErrorCode(error)) {
|
||||||
case FileSystemProviderErrorCode.FileNotFound:
|
case FileSystemProviderErrorCode.FileNotFound:
|
||||||
return FileOperationResult.FILE_NOT_FOUND;
|
return FileOperationResult.FILE_NOT_FOUND;
|
||||||
@@ -576,8 +561,7 @@ export interface IBaseStatWithMetadata extends IBaseStat {
|
|||||||
export interface IFileStat extends IBaseStat {
|
export interface IFileStat extends IBaseStat {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The resource is a directory. if {{true}}
|
* The resource is a directory
|
||||||
* {{encoding}} has no meaning.
|
|
||||||
*/
|
*/
|
||||||
isDirectory: boolean;
|
isDirectory: boolean;
|
||||||
|
|
||||||
@@ -608,147 +592,23 @@ export interface IResolveFileResultWithMetadata extends IResolveFileResult {
|
|||||||
stat?: IFileStatWithMetadata;
|
stat?: IFileStatWithMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export interface IFileContent extends IBaseStatWithMetadata {
|
||||||
* Content and meta information of a file.
|
|
||||||
*/
|
|
||||||
export interface IContent extends IBaseStatWithMetadata {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The content of a text file.
|
* The content of a file as buffer.
|
||||||
*/
|
*/
|
||||||
value: string;
|
value: VSBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IFileStreamContent extends IBaseStatWithMetadata {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The encoding of the content if known.
|
* The content of a file as stream.
|
||||||
*/
|
*/
|
||||||
encoding: string;
|
value: VSBufferReadableStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this should eventually replace IContent such
|
export interface IReadFileOptions {
|
||||||
// that we have a clear separation between content
|
|
||||||
// and metadata (TODO@Joh, TODO@Ben)
|
|
||||||
export interface IContentData {
|
|
||||||
encoding: string;
|
|
||||||
stream: IStringStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Stream emitting strings.
|
|
||||||
*/
|
|
||||||
export interface IStringStream {
|
|
||||||
on(event: 'data', callback: (chunk: string) => void): void;
|
|
||||||
on(event: 'error', callback: (err: any) => void): void;
|
|
||||||
on(event: 'end', callback: () => void): void;
|
|
||||||
on(event: string, callback: any): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Text snapshot that works like an iterator.
|
|
||||||
* Will try to return chunks of roughly ~64KB size.
|
|
||||||
* Will return null when finished.
|
|
||||||
*/
|
|
||||||
export interface ITextSnapshot {
|
|
||||||
read(): string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to convert a snapshot into its full string form.
|
|
||||||
*/
|
|
||||||
export function snapshotToString(snapshot: ITextSnapshot): string {
|
|
||||||
const chunks: string[] = [];
|
|
||||||
|
|
||||||
let chunk: string | null;
|
|
||||||
while (typeof (chunk = snapshot.read()) === 'string') {
|
|
||||||
chunks.push(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
return chunks.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function stringToSnapshot(value: string): ITextSnapshot {
|
|
||||||
let done = false;
|
|
||||||
|
|
||||||
return {
|
|
||||||
read(): string | null {
|
|
||||||
if (!done) {
|
|
||||||
done = true;
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TextSnapshotReadable implements VSBufferReadable {
|
|
||||||
private preambleHandled: boolean;
|
|
||||||
|
|
||||||
constructor(private snapshot: ITextSnapshot, private preamble?: string) { }
|
|
||||||
|
|
||||||
read(): VSBuffer | null {
|
|
||||||
let value = this.snapshot.read();
|
|
||||||
|
|
||||||
// Handle preamble if provided
|
|
||||||
if (!this.preambleHandled) {
|
|
||||||
this.preambleHandled = true;
|
|
||||||
|
|
||||||
if (typeof this.preamble === 'string') {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
value = this.preamble + value;
|
|
||||||
} else {
|
|
||||||
value = this.preamble;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return VSBuffer.fromString(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toBufferOrReadable(value: string): VSBuffer;
|
|
||||||
export function toBufferOrReadable(value: ITextSnapshot): VSBufferReadable;
|
|
||||||
export function toBufferOrReadable(value: string | ITextSnapshot): VSBuffer | VSBufferReadable;
|
|
||||||
export function toBufferOrReadable(value: string | ITextSnapshot | undefined): VSBuffer | VSBufferReadable | undefined;
|
|
||||||
export function toBufferOrReadable(value: string | ITextSnapshot | undefined): VSBuffer | VSBufferReadable | undefined {
|
|
||||||
if (typeof value === 'undefined') {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return VSBuffer.fromString(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TextSnapshotReadable(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Streamable content and meta information of a file.
|
|
||||||
*/
|
|
||||||
export interface IStreamContent extends IBaseStatWithMetadata {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The streamable content of a text file.
|
|
||||||
*/
|
|
||||||
value: IStringStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The encoding of the content if known.
|
|
||||||
*/
|
|
||||||
encoding: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IResolveContentOptions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The optional acceptTextOnly parameter allows to fail this request early if the file
|
|
||||||
* contents are not textual.
|
|
||||||
*/
|
|
||||||
acceptTextOnly?: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The optional etag parameter allows to return early from resolving the resource if
|
* The optional etag parameter allows to return early from resolving the resource if
|
||||||
@@ -758,22 +618,25 @@ export interface IResolveContentOptions {
|
|||||||
*/
|
*/
|
||||||
etag?: string;
|
etag?: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* The optional encoding parameter allows to specify the desired encoding when resolving
|
|
||||||
* the contents of the file.
|
|
||||||
*/
|
|
||||||
encoding?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The optional guessEncoding parameter allows to guess encoding from content of the file.
|
|
||||||
*/
|
|
||||||
autoGuessEncoding?: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is an integer specifying where to begin reading from in the file. If position is null,
|
* Is an integer specifying where to begin reading from in the file. If position is null,
|
||||||
* data will be read from the current file position.
|
* data will be read from the current file position.
|
||||||
*/
|
*/
|
||||||
position?: number;
|
position?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is an integer specifying how many bytes to read from the file. By default, all bytes
|
||||||
|
* will be read.
|
||||||
|
*/
|
||||||
|
length?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If provided, the size of the file will be checked against the limits.
|
||||||
|
*/
|
||||||
|
limits?: {
|
||||||
|
size?: number;
|
||||||
|
memory?: number;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IWriteFileOptions {
|
export interface IWriteFileOptions {
|
||||||
@@ -789,30 +652,6 @@ export interface IWriteFileOptions {
|
|||||||
etag?: string;
|
etag?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IWriteTextFileOptions extends IWriteFileOptions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The encoding to use when updating a file.
|
|
||||||
*/
|
|
||||||
encoding?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If set to true, will enforce the selected encoding and not perform any detection using BOMs.
|
|
||||||
*/
|
|
||||||
overwriteEncoding?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to overwrite a file even if it is readonly.
|
|
||||||
*/
|
|
||||||
overwriteReadonly?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wether to write to the file as elevated (admin) user. When setting this option a prompt will
|
|
||||||
* ask the user to authenticate as super user.
|
|
||||||
*/
|
|
||||||
writeElevated?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IResolveFileOptions {
|
export interface IResolveFileOptions {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -847,7 +686,7 @@ export interface ICreateFileOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class FileOperationError extends Error {
|
export class FileOperationError extends Error {
|
||||||
constructor(message: string, public fileOperationResult: FileOperationResult, public options?: IResolveContentOptions & IWriteTextFileOptions & ICreateFileOptions) {
|
constructor(message: string, public fileOperationResult: FileOperationResult, public options?: IReadFileOptions & IWriteFileOptions & ICreateFileOptions) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -857,7 +696,6 @@ export class FileOperationError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const enum FileOperationResult {
|
export const enum FileOperationResult {
|
||||||
FILE_IS_BINARY,
|
|
||||||
FILE_IS_DIRECTORY,
|
FILE_IS_DIRECTORY,
|
||||||
FILE_NOT_FOUND,
|
FILE_NOT_FOUND,
|
||||||
FILE_NOT_MODIFIED_SINCE,
|
FILE_NOT_MODIFIED_SINCE,
|
||||||
@@ -906,247 +744,6 @@ export interface IFilesConfiguration {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SUPPORTED_ENCODINGS: { [encoding: string]: { labelLong: string; labelShort: string; order: number; encodeOnly?: boolean; alias?: string } } = {
|
|
||||||
utf8: {
|
|
||||||
labelLong: 'UTF-8',
|
|
||||||
labelShort: 'UTF-8',
|
|
||||||
order: 1,
|
|
||||||
alias: 'utf8bom'
|
|
||||||
},
|
|
||||||
utf8bom: {
|
|
||||||
labelLong: 'UTF-8 with BOM',
|
|
||||||
labelShort: 'UTF-8 with BOM',
|
|
||||||
encodeOnly: true,
|
|
||||||
order: 2,
|
|
||||||
alias: 'utf8'
|
|
||||||
},
|
|
||||||
utf16le: {
|
|
||||||
labelLong: 'UTF-16 LE',
|
|
||||||
labelShort: 'UTF-16 LE',
|
|
||||||
order: 3
|
|
||||||
},
|
|
||||||
utf16be: {
|
|
||||||
labelLong: 'UTF-16 BE',
|
|
||||||
labelShort: 'UTF-16 BE',
|
|
||||||
order: 4
|
|
||||||
},
|
|
||||||
windows1252: {
|
|
||||||
labelLong: 'Western (Windows 1252)',
|
|
||||||
labelShort: 'Windows 1252',
|
|
||||||
order: 5
|
|
||||||
},
|
|
||||||
iso88591: {
|
|
||||||
labelLong: 'Western (ISO 8859-1)',
|
|
||||||
labelShort: 'ISO 8859-1',
|
|
||||||
order: 6
|
|
||||||
},
|
|
||||||
iso88593: {
|
|
||||||
labelLong: 'Western (ISO 8859-3)',
|
|
||||||
labelShort: 'ISO 8859-3',
|
|
||||||
order: 7
|
|
||||||
},
|
|
||||||
iso885915: {
|
|
||||||
labelLong: 'Western (ISO 8859-15)',
|
|
||||||
labelShort: 'ISO 8859-15',
|
|
||||||
order: 8
|
|
||||||
},
|
|
||||||
macroman: {
|
|
||||||
labelLong: 'Western (Mac Roman)',
|
|
||||||
labelShort: 'Mac Roman',
|
|
||||||
order: 9
|
|
||||||
},
|
|
||||||
cp437: {
|
|
||||||
labelLong: 'DOS (CP 437)',
|
|
||||||
labelShort: 'CP437',
|
|
||||||
order: 10
|
|
||||||
},
|
|
||||||
windows1256: {
|
|
||||||
labelLong: 'Arabic (Windows 1256)',
|
|
||||||
labelShort: 'Windows 1256',
|
|
||||||
order: 11
|
|
||||||
},
|
|
||||||
iso88596: {
|
|
||||||
labelLong: 'Arabic (ISO 8859-6)',
|
|
||||||
labelShort: 'ISO 8859-6',
|
|
||||||
order: 12
|
|
||||||
},
|
|
||||||
windows1257: {
|
|
||||||
labelLong: 'Baltic (Windows 1257)',
|
|
||||||
labelShort: 'Windows 1257',
|
|
||||||
order: 13
|
|
||||||
},
|
|
||||||
iso88594: {
|
|
||||||
labelLong: 'Baltic (ISO 8859-4)',
|
|
||||||
labelShort: 'ISO 8859-4',
|
|
||||||
order: 14
|
|
||||||
},
|
|
||||||
iso885914: {
|
|
||||||
labelLong: 'Celtic (ISO 8859-14)',
|
|
||||||
labelShort: 'ISO 8859-14',
|
|
||||||
order: 15
|
|
||||||
},
|
|
||||||
windows1250: {
|
|
||||||
labelLong: 'Central European (Windows 1250)',
|
|
||||||
labelShort: 'Windows 1250',
|
|
||||||
order: 16
|
|
||||||
},
|
|
||||||
iso88592: {
|
|
||||||
labelLong: 'Central European (ISO 8859-2)',
|
|
||||||
labelShort: 'ISO 8859-2',
|
|
||||||
order: 17
|
|
||||||
},
|
|
||||||
cp852: {
|
|
||||||
labelLong: 'Central European (CP 852)',
|
|
||||||
labelShort: 'CP 852',
|
|
||||||
order: 18
|
|
||||||
},
|
|
||||||
windows1251: {
|
|
||||||
labelLong: 'Cyrillic (Windows 1251)',
|
|
||||||
labelShort: 'Windows 1251',
|
|
||||||
order: 19
|
|
||||||
},
|
|
||||||
cp866: {
|
|
||||||
labelLong: 'Cyrillic (CP 866)',
|
|
||||||
labelShort: 'CP 866',
|
|
||||||
order: 20
|
|
||||||
},
|
|
||||||
iso88595: {
|
|
||||||
labelLong: 'Cyrillic (ISO 8859-5)',
|
|
||||||
labelShort: 'ISO 8859-5',
|
|
||||||
order: 21
|
|
||||||
},
|
|
||||||
koi8r: {
|
|
||||||
labelLong: 'Cyrillic (KOI8-R)',
|
|
||||||
labelShort: 'KOI8-R',
|
|
||||||
order: 22
|
|
||||||
},
|
|
||||||
koi8u: {
|
|
||||||
labelLong: 'Cyrillic (KOI8-U)',
|
|
||||||
labelShort: 'KOI8-U',
|
|
||||||
order: 23
|
|
||||||
},
|
|
||||||
iso885913: {
|
|
||||||
labelLong: 'Estonian (ISO 8859-13)',
|
|
||||||
labelShort: 'ISO 8859-13',
|
|
||||||
order: 24
|
|
||||||
},
|
|
||||||
windows1253: {
|
|
||||||
labelLong: 'Greek (Windows 1253)',
|
|
||||||
labelShort: 'Windows 1253',
|
|
||||||
order: 25
|
|
||||||
},
|
|
||||||
iso88597: {
|
|
||||||
labelLong: 'Greek (ISO 8859-7)',
|
|
||||||
labelShort: 'ISO 8859-7',
|
|
||||||
order: 26
|
|
||||||
},
|
|
||||||
windows1255: {
|
|
||||||
labelLong: 'Hebrew (Windows 1255)',
|
|
||||||
labelShort: 'Windows 1255',
|
|
||||||
order: 27
|
|
||||||
},
|
|
||||||
iso88598: {
|
|
||||||
labelLong: 'Hebrew (ISO 8859-8)',
|
|
||||||
labelShort: 'ISO 8859-8',
|
|
||||||
order: 28
|
|
||||||
},
|
|
||||||
iso885910: {
|
|
||||||
labelLong: 'Nordic (ISO 8859-10)',
|
|
||||||
labelShort: 'ISO 8859-10',
|
|
||||||
order: 29
|
|
||||||
},
|
|
||||||
iso885916: {
|
|
||||||
labelLong: 'Romanian (ISO 8859-16)',
|
|
||||||
labelShort: 'ISO 8859-16',
|
|
||||||
order: 30
|
|
||||||
},
|
|
||||||
windows1254: {
|
|
||||||
labelLong: 'Turkish (Windows 1254)',
|
|
||||||
labelShort: 'Windows 1254',
|
|
||||||
order: 31
|
|
||||||
},
|
|
||||||
iso88599: {
|
|
||||||
labelLong: 'Turkish (ISO 8859-9)',
|
|
||||||
labelShort: 'ISO 8859-9',
|
|
||||||
order: 32
|
|
||||||
},
|
|
||||||
windows1258: {
|
|
||||||
labelLong: 'Vietnamese (Windows 1258)',
|
|
||||||
labelShort: 'Windows 1258',
|
|
||||||
order: 33
|
|
||||||
},
|
|
||||||
gbk: {
|
|
||||||
labelLong: 'Simplified Chinese (GBK)',
|
|
||||||
labelShort: 'GBK',
|
|
||||||
order: 34
|
|
||||||
},
|
|
||||||
gb18030: {
|
|
||||||
labelLong: 'Simplified Chinese (GB18030)',
|
|
||||||
labelShort: 'GB18030',
|
|
||||||
order: 35
|
|
||||||
},
|
|
||||||
cp950: {
|
|
||||||
labelLong: 'Traditional Chinese (Big5)',
|
|
||||||
labelShort: 'Big5',
|
|
||||||
order: 36
|
|
||||||
},
|
|
||||||
big5hkscs: {
|
|
||||||
labelLong: 'Traditional Chinese (Big5-HKSCS)',
|
|
||||||
labelShort: 'Big5-HKSCS',
|
|
||||||
order: 37
|
|
||||||
},
|
|
||||||
shiftjis: {
|
|
||||||
labelLong: 'Japanese (Shift JIS)',
|
|
||||||
labelShort: 'Shift JIS',
|
|
||||||
order: 38
|
|
||||||
},
|
|
||||||
eucjp: {
|
|
||||||
labelLong: 'Japanese (EUC-JP)',
|
|
||||||
labelShort: 'EUC-JP',
|
|
||||||
order: 39
|
|
||||||
},
|
|
||||||
euckr: {
|
|
||||||
labelLong: 'Korean (EUC-KR)',
|
|
||||||
labelShort: 'EUC-KR',
|
|
||||||
order: 40
|
|
||||||
},
|
|
||||||
windows874: {
|
|
||||||
labelLong: 'Thai (Windows 874)',
|
|
||||||
labelShort: 'Windows 874',
|
|
||||||
order: 41
|
|
||||||
},
|
|
||||||
iso885911: {
|
|
||||||
labelLong: 'Latin/Thai (ISO 8859-11)',
|
|
||||||
labelShort: 'ISO 8859-11',
|
|
||||||
order: 42
|
|
||||||
},
|
|
||||||
koi8ru: {
|
|
||||||
labelLong: 'Cyrillic (KOI8-RU)',
|
|
||||||
labelShort: 'KOI8-RU',
|
|
||||||
order: 43
|
|
||||||
},
|
|
||||||
koi8t: {
|
|
||||||
labelLong: 'Tajik (KOI8-T)',
|
|
||||||
labelShort: 'KOI8-T',
|
|
||||||
order: 44
|
|
||||||
},
|
|
||||||
gb2312: {
|
|
||||||
labelLong: 'Simplified Chinese (GB 2312)',
|
|
||||||
labelShort: 'GB 2312',
|
|
||||||
order: 45
|
|
||||||
},
|
|
||||||
cp865: {
|
|
||||||
labelLong: 'Nordic DOS (CP 865)',
|
|
||||||
labelShort: 'CP 865',
|
|
||||||
order: 46
|
|
||||||
},
|
|
||||||
cp850: {
|
|
||||||
labelLong: 'Western European DOS (CP 850)',
|
|
||||||
labelShort: 'CP 850',
|
|
||||||
order: 47
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum FileKind {
|
export enum FileKind {
|
||||||
FILE,
|
FILE,
|
||||||
FOLDER,
|
FOLDER,
|
||||||
@@ -1165,20 +762,3 @@ export function etag(mtime: number | undefined, size: number | undefined): strin
|
|||||||
|
|
||||||
return mtime.toString(29) + size.toString(31);
|
return mtime.toString(29) + size.toString(31);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO@ben remove traces of legacy file service
|
|
||||||
export const ILegacyFileService = createDecorator<ILegacyFileService>('legacyFileService');
|
|
||||||
export interface ILegacyFileService extends IDisposable {
|
|
||||||
_serviceBrand: any;
|
|
||||||
|
|
||||||
encoding: IResourceEncodings;
|
|
||||||
|
|
||||||
onAfterOperation: Event<FileOperationEvent>;
|
|
||||||
|
|
||||||
registerProvider(scheme: string, provider: IFileSystemProvider): IDisposable;
|
|
||||||
|
|
||||||
resolveContent(resource: URI, options?: IResolveContentOptions): Promise<IContent>;
|
|
||||||
|
|
||||||
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
|
||||||
}
|
|
||||||
@@ -13,6 +13,49 @@ export interface ResolvedAuthority {
|
|||||||
readonly port: number;
|
readonly port: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum RemoteAuthorityResolverErrorCode {
|
||||||
|
Unknown = 'Unknown',
|
||||||
|
NotAvailable = 'NotAvailable',
|
||||||
|
TemporarilyNotAvailable = 'TemporarilyNotAvailable',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RemoteAuthorityResolverError extends Error {
|
||||||
|
|
||||||
|
public static isHandledNotAvailable(err: any): boolean {
|
||||||
|
if (err instanceof RemoteAuthorityResolverError) {
|
||||||
|
if (err._code === RemoteAuthorityResolverErrorCode.NotAvailable && err._detail === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static isTemporarilyNotAvailable(err: any): boolean {
|
||||||
|
if (err instanceof RemoteAuthorityResolverError) {
|
||||||
|
return err._code === RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly _message: string | undefined;
|
||||||
|
public readonly _code: RemoteAuthorityResolverErrorCode;
|
||||||
|
public readonly _detail: any;
|
||||||
|
|
||||||
|
constructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: any) {
|
||||||
|
super(message);
|
||||||
|
|
||||||
|
this._message = message;
|
||||||
|
this._code = code;
|
||||||
|
this._detail = detail;
|
||||||
|
|
||||||
|
// workaround when extending builtin objects and when compiling to ES5, see:
|
||||||
|
// https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
|
||||||
|
if (typeof (<any>Object).setPrototypeOf === 'function') {
|
||||||
|
(<any>Object).setPrototypeOf(this, RemoteAuthorityResolverError.prototype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface IRemoteAuthorityResolverService {
|
export interface IRemoteAuthorityResolverService {
|
||||||
|
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|||||||
@@ -4,14 +4,11 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { isAbsolute } from 'vs/base/common/path';
|
|
||||||
import * as resources from 'vs/base/common/resources';
|
import * as resources from 'vs/base/common/resources';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { TernarySearchTree } from 'vs/base/common/map';
|
import { TernarySearchTree } from 'vs/base/common/map';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { IWorkspaceIdentifier, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isRawUriWorkspaceFolder, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
import { IWorkspaceIdentifier, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isRawUriWorkspaceFolder, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||||
import { coalesce, distinct } from 'vs/base/common/arrays';
|
|
||||||
import { isLinux } from 'vs/base/common/platform';
|
|
||||||
|
|
||||||
export const IWorkspaceContextService = createDecorator<IWorkspaceContextService>('contextService');
|
export const IWorkspaceContextService = createDecorator<IWorkspaceContextService>('contextService');
|
||||||
|
|
||||||
@@ -225,17 +222,21 @@ export class WorkspaceFolder implements IWorkspaceFolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo?: URI): WorkspaceFolder[] {
|
export function toWorkspaceFolder(resource: URI): WorkspaceFolder {
|
||||||
let workspaceFolders = parseWorkspaceFolders(configuredFolders, relativeTo);
|
return new WorkspaceFolder({ uri: resource, index: 0, name: resources.basenameOrAuthority(resource) }, { uri: resource.toString() });
|
||||||
return ensureUnique(coalesce(workspaceFolders))
|
|
||||||
.map(({ uri, raw, name }, index) => new WorkspaceFolder({ uri, name: name || resources.basenameOrAuthority(uri), index }, raw));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], relativeTo: URI | undefined): Array<WorkspaceFolder | undefined> {
|
export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], workspaceConfigFile: URI): WorkspaceFolder[] {
|
||||||
return configuredFolders.map((configuredFolder, index) => {
|
let result: WorkspaceFolder[] = [];
|
||||||
|
let seen: { [uri: string]: boolean } = Object.create(null);
|
||||||
|
|
||||||
|
const relativeTo = resources.dirname(workspaceConfigFile);
|
||||||
|
for (let configuredFolder of configuredFolders) {
|
||||||
let uri: URI | null = null;
|
let uri: URI | null = null;
|
||||||
if (isRawFileWorkspaceFolder(configuredFolder)) {
|
if (isRawFileWorkspaceFolder(configuredFolder)) {
|
||||||
uri = toUri(configuredFolder.path, relativeTo);
|
if (configuredFolder.path) {
|
||||||
|
uri = resources.resolvePath(relativeTo, configuredFolder.path);
|
||||||
|
}
|
||||||
} else if (isRawUriWorkspaceFolder(configuredFolder)) {
|
} else if (isRawUriWorkspaceFolder(configuredFolder)) {
|
||||||
try {
|
try {
|
||||||
uri = URI.parse(configuredFolder.uri);
|
uri = URI.parse(configuredFolder.uri);
|
||||||
@@ -248,25 +249,16 @@ function parseWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], rela
|
|||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!uri) {
|
if (uri) {
|
||||||
return undefined;
|
// remove duplicates
|
||||||
}
|
let comparisonKey = resources.getComparisonKey(uri);
|
||||||
return new WorkspaceFolder({ uri, name: configuredFolder.name! /*is ensured in caller*/, index }, configuredFolder);
|
if (!seen[comparisonKey]) {
|
||||||
});
|
seen[comparisonKey] = true;
|
||||||
}
|
|
||||||
|
|
||||||
function toUri(path: string, relativeTo: URI | undefined): URI | null {
|
const name = configuredFolder.name || resources.basenameOrAuthority(uri);
|
||||||
if (path) {
|
result.push(new WorkspaceFolder({ uri, name, index: result.length }, configuredFolder));
|
||||||
if (isAbsolute(path)) {
|
}
|
||||||
return URI.file(path);
|
|
||||||
}
|
|
||||||
if (relativeTo) {
|
|
||||||
return resources.joinPath(relativeTo, path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureUnique(folders: WorkspaceFolder[]): WorkspaceFolder[] {
|
|
||||||
return distinct(folders, folder => isLinux ? folder.uri.toString() : folder.uri.toString().toLowerCase());
|
|
||||||
}
|
|
||||||
@@ -4,15 +4,12 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
import { Workspace, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
import { isWindows } from 'vs/base/common/platform';
|
import { isWindows } from 'vs/base/common/platform';
|
||||||
|
|
||||||
const wsUri = URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace');
|
const wsUri = URI.file(isWindows ? 'C:\\testWorkspace' : '/testWorkspace');
|
||||||
export const TestWorkspace = testWorkspace(wsUri);
|
export const TestWorkspace = testWorkspace(wsUri);
|
||||||
|
|
||||||
export function testWorkspace(resource: URI): Workspace {
|
export function testWorkspace(resource: URI): Workspace {
|
||||||
return new Workspace(
|
return new Workspace(resource.toString(), [toWorkspaceFolder(resource)]);
|
||||||
resource.toString(),
|
|
||||||
toWorkspaceFolders([{ path: resource.fsPath }])
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,30 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
|
import * as path from 'vs/base/common/path';
|
||||||
import { Workspace, toWorkspaceFolders, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
import { Workspace, toWorkspaceFolders, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
|
import { IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
|
||||||
|
import { isWindows } from 'vs/base/common/platform';
|
||||||
|
|
||||||
suite('Workspace', () => {
|
suite('Workspace', () => {
|
||||||
|
|
||||||
|
const fileFolder = isWindows ? 'c:\\src' : '/src';
|
||||||
|
const abcFolder = isWindows ? 'c:\\abc' : '/abc';
|
||||||
|
|
||||||
|
const testFolderUri = URI.file(path.join(fileFolder, 'test'));
|
||||||
|
const mainFolderUri = URI.file(path.join(fileFolder, 'main'));
|
||||||
|
const test1FolderUri = URI.file(path.join(fileFolder, 'test1'));
|
||||||
|
const test2FolderUri = URI.file(path.join(fileFolder, 'test2'));
|
||||||
|
const test3FolderUri = URI.file(path.join(fileFolder, 'test3'));
|
||||||
|
const abcTest1FolderUri = URI.file(path.join(abcFolder, 'test1'));
|
||||||
|
const abcTest3FolderUri = URI.file(path.join(abcFolder, 'test3'));
|
||||||
|
|
||||||
|
const workspaceConfigUri = URI.file(path.join(fileFolder, 'test.code-workspace'));
|
||||||
|
|
||||||
test('getFolder returns the folder with given uri', () => {
|
test('getFolder returns the folder with given uri', () => {
|
||||||
const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 2 });
|
const expected = new WorkspaceFolder({ uri: testFolderUri, name: '', index: 2 });
|
||||||
let testObject = new Workspace('', [new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 0 }), expected, new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]);
|
let testObject = new Workspace('', [new WorkspaceFolder({ uri: mainFolderUri, name: '', index: 0 }), expected, new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]);
|
||||||
|
|
||||||
const actual = testObject.getFolder(expected.uri);
|
const actual = testObject.getFolder(expected.uri);
|
||||||
|
|
||||||
@@ -20,172 +35,172 @@ suite('Workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('getFolder returns the folder if the uri is sub', () => {
|
test('getFolder returns the folder if the uri is sub', () => {
|
||||||
const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 0 });
|
const expected = new WorkspaceFolder({ uri: testFolderUri, name: '', index: 0 });
|
||||||
let testObject = new Workspace('', [expected, new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 1 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]);
|
let testObject = new Workspace('', [expected, new WorkspaceFolder({ uri: mainFolderUri, name: '', index: 1 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 2 })]);
|
||||||
|
|
||||||
const actual = testObject.getFolder(URI.file('/src/test/a'));
|
const actual = testObject.getFolder(URI.file(path.join(fileFolder, 'test/a')));
|
||||||
|
|
||||||
assert.equal(actual, expected);
|
assert.equal(actual, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getFolder returns the closest folder if the uri is sub', () => {
|
test('getFolder returns the closest folder if the uri is sub', () => {
|
||||||
const expected = new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 2 });
|
const expected = new WorkspaceFolder({ uri: testFolderUri, name: '', index: 2 });
|
||||||
let testObject = new Workspace('', [new WorkspaceFolder({ uri: URI.file('/src/main'), name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 }), expected]);
|
let testObject = new Workspace('', [new WorkspaceFolder({ uri: mainFolderUri, name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 }), expected]);
|
||||||
|
|
||||||
const actual = testObject.getFolder(URI.file('/src/test/a'));
|
const actual = testObject.getFolder(URI.file(path.join(fileFolder, 'test/a')));
|
||||||
|
|
||||||
assert.equal(actual, expected);
|
assert.equal(actual, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getFolder returns null if the uri is not sub', () => {
|
test('getFolder returns null if the uri is not sub', () => {
|
||||||
let testObject = new Workspace('', [new WorkspaceFolder({ uri: URI.file('/src/test'), name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 })]);
|
let testObject = new Workspace('', [new WorkspaceFolder({ uri: testFolderUri, name: '', index: 0 }), new WorkspaceFolder({ uri: URI.file('/src/code'), name: '', index: 1 })]);
|
||||||
|
|
||||||
const actual = testObject.getFolder(URI.file('/src/main/a'));
|
const actual = testObject.getFolder(URI.file(path.join(fileFolder, 'main/a')));
|
||||||
|
|
||||||
assert.equal(actual, undefined);
|
assert.equal(actual, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toWorkspaceFolders with single absolute folder', () => {
|
test('toWorkspaceFolders with single absolute folder', () => {
|
||||||
const actual = toWorkspaceFolders([{ path: '/src/test' }]);
|
const actual = toWorkspaceFolders([{ path: '/src/test' }], workspaceConfigUri);
|
||||||
|
|
||||||
assert.equal(actual.length, 1);
|
assert.equal(actual.length, 1);
|
||||||
assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath);
|
assert.equal(actual[0].uri.fsPath, testFolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test');
|
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test');
|
||||||
assert.equal(actual[0].index, 0);
|
assert.equal(actual[0].index, 0);
|
||||||
assert.equal(actual[0].name, 'test');
|
assert.equal(actual[0].name, 'test');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toWorkspaceFolders with single relative folder', () => {
|
test('toWorkspaceFolders with single relative folder', () => {
|
||||||
const actual = toWorkspaceFolders([{ path: './test' }], URI.file('src'));
|
const actual = toWorkspaceFolders([{ path: './test' }], workspaceConfigUri);
|
||||||
|
|
||||||
assert.equal(actual.length, 1);
|
assert.equal(actual.length, 1);
|
||||||
assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath);
|
assert.equal(actual[0].uri.fsPath, testFolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, './test');
|
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, './test');
|
||||||
assert.equal(actual[0].index, 0);
|
assert.equal(actual[0].index, 0);
|
||||||
assert.equal(actual[0].name, 'test');
|
assert.equal(actual[0].name, 'test');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toWorkspaceFolders with single absolute folder with name', () => {
|
test('toWorkspaceFolders with single absolute folder with name', () => {
|
||||||
const actual = toWorkspaceFolders([{ path: '/src/test', name: 'hello' }]);
|
const actual = toWorkspaceFolders([{ path: '/src/test', name: 'hello' }], workspaceConfigUri);
|
||||||
|
|
||||||
assert.equal(actual.length, 1);
|
assert.equal(actual.length, 1);
|
||||||
|
|
||||||
assert.equal(actual[0].uri.fsPath, URI.file('/src/test').fsPath);
|
assert.equal(actual[0].uri.fsPath, testFolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test');
|
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test');
|
||||||
assert.equal(actual[0].index, 0);
|
assert.equal(actual[0].index, 0);
|
||||||
assert.equal(actual[0].name, 'hello');
|
assert.equal(actual[0].name, 'hello');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toWorkspaceFolders with multiple unique absolute folders', () => {
|
test('toWorkspaceFolders with multiple unique absolute folders', () => {
|
||||||
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3' }, { path: '/src/test1' }]);
|
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3' }, { path: '/src/test1' }], workspaceConfigUri);
|
||||||
|
|
||||||
assert.equal(actual.length, 3);
|
assert.equal(actual.length, 3);
|
||||||
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
|
assert.equal(actual[0].uri.fsPath, test2FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
||||||
assert.equal(actual[0].index, 0);
|
assert.equal(actual[0].index, 0);
|
||||||
assert.equal(actual[0].name, 'test2');
|
assert.equal(actual[0].name, 'test2');
|
||||||
|
|
||||||
assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath);
|
assert.equal(actual[1].uri.fsPath, test3FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test3');
|
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test3');
|
||||||
assert.equal(actual[1].index, 1);
|
assert.equal(actual[1].index, 1);
|
||||||
assert.equal(actual[1].name, 'test3');
|
assert.equal(actual[1].name, 'test3');
|
||||||
|
|
||||||
assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath);
|
assert.equal(actual[2].uri.fsPath, test1FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/src/test1');
|
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/src/test1');
|
||||||
assert.equal(actual[2].index, 2);
|
assert.equal(actual[2].index, 2);
|
||||||
assert.equal(actual[2].name, 'test1');
|
assert.equal(actual[2].name, 'test1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toWorkspaceFolders with multiple unique absolute folders with names', () => {
|
test('toWorkspaceFolders with multiple unique absolute folders with names', () => {
|
||||||
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3', name: 'noName' }, { path: '/src/test1' }]);
|
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3', name: 'noName' }, { path: '/src/test1' }], workspaceConfigUri);
|
||||||
|
|
||||||
assert.equal(actual.length, 3);
|
assert.equal(actual.length, 3);
|
||||||
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
|
assert.equal(actual[0].uri.fsPath, test2FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
||||||
assert.equal(actual[0].index, 0);
|
assert.equal(actual[0].index, 0);
|
||||||
assert.equal(actual[0].name, 'test2');
|
assert.equal(actual[0].name, 'test2');
|
||||||
|
|
||||||
assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath);
|
assert.equal(actual[1].uri.fsPath, test3FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test3');
|
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test3');
|
||||||
assert.equal(actual[1].index, 1);
|
assert.equal(actual[1].index, 1);
|
||||||
assert.equal(actual[1].name, 'noName');
|
assert.equal(actual[1].name, 'noName');
|
||||||
|
|
||||||
assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath);
|
assert.equal(actual[2].uri.fsPath, test1FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/src/test1');
|
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/src/test1');
|
||||||
assert.equal(actual[2].index, 2);
|
assert.equal(actual[2].index, 2);
|
||||||
assert.equal(actual[2].name, 'test1');
|
assert.equal(actual[2].name, 'test1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toWorkspaceFolders with multiple unique absolute and relative folders', () => {
|
test('toWorkspaceFolders with multiple unique absolute and relative folders', () => {
|
||||||
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/abc/test3', name: 'noName' }, { path: './test1' }], URI.file('src'));
|
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/abc/test3', name: 'noName' }, { path: './test1' }], workspaceConfigUri);
|
||||||
|
|
||||||
assert.equal(actual.length, 3);
|
assert.equal(actual.length, 3);
|
||||||
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
|
assert.equal(actual[0].uri.fsPath, test2FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
||||||
assert.equal(actual[0].index, 0);
|
assert.equal(actual[0].index, 0);
|
||||||
assert.equal(actual[0].name, 'test2');
|
assert.equal(actual[0].name, 'test2');
|
||||||
|
|
||||||
assert.equal(actual[1].uri.fsPath, URI.file('/abc/test3').fsPath);
|
assert.equal(actual[1].uri.fsPath, abcTest3FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/abc/test3');
|
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/abc/test3');
|
||||||
assert.equal(actual[1].index, 1);
|
assert.equal(actual[1].index, 1);
|
||||||
assert.equal(actual[1].name, 'noName');
|
assert.equal(actual[1].name, 'noName');
|
||||||
|
|
||||||
assert.equal(actual[2].uri.fsPath, URI.file('/src/test1').fsPath);
|
assert.equal(actual[2].uri.fsPath, test1FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, './test1');
|
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, './test1');
|
||||||
assert.equal(actual[2].index, 2);
|
assert.equal(actual[2].index, 2);
|
||||||
assert.equal(actual[2].name, 'test1');
|
assert.equal(actual[2].name, 'test1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toWorkspaceFolders with multiple absolute folders with duplicates', () => {
|
test('toWorkspaceFolders with multiple absolute folders with duplicates', () => {
|
||||||
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test2', name: 'noName' }, { path: '/src/test1' }]);
|
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test2', name: 'noName' }, { path: '/src/test1' }], workspaceConfigUri);
|
||||||
|
|
||||||
assert.equal(actual.length, 2);
|
assert.equal(actual.length, 2);
|
||||||
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
|
assert.equal(actual[0].uri.fsPath, test2FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
||||||
assert.equal(actual[0].index, 0);
|
assert.equal(actual[0].index, 0);
|
||||||
assert.equal(actual[0].name, 'test2');
|
assert.equal(actual[0].name, 'test2');
|
||||||
|
|
||||||
assert.equal(actual[1].uri.fsPath, URI.file('/src/test1').fsPath);
|
assert.equal(actual[1].uri.fsPath, test1FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test1');
|
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test1');
|
||||||
assert.equal(actual[1].index, 1);
|
assert.equal(actual[1].index, 1);
|
||||||
assert.equal(actual[1].name, 'test1');
|
assert.equal(actual[1].name, 'test1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toWorkspaceFolders with multiple absolute and relative folders with duplicates', () => {
|
test('toWorkspaceFolders with multiple absolute and relative folders with duplicates', () => {
|
||||||
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3', name: 'noName' }, { path: './test3' }, { path: '/abc/test1' }], URI.file('src'));
|
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '/src/test3', name: 'noName' }, { path: './test3' }, { path: '/abc/test1' }], workspaceConfigUri);
|
||||||
|
|
||||||
assert.equal(actual.length, 3);
|
assert.equal(actual.length, 3);
|
||||||
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
|
assert.equal(actual[0].uri.fsPath, test2FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
||||||
assert.equal(actual[0].index, 0);
|
assert.equal(actual[0].index, 0);
|
||||||
assert.equal(actual[0].name, 'test2');
|
assert.equal(actual[0].name, 'test2');
|
||||||
|
|
||||||
assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath);
|
assert.equal(actual[1].uri.fsPath, test3FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test3');
|
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, '/src/test3');
|
||||||
assert.equal(actual[1].index, 1);
|
assert.equal(actual[1].index, 1);
|
||||||
assert.equal(actual[1].name, 'noName');
|
assert.equal(actual[1].name, 'noName');
|
||||||
|
|
||||||
assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath);
|
assert.equal(actual[2].uri.fsPath, abcTest1FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/abc/test1');
|
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/abc/test1');
|
||||||
assert.equal(actual[2].index, 2);
|
assert.equal(actual[2].index, 2);
|
||||||
assert.equal(actual[2].name, 'test1');
|
assert.equal(actual[2].name, 'test1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toWorkspaceFolders with multiple absolute and relative folders with invalid paths', () => {
|
test('toWorkspaceFolders with multiple absolute and relative folders with invalid paths', () => {
|
||||||
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '', name: 'noName' }, { path: './test3' }, { path: '/abc/test1' }], URI.file('src'));
|
const actual = toWorkspaceFolders([{ path: '/src/test2' }, { path: '', name: 'noName' }, { path: './test3' }, { path: '/abc/test1' }], workspaceConfigUri);
|
||||||
|
|
||||||
assert.equal(actual.length, 3);
|
assert.equal(actual.length, 3);
|
||||||
assert.equal(actual[0].uri.fsPath, URI.file('/src/test2').fsPath);
|
assert.equal(actual[0].uri.fsPath, test2FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
assert.equal((<IRawFileWorkspaceFolder>actual[0].raw).path, '/src/test2');
|
||||||
assert.equal(actual[0].index, 0);
|
assert.equal(actual[0].index, 0);
|
||||||
assert.equal(actual[0].name, 'test2');
|
assert.equal(actual[0].name, 'test2');
|
||||||
|
|
||||||
assert.equal(actual[1].uri.fsPath, URI.file('/src/test3').fsPath);
|
assert.equal(actual[1].uri.fsPath, test3FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, './test3');
|
assert.equal((<IRawFileWorkspaceFolder>actual[1].raw).path, './test3');
|
||||||
assert.equal(actual[1].index, 1);
|
assert.equal(actual[1].index, 1);
|
||||||
assert.equal(actual[1].name, 'test3');
|
assert.equal(actual[1].name, 'test3');
|
||||||
|
|
||||||
assert.equal(actual[2].uri.fsPath, URI.file('/abc/test1').fsPath);
|
assert.equal(actual[2].uri.fsPath, abcTest1FolderUri.fsPath);
|
||||||
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/abc/test1');
|
assert.equal((<IRawFileWorkspaceFolder>actual[2].raw).path, '/abc/test1');
|
||||||
assert.equal(actual[2].index, 2);
|
assert.equal(actual[2].index, 2);
|
||||||
assert.equal(actual[2].name, 'test1');
|
assert.equal(actual[2].name, 'test1');
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
|||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { originalFSPath, dirname as resourcesDirname, isEqualOrParent, joinPath } from 'vs/base/common/resources';
|
import { originalFSPath, isEqualOrParent, joinPath } from 'vs/base/common/resources';
|
||||||
|
|
||||||
export interface IStoredWorkspace {
|
export interface IStoredWorkspace {
|
||||||
folders: IStoredWorkspaceFolder[];
|
folders: IStoredWorkspaceFolder[];
|
||||||
@@ -71,7 +71,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain
|
|||||||
return {
|
return {
|
||||||
id: workspaceIdentifier.id,
|
id: workspaceIdentifier.id,
|
||||||
configPath: workspaceIdentifier.configPath,
|
configPath: workspaceIdentifier.configPath,
|
||||||
folders: toWorkspaceFolders(workspace.folders, resourcesDirname(path)),
|
folders: toWorkspaceFolders(workspace.folders, workspaceIdentifier.configPath),
|
||||||
remoteAuthority: workspace.remoteAuthority
|
remoteAuthority: workspace.remoteAuthority
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
13
src/vs/vscode.proposed.d.ts
vendored
13
src/vs/vscode.proposed.d.ts
vendored
@@ -72,6 +72,10 @@ declare module 'vscode' {
|
|||||||
|
|
||||||
//#region Alex - resolvers
|
//#region Alex - resolvers
|
||||||
|
|
||||||
|
export interface RemoteAuthorityResolverContext {
|
||||||
|
resolveAttempt: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class ResolvedAuthority {
|
export class ResolvedAuthority {
|
||||||
readonly host: string;
|
readonly host: string;
|
||||||
readonly port: number;
|
readonly port: number;
|
||||||
@@ -79,8 +83,15 @@ declare module 'vscode' {
|
|||||||
constructor(host: string, port: number);
|
constructor(host: string, port: number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RemoteAuthorityResolverError extends Error {
|
||||||
|
static NotAvailable(message?: string, handled?: boolean): RemoteAuthorityResolverError;
|
||||||
|
static TemporarilyNotAvailable(message?: string): RemoteAuthorityResolverError;
|
||||||
|
|
||||||
|
constructor(message?: string);
|
||||||
|
}
|
||||||
|
|
||||||
export interface RemoteAuthorityResolver {
|
export interface RemoteAuthorityResolver {
|
||||||
resolve(authority: string): ResolvedAuthority | Thenable<ResolvedAuthority>;
|
resolve(authority: string, context: RemoteAuthorityResolverContext): ResolvedAuthority | Thenable<ResolvedAuthority>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResourceLabelFormatter {
|
export interface ResourceLabelFormatter {
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||||||
cwd: request.shellLaunchConfig.cwd,
|
cwd: request.shellLaunchConfig.cwd,
|
||||||
env: request.shellLaunchConfig.env
|
env: request.shellLaunchConfig.env
|
||||||
};
|
};
|
||||||
this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows);
|
this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed);
|
||||||
request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data));
|
request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data));
|
||||||
request.proxy.onResize(dimensions => this._proxy.$acceptProcessResize(request.proxy.terminalId, dimensions.cols, dimensions.rows));
|
request.proxy.onResize(dimensions => this._proxy.$acceptProcessResize(request.proxy.terminalId, dimensions.cols, dimensions.rows));
|
||||||
request.proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(request.proxy.terminalId, immediate));
|
request.proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(request.proxy.terminalId, immediate));
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import { IRPCProtocol, createExtHostContextProxyIdentifier as createExtId, creat
|
|||||||
import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
|
import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||||
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
import { ResolvedAuthority, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
|
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
|
||||||
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||||
@@ -812,8 +812,24 @@ export interface ExtHostSearchShape {
|
|||||||
$clearCache(cacheKey: string): Promise<void>;
|
$clearCache(cacheKey: string): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IResolveAuthorityErrorResult {
|
||||||
|
type: 'error';
|
||||||
|
error: {
|
||||||
|
message: string | undefined;
|
||||||
|
code: RemoteAuthorityResolverErrorCode;
|
||||||
|
detail: any;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IResolveAuthorityOKResult {
|
||||||
|
type: 'ok';
|
||||||
|
value: ResolvedAuthority;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAuthorityOKResult;
|
||||||
|
|
||||||
export interface ExtHostExtensionServiceShape {
|
export interface ExtHostExtensionServiceShape {
|
||||||
$resolveAuthority(remoteAuthority: string): Promise<ResolvedAuthority>;
|
$resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult>;
|
||||||
$startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
|
$startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
|
||||||
$activateByEvent(activationEvent: string): Promise<void>;
|
$activateByEvent(activationEvent: string): Promise<void>;
|
||||||
$activate(extensionId: ExtensionIdentifier, activationEvent: string): Promise<boolean>;
|
$activate(extensionId: ExtensionIdentifier, activationEvent: string): Promise<boolean>;
|
||||||
@@ -1062,7 +1078,7 @@ export interface ExtHostTerminalServiceShape {
|
|||||||
$acceptTerminalRendererInput(id: number, data: string): void;
|
$acceptTerminalRendererInput(id: number, data: string): void;
|
||||||
$acceptTerminalTitleChange(id: number, name: string): void;
|
$acceptTerminalTitleChange(id: number, name: string): void;
|
||||||
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
|
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
|
||||||
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number): void;
|
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void;
|
||||||
$acceptProcessInput(id: number, data: string): void;
|
$acceptProcessInput(id: number, data: string): void;
|
||||||
$acceptProcessResize(id: number, cols: number, rows: number): void;
|
$acceptProcessResize(id: number, cols: number, rows: number): void;
|
||||||
$acceptProcessShutdown(id: number, immediate: boolean): void;
|
$acceptProcessShutdown(id: number, immediate: boolean): void;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { generateUuid } from 'vs/base/common/uuid';
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files';
|
import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files';
|
||||||
|
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||||
|
|
||||||
function es5ClassCompat(target: Function): any {
|
function es5ClassCompat(target: Function): any {
|
||||||
///@ts-ignore
|
///@ts-ignore
|
||||||
@@ -445,6 +446,35 @@ export class ResolvedAuthority {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RemoteAuthorityResolverError extends Error {
|
||||||
|
|
||||||
|
static NotAvailable(message?: string, handled?: boolean): RemoteAuthorityResolverError {
|
||||||
|
return new RemoteAuthorityResolverError(message, RemoteAuthorityResolverErrorCode.NotAvailable, handled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TemporarilyNotAvailable(message?: string): RemoteAuthorityResolverError {
|
||||||
|
return new RemoteAuthorityResolverError(message, RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly _message: string | undefined;
|
||||||
|
public readonly _code: RemoteAuthorityResolverErrorCode;
|
||||||
|
public readonly _detail: any;
|
||||||
|
|
||||||
|
constructor(message?: string, code: RemoteAuthorityResolverErrorCode = RemoteAuthorityResolverErrorCode.Unknown, detail?: any) {
|
||||||
|
super(message);
|
||||||
|
|
||||||
|
this._message = message;
|
||||||
|
this._code = code;
|
||||||
|
this._detail = detail;
|
||||||
|
|
||||||
|
// workaround when extending builtin objects and when compiling to ES5, see:
|
||||||
|
// https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
|
||||||
|
if (typeof (<any>Object).setPrototypeOf === 'function') {
|
||||||
|
(<any>Object).setPrototypeOf(this, RemoteAuthorityResolverError.prototype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export enum EndOfLine {
|
export enum EndOfLine {
|
||||||
LF = 1,
|
LF = 1,
|
||||||
CRLF = 2
|
CRLF = 2
|
||||||
|
|||||||
@@ -814,6 +814,7 @@ export function createApiFactory(
|
|||||||
Range: extHostTypes.Range,
|
Range: extHostTypes.Range,
|
||||||
RelativePattern: extHostTypes.RelativePattern,
|
RelativePattern: extHostTypes.RelativePattern,
|
||||||
ResolvedAuthority: extHostTypes.ResolvedAuthority,
|
ResolvedAuthority: extHostTypes.ResolvedAuthority,
|
||||||
|
RemoteAuthorityResolverError: extHostTypes.RemoteAuthorityResolverError,
|
||||||
Selection: extHostTypes.Selection,
|
Selection: extHostTypes.Selection,
|
||||||
SelectionRange: extHostTypes.SelectionRange,
|
SelectionRange: extHostTypes.SelectionRange,
|
||||||
ShellExecution: extHostTypes.ShellExecution,
|
ShellExecution: extHostTypes.ShellExecution,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export interface StatusPipeArgs {
|
|||||||
export interface RunCommandPipeArgs {
|
export interface RunCommandPipeArgs {
|
||||||
type: 'command';
|
type: 'command';
|
||||||
command: string;
|
command: string;
|
||||||
args: string[];
|
args: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CLIServer {
|
export class CLIServer {
|
||||||
@@ -99,7 +99,9 @@ export class CLIServer {
|
|||||||
for (const s of folderURIs) {
|
for (const s of folderURIs) {
|
||||||
try {
|
try {
|
||||||
urisToOpen.push({ folderUri: URI.parse(s) });
|
urisToOpen.push({ folderUri: URI.parse(s) });
|
||||||
forceNewWindow = true;
|
if (!addMode && !forceReuseWindow) {
|
||||||
|
forceNewWindow = true;
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
@@ -110,7 +112,9 @@ export class CLIServer {
|
|||||||
try {
|
try {
|
||||||
if (hasWorkspaceFileExtension(s)) {
|
if (hasWorkspaceFileExtension(s)) {
|
||||||
urisToOpen.push({ workspaceUri: URI.parse(s) });
|
urisToOpen.push({ workspaceUri: URI.parse(s) });
|
||||||
forceNewWindow = true;
|
if (!forceReuseWindow) {
|
||||||
|
forceNewWindow = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
urisToOpen.push({ fileUri: URI.parse(s) });
|
urisToOpen.push({ fileUri: URI.parse(s) });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
|||||||
// {{SQL CARBON EDIT}} - Remove createApiFactory initializeExtensionApi, and IExtensionApiFactory imports
|
// {{SQL CARBON EDIT}} - Remove createApiFactory initializeExtensionApi, and IExtensionApiFactory imports
|
||||||
// import { createApiFactory, IExtensionApiFactory } from 'vs/workbench/api/node/extHost.api.impl';
|
// import { createApiFactory, IExtensionApiFactory } from 'vs/workbench/api/node/extHost.api.impl';
|
||||||
import { NodeModuleRequireInterceptor, VSCodeNodeModuleFactory, KeytarNodeModuleFactory, OpenNodeModuleFactory } from 'vs/workbench/api/node/extHostRequireInterceptor';
|
import { NodeModuleRequireInterceptor, VSCodeNodeModuleFactory, KeytarNodeModuleFactory, OpenNodeModuleFactory } from 'vs/workbench/api/node/extHostRequireInterceptor';
|
||||||
import { ExtHostExtensionServiceShape, IEnvironment, IInitData, IMainContext, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape } from 'vs/workbench/api/common/extHost.protocol';
|
import { ExtHostExtensionServiceShape, IEnvironment, IInitData, IMainContext, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||||
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionModule, HostExtension } from 'vs/workbench/api/common/extHostExtensionActivator';
|
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionModule, HostExtension } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||||
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
|
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
|
||||||
@@ -27,7 +27,6 @@ import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/c
|
|||||||
import { connectProxyResolver } from 'vs/workbench/services/extensions/node/proxyResolver';
|
import { connectProxyResolver } from 'vs/workbench/services/extensions/node/proxyResolver';
|
||||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||||
import * as errors from 'vs/base/common/errors';
|
import * as errors from 'vs/base/common/errors';
|
||||||
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IWorkspace } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||||
@@ -37,6 +36,7 @@ import { VSBuffer } from 'vs/base/common/buffer';
|
|||||||
import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||||
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
||||||
import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths';
|
import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths';
|
||||||
|
import { RemoteAuthorityResolverError } from 'vs/workbench/api/common/extHostTypes';
|
||||||
|
|
||||||
interface ITestRunner {
|
interface ITestRunner {
|
||||||
run(testsRoot: string, clb: (error: Error, failures?: number) => void): void;
|
run(testsRoot: string, clb: (error: Error, failures?: number) => void): void;
|
||||||
@@ -600,7 +600,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
|||||||
|
|
||||||
// -- called by main thread
|
// -- called by main thread
|
||||||
|
|
||||||
public async $resolveAuthority(remoteAuthority: string): Promise<ResolvedAuthority> {
|
public async $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult> {
|
||||||
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
||||||
if (authorityPlusIndex === -1) {
|
if (authorityPlusIndex === -1) {
|
||||||
throw new Error(`Not an authority that can be resolved!`);
|
throw new Error(`Not an authority that can be resolved!`);
|
||||||
@@ -615,12 +615,29 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
|||||||
throw new Error(`No resolver available for ${authorityPrefix}`);
|
throw new Error(`No resolver available for ${authorityPrefix}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await resolver.resolve(remoteAuthority);
|
try {
|
||||||
return {
|
const result = await resolver.resolve(remoteAuthority, { resolveAttempt });
|
||||||
authority: remoteAuthority,
|
return {
|
||||||
host: result.host,
|
type: 'ok',
|
||||||
port: result.port,
|
value: {
|
||||||
};
|
authority: remoteAuthority,
|
||||||
|
host: result.host,
|
||||||
|
port: result.port,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof RemoteAuthorityResolverError) {
|
||||||
|
return {
|
||||||
|
type: 'error',
|
||||||
|
error: {
|
||||||
|
code: err._code,
|
||||||
|
message: err._message,
|
||||||
|
detail: err._detail
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
|
public $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
|
||||||
@@ -680,7 +697,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
|||||||
let buff = VSBuffer.alloc(size);
|
let buff = VSBuffer.alloc(size);
|
||||||
let value = Math.random() % 256;
|
let value = Math.random() % 256;
|
||||||
for (let i = 0; i < size; i++) {
|
for (let i = 0; i < size; i++) {
|
||||||
buff.writeUint8(value, i);
|
buff.writeUInt8(value, i);
|
||||||
}
|
}
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $createProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number): 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,
|
||||||
executable: shellLaunchConfigDto.executable,
|
executable: shellLaunchConfigDto.executable,
|
||||||
@@ -445,31 +445,31 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||||||
env: shellLaunchConfigDto.env
|
env: shellLaunchConfigDto.env
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: This function duplicates a lot of TerminalProcessManager.createProcess, ideally
|
// Merge in shell and args from settings
|
||||||
// they would be merged into a single implementation.
|
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
|
||||||
const terminalConfig = configProvider.getConfiguration('terminal.integrated');
|
|
||||||
|
|
||||||
if (!shellLaunchConfig.executable) {
|
if (!shellLaunchConfig.executable) {
|
||||||
// TODO: This duplicates some of TerminalConfigHelper.mergeDefaultShellPathAndArgs and should be merged
|
const fetchSetting = (key: string) => {
|
||||||
// this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig);
|
const setting = configProvider
|
||||||
|
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
||||||
const platformKey = platform.isWindows ? 'windows' : platform.isMacintosh ? 'osx' : 'linux';
|
.inspect<string | string[]>(key.substr(key.lastIndexOf('.') + 1));
|
||||||
const shellConfigValue: string | undefined = terminalConfig.get(`shell.${platformKey}`);
|
return {
|
||||||
const shellArgsConfigValue: string | undefined = terminalConfig.get(`shellArgs.${platformKey}`);
|
user: setting ? setting.globalValue : undefined,
|
||||||
|
value: setting ? setting.workspaceValue : undefined,
|
||||||
shellLaunchConfig.executable = shellConfigValue;
|
default: setting ? setting.defaultValue : undefined,
|
||||||
shellLaunchConfig.args = shellArgsConfigValue;
|
};
|
||||||
|
};
|
||||||
|
terminalEnvironment.mergeDefaultShellPathAndArgs(shellLaunchConfig, fetchSetting, isWorkspaceShellAllowed || false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: @daniel
|
// Get the initial cwd
|
||||||
|
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||||
|
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
|
// TODO: Pull in and resolve config settings
|
||||||
// // Resolve env vars from config and shell
|
// // Resolve env vars from config and shell
|
||||||
// const lastActiveWorkspaceRoot = this._workspaceContextService.getWorkspaceFolder(lastActiveWorkspaceRootUri);
|
// const lastActiveWorkspaceRoot = this._workspaceContextService.getWorkspaceFolder(lastActiveWorkspaceRootUri);
|
||||||
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
|
||||||
// const envFromConfig = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...terminalConfig.env[platformKey] }, lastActiveWorkspaceRoot);
|
// const envFromConfig = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...terminalConfig.env[platformKey] }, lastActiveWorkspaceRoot);
|
||||||
const envFromConfig = { ...terminalConfig.env[platformKey] };
|
const envFromConfig = { ...terminalConfig.env[platformKey] };
|
||||||
// const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot);
|
// const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot);
|
||||||
@@ -501,7 +501,6 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||||||
this._terminalProcesses[id] = p;
|
this._terminalProcesses[id] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public $acceptProcessInput(id: number, data: string): void {
|
public $acceptProcessInput(id: number, data: string): void {
|
||||||
this._terminalProcesses[id].input(data);
|
this._terminalProcesses[id].input(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { RemoteAuthorityResolverService } from 'vs/platform/remote/browser/remot
|
|||||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { FileService3 } from 'vs/workbench/services/files2/browser/fileService2';
|
import { FileService } from 'vs/workbench/services/files/common/fileService';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
class CodeRendererMain extends Disposable {
|
class CodeRendererMain extends Disposable {
|
||||||
@@ -78,7 +78,7 @@ class CodeRendererMain extends Disposable {
|
|||||||
serviceCollection.set(IRemoteAgentService, remoteAgentService);
|
serviceCollection.set(IRemoteAgentService, remoteAgentService);
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
const fileService = this._register(new FileService3(logService));
|
const fileService = this._register(new FileService(logService));
|
||||||
serviceCollection.set(IFileService, fileService);
|
serviceCollection.set(IFileService, fileService);
|
||||||
|
|
||||||
const connection = remoteAgentService.getConnection();
|
const connection = remoteAgentService.getConnection();
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||||
import { ITextSnapshot } from 'vs/platform/files/common/files';
|
import { ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model';
|
||||||
import { ITextBufferFactory } from 'vs/editor/common/model';
|
|
||||||
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
||||||
import { keys, ResourceMap } from 'vs/base/common/map';
|
import { keys, ResourceMap } from 'vs/base/common/map';
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
@@ -52,7 +51,7 @@ import { ExportData } from 'vs/base/common/performance';
|
|||||||
import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history';
|
import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history';
|
||||||
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
||||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||||
import { IWorkspaceContextService, Workspace, toWorkspaceFolders, IWorkspaceFolder, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService, Workspace, toWorkspaceFolder, IWorkspaceFolder, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
|
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
@@ -1366,10 +1365,7 @@ export class SimpleWorkspaceService implements IWorkspaceContextService {
|
|||||||
readonly onDidChangeWorkbenchState = Event.None;
|
readonly onDidChangeWorkbenchState = Event.None;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.workspace = new Workspace(
|
this.workspace = new Workspace(workspaceResource.toString(), [toWorkspaceFolder(workspaceResource)]);
|
||||||
workspaceResource.toString(),
|
|
||||||
toWorkspaceFolders([{ uri: workspaceResource.toString() }])
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getFolders(): IWorkspaceFolder[] {
|
getFolders(): IWorkspaceFolder[] {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
|||||||
import { ResourceViewerContext, ResourceViewer } from 'vs/workbench/browser/parts/editor/resourceViewer';
|
import { ResourceViewerContext, ResourceViewer } from 'vs/workbench/browser/parts/editor/resourceViewer';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Dimension, size, clearNode } from 'vs/base/browser/dom';
|
import { Dimension, size, clearNode } from 'vs/base/browser/dom';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { dispose } from 'vs/base/common/lifecycle';
|
import { dispose } from 'vs/base/common/lifecycle';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
@@ -47,7 +47,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
|||||||
callbacks: IOpenCallbacks,
|
callbacks: IOpenCallbacks,
|
||||||
telemetryService: ITelemetryService,
|
telemetryService: ITelemetryService,
|
||||||
themeService: IThemeService,
|
themeService: IThemeService,
|
||||||
@IFileService private readonly _fileService: IFileService,
|
@ITextFileService private readonly textFileService: ITextFileService,
|
||||||
@IStorageService storageService: IStorageService
|
@IStorageService storageService: IStorageService
|
||||||
) {
|
) {
|
||||||
super(id, telemetryService, themeService, storageService);
|
super(id, telemetryService, themeService, storageService);
|
||||||
@@ -89,7 +89,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
|||||||
// Render Input
|
// Render Input
|
||||||
this.resourceViewerContext = ResourceViewer.show(
|
this.resourceViewerContext = ResourceViewer.show(
|
||||||
{ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag(), mime: model.getMime() },
|
{ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag(), mime: model.getMime() },
|
||||||
this._fileService,
|
this.textFileService,
|
||||||
this.binaryContainer,
|
this.binaryContainer,
|
||||||
this.scrollbar,
|
this.scrollbar,
|
||||||
resource => this.handleOpenInternalCallback(input, options),
|
resource => this.handleOpenInternalCallback(input, options),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { BaseBinaryResourceEditor } from 'vs/workbench/browser/parts/editor/bina
|
|||||||
import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor';
|
import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||||
import { SUPPORTED_ENCODINGS, IFileService, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files';
|
import { IFileService, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService';
|
import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService';
|
||||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||||
@@ -35,7 +35,7 @@ import { Selection } from 'vs/editor/common/core/selection';
|
|||||||
import { TabFocus } from 'vs/editor/common/config/commonEditorConfig';
|
import { TabFocus } from 'vs/editor/common/config/commonEditorConfig';
|
||||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||||
import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService, SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||||
import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||||
@@ -1152,7 +1152,8 @@ export class ChangeEncodingAction extends Action {
|
|||||||
@IEditorService private readonly editorService: IEditorService,
|
@IEditorService private readonly editorService: IEditorService,
|
||||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||||
@ITextResourceConfigurationService private readonly textResourceConfigurationService: ITextResourceConfigurationService,
|
@ITextResourceConfigurationService private readonly textResourceConfigurationService: ITextResourceConfigurationService,
|
||||||
@IFileService private readonly fileService: IFileService
|
@IFileService private readonly fileService: IFileService,
|
||||||
|
@ITextFileService private readonly textFileService: ITextFileService
|
||||||
) {
|
) {
|
||||||
super(actionId, actionLabel);
|
super(actionId, actionLabel);
|
||||||
}
|
}
|
||||||
@@ -1203,7 +1204,7 @@ export class ChangeEncodingAction extends Action {
|
|||||||
return Promise.resolve(null); // encoding detection only possible for resources the file service can handle
|
return Promise.resolve(null); // encoding detection only possible for resources the file service can handle
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.fileService.resolveContent(resource, { autoGuessEncoding: true, acceptTextOnly: true }).then(content => content.encoding, err => null);
|
return this.textFileService.read(resource, { autoGuessEncoding: true, acceptTextOnly: true }).then(content => content.encoding, err => null);
|
||||||
})
|
})
|
||||||
.then((guessedEncoding: string) => {
|
.then((guessedEncoding: string) => {
|
||||||
const isReopenWithEncoding = (action === reopenWithEncodingPick);
|
const isReopenWithEncoding = (action === reopenWithEncodingPick);
|
||||||
|
|||||||
@@ -145,8 +145,13 @@ export class NoTabsTitleControl extends TitleControl {
|
|||||||
this.redraw();
|
this.redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEditorLabel(editor: IEditorInput): void {
|
updateEditorLabel(editor?: IEditorInput): void {
|
||||||
this.ifEditorIsActive(editor, () => this.redraw());
|
if (!editor) {
|
||||||
|
editor = withNullAsUndefined(this.group.activeEditor);
|
||||||
|
}
|
||||||
|
if (editor) {
|
||||||
|
this.ifEditorIsActive(editor, () => this.redraw());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEditorDirty(editor: IEditorInput): void {
|
updateEditorDirty(editor: IEditorInput): void {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { Action } from 'vs/base/common/actions';
|
|||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { memoize } from 'vs/base/common/decorators';
|
import { memoize } from 'vs/base/common/decorators';
|
||||||
import * as platform from 'vs/base/common/platform';
|
import * as platform from 'vs/base/common/platform';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
|
||||||
export interface IResourceDescriptor {
|
export interface IResourceDescriptor {
|
||||||
readonly resource: URI;
|
readonly resource: URI;
|
||||||
@@ -72,7 +72,7 @@ export class ResourceViewer {
|
|||||||
|
|
||||||
static show(
|
static show(
|
||||||
descriptor: IResourceDescriptor,
|
descriptor: IResourceDescriptor,
|
||||||
fileService: IFileService,
|
textFileService: ITextFileService,
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
scrollbar: DomScrollableElement,
|
scrollbar: DomScrollableElement,
|
||||||
openInternalClb: (uri: URI) => void,
|
openInternalClb: (uri: URI) => void,
|
||||||
@@ -85,7 +85,7 @@ export class ResourceViewer {
|
|||||||
|
|
||||||
// Images
|
// Images
|
||||||
if (ResourceViewer.isImageResource(descriptor)) {
|
if (ResourceViewer.isImageResource(descriptor)) {
|
||||||
return ImageView.create(container, descriptor, fileService, scrollbar, openExternalClb, metadataClb);
|
return ImageView.create(container, descriptor, textFileService, scrollbar, openExternalClb, metadataClb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Large Files
|
// Large Files
|
||||||
@@ -114,13 +114,13 @@ class ImageView {
|
|||||||
static create(
|
static create(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
descriptor: IResourceDescriptor,
|
descriptor: IResourceDescriptor,
|
||||||
fileService: IFileService,
|
textFileService: ITextFileService,
|
||||||
scrollbar: DomScrollableElement,
|
scrollbar: DomScrollableElement,
|
||||||
openExternalClb: (uri: URI) => void,
|
openExternalClb: (uri: URI) => void,
|
||||||
metadataClb: (meta: string) => void
|
metadataClb: (meta: string) => void
|
||||||
): ResourceViewerContext {
|
): ResourceViewerContext {
|
||||||
if (ImageView.shouldShowImageInline(descriptor)) {
|
if (ImageView.shouldShowImageInline(descriptor)) {
|
||||||
return InlineImageView.create(container, descriptor, fileService, scrollbar, metadataClb);
|
return InlineImageView.create(container, descriptor, textFileService, scrollbar, metadataClb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return LargeImageView.create(container, descriptor, openExternalClb, metadataClb);
|
return LargeImageView.create(container, descriptor, openExternalClb, metadataClb);
|
||||||
@@ -357,7 +357,7 @@ class InlineImageView {
|
|||||||
static create(
|
static create(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
descriptor: IResourceDescriptor,
|
descriptor: IResourceDescriptor,
|
||||||
fileService: IFileService,
|
textFileService: ITextFileService,
|
||||||
scrollbar: DomScrollableElement,
|
scrollbar: DomScrollableElement,
|
||||||
metadataClb: (meta: string) => void
|
metadataClb: (meta: string) => void
|
||||||
) {
|
) {
|
||||||
@@ -559,7 +559,7 @@ class InlineImageView {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
InlineImageView.imageSrc(descriptor, fileService).then(dataUri => {
|
InlineImageView.imageSrc(descriptor, textFileService).then(dataUri => {
|
||||||
const imgs = container.getElementsByTagName('img');
|
const imgs = container.getElementsByTagName('img');
|
||||||
if (imgs.length) {
|
if (imgs.length) {
|
||||||
imgs[0].src = dataUri;
|
imgs[0].src = dataUri;
|
||||||
@@ -569,12 +569,12 @@ class InlineImageView {
|
|||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static imageSrc(descriptor: IResourceDescriptor, fileService: IFileService): Promise<string> {
|
private static imageSrc(descriptor: IResourceDescriptor, textFileService: ITextFileService): Promise<string> {
|
||||||
if (descriptor.resource.scheme === Schemas.data) {
|
if (descriptor.resource.scheme === Schemas.data) {
|
||||||
return Promise.resolve(descriptor.resource.toString(true /* skip encoding */));
|
return Promise.resolve(descriptor.resource.toString(true /* skip encoding */));
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileService.resolveContent(descriptor.resource, { encoding: 'base64' }).then(data => {
|
return textFileService.read(descriptor.resource, { encoding: 'base64' }).then(data => {
|
||||||
const mime = getMime(descriptor);
|
const mime = getMime(descriptor);
|
||||||
|
|
||||||
return `data:${mime};base64,${data.value}`;
|
return `data:${mime};base64,${data.value}`;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||||||
import { BreadcrumbsControl } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
|
import { BreadcrumbsControl } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||||
|
import { ILabelService } from 'vs/platform/label/common/label';
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}} -- Display the editor's tab color
|
// {{SQL CARBON EDIT}} -- Display the editor's tab color
|
||||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||||
@@ -94,8 +95,9 @@ export class TabsTitleControl extends TitleControl {
|
|||||||
// {{SQL CARBON EDIT}} -- Display the editor's tab color
|
// {{SQL CARBON EDIT}} -- Display the editor's tab color
|
||||||
@ICommandService private commandService: ICommandService,
|
@ICommandService private commandService: ICommandService,
|
||||||
// {{SQL CARBON EDIT}} -- End
|
// {{SQL CARBON EDIT}} -- End
|
||||||
|
@ILabelService labelService: ILabelService
|
||||||
) {
|
) {
|
||||||
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService);
|
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService, labelService);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected create(parent: HTMLElement): void {
|
protected create(parent: HTMLElement): void {
|
||||||
|
|||||||
@@ -15,13 +15,12 @@ import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
|||||||
import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator';
|
import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator';
|
||||||
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
|
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
|
||||||
import { TextDiffEditorModel } from 'vs/workbench/common/editor/textDiffEditorModel';
|
import { TextDiffEditorModel } from 'vs/workbench/common/editor/textDiffEditorModel';
|
||||||
import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { ScrollType, IDiffEditorViewState, IDiffEditorModel } from 'vs/editor/common/editorCommon';
|
import { ScrollType, IDiffEditorViewState, IDiffEditorModel } from 'vs/editor/common/editorCommon';
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
@@ -242,10 +241,11 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
|||||||
private isFileBinaryError(error: Error | Error[]): boolean {
|
private isFileBinaryError(error: Error | Error[]): boolean {
|
||||||
if (types.isArray(error)) {
|
if (types.isArray(error)) {
|
||||||
const errors = <Error[]>error;
|
const errors = <Error[]>error;
|
||||||
|
|
||||||
return errors.some(e => this.isFileBinaryError(e));
|
return errors.some(e => this.isFileBinaryError(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_IS_BINARY;
|
return (<TextFileOperationError>error).textFileOperationResult === TextFileOperationResult.FILE_IS_BINARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearInput(): void {
|
clearInput(): void {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
|||||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||||
|
import { ILabelService } from 'vs/platform/label/common/label';
|
||||||
|
|
||||||
export interface IToolbarActions {
|
export interface IToolbarActions {
|
||||||
primary: IAction[];
|
primary: IAction[];
|
||||||
@@ -79,6 +80,7 @@ export abstract class TitleControl extends Themable {
|
|||||||
@IExtensionService private readonly extensionService: IExtensionService,
|
@IExtensionService private readonly extensionService: IExtensionService,
|
||||||
@IConfigurationService protected configurationService: IConfigurationService,
|
@IConfigurationService protected configurationService: IConfigurationService,
|
||||||
@IFileService private readonly fileService: IFileService,
|
@IFileService private readonly fileService: IFileService,
|
||||||
|
@ILabelService private readonly labelService: ILabelService
|
||||||
) {
|
) {
|
||||||
super(themeService);
|
super(themeService);
|
||||||
|
|
||||||
@@ -91,6 +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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract create(parent: HTMLElement): void;
|
protected abstract create(parent: HTMLElement): void;
|
||||||
@@ -340,7 +343,7 @@ 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 updateEditorDirty(editor: IEditorInput): void;
|
abstract updateEditorDirty(editor: IEditorInput): void;
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,13 @@
|
|||||||
padding: 6px 6px 4px 6px;
|
padding: 6px 6px 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quick-input-and-message {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.quick-input-check-all {
|
.quick-input-check-all {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -65,7 +72,8 @@
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.quick-input-widget.show-checkboxes .quick-input-box {
|
.quick-input-widget.show-checkboxes .quick-input-box,
|
||||||
|
.quick-input-widget.show-checkboxes .quick-input-message {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +103,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.quick-input-message {
|
.quick-input-message {
|
||||||
margin: 0px 11px;
|
margin-top: -1px;
|
||||||
|
padding: 6px 5px 2px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.quick-input-progress.monaco-progress-container {
|
.quick-input-progress.monaco-progress-container {
|
||||||
|
|||||||
@@ -301,6 +301,18 @@ class QuickInput implements IQuickInput {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected showMessageDecoration(severity: Severity) {
|
||||||
|
this.ui.inputBox.showDecoration(severity);
|
||||||
|
if (severity === Severity.Error) {
|
||||||
|
const styles = this.ui.inputBox.stylesForType(severity);
|
||||||
|
this.ui.message.style.backgroundColor = styles.background ? `${styles.background}` : null;
|
||||||
|
this.ui.message.style.border = styles.border ? `1px solid ${styles.border}` : null;
|
||||||
|
} else {
|
||||||
|
this.ui.message.style.backgroundColor = '';
|
||||||
|
this.ui.message.style.border = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
this.hide();
|
this.hide();
|
||||||
this.disposables = dispose(this.disposables);
|
this.disposables = dispose(this.disposables);
|
||||||
@@ -742,10 +754,10 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||||||
}
|
}
|
||||||
if (this.validationMessage) {
|
if (this.validationMessage) {
|
||||||
this.ui.message.textContent = this.validationMessage;
|
this.ui.message.textContent = this.validationMessage;
|
||||||
this.ui.inputBox.showDecoration(Severity.Error);
|
this.showMessageDecoration(Severity.Error);
|
||||||
} else {
|
} else {
|
||||||
this.ui.message.textContent = null;
|
this.ui.message.textContent = null;
|
||||||
this.ui.inputBox.showDecoration(Severity.Ignore);
|
this.showMessageDecoration(Severity.Info);
|
||||||
}
|
}
|
||||||
this.ui.customButton.label = this.customLabel;
|
this.ui.customButton.label = this.customLabel;
|
||||||
this.ui.customButton.element.title = this.customHover;
|
this.ui.customButton.element.title = this.customHover;
|
||||||
@@ -876,11 +888,11 @@ class InputBox extends QuickInput implements IInputBox {
|
|||||||
}
|
}
|
||||||
if (!this.validationMessage && this.ui.message.textContent !== this.noValidationMessage) {
|
if (!this.validationMessage && this.ui.message.textContent !== this.noValidationMessage) {
|
||||||
this.ui.message.textContent = this.noValidationMessage;
|
this.ui.message.textContent = this.noValidationMessage;
|
||||||
this.ui.inputBox.showDecoration(Severity.Ignore);
|
this.showMessageDecoration(Severity.Info);
|
||||||
}
|
}
|
||||||
if (this.validationMessage && this.ui.message.textContent !== this.validationMessage) {
|
if (this.validationMessage && this.ui.message.textContent !== this.validationMessage) {
|
||||||
this.ui.message.textContent = this.validationMessage;
|
this.ui.message.textContent = this.validationMessage;
|
||||||
this.ui.inputBox.showDecoration(Severity.Error);
|
this.showMessageDecoration(Severity.Error);
|
||||||
}
|
}
|
||||||
this.ui.setVisibilities({ title: !!this.title || !!this.step, inputBox: true, message: true });
|
this.ui.setVisibilities({ title: !!this.title || !!this.step, inputBox: true, message: true });
|
||||||
}
|
}
|
||||||
@@ -1044,7 +1056,8 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.filterContainer = dom.append(headerContainer, $('.quick-input-filter'));
|
const extraContainer = dom.append(headerContainer, $('.quick-input-and-message'));
|
||||||
|
this.filterContainer = dom.append(extraContainer, $('.quick-input-filter'));
|
||||||
|
|
||||||
const inputBox = this._register(new QuickInputBox(this.filterContainer));
|
const inputBox = this._register(new QuickInputBox(this.filterContainer));
|
||||||
inputBox.setAttribute('aria-describedby', `${this.idPrefix}message`);
|
inputBox.setAttribute('aria-describedby', `${this.idPrefix}message`);
|
||||||
@@ -1075,7 +1088,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||||||
this.onDidCustomEmitter.fire();
|
this.onDidCustomEmitter.fire();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const message = dom.append(container, $(`#${this.idPrefix}message.quick-input-message`));
|
const message = dom.append(extraContainer, $(`#${this.idPrefix}message.quick-input-message`));
|
||||||
|
|
||||||
const progressBar = new ProgressBar(container);
|
const progressBar = new ProgressBar(container);
|
||||||
dom.addClass(progressBar.getContainer(), 'quick-input-progress');
|
dom.addClass(progressBar.getContainer(), 'quick-input-progress');
|
||||||
|
|||||||
@@ -101,6 +101,10 @@ export class QuickInputBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stylesForType(decoration: Severity) {
|
||||||
|
return this.inputBox.stylesForType(decoration === Severity.Info ? MessageType.INFO : decoration === Severity.Warning ? MessageType.WARNING : MessageType.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
setFocus(): void {
|
setFocus(): void {
|
||||||
this.inputBox.focus();
|
this.inputBox.focus();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import { Position, Parts, IWorkbenchLayoutService } from 'vs/workbench/services/
|
|||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||||
import { IFileService, ILegacyFileService } from 'vs/platform/files/common/files';
|
|
||||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
@@ -197,20 +196,12 @@ export class Workbench extends Layout {
|
|||||||
instantiationService.invokeFunction(accessor => {
|
instantiationService.invokeFunction(accessor => {
|
||||||
const lifecycleService = accessor.get(ILifecycleService);
|
const lifecycleService = accessor.get(ILifecycleService);
|
||||||
|
|
||||||
// TODO@Ben legacy file service
|
|
||||||
const fileService = accessor.get(IFileService) as any;
|
|
||||||
if (typeof fileService.setLegacyService === 'function') {
|
|
||||||
try {
|
|
||||||
fileService.setLegacyService(accessor.get(ILegacyFileService));
|
|
||||||
} catch (error) {
|
|
||||||
//ignore, legacy file service might not be registered
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO@Sandeep debt around cyclic dependencies
|
// TODO@Sandeep debt around cyclic dependencies
|
||||||
const configurationService = accessor.get(IConfigurationService) as any;
|
const configurationService = accessor.get(IConfigurationService) as any;
|
||||||
if (typeof configurationService.acquireInstantiationService === 'function') {
|
if (typeof configurationService.acquireInstantiationService === 'function') {
|
||||||
configurationService.acquireInstantiationService(instantiationService);
|
setTimeout(() => {
|
||||||
|
configurationService.acquireInstantiationService(instantiationService);
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal to lifecycle that services are set
|
// Signal to lifecycle that services are set
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ exports.collectModules = function () {
|
|||||||
|
|
||||||
createModuleDescription('vs/workbench/services/search/node/searchApp', []),
|
createModuleDescription('vs/workbench/services/search/node/searchApp', []),
|
||||||
|
|
||||||
createModuleDescription('vs/workbench/services/files2/node/watcher/unix/watcherApp', []),
|
createModuleDescription('vs/workbench/services/files/node/watcher/unix/watcherApp', []),
|
||||||
createModuleDescription('vs/workbench/services/files2/node/watcher/nsfw/watcherApp', []),
|
createModuleDescription('vs/workbench/services/files/node/watcher/nsfw/watcherApp', []),
|
||||||
|
|
||||||
createModuleDescription('vs/workbench/services/extensions/node/extensionHostProcess', []),
|
createModuleDescription('vs/workbench/services/extensions/node/extensionHostProcess', []),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,14 +3,13 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ITextModel, ITextBufferFactory } from 'vs/editor/common/model';
|
import { ITextModel, ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model';
|
||||||
import { EditorModel } from 'vs/workbench/common/editor';
|
import { EditorModel } from 'vs/workbench/common/editor';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ITextEditorModel, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
import { ITextEditorModel, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||||
import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService';
|
import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService';
|
||||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { ITextSnapshot } from 'vs/platform/files/common/files';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated.
|
* The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated.
|
||||||
|
|||||||
@@ -313,7 +313,13 @@ export const STATUS_BAR_HOST_NAME_BACKGROUND = registerColor('statusBarItem.host
|
|||||||
dark: STATUS_BAR_PROMINENT_ITEM_BACKGROUND,
|
dark: STATUS_BAR_PROMINENT_ITEM_BACKGROUND,
|
||||||
light: STATUS_BAR_PROMINENT_ITEM_BACKGROUND,
|
light: STATUS_BAR_PROMINENT_ITEM_BACKGROUND,
|
||||||
hc: STATUS_BAR_PROMINENT_ITEM_BACKGROUND
|
hc: STATUS_BAR_PROMINENT_ITEM_BACKGROUND
|
||||||
}, nls.localize('statusBarItemHostBackground', "Background color for the remote host name on the status bar."));
|
}, nls.localize('statusBarItemHostBackground', "Background color for the host indicator on the status bar."));
|
||||||
|
|
||||||
|
export const STATUS_BAR_HOST_NAME_FOREGROUND = registerColor('statusBarItem.hostForeground', {
|
||||||
|
dark: STATUS_BAR_PROMINENT_ITEM_FOREGROUND,
|
||||||
|
light: STATUS_BAR_PROMINENT_ITEM_FOREGROUND,
|
||||||
|
hc: STATUS_BAR_PROMINENT_ITEM_FOREGROUND
|
||||||
|
}, nls.localize('statusBarItemHostForeground', "Foreground color for the host indicator on the status bar."));
|
||||||
|
|
||||||
|
|
||||||
// < --- Activity Bar --- >
|
// < --- Activity Bar --- >
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export class LanguageConfigurationFileHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _handleConfigFile(languageIdentifier: LanguageIdentifier, configFileLocation: URI): void {
|
private _handleConfigFile(languageIdentifier: LanguageIdentifier, configFileLocation: URI): void {
|
||||||
this._fileService.resolveContent(configFileLocation, { encoding: 'utf8' }).then((contents) => {
|
this._fileService.readFile(configFileLocation).then((contents) => {
|
||||||
const errors: ParseError[] = [];
|
const errors: ParseError[] = [];
|
||||||
const configuration = <ILanguageConfiguration>parse(contents.value.toString(), errors);
|
const configuration = <ILanguageConfiguration>parse(contents.value.toString(), errors);
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
|
|||||||
@@ -559,7 +559,7 @@ class Launch extends AbstractLaunch implements ILaunch {
|
|||||||
const resource = this.uri;
|
const resource = this.uri;
|
||||||
let created = false;
|
let created = false;
|
||||||
|
|
||||||
return this.fileService.resolveContent(resource).then(content => content.value, err => {
|
return this.fileService.readFile(resource).then(content => content.value, err => {
|
||||||
// launch.json not found: create one by collecting launch configs from debugConfigProviders
|
// launch.json not found: create one by collecting launch configs from debugConfigProviders
|
||||||
return this.configurationManager.guessDebugger(type).then(adapter => {
|
return this.configurationManager.guessDebugger(type).then(adapter => {
|
||||||
if (adapter) {
|
if (adapter) {
|
||||||
@@ -576,19 +576,17 @@ class Launch extends AbstractLaunch implements ILaunch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
created = true; // pin only if config file is created #8727
|
created = true; // pin only if config file is created #8727
|
||||||
return this.textFileService.write(resource, content).then(() => {
|
return this.textFileService.write(resource, content).then(() => content);
|
||||||
// convert string into IContent; see #32135
|
|
||||||
return content;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}).then(content => {
|
}).then(content => {
|
||||||
if (!content) {
|
if (!content) {
|
||||||
return { editor: null, created: false };
|
return { editor: null, created: false };
|
||||||
}
|
}
|
||||||
const index = content.indexOf(`"${this.configurationManager.selectedConfiguration.name}"`);
|
const contentValue = content.toString();
|
||||||
|
const index = contentValue.indexOf(`"${this.configurationManager.selectedConfiguration.name}"`);
|
||||||
let startLineNumber = 1;
|
let startLineNumber = 1;
|
||||||
for (let i = 0; i < index; i++) {
|
for (let i = 0; i < index; i++) {
|
||||||
if (content.charAt(i) === '\n') {
|
if (contentValue.charAt(i) === '\n') {
|
||||||
startLineNumber++;
|
startLineNumber++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,35 +29,37 @@ export function getTerminalLauncher() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let _DEFAULT_TERMINAL_LINUX_READY: Promise<string> | null = null;
|
let _DEFAULT_TERMINAL_LINUX_READY: Promise<string> | null = null;
|
||||||
|
|
||||||
export function getDefaultTerminalLinuxReady(): Promise<string> {
|
export function getDefaultTerminalLinuxReady(): Promise<string> {
|
||||||
if (!_DEFAULT_TERMINAL_LINUX_READY) {
|
if (!_DEFAULT_TERMINAL_LINUX_READY) {
|
||||||
_DEFAULT_TERMINAL_LINUX_READY = new Promise<string>(c => {
|
_DEFAULT_TERMINAL_LINUX_READY = new Promise<string>(resolve => {
|
||||||
if (env.isLinux) {
|
if (env.isLinux) {
|
||||||
Promise.all<any>([pfs.exists('/etc/debian_version'), process.lazyEnv]).then(([isDebian]) => {
|
Promise.all<any>([pfs.exists('/etc/debian_version'), process.lazyEnv]).then(([isDebian]) => {
|
||||||
if (isDebian) {
|
if (isDebian) {
|
||||||
c('x-terminal-emulator');
|
resolve('x-terminal-emulator');
|
||||||
} else if (process.env.DESKTOP_SESSION === 'gnome' || process.env.DESKTOP_SESSION === 'gnome-classic') {
|
} else if (process.env.DESKTOP_SESSION === 'gnome' || process.env.DESKTOP_SESSION === 'gnome-classic') {
|
||||||
c('gnome-terminal');
|
resolve('gnome-terminal');
|
||||||
} else if (process.env.DESKTOP_SESSION === 'kde-plasma') {
|
} else if (process.env.DESKTOP_SESSION === 'kde-plasma') {
|
||||||
c('konsole');
|
resolve('konsole');
|
||||||
} else if (process.env.COLORTERM) {
|
} else if (process.env.COLORTERM) {
|
||||||
c(process.env.COLORTERM);
|
resolve(process.env.COLORTERM);
|
||||||
} else if (process.env.TERM) {
|
} else if (process.env.TERM) {
|
||||||
c(process.env.TERM);
|
resolve(process.env.TERM);
|
||||||
} else {
|
} else {
|
||||||
c('xterm');
|
resolve('xterm');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
c('xterm');
|
resolve('xterm');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return _DEFAULT_TERMINAL_LINUX_READY;
|
return _DEFAULT_TERMINAL_LINUX_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _DEFAULT_TERMINAL_WINDOWS: string | null = null;
|
let _DEFAULT_TERMINAL_WINDOWS: string | null = null;
|
||||||
|
|
||||||
export function getDefaultTerminalWindows(): string {
|
export function getDefaultTerminalWindows(): string {
|
||||||
if (!_DEFAULT_TERMINAL_WINDOWS) {
|
if (!_DEFAULT_TERMINAL_WINDOWS) {
|
||||||
const isWoW64 = !!process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
|
const isWoW64 = !!process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
|
||||||
@@ -82,7 +84,7 @@ class WinTerminalService extends TerminalLauncher {
|
|||||||
|
|
||||||
const exec = configuration.external.windowsExec || getDefaultTerminalWindows();
|
const exec = configuration.external.windowsExec || getDefaultTerminalWindows();
|
||||||
|
|
||||||
return new Promise<number | undefined>((c, e) => {
|
return new Promise<number | undefined>((resolve, reject) => {
|
||||||
|
|
||||||
const title = `"${dir} - ${TERMINAL_TITLE}"`;
|
const title = `"${dir} - ${TERMINAL_TITLE}"`;
|
||||||
const command = `""${args.join('" "')}" & pause"`; // use '|' to only pause on non-zero exit code
|
const command = `""${args.join('" "')}" & pause"`; // use '|' to only pause on non-zero exit code
|
||||||
@@ -104,9 +106,11 @@ class WinTerminalService extends TerminalLauncher {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const cmd = cp.spawn(WinTerminalService.CMD, cmdArgs, options);
|
const cmd = cp.spawn(WinTerminalService.CMD, cmdArgs, options);
|
||||||
cmd.on('error', e);
|
cmd.on('error', err => {
|
||||||
|
reject(improveError(err));
|
||||||
|
});
|
||||||
|
|
||||||
c(undefined);
|
resolve(undefined);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +124,7 @@ class MacTerminalService extends TerminalLauncher {
|
|||||||
|
|
||||||
const terminalApp = configuration.external.osxExec || MacTerminalService.DEFAULT_TERMINAL_OSX;
|
const terminalApp = configuration.external.osxExec || MacTerminalService.DEFAULT_TERMINAL_OSX;
|
||||||
|
|
||||||
return new Promise<number | undefined>((c, e) => {
|
return new Promise<number | undefined>((resolve, reject) => {
|
||||||
|
|
||||||
if (terminalApp === MacTerminalService.DEFAULT_TERMINAL_OSX || terminalApp === 'iTerm.app') {
|
if (terminalApp === MacTerminalService.DEFAULT_TERMINAL_OSX || terminalApp === 'iTerm.app') {
|
||||||
|
|
||||||
@@ -156,24 +160,26 @@ class MacTerminalService extends TerminalLauncher {
|
|||||||
|
|
||||||
let stderr = '';
|
let stderr = '';
|
||||||
const osa = cp.spawn(MacTerminalService.OSASCRIPT, osaArgs);
|
const osa = cp.spawn(MacTerminalService.OSASCRIPT, osaArgs);
|
||||||
osa.on('error', e);
|
osa.on('error', err => {
|
||||||
|
reject(improveError(err));
|
||||||
|
});
|
||||||
osa.stderr.on('data', (data) => {
|
osa.stderr.on('data', (data) => {
|
||||||
stderr += data.toString();
|
stderr += data.toString();
|
||||||
});
|
});
|
||||||
osa.on('exit', (code: number) => {
|
osa.on('exit', (code: number) => {
|
||||||
if (code === 0) { // OK
|
if (code === 0) { // OK
|
||||||
c(undefined);
|
resolve(undefined);
|
||||||
} else {
|
} else {
|
||||||
if (stderr) {
|
if (stderr) {
|
||||||
const lines = stderr.split('\n', 1);
|
const lines = stderr.split('\n', 1);
|
||||||
e(new Error(lines[0]));
|
reject(new Error(lines[0]));
|
||||||
} else {
|
} else {
|
||||||
e(new Error(nls.localize('mac.terminal.script.failed', "Script '{0}' failed with exit code {1}", script, code)));
|
reject(new Error(nls.localize('mac.terminal.script.failed', "Script '{0}' failed with exit code {1}", script, code)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
e(new Error(nls.localize('mac.terminal.type.not.supported', "'{0}' not supported", terminalApp)));
|
reject(new Error(nls.localize('mac.terminal.type.not.supported', "'{0}' not supported", terminalApp)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -188,7 +194,7 @@ class LinuxTerminalService extends TerminalLauncher {
|
|||||||
const terminalConfig = configuration.external;
|
const terminalConfig = configuration.external;
|
||||||
const execThenable: Promise<string> = terminalConfig.linuxExec ? Promise.resolve(terminalConfig.linuxExec) : getDefaultTerminalLinuxReady();
|
const execThenable: Promise<string> = terminalConfig.linuxExec ? Promise.resolve(terminalConfig.linuxExec) : getDefaultTerminalLinuxReady();
|
||||||
|
|
||||||
return new Promise<number | undefined>((c, e) => {
|
return new Promise<number | undefined>((resolve, reject) => {
|
||||||
|
|
||||||
let termArgs: string[] = [];
|
let termArgs: string[] = [];
|
||||||
//termArgs.push('--title');
|
//termArgs.push('--title');
|
||||||
@@ -218,19 +224,21 @@ class LinuxTerminalService extends TerminalLauncher {
|
|||||||
|
|
||||||
let stderr = '';
|
let stderr = '';
|
||||||
const cmd = cp.spawn(exec, termArgs, options);
|
const cmd = cp.spawn(exec, termArgs, options);
|
||||||
cmd.on('error', e);
|
cmd.on('error', err => {
|
||||||
|
reject(improveError(err));
|
||||||
|
});
|
||||||
cmd.stderr.on('data', (data) => {
|
cmd.stderr.on('data', (data) => {
|
||||||
stderr += data.toString();
|
stderr += data.toString();
|
||||||
});
|
});
|
||||||
cmd.on('exit', (code: number) => {
|
cmd.on('exit', (code: number) => {
|
||||||
if (code === 0) { // OK
|
if (code === 0) { // OK
|
||||||
c(undefined);
|
resolve(undefined);
|
||||||
} else {
|
} else {
|
||||||
if (stderr) {
|
if (stderr) {
|
||||||
const lines = stderr.split('\n', 1);
|
const lines = stderr.split('\n', 1);
|
||||||
e(new Error(lines[0]));
|
reject(new Error(lines[0]));
|
||||||
} else {
|
} else {
|
||||||
e(new Error(nls.localize('linux.term.failed', "'{0}' failed with exit code {1}", exec, code)));
|
reject(new Error(nls.localize('linux.term.failed', "'{0}' failed with exit code {1}", exec, code)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -239,6 +247,16 @@ class LinuxTerminalService extends TerminalLauncher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tries to turn OS errors into more meaningful error messages
|
||||||
|
*/
|
||||||
|
function improveError(err: Error): Error {
|
||||||
|
if (err['errno'] === 'ENOENT' && err['path']) {
|
||||||
|
return new Error(nls.localize('ext.term.app.not.found', "can't find terminal application '{0}'", err['path']));
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quote args if necessary and combine into a space separated string.
|
* Quote args if necessary and combine into a space separated string.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import { IExperimentService, ExperimentActionType, ExperimentState } from 'vs/wo
|
|||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||||
import { extname } from 'vs/base/common/resources';
|
import { extname } from 'vs/base/common/resources';
|
||||||
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
|
||||||
const milliSecondsInADay = 1000 * 60 * 60 * 24;
|
const milliSecondsInADay = 1000 * 60 * 60 * 24;
|
||||||
const choiceNever = localize('neverShowAgain', "Don't Show Again");
|
const choiceNever = localize('neverShowAgain', "Don't Show Again");
|
||||||
@@ -111,6 +112,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||||
@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
|
@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
|
||||||
@IExperimentService private readonly experimentService: IExperimentService,
|
@IExperimentService private readonly experimentService: IExperimentService,
|
||||||
|
@ITextFileService private readonly textFileService: ITextFileService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -339,8 +341,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(this.fileService.resolveContent(workspace.configuration)
|
return Promise.resolve(this.fileService.readFile(workspace.configuration)
|
||||||
.then(content => <IExtensionsConfigContent>(json.parse(content.value)['extensions']), err => null));
|
.then(content => <IExtensionsConfigContent>(json.parse(content.value.toString())['extensions']), err => null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -350,8 +352,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
const extensionsJsonUri = workspaceFolder.toResource(EXTENSIONS_CONFIG);
|
const extensionsJsonUri = workspaceFolder.toResource(EXTENSIONS_CONFIG);
|
||||||
|
|
||||||
return Promise.resolve(this.fileService.resolve(extensionsJsonUri)
|
return Promise.resolve(this.fileService.resolve(extensionsJsonUri)
|
||||||
.then(() => this.fileService.resolveContent(extensionsJsonUri))
|
.then(() => this.fileService.readFile(extensionsJsonUri))
|
||||||
.then(content => <IExtensionsConfigContent>json.parse(content.value), err => null));
|
.then(content => <IExtensionsConfigContent>json.parse(content.value.toString()), err => null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -968,7 +970,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
|
|
||||||
const storageKey = 'extensionsAssistant/dynamicWorkspaceRecommendations';
|
const storageKey = 'extensionsAssistant/dynamicWorkspaceRecommendations';
|
||||||
const workspaceUri = this.contextService.getWorkspace().folders[0].uri;
|
const workspaceUri = this.contextService.getWorkspace().folders[0].uri;
|
||||||
return Promise.all([getHashedRemotesFromUri(workspaceUri, this.fileService, false), getHashedRemotesFromUri(workspaceUri, this.fileService, true)]).then(([hashedRemotes1, hashedRemotes2]) => {
|
return Promise.all([getHashedRemotesFromUri(workspaceUri, this.fileService, this.textFileService, false), getHashedRemotesFromUri(workspaceUri, this.fileService, this.textFileService, true)]).then(([hashedRemotes1, hashedRemotes2]) => {
|
||||||
const hashedRemotes = (hashedRemotes1 || []).concat(hashedRemotes2 || []);
|
const hashedRemotes = (hashedRemotes1 || []).concat(hashedRemotes2 || []);
|
||||||
if (!hashedRemotes.length) {
|
if (!hashedRemotes.length) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@@ -252,6 +252,30 @@ 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': {
|
'extensions.showInstalledExtensionsByDefault': {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: localize('extensions.showInstalledExtensionsByDefault', "When enabled, extensions view shows installed extensions view by default."),
|
description: localize('extensions.showInstalledExtensionsByDefault', "When enabled, extensions view shows installed extensions view by default."),
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
|
|||||||
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';
|
||||||
import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery';
|
import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery';
|
||||||
import { IFileService, IContent } from 'vs/platform/files/common/files';
|
import { IFileService, IFileContent } from 'vs/platform/files/common/files';
|
||||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
@@ -168,8 +168,7 @@ export class InstallAction extends ExtensionAction {
|
|||||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
|
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
|
||||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||||
@ILabelService private readonly labelService: ILabelService,
|
@ILabelService private readonly labelService: ILabelService
|
||||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
|
||||||
) {
|
) {
|
||||||
super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false);
|
super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false);
|
||||||
this.update();
|
this.update();
|
||||||
@@ -196,12 +195,12 @@ export class InstallAction extends ExtensionAction {
|
|||||||
} else {
|
} else {
|
||||||
if (this._manifest && this.workbenchEnvironmentService.configuration.remoteAuthority) {
|
if (this._manifest && this.workbenchEnvironmentService.configuration.remoteAuthority) {
|
||||||
if (isUIExtension(this._manifest, this.configurationService)) {
|
if (isUIExtension(this._manifest, this.configurationService)) {
|
||||||
this.label = `${InstallAction.INSTALL_LABEL} (${this.extensionManagementServerService.localExtensionManagementServer.label})`;
|
this.label = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`;
|
||||||
this.tooltip = `${InstallAction.INSTALL_LABEL} (${this.extensionManagementServerService.localExtensionManagementServer.label})`;
|
this.tooltip = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`;
|
||||||
} else {
|
} else {
|
||||||
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.workbenchEnvironmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
||||||
this.label = `${InstallAction.INSTALL_LABEL} (${host})`;
|
this.label = `${InstallAction.INSTALL_LABEL} on ${host}`;
|
||||||
this.tooltip = `${InstallAction.INSTALL_LABEL} (${host})`;
|
this.tooltip = `${InstallAction.INSTALL_LABEL} on ${host}`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.label = InstallAction.INSTALL_LABEL;
|
this.label = InstallAction.INSTALL_LABEL;
|
||||||
@@ -319,7 +318,7 @@ export class RemoteInstallAction extends ExtensionAction {
|
|||||||
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
||||||
if (remoteAuthority) {
|
if (remoteAuthority) {
|
||||||
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
const host = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority) || localize('remote', "Remote");
|
||||||
this.label = `${RemoteInstallAction.INSTALL_LABEL} (${host})`;
|
this.label = `${RemoteInstallAction.INSTALL_LABEL} on ${host}`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1233,13 +1232,21 @@ export class ReloadAction extends ExtensionAction {
|
|||||||
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
||||||
if (runningExtension) {
|
if (runningExtension) {
|
||||||
// Extension is running
|
// Extension is running
|
||||||
const isSameVersionRunning = isSameExtensionRunning && this.extension.version === runningExtension.version;
|
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
if (!isSameVersionRunning && !this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
if (!this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) {
|
||||||
this.enabled = true;
|
if (isSameExtensionRunning) {
|
||||||
this.label = localize('reloadRequired', "Reload Required");
|
if (this.extension.version !== runningExtension.version) {
|
||||||
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
this.enabled = true;
|
||||||
this.tooltip = localize('postUpdateTooltip', "Please reload Azure Data Studio to enable the updated extension.");
|
this.label = localize('reloadRequired', "Reload Required");
|
||||||
|
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
|
this.tooltip = localize('postUpdateTooltip', "Please reload Azure Data Studio to enable the updated extension.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.enabled = true;
|
||||||
|
this.label = localize('reloadRequired', "Reload Required");
|
||||||
|
// {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||||
|
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isSameExtensionRunning) {
|
if (isSameExtensionRunning) {
|
||||||
@@ -2057,7 +2064,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
|||||||
|
|
||||||
protected openWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<any> {
|
protected openWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<any> {
|
||||||
return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
|
return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
|
||||||
.then(content => this.getSelectionPosition(content.value, content.resource, ['extensions', 'recommendations']))
|
.then(content => this.getSelectionPosition(content.value.toString(), content.resource, ['extensions', 'recommendations']))
|
||||||
.then(selection => this.editorService.openEditor({
|
.then(selection => this.editorService.openEditor({
|
||||||
resource: workspaceConfigurationFile,
|
resource: workspaceConfigurationFile,
|
||||||
options: {
|
options: {
|
||||||
@@ -2071,7 +2078,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
|||||||
return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
|
return this.getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile)
|
||||||
.then(content => {
|
.then(content => {
|
||||||
const extensionIdLowerCase = extensionId.toLowerCase();
|
const extensionIdLowerCase = extensionId.toLowerCase();
|
||||||
const workspaceExtensionsConfigContent: IExtensionsConfigContent = (json.parse(content.value) || {})['extensions'] || {};
|
const workspaceExtensionsConfigContent: IExtensionsConfigContent = (json.parse(content.value.toString()) || {})['extensions'] || {};
|
||||||
let insertInto = shouldRecommend ? workspaceExtensionsConfigContent.recommendations || [] : workspaceExtensionsConfigContent.unwantedRecommendations || [];
|
let insertInto = shouldRecommend ? workspaceExtensionsConfigContent.recommendations || [] : workspaceExtensionsConfigContent.unwantedRecommendations || [];
|
||||||
let removeFrom = shouldRecommend ? workspaceExtensionsConfigContent.unwantedRecommendations || [] : workspaceExtensionsConfigContent.recommendations || [];
|
let removeFrom = shouldRecommend ? workspaceExtensionsConfigContent.unwantedRecommendations || [] : workspaceExtensionsConfigContent.recommendations || [];
|
||||||
|
|
||||||
@@ -2131,26 +2138,26 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getWorkspaceExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
|
protected getWorkspaceExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
|
||||||
return Promise.resolve(this.fileService.resolveContent(extensionsFileResource))
|
return Promise.resolve(this.fileService.readFile(extensionsFileResource))
|
||||||
.then(content => {
|
.then(content => {
|
||||||
return (json.parse(content.value) || {})['extensions'] || {};
|
return (json.parse(content.value.toString()) || {})['extensions'] || {};
|
||||||
}, err => ({ recommendations: [], unwantedRecommendations: [] }));
|
}, err => ({ recommendations: [], unwantedRecommendations: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getWorkspaceFolderExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
|
protected getWorkspaceFolderExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
|
||||||
return Promise.resolve(this.fileService.resolveContent(extensionsFileResource))
|
return Promise.resolve(this.fileService.readFile(extensionsFileResource))
|
||||||
.then(content => {
|
.then(content => {
|
||||||
return (<IExtensionsConfigContent>json.parse(content.value));
|
return (<IExtensionsConfigContent>json.parse(content.value.toString()));
|
||||||
}, err => ({ recommendations: [], unwantedRecommendations: [] }));
|
}, err => ({ recommendations: [], unwantedRecommendations: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
private getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<IContent> {
|
private getOrUpdateWorkspaceConfigurationFile(workspaceConfigurationFile: URI): Promise<IFileContent> {
|
||||||
return Promise.resolve(this.fileService.resolveContent(workspaceConfigurationFile))
|
return Promise.resolve(this.fileService.readFile(workspaceConfigurationFile))
|
||||||
.then(content => {
|
.then(content => {
|
||||||
const workspaceRecommendations = <IExtensionsConfigContent>json.parse(content.value)['extensions'];
|
const workspaceRecommendations = <IExtensionsConfigContent>json.parse(content.value.toString())['extensions'];
|
||||||
if (!workspaceRecommendations || !workspaceRecommendations.recommendations) {
|
if (!workspaceRecommendations || !workspaceRecommendations.recommendations) {
|
||||||
return this.jsonEditingService.write(workspaceConfigurationFile, { key: 'extensions', value: { recommendations: [] } }, true)
|
return this.jsonEditingService.write(workspaceConfigurationFile, { key: 'extensions', value: { recommendations: [] } }, true)
|
||||||
.then(() => this.fileService.resolveContent(workspaceConfigurationFile));
|
.then(() => this.fileService.readFile(workspaceConfigurationFile));
|
||||||
}
|
}
|
||||||
return content;
|
return content;
|
||||||
});
|
});
|
||||||
@@ -2179,8 +2186,8 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getOrCreateExtensionsFile(extensionsFileResource: URI): Promise<{ created: boolean, extensionsFileResource: URI, content: string }> {
|
private getOrCreateExtensionsFile(extensionsFileResource: URI): Promise<{ created: boolean, extensionsFileResource: URI, content: string }> {
|
||||||
return Promise.resolve(this.fileService.resolveContent(extensionsFileResource)).then(content => {
|
return Promise.resolve(this.fileService.readFile(extensionsFileResource)).then(content => {
|
||||||
return { created: false, extensionsFileResource, content: content.value };
|
return { created: false, extensionsFileResource, content: content.value.toString() };
|
||||||
}, err => {
|
}, err => {
|
||||||
return this.textFileService.write(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => {
|
return this.textFileService.write(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => {
|
||||||
return { created: true, extensionsFileResource, content: ExtensionsConfigurationInitialContent };
|
return { created: true, extensionsFileResource, content: ExtensionsConfigurationInitialContent };
|
||||||
@@ -2562,29 +2569,42 @@ export class DisabledLabelAction extends ExtensionAction {
|
|||||||
|
|
||||||
updateWhenCounterExtensionChanges: boolean = true;
|
updateWhenCounterExtensionChanges: boolean = true;
|
||||||
private disposables: IDisposable[] = [];
|
private disposables: IDisposable[] = [];
|
||||||
|
private _runningExtensions: IExtensionDescription[] | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly warningAction: SystemDisabledWarningAction,
|
private readonly warningAction: SystemDisabledWarningAction,
|
||||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
|
||||||
|
@IExtensionService private readonly extensionService: IExtensionService,
|
||||||
) {
|
) {
|
||||||
super('extensions.disabledLabel', warningAction.tooltip, `${DisabledLabelAction.Class} hide`, false);
|
super('extensions.disabledLabel', warningAction.tooltip, `${DisabledLabelAction.Class} hide`, false);
|
||||||
warningAction.onDidChange(() => this.update(), this, this.disposables);
|
warningAction.onDidChange(() => this.update(), this, this.disposables);
|
||||||
|
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
|
||||||
|
this.updateRunningExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateRunningExtensions(): void {
|
||||||
|
this.extensionService.getExtensions().then(runningExtensions => { this._runningExtensions = runningExtensions; this.update(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
update(): void {
|
update(): void {
|
||||||
this.class = `${DisabledLabelAction.Class} hide`;
|
this.class = `${DisabledLabelAction.Class} hide`;
|
||||||
this.label = '';
|
this.label = '';
|
||||||
|
this.enabled = false;
|
||||||
if (this.warningAction.enabled) {
|
if (this.warningAction.enabled) {
|
||||||
this.enabled = true;
|
this.enabled = true;
|
||||||
this.class = DisabledLabelAction.Class;
|
this.class = DisabledLabelAction.Class;
|
||||||
this.label = this.warningAction.tooltip;
|
this.label = this.warningAction.tooltip;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.extension && this.extension.local && !this.extensionEnablementService.isEnabled(this.extension.local)) {
|
if (this.extension && this.extension.local && this._runningExtensions) {
|
||||||
this.enabled = true;
|
const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local);
|
||||||
this.class = DisabledLabelAction.Class;
|
const isExtensionRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value }, this.extension.identifier));
|
||||||
this.label = localize('disabled by user', "This extension is disabled by the user.");
|
if (!isExtensionRunning && !isEnabled) {
|
||||||
return;
|
this.enabled = true;
|
||||||
|
this.class = DisabledLabelAction.Class;
|
||||||
|
this.label = localize('disabled by user', "This extension is disabled by the user.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2630,31 +2650,37 @@ export class SystemDisabledWarningAction extends ExtensionAction {
|
|||||||
this.class = `${SystemDisabledWarningAction.Class} hide`;
|
this.class = `${SystemDisabledWarningAction.Class} hide`;
|
||||||
this.tooltip = '';
|
this.tooltip = '';
|
||||||
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) {
|
||||||
if (
|
|
||||||
// Local Workspace Extension
|
|
||||||
this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)
|
|
||||||
) {
|
|
||||||
this.enabled = true;
|
|
||||||
this.class = `${SystemDisabledWarningAction.Class}`;
|
|
||||||
this.tooltip = localize('disabled workspace Extension', "This extension from {0} server is disabled because it cannot run in a window connected to the remote server.", this.getServerLabel(this.extensionManagementServerService.localExtensionManagementServer));
|
|
||||||
if (!this.extensionsWorkbenchService.local.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
|
|
||||||
&& this.extensionsWorkbenchService.canInstall(this.extension)
|
|
||||||
) {
|
|
||||||
// Extension does not exist in remote
|
|
||||||
this.tooltip = `${this.tooltip} ${localize('Install in remote server', "Install it in {0} server to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer))}`;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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;
|
||||||
if (
|
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
|
||||||
// Not same as running extension
|
const localExtensionServer = localExtension ? localExtension.server : null;
|
||||||
runningExtensionServer && this.extension.server !== runningExtensionServer
|
if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)) {
|
||||||
) {
|
if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||||
this.enabled = true;
|
this.enabled = true;
|
||||||
this.class = `${SystemDisabledWarningAction.Class}`;
|
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||||
this.tooltip = localize('disabled because running in another server', "This extension from {0} server is disabled because another instance of same extension from {1} server is enabled.", this.getServerLabel(this.extension.server), this.getServerLabel(runningExtensionServer));
|
this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
if (localExtensionServer !== this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||||
|
this.enabled = true;
|
||||||
|
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||||
|
this.tooltip = localize('Install in remote server', "Install the extension on '{0}' to enable.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.configurationService)) {
|
||||||
|
if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
|
||||||
|
this.enabled = true;
|
||||||
|
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||||
|
this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (localExtensionServer !== this.extensionManagementServerService.localExtensionManagementServer) {
|
||||||
|
this.enabled = true;
|
||||||
|
this.class = `${SystemDisabledWarningAction.Class}`;
|
||||||
|
this.tooltip = localize('Install in local server', "Install the extension locally to enable.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2878,7 +2904,7 @@ export class InstallVSIXAction extends Action {
|
|||||||
this.extensionsWorkbenchService.install(vsix).then(extension => {
|
this.extensionsWorkbenchService.install(vsix).then(extension => {
|
||||||
const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
|
const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
|
||||||
const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Azure Data Studio to complete installing the extension {0}.", extension.identifier.id)
|
const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Azure Data Studio to complete installing the extension {0}.", extension.identifier.id)
|
||||||
: localize('InstallVSIXAction.success', "Installing the extension {0} is completed.", extension.identifier.id);
|
: localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.identifier.id);
|
||||||
const actions = requireReload ? [{
|
const actions = requireReload ? [{
|
||||||
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
|
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
|
||||||
run: () => this.windowService.reloadWindow()
|
run: () => this.windowService.reloadWindow()
|
||||||
@@ -2911,7 +2937,7 @@ export class InstallVSIXAction extends Action {
|
|||||||
this.extensionsWorkbenchService.install(vsix).then(extension => {
|
this.extensionsWorkbenchService.install(vsix).then(extension => {
|
||||||
const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
|
const requireReload = !(extension.local && this.extensionService.canAddExtension(toExtensionDescription(extension.local)));
|
||||||
const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Azure Data Studio to complete installing the extension {0}.", extension.identifier.id)
|
const message = requireReload ? localize('InstallVSIXAction.successReload', "Please reload Azure Data Studio to complete installing the extension {0}.", extension.identifier.id)
|
||||||
: localize('InstallVSIXAction.success', "Installing the extension {0} is completed.", extension.identifier.id);
|
: localize('InstallVSIXAction.success', "Completed installing the extension {0}.", extension.identifier.id);
|
||||||
const actions = requireReload ? [{
|
const actions = requireReload ? [{
|
||||||
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
|
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
|
||||||
run: () => this.windowService.reloadWindow()
|
run: () => this.windowService.reloadWindow()
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||||||
const element = append(root, $('.extension'));
|
const element = append(root, $('.extension'));
|
||||||
const iconContainer = append(element, $('.icon-container'));
|
const iconContainer = append(element, $('.icon-container'));
|
||||||
const icon = append(iconContainer, $<HTMLImageElement>('img.icon'));
|
const icon = append(iconContainer, $<HTMLImageElement>('img.icon'));
|
||||||
const badgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, iconContainer);
|
const iconRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, iconContainer);
|
||||||
const details = append(element, $('.details'));
|
const details = append(element, $('.details'));
|
||||||
const headerContainer = append(details, $('.header-container'));
|
const headerContainer = append(details, $('.header-container'));
|
||||||
const header = append(headerContainer, $('.header'));
|
const header = append(headerContainer, $('.header'));
|
||||||
@@ -74,6 +74,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||||||
const version = append(header, $('span.version'));
|
const version = append(header, $('span.version'));
|
||||||
const installCount = append(header, $('span.install-count'));
|
const installCount = append(header, $('span.install-count'));
|
||||||
const ratings = append(header, $('span.ratings'));
|
const ratings = append(header, $('span.ratings'));
|
||||||
|
const headerRemoteBadgeWidget = this.instantiationService.createInstance(RemoteBadgeWidget, header);
|
||||||
const description = append(details, $('.description.ellipsis'));
|
const description = append(details, $('.description.ellipsis'));
|
||||||
const footer = append(details, $('.footer'));
|
const footer = append(details, $('.footer'));
|
||||||
const author = append(footer, $('.author.ellipsis'));
|
const author = append(footer, $('.author.ellipsis'));
|
||||||
@@ -89,10 +90,11 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||||||
actionbar.onDidRun(({ error }) => error && this.notificationService.error(error));
|
actionbar.onDidRun(({ error }) => error && this.notificationService.error(error));
|
||||||
|
|
||||||
const systemDisabledWarningAction = this.instantiationService.createInstance(SystemDisabledWarningAction);
|
const systemDisabledWarningAction = this.instantiationService.createInstance(SystemDisabledWarningAction);
|
||||||
|
const reloadAction = this.instantiationService.createInstance(ReloadAction);
|
||||||
const actions = [
|
const actions = [
|
||||||
this.instantiationService.createInstance(StatusLabelAction),
|
this.instantiationService.createInstance(StatusLabelAction),
|
||||||
this.instantiationService.createInstance(UpdateAction),
|
this.instantiationService.createInstance(UpdateAction),
|
||||||
this.instantiationService.createInstance(ReloadAction),
|
reloadAction,
|
||||||
this.instantiationService.createInstance(InstallAction),
|
this.instantiationService.createInstance(InstallAction),
|
||||||
this.instantiationService.createInstance(RemoteInstallAction),
|
this.instantiationService.createInstance(RemoteInstallAction),
|
||||||
this.instantiationService.createInstance(MaliciousStatusLabelAction, false),
|
this.instantiationService.createInstance(MaliciousStatusLabelAction, false),
|
||||||
@@ -100,10 +102,11 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||||||
this.instantiationService.createInstance(ManageExtensionAction)
|
this.instantiationService.createInstance(ManageExtensionAction)
|
||||||
];
|
];
|
||||||
const disabledLabelAction = this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction);
|
const disabledLabelAction = this.instantiationService.createInstance(DisabledLabelAction, systemDisabledWarningAction);
|
||||||
const tooltipWidget = this.instantiationService.createInstance(TooltipWidget, root, disabledLabelAction, recommendationWidget);
|
const tooltipWidget = this.instantiationService.createInstance(TooltipWidget, root, disabledLabelAction, recommendationWidget, reloadAction);
|
||||||
const widgets = [
|
const widgets = [
|
||||||
recommendationWidget,
|
recommendationWidget,
|
||||||
badgeWidget,
|
iconRemoteBadgeWidget,
|
||||||
|
headerRemoteBadgeWidget,
|
||||||
tooltipWidget,
|
tooltipWidget,
|
||||||
this.instantiationService.createInstance(Label, version, (e: IExtension) => e.version),
|
this.instantiationService.createInstance(Label, version, (e: IExtension) => e.version),
|
||||||
this.instantiationService.createInstance(InstallCountWidget, installCount, true),
|
this.instantiationService.createInstance(InstallCountWidget, installCount, true),
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ import * as platform from 'vs/base/common/platform';
|
|||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { IExtensionManagementServerService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
import { IExtensionManagementServerService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
import { ILabelService } from 'vs/platform/label/common/label';
|
import { ILabelService } from 'vs/platform/label/common/label';
|
||||||
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction, ReloadAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||||
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme';
|
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme';
|
||||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
|
||||||
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
|
export abstract class ExtensionWidget extends Disposable implements IExtensionContainer {
|
||||||
private _extension: IExtension;
|
private _extension: IExtension;
|
||||||
@@ -148,11 +149,15 @@ export class TooltipWidget extends ExtensionWidget {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly parent: HTMLElement,
|
private readonly parent: HTMLElement,
|
||||||
private readonly extensionLabelAction: DisabledLabelAction,
|
private readonly extensionLabelAction: DisabledLabelAction,
|
||||||
private readonly recommendationWidget: RecommendationWidget
|
private readonly recommendationWidget: RecommendationWidget,
|
||||||
|
private readonly reloadAction: ReloadAction
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._register(this.extensionLabelAction.onDidChange(() => this.render()));
|
this._register(Event.any<any>(
|
||||||
this._register(this.recommendationWidget.onDidChangeTooltip(() => this.render()));
|
this.extensionLabelAction.onDidChange,
|
||||||
|
this.reloadAction.onDidChange,
|
||||||
|
this.recommendationWidget.onDidChangeTooltip
|
||||||
|
)(() => this.render()));
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): void {
|
render(): void {
|
||||||
@@ -166,6 +171,9 @@ export class TooltipWidget extends ExtensionWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getTitle(): string {
|
private getTitle(): string {
|
||||||
|
if (this.reloadAction.enabled) {
|
||||||
|
return this.reloadAction.tooltip;
|
||||||
|
}
|
||||||
if (this.extensionLabelAction.enabled) {
|
if (this.extensionLabelAction.enabled) {
|
||||||
return this.extensionLabelAction.label;
|
return this.extensionLabelAction.label;
|
||||||
}
|
}
|
||||||
@@ -235,30 +243,30 @@ export class RecommendationWidget extends ExtensionWidget {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class RemoteBadgeWidget extends ExtensionWidget {
|
export class RemoteBadgeWidget extends ExtensionWidget {
|
||||||
|
|
||||||
private element: HTMLElement | null;
|
private remoteBadge: RemoteBadge | null;
|
||||||
private disposables: IDisposable[] = [];
|
private disposables: IDisposable[] = [];
|
||||||
|
|
||||||
|
private element: HTMLElement;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private parent: HTMLElement,
|
parent: HTMLElement,
|
||||||
@ILabelService private readonly labelService: ILabelService,
|
|
||||||
@IThemeService private readonly themeService: IThemeService,
|
|
||||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
this.element = append(parent, $('.extension-remote-badge-container'));
|
||||||
this.render();
|
this.render();
|
||||||
this._register(toDisposable(() => this.clear()));
|
this._register(toDisposable(() => this.clear()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private clear(): void {
|
private clear(): void {
|
||||||
if (this.element) {
|
if (this.remoteBadge) {
|
||||||
this.parent.removeChild(this.element);
|
this.element.removeChild(this.remoteBadge.element);
|
||||||
|
this.remoteBadge.dispose();
|
||||||
}
|
}
|
||||||
this.element = null;
|
this.remoteBadge = null;
|
||||||
this.disposables = dispose(this.disposables);
|
this.disposables = dispose(this.disposables);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,30 +276,56 @@ export class RemoteBadgeWidget extends ExtensionWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||||
this.element = append(this.parent, $('div.extension-remote-badge'));
|
this.remoteBadge = this.instantiationService.createInstance(RemoteBadge);
|
||||||
append(this.element, $('span.octicon.octicon-remote'));
|
append(this.element, this.remoteBadge.element);
|
||||||
|
|
||||||
const applyBadgeStyle = () => {
|
|
||||||
if (!this.element) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const bgColor = this.themeService.getTheme().getColor(STATUS_BAR_HOST_NAME_BACKGROUND);
|
|
||||||
const fgColor = this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY ? this.themeService.getTheme().getColor(STATUS_BAR_NO_FOLDER_FOREGROUND) : this.themeService.getTheme().getColor(STATUS_BAR_FOREGROUND);
|
|
||||||
this.element.style.backgroundColor = bgColor ? bgColor.toString() : '';
|
|
||||||
this.element.style.color = fgColor ? fgColor.toString() : '';
|
|
||||||
};
|
|
||||||
applyBadgeStyle();
|
|
||||||
this.themeService.onThemeChange(applyBadgeStyle, this, this.disposables);
|
|
||||||
this.workspaceContextService.onDidChangeWorkbenchState(applyBadgeStyle, this, this.disposables);
|
|
||||||
|
|
||||||
const updateTitle = () => {
|
|
||||||
if (this.element) {
|
|
||||||
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.labelService.onDidChangeFormatters(() => updateTitle(), this, this.disposables);
|
|
||||||
updateTitle();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
if (this.remoteBadge) {
|
||||||
|
this.remoteBadge.dispose();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RemoteBadge extends Disposable {
|
||||||
|
|
||||||
|
readonly element: HTMLElement;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@ILabelService private readonly labelService: ILabelService,
|
||||||
|
@IThemeService private readonly themeService: IThemeService,
|
||||||
|
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||||
|
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.element = $('div.extension-remote-badge');
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
private render(): void {
|
||||||
|
append(this.element, $('span.octicon.octicon-remote'));
|
||||||
|
|
||||||
|
const applyBadgeStyle = () => {
|
||||||
|
if (!this.element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const bgColor = this.themeService.getTheme().getColor(STATUS_BAR_HOST_NAME_BACKGROUND);
|
||||||
|
const fgColor = this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY ? this.themeService.getTheme().getColor(STATUS_BAR_NO_FOLDER_FOREGROUND) : this.themeService.getTheme().getColor(STATUS_BAR_FOREGROUND);
|
||||||
|
this.element.style.backgroundColor = bgColor ? bgColor.toString() : '';
|
||||||
|
this.element.style.color = fgColor ? fgColor.toString() : '';
|
||||||
|
};
|
||||||
|
applyBadgeStyle();
|
||||||
|
this._register(this.themeService.onThemeChange(() => applyBadgeStyle()));
|
||||||
|
this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => applyBadgeStyle()));
|
||||||
|
|
||||||
|
const updateTitle = () => {
|
||||||
|
if (this.element) {
|
||||||
|
this.element.title = localize('remote extension title', "Extension in {0}", this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.environmentService.configuration.remoteAuthority));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this._register(this.labelService.onDidChangeFormatters(() => updateTitle()));
|
||||||
|
updateTitle();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,17 @@
|
|||||||
.extension-editor > .header > .icon-container .extension-remote-badge {
|
.extension-editor > .header > .icon-container .extension-remote-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
top: 94px;
|
top: 88px;
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
line-height: 38px;
|
||||||
|
border-radius: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extension-editor > .header > .icon-container .extension-remote-badge .octicon {
|
||||||
|
font-size: 32px;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extension-editor > .header > .details {
|
.extension-editor > .header > .details {
|
||||||
|
|||||||
@@ -102,10 +102,32 @@
|
|||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extensions-viewlet > .extensions .monaco-list-row > .extension > .icon-container > .extension-remote-badge {
|
.extensions-viewlet > .extensions .monaco-list-row > .extension > .icon-container .extension-remote-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
line-height: 22px;
|
||||||
|
border-radius: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header > .extension-remote-badge-container {
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header .extension-remote-badge {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
line-height: 14px;
|
||||||
|
border-radius: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extensions-viewlet > .extensions .monaco-list-row > .extension > .details > .header-container > .header .extension-remote-badge > .octicon {
|
||||||
|
font-size: 13px;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extensions-viewlet.narrow > .extensions .extension > .icon-container,
|
.extensions-viewlet.narrow > .extensions .extension > .icon-container,
|
||||||
@@ -146,10 +168,13 @@
|
|||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
flex: 1;
|
|
||||||
min-width: fit-content;
|
min-width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extensions-viewlet:not(.narrow) > .extensions .extension > .details > .header-container > .header > .version {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count:not(:empty) {
|
.extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count:not(:empty) {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
margin: 0 6px;
|
margin: 0 6px;
|
||||||
@@ -164,6 +189,7 @@
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extensions-viewlet:not(.narrow) > .extensions .extension > .details > .header-container > .header > .extension-remote-badge-container,
|
||||||
.extensions-viewlet.narrow > .extensions .extension > .details > .header-container > .header > .ratings,
|
.extensions-viewlet.narrow > .extensions .extension > .details > .header-container > .header > .ratings,
|
||||||
.extensions-viewlet.narrow > .extensions .extension > .details > .header-container > .header > .install-count {
|
.extensions-viewlet.narrow > .extensions .extension > .details > .header-container > .header > .install-count {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -46,12 +46,4 @@
|
|||||||
|
|
||||||
.extension-ratings.small > .count {
|
.extension-ratings.small > .count {
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
|
||||||
|
|
||||||
.extension-remote-badge {
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
line-height: 22px;
|
|
||||||
border-radius: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
@@ -254,7 +254,7 @@ class Extension implements IExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.local && this.local.readmeUrl) {
|
if (this.local && this.local.readmeUrl) {
|
||||||
return this.fileService.resolveContent(this.local.readmeUrl, { encoding: 'utf8' }).then(content => content.value);
|
return this.fileService.readFile(this.local.readmeUrl).then(content => content.value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.type === ExtensionType.System) {
|
if (this.type === ExtensionType.System) {
|
||||||
@@ -297,7 +297,7 @@ ${this.description}
|
|||||||
return Promise.reject(new Error('not available'));
|
return Promise.reject(new Error('not available'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.fileService.resolveContent(changelogUrl, { encoding: 'utf8' }).then(content => content.value);
|
return this.fileService.readFile(changelogUrl).then(content => content.value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
get dependencies(): string[] {
|
get dependencies(): string[] {
|
||||||
|
|||||||
@@ -21,12 +21,11 @@ import { Emitter } from 'vs/base/common/event';
|
|||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||||
import { TestTextResourceConfigurationService, TestContextService, TestLifecycleService, TestEnvironmentService, TestStorageService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices';
|
import { TestContextService, TestLifecycleService, TestSharedProcessService } from 'vs/workbench/test/workbenchTestServices';
|
||||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
|
import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
|
||||||
import { LegacyFileService } from 'vs/workbench/services/files/node/fileService';
|
|
||||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||||
import { IPager } from 'vs/base/common/paging';
|
import { IPager } from 'vs/base/common/paging';
|
||||||
import { assign } from 'vs/base/common/objects';
|
import { assign } from 'vs/base/common/objects';
|
||||||
@@ -47,6 +46,11 @@ import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/ele
|
|||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
||||||
|
import { FileService } from 'vs/workbench/services/files/common/fileService';
|
||||||
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider';
|
||||||
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
|
||||||
const mockExtensionGallery: IGalleryExtension[] = [
|
const mockExtensionGallery: IGalleryExtension[] = [
|
||||||
aGalleryExtension('MockExtension1', {
|
aGalleryExtension('MockExtension1', {
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
|
|||||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
|
import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of editor for binary files like images.
|
* An implementation of editor for binary files like images.
|
||||||
@@ -26,10 +26,10 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
|
|||||||
constructor(
|
constructor(
|
||||||
@ITelemetryService telemetryService: ITelemetryService,
|
@ITelemetryService telemetryService: ITelemetryService,
|
||||||
@IThemeService themeService: IThemeService,
|
@IThemeService themeService: IThemeService,
|
||||||
@IFileService fileService: IFileService,
|
|
||||||
@IWindowsService private readonly windowsService: IWindowsService,
|
@IWindowsService private readonly windowsService: IWindowsService,
|
||||||
@IEditorService private readonly editorService: IEditorService,
|
@IEditorService private readonly editorService: IEditorService,
|
||||||
@IStorageService storageService: IStorageService
|
@IStorageService storageService: IStorageService,
|
||||||
|
@ITextFileService textFileService: ITextFileService
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
BinaryFileEditor.ID,
|
BinaryFileEditor.ID,
|
||||||
@@ -39,7 +39,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
|
|||||||
},
|
},
|
||||||
telemetryService,
|
telemetryService,
|
||||||
themeService,
|
themeService,
|
||||||
fileService,
|
textFileService,
|
||||||
storageService
|
storageService
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { isValidBasename } from 'vs/base/common/extpath';
|
|||||||
import { basename } from 'vs/base/common/resources';
|
import { basename } from 'vs/base/common/resources';
|
||||||
import { Action } from 'vs/base/common/actions';
|
import { Action } from 'vs/base/common/actions';
|
||||||
import { VIEWLET_ID, TEXT_FILE_EDITOR_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
import { VIEWLET_ID, TEXT_FILE_EDITOR_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||||
import { ITextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileEditorModel, ITextFileService, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { BaseTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor';
|
import { BaseTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||||
import { EditorOptions, TextEditorOptions, IEditorCloseEvent } from 'vs/workbench/common/editor';
|
import { EditorOptions, TextEditorOptions, IEditorCloseEvent } from 'vs/workbench/common/editor';
|
||||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||||
@@ -170,7 +170,7 @@ export class TextFileEditor extends BaseTextEditor {
|
|||||||
// In case we tried to open a file inside the text editor and the response
|
// In case we tried to open a file inside the text editor and the response
|
||||||
// indicates that this is not a text file, reopen the file through the binary
|
// indicates that this is not a text file, reopen the file through the binary
|
||||||
// editor.
|
// editor.
|
||||||
if ((<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_IS_BINARY) {
|
if ((<TextFileOperationError>error).textFileOperationResult === TextFileOperationResult.FILE_IS_BINARY) {
|
||||||
return this.openAsBinary(input, options);
|
return this.openAsBinary(input, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur
|
|||||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||||
import { IEditorInputFactory, EditorInput, IFileEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor';
|
import { IEditorInputFactory, EditorInput, IFileEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor';
|
||||||
import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS } from 'vs/platform/files/common/files';
|
import { AutoSaveConfiguration, HotExitConfiguration } from 'vs/platform/files/common/files';
|
||||||
import { VIEWLET_ID, SortOrderConfiguration, FILE_EDITOR_INPUT_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
import { VIEWLET_ID, SortOrderConfiguration, FILE_EDITOR_INPUT_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||||
import { FileEditorTracker } from 'vs/workbench/contrib/files/browser/editors/fileEditorTracker';
|
import { FileEditorTracker } from 'vs/workbench/contrib/files/browser/editors/fileEditorTracker';
|
||||||
import { SaveErrorHandler } from 'vs/workbench/contrib/files/browser/saveErrorHandler';
|
import { SaveErrorHandler } from 'vs/workbench/contrib/files/browser/saveErrorHandler';
|
||||||
@@ -37,6 +37,7 @@ import { ILabelService } from 'vs/platform/label/common/label';
|
|||||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
import { ExplorerService } from 'vs/workbench/contrib/files/common/explorerService';
|
import { ExplorerService } from 'vs/workbench/contrib/files/common/explorerService';
|
||||||
|
import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
|
||||||
// Viewlet Action
|
// Viewlet Action
|
||||||
export class OpenExplorerViewletAction extends ShowViewletAction {
|
export class OpenExplorerViewletAction extends ShowViewletAction {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { basename } from 'vs/base/common/resources';
|
|||||||
import { Action } from 'vs/base/common/actions';
|
import { Action } from 'vs/base/common/actions';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||||
import { ITextFileService, ISaveErrorHandler, ITextFileEditorModel, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService, ISaveErrorHandler, ITextFileEditorModel, IResolvedTextFileEditorModel, IWriteTextFileOptions } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||||
@@ -134,7 +134,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I
|
|||||||
// Any other save error
|
// Any other save error
|
||||||
else {
|
else {
|
||||||
const isReadonly = fileOperationError.fileOperationResult === FileOperationResult.FILE_READ_ONLY;
|
const isReadonly = fileOperationError.fileOperationResult === FileOperationResult.FILE_READ_ONLY;
|
||||||
const triedToMakeWriteable = isReadonly && fileOperationError.options && fileOperationError.options.overwriteReadonly;
|
const triedToMakeWriteable = isReadonly && fileOperationError.options && (fileOperationError.options as IWriteTextFileOptions).overwriteReadonly;
|
||||||
const isPermissionDenied = fileOperationError.fileOperationResult === FileOperationResult.FILE_PERMISSION_DENIED;
|
const isPermissionDenied = fileOperationError.fileOperationResult === FileOperationResult.FILE_PERMISSION_DENIED;
|
||||||
|
|
||||||
// Save Elevated (TODO@remote cannot write elevated https://github.com/Microsoft/vscode/issues/48659)
|
// Save Elevated (TODO@remote cannot write elevated https://github.com/Microsoft/vscode/issues/48659)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditor
|
|||||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||||
import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||||
import { ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent, LoadReason } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IReference } from 'vs/base/common/lifecycle';
|
import { IReference } from 'vs/base/common/lifecycle';
|
||||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||||
@@ -269,7 +269,10 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
|
|||||||
}, error => {
|
}, error => {
|
||||||
|
|
||||||
// In case of an error that indicates that the file is binary or too large, just return with the binary editor model
|
// In case of an error that indicates that the file is binary or too large, just return with the binary editor model
|
||||||
if ((<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_IS_BINARY || (<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_TOO_LARGE) {
|
if (
|
||||||
|
(<TextFileOperationError>error).textFileOperationResult === TextFileOperationResult.FILE_IS_BINARY ||
|
||||||
|
(<FileOperationError>error).fileOperationResult === FileOperationResult.FILE_TOO_LARGE
|
||||||
|
) {
|
||||||
return this.doResolveAsBinary();
|
return this.doResolveAsBinary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider {
|
|||||||
private resolveEditorModel(resource: URI, createAsNeeded: boolean = true): Promise<ITextModel | null> {
|
private resolveEditorModel(resource: URI, createAsNeeded: boolean = true): Promise<ITextModel | null> {
|
||||||
const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority);
|
const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority);
|
||||||
|
|
||||||
return this.textFileService.resolve(savedFileResource).then(content => {
|
return this.textFileService.readStream(savedFileResource).then(content => {
|
||||||
let codeEditorModel = this.modelService.getModel(resource);
|
let codeEditorModel = this.modelService.getModel(resource);
|
||||||
if (codeEditorModel) {
|
if (codeEditorModel) {
|
||||||
this.modelService.updateModel(codeEditorModel, content.value);
|
this.modelService.updateModel(codeEditorModel, content.value);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
|||||||
import { workbenchInstantiationService, TestTextFileService } from 'vs/workbench/test/workbenchTestServices';
|
import { workbenchInstantiationService, TestTextFileService } from 'vs/workbench/test/workbenchTestServices';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { EncodingMode, Verbosity } from 'vs/workbench/common/editor';
|
import { EncodingMode, Verbosity } from 'vs/workbench/common/editor';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { FileOperationResult, FileOperationError } from 'vs/platform/files/common/files';
|
import { FileOperationResult, FileOperationError } from 'vs/platform/files/common/files';
|
||||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||||
@@ -155,7 +155,7 @@ suite('Files - FileEditorInput', () => {
|
|||||||
test('resolve handles binary files', function () {
|
test('resolve handles binary files', function () {
|
||||||
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined);
|
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined);
|
||||||
|
|
||||||
accessor.textFileService.setResolveTextContentErrorOnce(new FileOperationError('error', FileOperationResult.FILE_IS_BINARY));
|
accessor.textFileService.setResolveTextContentErrorOnce(new TextFileOperationError('error', TextFileOperationResult.FILE_IS_BINARY));
|
||||||
|
|
||||||
return input.resolve().then(resolved => {
|
return input.resolve().then(resolved => {
|
||||||
assert.ok(resolved);
|
assert.ok(resolved);
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import { toResource } from 'vs/base/test/common/utils';
|
|||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { workbenchInstantiationService, TestTextFileService, TestFileService } from 'vs/workbench/test/workbenchTestServices';
|
import { workbenchInstantiationService, TestTextFileService, TestFileService } from 'vs/workbench/test/workbenchTestServices';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ITextFileService, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService, IResolvedTextFileEditorModel, snapshotToString } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { FileChangesEvent, FileChangeType, IFileService, snapshotToString } from 'vs/platform/files/common/files';
|
import { FileChangesEvent, FileChangeType, IFileService } from 'vs/platform/files/common/files';
|
||||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
import { timeout } from 'vs/base/common/async';
|
import { timeout } from 'vs/base/common/async';
|
||||||
|
|
||||||
|
|||||||
@@ -511,20 +511,20 @@ export class SettingsTargetsWidget extends Widget {
|
|||||||
actionItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : undefined
|
actionItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : undefined
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.userLocalSettings = new Action('userSettings', localize('userSettings', "User Settings"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_LOCAL));
|
this.userLocalSettings = new Action('userSettings', localize('userSettings', "User"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_LOCAL));
|
||||||
this.userLocalSettings.tooltip = this.userLocalSettings.label;
|
this.userLocalSettings.tooltip = this.userLocalSettings.label;
|
||||||
|
|
||||||
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
|
||||||
const hostLabel = remoteAuthority && this.labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAuthority);
|
const hostLabel = remoteAuthority && this.labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAuthority);
|
||||||
const remoteSettingsLabel = localize('userSettingsRemote', "Remote Settings") +
|
const remoteSettingsLabel = localize('userSettingsRemote', "Remote") +
|
||||||
(hostLabel ? ` (${hostLabel})` : '');
|
(hostLabel ? ` (${hostLabel})` : '');
|
||||||
this.userRemoteSettings = new Action('userSettingsRemote', remoteSettingsLabel, '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_REMOTE));
|
this.userRemoteSettings = new Action('userSettingsRemote', remoteSettingsLabel, '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_REMOTE));
|
||||||
this.userRemoteSettings.tooltip = this.userRemoteSettings.label;
|
this.userRemoteSettings.tooltip = this.userRemoteSettings.label;
|
||||||
|
|
||||||
this.workspaceSettings = new Action('workspaceSettings', localize('workspaceSettings', "Workspace Settings"), '.settings-tab', false, () => this.updateTarget(ConfigurationTarget.WORKSPACE));
|
this.workspaceSettings = new Action('workspaceSettings', localize('workspaceSettings', "Workspace"), '.settings-tab', false, () => this.updateTarget(ConfigurationTarget.WORKSPACE));
|
||||||
this.workspaceSettings.tooltip = this.workspaceSettings.label;
|
this.workspaceSettings.tooltip = this.workspaceSettings.label;
|
||||||
|
|
||||||
const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder Settings"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder.uri));
|
const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder.uri));
|
||||||
this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionItem, folderSettingsAction);
|
this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionItem, folderSettingsAction);
|
||||||
|
|
||||||
this.update();
|
this.update();
|
||||||
@@ -551,14 +551,14 @@ export class SettingsTargetsWidget extends Widget {
|
|||||||
|
|
||||||
setResultCount(settingsTarget: SettingsTarget, count: number): void {
|
setResultCount(settingsTarget: SettingsTarget, count: number): void {
|
||||||
if (settingsTarget === ConfigurationTarget.WORKSPACE) {
|
if (settingsTarget === ConfigurationTarget.WORKSPACE) {
|
||||||
let label = localize('workspaceSettings', "Workspace Settings");
|
let label = localize('workspaceSettings', "Workspace");
|
||||||
if (count) {
|
if (count) {
|
||||||
label += ` (${count})`;
|
label += ` (${count})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.workspaceSettings.label = label;
|
this.workspaceSettings.label = label;
|
||||||
} else if (settingsTarget === ConfigurationTarget.USER_LOCAL) {
|
} else if (settingsTarget === ConfigurationTarget.USER_LOCAL) {
|
||||||
let label = localize('userSettings', "User Settings");
|
let label = localize('userSettings', "User");
|
||||||
if (count) {
|
if (count) {
|
||||||
label += ` (${count})`;
|
label += ` (${count})`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/
|
|||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
import { IFolderQuery, IPatternInfo, QueryType, ITextQuery, IFileQuery } from 'vs/workbench/services/search/common/search';
|
import { IFolderQuery, IPatternInfo, QueryType, ITextQuery, IFileQuery } from 'vs/workbench/services/search/common/search';
|
||||||
import { IWorkspaceContextService, toWorkspaceFolders, Workspace } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService, toWorkspaceFolder, Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
||||||
import { ISearchPathsInfo, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
|
import { ISearchPathsInfo, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||||
import { TestContextService, TestEnvironmentService } from 'vs/workbench/test/workbenchTestServices';
|
import { TestContextService, TestEnvironmentService } from 'vs/workbench/test/workbenchTestServices';
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@ suite('QueryBuilder', () => {
|
|||||||
const PATTERN_INFO: IPatternInfo = { pattern: 'a' };
|
const PATTERN_INFO: IPatternInfo = { pattern: 'a' };
|
||||||
const ROOT_1 = fixPath('/foo/root1');
|
const ROOT_1 = fixPath('/foo/root1');
|
||||||
const ROOT_1_URI = getUri(ROOT_1);
|
const ROOT_1_URI = getUri(ROOT_1);
|
||||||
|
const WS_CONFIG_PATH = getUri('/bar/test.code-workspace'); // location of the workspace file (not important except that it is a file URI)
|
||||||
|
|
||||||
let instantiationService: TestInstantiationService;
|
let instantiationService: TestInstantiationService;
|
||||||
let queryBuilder: QueryBuilder;
|
let queryBuilder: QueryBuilder;
|
||||||
@@ -40,7 +41,7 @@ suite('QueryBuilder', () => {
|
|||||||
instantiationService.stub(IConfigurationService, mockConfigService);
|
instantiationService.stub(IConfigurationService, mockConfigService);
|
||||||
|
|
||||||
mockContextService = new TestContextService();
|
mockContextService = new TestContextService();
|
||||||
mockWorkspace = new Workspace('workspace', toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }]));
|
mockWorkspace = new Workspace('workspace', [toWorkspaceFolder(ROOT_1_URI)]);
|
||||||
mockContextService.setWorkspace(mockWorkspace);
|
mockContextService.setWorkspace(mockWorkspace);
|
||||||
|
|
||||||
instantiationService.stub(IWorkspaceContextService, mockContextService);
|
instantiationService.stub(IWorkspaceContextService, mockContextService);
|
||||||
@@ -277,7 +278,7 @@ suite('QueryBuilder', () => {
|
|||||||
const ROOT_2_URI = getUri(ROOT_2);
|
const ROOT_2_URI = getUri(ROOT_2);
|
||||||
const ROOT_3 = fixPath('/project/root3');
|
const ROOT_3 = fixPath('/project/root3');
|
||||||
const ROOT_3_URI = getUri(ROOT_3);
|
const ROOT_3_URI = getUri(ROOT_3);
|
||||||
mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }, { path: ROOT_2_URI.fsPath }, { path: ROOT_3_URI.fsPath }]);
|
mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }, { path: ROOT_2_URI.fsPath }, { path: ROOT_3_URI.fsPath }], WS_CONFIG_PATH);
|
||||||
mockWorkspace.configuration = uri.file(fixPath('/config'));
|
mockWorkspace.configuration = uri.file(fixPath('/config'));
|
||||||
|
|
||||||
mockConfigService.setUserConfiguration('search', {
|
mockConfigService.setUserConfiguration('search', {
|
||||||
@@ -689,7 +690,7 @@ suite('QueryBuilder', () => {
|
|||||||
|
|
||||||
test('relative includes w/two root folders', () => {
|
test('relative includes w/two root folders', () => {
|
||||||
const ROOT_2 = '/project/root2';
|
const ROOT_2 = '/project/root2';
|
||||||
mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }, { path: getUri(ROOT_2).fsPath }]);
|
mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }, { path: getUri(ROOT_2).fsPath }], WS_CONFIG_PATH);
|
||||||
mockWorkspace.configuration = uri.file(fixPath('config'));
|
mockWorkspace.configuration = uri.file(fixPath('config'));
|
||||||
|
|
||||||
const cases: [string, ISearchPathsInfo][] = [
|
const cases: [string, ISearchPathsInfo][] = [
|
||||||
@@ -730,7 +731,7 @@ suite('QueryBuilder', () => {
|
|||||||
test('include ./foldername', () => {
|
test('include ./foldername', () => {
|
||||||
const ROOT_2 = '/project/root2';
|
const ROOT_2 = '/project/root2';
|
||||||
const ROOT_1_FOLDERNAME = 'foldername';
|
const ROOT_1_FOLDERNAME = 'foldername';
|
||||||
mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath, name: ROOT_1_FOLDERNAME }, { path: getUri(ROOT_2).fsPath }]);
|
mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath, name: ROOT_1_FOLDERNAME }, { path: getUri(ROOT_2).fsPath }], WS_CONFIG_PATH);
|
||||||
mockWorkspace.configuration = uri.file(fixPath('config'));
|
mockWorkspace.configuration = uri.file(fixPath('config'));
|
||||||
|
|
||||||
const cases: [string, ISearchPathsInfo][] = [
|
const cases: [string, ISearchPathsInfo][] = [
|
||||||
@@ -758,7 +759,7 @@ suite('QueryBuilder', () => {
|
|||||||
test('relative includes w/multiple ambiguous root folders', () => {
|
test('relative includes w/multiple ambiguous root folders', () => {
|
||||||
const ROOT_2 = '/project/rootB';
|
const ROOT_2 = '/project/rootB';
|
||||||
const ROOT_3 = '/otherproject/rootB';
|
const ROOT_3 = '/otherproject/rootB';
|
||||||
mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }, { path: getUri(ROOT_2).fsPath }, { path: getUri(ROOT_3).fsPath }]);
|
mockWorkspace.folders = toWorkspaceFolders([{ path: ROOT_1_URI.fsPath }, { path: getUri(ROOT_2).fsPath }, { path: getUri(ROOT_3).fsPath }], WS_CONFIG_PATH);
|
||||||
mockWorkspace.configuration = uri.file(fixPath('/config'));
|
mockWorkspace.configuration = uri.file(fixPath('/config'));
|
||||||
|
|
||||||
const cases: [string, ISearchPathsInfo][] = [
|
const cases: [string, ISearchPathsInfo][] = [
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ export class SnippetFile {
|
|||||||
|
|
||||||
load(): Promise<this> {
|
load(): Promise<this> {
|
||||||
if (!this._loadPromise) {
|
if (!this._loadPromise) {
|
||||||
this._loadPromise = Promise.resolve(this._fileService.resolveContent(this.location, { encoding: 'utf8' })).then(content => {
|
this._loadPromise = Promise.resolve(this._fileService.readFile(this.location)).then(content => {
|
||||||
const data = <JsonSerializedSnippets>jsonParse(content.value.toString());
|
const data = <JsonSerializedSnippets>jsonParse(content.value.toString());
|
||||||
if (typeof data === 'object') {
|
if (typeof data === 'object') {
|
||||||
forEach(data, entry => {
|
forEach(data, entry => {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { localize } from 'vs/nls';
|
|||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IFileService, IFileStat, IResolveFileResult, IContent } from 'vs/platform/files/common/files';
|
import { IFileService, IFileStat, IResolveFileResult } from 'vs/platform/files/common/files';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
@@ -20,6 +20,7 @@ import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspa
|
|||||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
import { joinPath } from 'vs/base/common/resources';
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
|
import { ITextFileService, ITextFileContent } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
|
||||||
const SshProtocolMatcher = /^([^@:]+@)?([^:]+):/;
|
const SshProtocolMatcher = /^([^@:]+@)?([^:]+):/;
|
||||||
const SshUrlMatcher = /^([^@:]+@)?([^:]+):(.+)$/;
|
const SshUrlMatcher = /^([^@:]+@)?([^:]+):(.+)$/;
|
||||||
@@ -193,14 +194,14 @@ export function getHashedRemotesFromConfig(text: string, stripEndingDotGit: bool
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHashedRemotesFromUri(workspaceUri: URI, fileService: IFileService, stripEndingDotGit: boolean = false): Promise<string[]> {
|
export function getHashedRemotesFromUri(workspaceUri: URI, fileService: IFileService, textFileService: ITextFileService, stripEndingDotGit: boolean = false): Promise<string[]> {
|
||||||
const path = workspaceUri.path;
|
const path = workspaceUri.path;
|
||||||
const uri = workspaceUri.with({ path: `${path !== '/' ? path : ''}/.git/config` });
|
const uri = workspaceUri.with({ path: `${path !== '/' ? path : ''}/.git/config` });
|
||||||
return fileService.exists(uri).then(exists => {
|
return fileService.exists(uri).then(exists => {
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return fileService.resolveContent(uri, { acceptTextOnly: true }).then(
|
return textFileService.read(uri, { acceptTextOnly: true }).then(
|
||||||
content => getHashedRemotesFromConfig(content.value, stripEndingDotGit),
|
content => getHashedRemotesFromConfig(content.value, stripEndingDotGit),
|
||||||
err => [] // ignore missing or binary file
|
err => [] // ignore missing or binary file
|
||||||
);
|
);
|
||||||
@@ -221,7 +222,8 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
|||||||
@IWindowService private readonly windowService: IWindowService,
|
@IWindowService private readonly windowService: IWindowService,
|
||||||
@INotificationService private readonly notificationService: INotificationService,
|
@INotificationService private readonly notificationService: INotificationService,
|
||||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||||
@IStorageService private readonly storageService: IStorageService
|
@IStorageService private readonly storageService: IStorageService,
|
||||||
|
@ITextFileService private readonly textFileService: ITextFileService
|
||||||
) {
|
) {
|
||||||
this.report();
|
this.report();
|
||||||
}
|
}
|
||||||
@@ -434,7 +436,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
|||||||
tags['workspace.android.cpp'] = true;
|
tags['workspace.android.cpp'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFilePromises(filename: string, fileService: IFileService, contentHandler: (content: IContent) => void): Promise<void>[] {
|
function getFilePromises(filename: string, fileService: IFileService, textFileService: ITextFileService, contentHandler: (content: ITextFileContent) => void): Promise<void>[] {
|
||||||
return !nameSet.has(filename) ? [] : (folders as URI[]).map(workspaceUri => {
|
return !nameSet.has(filename) ? [] : (folders as URI[]).map(workspaceUri => {
|
||||||
const uri = workspaceUri.with({ path: `${workspaceUri.path !== '/' ? workspaceUri.path : ''}/${filename}` });
|
const uri = workspaceUri.with({ path: `${workspaceUri.path !== '/' ? workspaceUri.path : ''}/${filename}` });
|
||||||
return fileService.exists(uri).then(exists => {
|
return fileService.exists(uri).then(exists => {
|
||||||
@@ -442,7 +444,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileService.resolveContent(uri, { acceptTextOnly: true }).then(contentHandler);
|
return textFileService.read(uri, { acceptTextOnly: true }).then(contentHandler);
|
||||||
}, err => {
|
}, err => {
|
||||||
// Ignore missing file
|
// Ignore missing file
|
||||||
});
|
});
|
||||||
@@ -468,7 +470,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const requirementsTxtPromises = getFilePromises('requirements.txt', this.fileService, content => {
|
const requirementsTxtPromises = getFilePromises('requirements.txt', this.fileService, this.textFileService, content => {
|
||||||
const dependencies: string[] = content.value.split(/\r\n|\r|\n/);
|
const dependencies: string[] = content.value.split(/\r\n|\r|\n/);
|
||||||
for (let dependency of dependencies) {
|
for (let dependency of dependencies) {
|
||||||
// Dependencies in requirements.txt can have 3 formats: `foo==3.1, foo>=3.1, foo`
|
// Dependencies in requirements.txt can have 3 formats: `foo==3.1, foo>=3.1, foo`
|
||||||
@@ -479,7 +481,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const pipfilePromises = getFilePromises('pipfile', this.fileService, content => {
|
const pipfilePromises = getFilePromises('pipfile', this.fileService, this.textFileService, content => {
|
||||||
let dependencies: string[] = content.value.split(/\r\n|\r|\n/);
|
let dependencies: string[] = content.value.split(/\r\n|\r|\n/);
|
||||||
|
|
||||||
// We're only interested in the '[packages]' section of the Pipfile
|
// We're only interested in the '[packages]' section of the Pipfile
|
||||||
@@ -499,7 +501,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const packageJsonPromises = getFilePromises('package.json', this.fileService, content => {
|
const packageJsonPromises = getFilePromises('package.json', this.fileService, this.textFileService, content => {
|
||||||
try {
|
try {
|
||||||
const packageJsonContents = JSON.parse(content.value);
|
const packageJsonContents = JSON.parse(content.value);
|
||||||
if (packageJsonContents['dependencies']) {
|
if (packageJsonContents['dependencies']) {
|
||||||
@@ -624,7 +626,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
|||||||
if (!exists) {
|
if (!exists) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return this.fileService.resolveContent(uri, { acceptTextOnly: true }).then(
|
return this.textFileService.read(uri, { acceptTextOnly: true }).then(
|
||||||
content => getDomainsOfRemotes(content.value, SecondLevelDomainWhitelist),
|
content => getDomainsOfRemotes(content.value, SecondLevelDomainWhitelist),
|
||||||
err => [] // ignore missing or binary file
|
err => [] // ignore missing or binary file
|
||||||
);
|
);
|
||||||
@@ -644,7 +646,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
|||||||
|
|
||||||
private reportRemotes(workspaceUris: URI[]): void {
|
private reportRemotes(workspaceUris: URI[]): void {
|
||||||
Promise.all<string[]>(workspaceUris.map(workspaceUri => {
|
Promise.all<string[]>(workspaceUris.map(workspaceUri => {
|
||||||
return getHashedRemotesFromUri(workspaceUri, this.fileService, true);
|
return getHashedRemotesFromUri(workspaceUri, this.fileService, this.textFileService, true);
|
||||||
})).then(hashedRemotes => {
|
})).then(hashedRemotes => {
|
||||||
/* __GDPR__
|
/* __GDPR__
|
||||||
"workspace.hashedRemotes" : {
|
"workspace.hashedRemotes" : {
|
||||||
@@ -693,7 +695,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
|
|||||||
if (!exists) {
|
if (!exists) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.fileService.resolveContent(uri, { acceptTextOnly: true }).then(
|
return this.textFileService.read(uri, { acceptTextOnly: true }).then(
|
||||||
content => !!content.value.match(/azure/i),
|
content => !!content.value.match(/azure/i),
|
||||||
err => false
|
err => false
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import * as path from 'vs/base/common/path';
|
|
||||||
import * as platform from 'vs/base/common/platform';
|
import * as platform from 'vs/base/common/platform';
|
||||||
import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
@@ -14,6 +13,7 @@ import Severity from 'vs/base/common/severity';
|
|||||||
import { Terminal as XTermTerminal } from 'vscode-xterm';
|
import { Terminal as XTermTerminal } from 'vscode-xterm';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal';
|
import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||||
|
import { mergeDefaultShellPathAndArgs } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||||
|
|
||||||
const MINIMUM_FONT_SIZE = 6;
|
const MINIMUM_FONT_SIZE = 6;
|
||||||
const MAXIMUM_FONT_SIZE = 25;
|
const MAXIMUM_FONT_SIZE = 25;
|
||||||
@@ -167,9 +167,9 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
|
|||||||
return this._storageService.getBoolean(IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, StorageScope.WORKSPACE, defaultValue);
|
return this._storageService.getBoolean(IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, StorageScope.WORKSPACE, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkWorkspaceShellPermissions(platformOverride: platform.Platform = platform.platform): boolean {
|
public checkWorkspaceShellPermissions(osOverride: platform.OperatingSystem = platform.OS): boolean {
|
||||||
// Check whether there is a workspace setting
|
// Check whether there is a workspace setting
|
||||||
const platformKey = platformOverride === platform.Platform.Windows ? 'windows' : platformOverride === platform.Platform.Mac ? 'osx' : 'linux';
|
const platformKey = osOverride === platform.OperatingSystem.Windows ? 'windows' : osOverride === platform.OperatingSystem.Macintosh ? 'osx' : 'linux';
|
||||||
const shellConfigValue = this._workspaceConfigurationService.inspect<string>(`terminal.integrated.shell.${platformKey}`);
|
const shellConfigValue = this._workspaceConfigurationService.inspect<string>(`terminal.integrated.shell.${platformKey}`);
|
||||||
const shellArgsConfigValue = this._workspaceConfigurationService.inspect<string[]>(`terminal.integrated.shellArgs.${platformKey}`);
|
const shellArgsConfigValue = this._workspaceConfigurationService.inspect<string[]>(`terminal.integrated.shellArgs.${platformKey}`);
|
||||||
const envConfigValue = this._workspaceConfigurationService.inspect<string[]>(`terminal.integrated.env.${platformKey}`);
|
const envConfigValue = this._workspaceConfigurationService.inspect<string[]>(`terminal.integrated.env.${platformKey}`);
|
||||||
@@ -228,28 +228,8 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride: platform.Platform = platform.platform): void {
|
public mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride: platform.Platform = platform.platform): void {
|
||||||
const isWorkspaceShellAllowed = this.checkWorkspaceShellPermissions(platformOverride);
|
const isWorkspaceShellAllowed = this.checkWorkspaceShellPermissions(platformOverride === platform.Platform.Windows ? platform.OperatingSystem.Windows : (platformOverride === platform.Platform.Mac ? platform.OperatingSystem.Macintosh : platform.OperatingSystem.Linux));
|
||||||
const platformKey = platformOverride === platform.Platform.Windows ? 'windows' : platformOverride === platform.Platform.Mac ? 'osx' : 'linux';
|
mergeDefaultShellPathAndArgs(shell, (key) => this._workspaceConfigurationService.inspect(key), isWorkspaceShellAllowed);
|
||||||
const shellConfigValue = this._workspaceConfigurationService.inspect<string>(`terminal.integrated.shell.${platformKey}`);
|
|
||||||
const shellArgsConfigValue = this._workspaceConfigurationService.inspect<string[]>(`terminal.integrated.shellArgs.${platformKey}`);
|
|
||||||
|
|
||||||
shell.executable = (isWorkspaceShellAllowed ? shellConfigValue.value : shellConfigValue.user) || shellConfigValue.default;
|
|
||||||
shell.args = (isWorkspaceShellAllowed ? shellArgsConfigValue.value : shellArgsConfigValue.user) || shellArgsConfigValue.default;
|
|
||||||
|
|
||||||
// Change Sysnative to System32 if the OS is Windows but NOT WoW64. It's
|
|
||||||
// safe to assume that this was used by accident as Sysnative does not
|
|
||||||
// exist and will break the terminal in non-WoW64 environments.
|
|
||||||
if ((platformOverride === platform.Platform.Windows) && !process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432') && process.env.windir) {
|
|
||||||
const sysnativePath = path.join(process.env.windir, 'Sysnative').toLowerCase();
|
|
||||||
if (shell.executable.toLowerCase().indexOf(sysnativePath) === 0) {
|
|
||||||
shell.executable = path.join(process.env.windir, 'System32', shell.executable.substr(sysnativePath.length));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert / to \ on Windows for convenience
|
|
||||||
if (platformOverride === platform.Platform.Windows) {
|
|
||||||
shell.executable = shell.executable.replace(/\//g, '\\');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _toInteger(source: any, minimum: number, maximum: number, fallback: number): number {
|
private _toInteger(source: any, minimum: number, maximum: number, fallback: number): number {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import * as platform from 'vs/base/common/platform';
|
import * as platform from 'vs/base/common/platform';
|
||||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalConfigHelper, ITerminalChildProcess, IBeforeProcessDataEvent } from 'vs/workbench/contrib/terminal/common/terminal';
|
import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalConfigHelper, ITerminalChildProcess, IBeforeProcessDataEvent, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||||
@@ -22,6 +22,7 @@ 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;
|
||||||
@@ -133,16 +134,13 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(hasRemoteAuthority ? REMOTE_HOST_SCHEME : undefined);
|
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(hasRemoteAuthority ? REMOTE_HOST_SCHEME : undefined);
|
||||||
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows);
|
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, this._configHelper);
|
||||||
} else {
|
} else {
|
||||||
this._process = this._launchProcess(shellLaunchConfig, cols, rows);
|
this._process = this._launchProcess(shellLaunchConfig, cols, rows);
|
||||||
}
|
}
|
||||||
this.processState = ProcessState.LAUNCHING;
|
this.processState = ProcessState.LAUNCHING;
|
||||||
|
|
||||||
// The process is non-null, but TS isn't clever enough to know
|
this._process.onProcessData(data => {
|
||||||
const p = this._process!;
|
|
||||||
|
|
||||||
p.onProcessData(data => {
|
|
||||||
const beforeProcessDataEvent: IBeforeProcessDataEvent = { data };
|
const beforeProcessDataEvent: IBeforeProcessDataEvent = { data };
|
||||||
this._onBeforeProcessData.fire(beforeProcessDataEvent);
|
this._onBeforeProcessData.fire(beforeProcessDataEvent);
|
||||||
if (beforeProcessDataEvent.data && beforeProcessDataEvent.data.length > 0) {
|
if (beforeProcessDataEvent.data && beforeProcessDataEvent.data.length > 0) {
|
||||||
@@ -150,19 +148,19 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
p.onProcessIdReady(pid => {
|
this._process.onProcessIdReady(pid => {
|
||||||
this.shellProcessId = pid;
|
this.shellProcessId = pid;
|
||||||
this._onProcessReady.fire();
|
this._onProcessReady.fire();
|
||||||
|
|
||||||
// Send any queued data that's waiting
|
// Send any queued data that's waiting
|
||||||
if (this._preLaunchInputQueue.length > 0) {
|
if (this._preLaunchInputQueue.length > 0 && this._process) {
|
||||||
p.input(this._preLaunchInputQueue.join(''));
|
this._process.input(this._preLaunchInputQueue.join(''));
|
||||||
this._preLaunchInputQueue.length = 0;
|
this._preLaunchInputQueue.length = 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
p.onProcessTitleChanged(title => this._onProcessTitle.fire(title));
|
this._process.onProcessTitleChanged(title => this._onProcessTitle.fire(title));
|
||||||
p.onProcessExit(exitCode => this._onExit(exitCode));
|
this._process.onProcessExit(exitCode => this._onExit(exitCode));
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.processState === ProcessState.LAUNCHING) {
|
if (this.processState === ProcessState.LAUNCHING) {
|
||||||
@@ -175,32 +173,41 @@ 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);
|
||||||
|
|
||||||
// Compel type system as process.env should not have any undefined entries
|
this._logService.debug(`Terminal process launching`, shellLaunchConfig, initialCwd, cols, rows, env);
|
||||||
|
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 = {};
|
let env: platform.IProcessEnvironment = {};
|
||||||
|
|
||||||
if (shellLaunchConfig.strictEnv) {
|
if (shellLaunchConfig.strictEnv) {
|
||||||
// Only base the terminal process environment on this environment and add the
|
// strictEnv is true, only use the requested env (ignoring null entries)
|
||||||
// various mixins when strictEnv is false
|
terminalEnvironment.mergeNonNullKeys(env, shellLaunchConfig.env);
|
||||||
env = { ...shellLaunchConfig.env } as any;
|
|
||||||
} else {
|
} else {
|
||||||
// Merge process env with the env from config and from shellLaunchConfig
|
// Merge process env with the env from config and from shellLaunchConfig
|
||||||
env = { ...process.env } as any;
|
terminalEnvironment.mergeNonNullKeys(env, process.env);
|
||||||
|
|
||||||
// Resolve env vars from config and shell
|
// Determine config env based on workspace shell permissions
|
||||||
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : null;
|
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : null;
|
||||||
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||||
const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions();
|
const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions();
|
||||||
const envFromConfigValue = this._workspaceConfigurationService.inspect<{ [key: string]: string }>(`terminal.integrated.env.${platformKey}`);
|
const envFromConfigValue = this._workspaceConfigurationService.inspect<ITerminalEnvironment | undefined>(`terminal.integrated.env.${platformKey}`);
|
||||||
const allowedEnvFromConfig = (isWorkspaceShellAllowed ? envFromConfigValue.value : envFromConfigValue.user);
|
const allowedEnvFromConfig = { ...(isWorkspaceShellAllowed ? envFromConfigValue.value : envFromConfigValue.user) };
|
||||||
const envFromConfig = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...allowedEnvFromConfig }, lastActiveWorkspaceRoot);
|
|
||||||
const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot);
|
|
||||||
shellLaunchConfig.env = envFromShell;
|
|
||||||
|
|
||||||
terminalEnvironment.mergeEnvironments(env, envFromConfig);
|
// 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);
|
terminalEnvironment.mergeEnvironments(env, shellLaunchConfig.env);
|
||||||
|
|
||||||
// Sanitize the environment, removing any undesirable VS Code and Electron environment
|
// Sanitize the environment, removing any undesirable VS Code and Electron environment
|
||||||
@@ -210,9 +217,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
|||||||
// Adding other env keys necessary to create the process
|
// Adding other env keys necessary to create the process
|
||||||
terminalEnvironment.addTerminalEnvironmentKeys(env, this._productService.version, platform.locale, this._configHelper.config.setLocaleVariables);
|
terminalEnvironment.addTerminalEnvironmentKeys(env, this._productService.version, platform.locale, this._configHelper.config.setLocaleVariables);
|
||||||
}
|
}
|
||||||
|
return 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setDimensions(cols: number, rows: number): void {
|
public setDimensions(cols: number, rows: number): void {
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export interface ITerminalConfigHelper {
|
|||||||
mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride?: platform.Platform): void;
|
mergeDefaultShellPathAndArgs(shell: IShellLaunchConfig, platformOverride?: platform.Platform): void;
|
||||||
/** Sets whether a workspace shell configuration is allowed or not */
|
/** Sets whether a workspace shell configuration is allowed or not */
|
||||||
setWorkspaceShellAllowed(isAllowed: boolean): void;
|
setWorkspaceShellAllowed(isAllowed: boolean): void;
|
||||||
checkWorkspaceShellPermissions(platformOverride?: platform.Platform): boolean;
|
checkWorkspaceShellPermissions(osOverride?: platform.OperatingSystem): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITerminalFont {
|
export interface ITerminalFont {
|
||||||
@@ -268,7 +268,7 @@ export interface ITerminalService {
|
|||||||
preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise<string>;
|
preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise<string>;
|
||||||
|
|
||||||
extHostReady(remoteAuthority: string): void;
|
extHostReady(remoteAuthority: string): void;
|
||||||
requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void;
|
requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum Direction {
|
export const enum Direction {
|
||||||
@@ -714,6 +714,7 @@ export interface ITerminalProcessExtHostRequest {
|
|||||||
activeWorkspaceRootUri: URI;
|
activeWorkspaceRootUri: URI;
|
||||||
cols: number;
|
cols: number;
|
||||||
rows: number;
|
rows: number;
|
||||||
|
isWorkspaceShellAllowed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum LinuxDistro {
|
export enum LinuxDistro {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati
|
|||||||
* This module contains utility functions related to the environment, cwd and paths.
|
* This module contains utility functions related to the environment, cwd and paths.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function mergeEnvironments(parent: platform.IProcessEnvironment, other?: ITerminalEnvironment): void {
|
export function mergeEnvironments(parent: platform.IProcessEnvironment, other: ITerminalEnvironment | undefined): void {
|
||||||
if (!other) {
|
if (!other) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -49,14 +49,28 @@ function _mergeEnvironmentValue(env: ITerminalEnvironment, key: string, value: s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addTerminalEnvironmentKeys(env: ITerminalEnvironment, version: string | undefined, locale: string | undefined, setLocaleVariables: boolean): void {
|
export function addTerminalEnvironmentKeys(env: platform.IProcessEnvironment, version: string | undefined, locale: string | undefined, setLocaleVariables: boolean): void {
|
||||||
env['TERM_PROGRAM'] = 'vscode';
|
env['TERM_PROGRAM'] = 'vscode';
|
||||||
env['TERM_PROGRAM_VERSION'] = version ? version : null;
|
if (version) {
|
||||||
|
env['TERM_PROGRAM_VERSION'] = version;
|
||||||
|
}
|
||||||
if (setLocaleVariables) {
|
if (setLocaleVariables) {
|
||||||
env['LANG'] = _getLangEnvVariable(locale);
|
env['LANG'] = _getLangEnvVariable(locale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mergeNonNullKeys(env: platform.IProcessEnvironment, other: ITerminalEnvironment | NodeJS.ProcessEnv | undefined) {
|
||||||
|
if (!other) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const key of Object.keys(other)) {
|
||||||
|
const value = other[key];
|
||||||
|
if (value) {
|
||||||
|
env[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function resolveConfigurationVariables(configurationResolverService: IConfigurationResolverService, env: ITerminalEnvironment, lastActiveWorkspaceRoot: IWorkspaceFolder | null): ITerminalEnvironment {
|
export 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];
|
||||||
@@ -144,3 +158,34 @@ export function escapeNonWindowsPath(path: string): string {
|
|||||||
}
|
}
|
||||||
return newPath;
|
return newPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mergeDefaultShellPathAndArgs(
|
||||||
|
shell: IShellLaunchConfig,
|
||||||
|
fetchSetting: (key: string) => { user: string | string[] | undefined, value: string | string[] | undefined, default: string | string[] | undefined },
|
||||||
|
isWorkspaceShellAllowed: boolean,
|
||||||
|
platformOverride: platform.Platform = platform.platform
|
||||||
|
): void {
|
||||||
|
const platformKey = platformOverride === platform.Platform.Windows ? 'windows' : platformOverride === platform.Platform.Mac ? 'osx' : 'linux';
|
||||||
|
const shellConfigValue = fetchSetting(`terminal.integrated.shell.${platformKey}`);
|
||||||
|
// const shellConfigValue = this._workspaceConfigurationService.inspect<string>(`terminal.integrated.shell.${platformKey}`);
|
||||||
|
const shellArgsConfigValue = fetchSetting(`terminal.integrated.shellArgs.${platformKey}`);
|
||||||
|
// const shellArgsConfigValue = this._workspaceConfigurationService.inspect<string[]>(`terminal.integrated.shellArgs.${platformKey}`);
|
||||||
|
|
||||||
|
shell.executable = (isWorkspaceShellAllowed ? <string>shellConfigValue.value : <string>shellConfigValue.user) || <string>shellConfigValue.default;
|
||||||
|
shell.args = (isWorkspaceShellAllowed ? <string[]>shellArgsConfigValue.value : <string[]>shellArgsConfigValue.user) || <string[]>shellArgsConfigValue.default;
|
||||||
|
|
||||||
|
// Change Sysnative to System32 if the OS is Windows but NOT WoW64. It's
|
||||||
|
// safe to assume that this was used by accident as Sysnative does not
|
||||||
|
// exist and will break the terminal in non-WoW64 environments.
|
||||||
|
if ((platformOverride === platform.Platform.Windows) && !process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432') && process.env.windir) {
|
||||||
|
const sysnativePath = path.join(process.env.windir, 'Sysnative').toLowerCase();
|
||||||
|
if (shell.executable && shell.executable.toLowerCase().indexOf(sysnativePath) === 0) {
|
||||||
|
shell.executable = path.join(process.env.windir, 'System32', shell.executable.substr(sysnativePath.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert / to \ on Windows for convenience
|
||||||
|
if (shell.executable && platformOverride === platform.Platform.Windows) {
|
||||||
|
shell.executable = shell.executable.replace(/\//g, '\\');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,9 +4,13 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { ITerminalService, ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal';
|
import { ITerminalService, ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
|
import * as nls from 'vs/nls';
|
||||||
|
|
||||||
|
let hasReceivedResponse: boolean = false;
|
||||||
|
|
||||||
export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerminalProcessExtHostProxy {
|
export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerminalProcessExtHostProxy {
|
||||||
private _disposables: IDisposable[] = [];
|
private _disposables: IDisposable[] = [];
|
||||||
@@ -43,10 +47,19 @@ export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerm
|
|||||||
activeWorkspaceRootUri: URI,
|
activeWorkspaceRootUri: URI,
|
||||||
cols: number,
|
cols: number,
|
||||||
rows: number,
|
rows: number,
|
||||||
@ITerminalService private readonly _terminalService: ITerminalService
|
configHelper: ITerminalConfigHelper,
|
||||||
|
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||||
|
@IRemoteAgentService readonly remoteAgentService: IRemoteAgentService
|
||||||
) {
|
) {
|
||||||
this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows);
|
remoteAgentService.getEnvironment().then(env => {
|
||||||
setTimeout(() => this._onProcessTitleChanged.fire('Starting...'), 0);
|
if (!env) {
|
||||||
|
throw new Error('Could not fetch environment');
|
||||||
|
}
|
||||||
|
this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper.checkWorkspaceShellPermissions(env.os));
|
||||||
|
});
|
||||||
|
if (!hasReceivedResponse) {
|
||||||
|
setTimeout(() => this._onProcessTitleChanged.fire(nls.localize('terminal.integrated.starting', "Starting...")), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
@@ -59,6 +72,7 @@ export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerm
|
|||||||
}
|
}
|
||||||
|
|
||||||
public emitTitle(title: string): void {
|
public emitTitle(title: string): void {
|
||||||
|
// hasReceivedResponse = true;
|
||||||
this._onProcessTitleChanged.fire(title);
|
this._onProcessTitleChanged.fire(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ export abstract class TerminalService implements ITerminalService {
|
|||||||
return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction);
|
return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number): void {
|
public requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void {
|
||||||
this._extensionService.whenInstalledExtensionsRegistered().then(async () => {
|
this._extensionService.whenInstalledExtensionsRegistered().then(async () => {
|
||||||
// Wait for the remoteAuthority to be ready (and listening for events) before proceeding
|
// Wait for the remoteAuthority to be ready (and listening for events) before proceeding
|
||||||
const conn = this._remoteAgentService.getConnection();
|
const conn = this._remoteAgentService.getConnection();
|
||||||
@@ -127,7 +127,7 @@ export abstract class TerminalService implements ITerminalService {
|
|||||||
while (!this._extHostsReady[remoteAuthority] && ++retries < 50) {
|
while (!this._extHostsReady[remoteAuthority] && ++retries < 50) {
|
||||||
await timeout(100);
|
await timeout(100);
|
||||||
}
|
}
|
||||||
this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows });
|
this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -234,8 +234,8 @@ CommandsRegistry.registerCommand('_workbench.captureSyntaxTokens', function (acc
|
|||||||
let fileName = basename(resource);
|
let fileName = basename(resource);
|
||||||
let snapper = accessor.get(IInstantiationService).createInstance(Snapper);
|
let snapper = accessor.get(IInstantiationService).createInstance(Snapper);
|
||||||
|
|
||||||
return fileService.resolveContent(resource).then(content => {
|
return fileService.readFile(resource).then(content => {
|
||||||
return snapper.captureSyntaxTokens(fileName, content.value);
|
return snapper.captureSyntaxTokens(fileName, content.value.toString());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import * as modes from 'vs/editor/common/modes';
|
|||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||||
@@ -118,7 +118,7 @@ class WebviewProtocolProvider extends Disposable {
|
|||||||
private readonly _extensionLocation: URI | undefined,
|
private readonly _extensionLocation: URI | undefined,
|
||||||
private readonly _getLocalResourceRoots: () => ReadonlyArray<URI>,
|
private readonly _getLocalResourceRoots: () => ReadonlyArray<URI>,
|
||||||
private readonly _environmentService: IEnvironmentService,
|
private readonly _environmentService: IEnvironmentService,
|
||||||
private readonly _fileService: IFileService,
|
private readonly _textFileService: ITextFileService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -137,11 +137,11 @@ class WebviewProtocolProvider extends Disposable {
|
|||||||
|
|
||||||
const appRootUri = URI.file(this._environmentService.appRoot);
|
const appRootUri = URI.file(this._environmentService.appRoot);
|
||||||
|
|
||||||
registerFileProtocol(contents, WebviewProtocol.CoreResource, this._fileService, undefined, () => [
|
registerFileProtocol(contents, WebviewProtocol.CoreResource, this._textFileService, undefined, () => [
|
||||||
appRootUri
|
appRootUri
|
||||||
]);
|
]);
|
||||||
|
|
||||||
registerFileProtocol(contents, WebviewProtocol.VsCodeResource, this._fileService, this._extensionLocation, () =>
|
registerFileProtocol(contents, WebviewProtocol.VsCodeResource, this._textFileService, this._extensionLocation, () =>
|
||||||
this._getLocalResourceRoots()
|
this._getLocalResourceRoots()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -374,7 +374,7 @@ export class WebviewElement extends Disposable implements Webview {
|
|||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
@IThemeService themeService: IThemeService,
|
@IThemeService themeService: IThemeService,
|
||||||
@IEnvironmentService environmentService: IEnvironmentService,
|
@IEnvironmentService environmentService: IEnvironmentService,
|
||||||
@IFileService fileService: IFileService,
|
@ITextFileService textFileService: ITextFileService,
|
||||||
@ITunnelService tunnelService: ITunnelService,
|
@ITunnelService tunnelService: ITunnelService,
|
||||||
@ITelemetryService telemetryService: ITelemetryService,
|
@ITelemetryService telemetryService: ITelemetryService,
|
||||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||||
@@ -412,7 +412,7 @@ export class WebviewElement extends Disposable implements Webview {
|
|||||||
this._options.extension ? this._options.extension.location : undefined,
|
this._options.extension ? this._options.extension.location : undefined,
|
||||||
() => (this._contentOptions.localResourceRoots || []),
|
() => (this._contentOptions.localResourceRoots || []),
|
||||||
environmentService,
|
environmentService,
|
||||||
fileService));
|
textFileService));
|
||||||
|
|
||||||
this._register(new WebviewPortMappingProvider(
|
this._register(new WebviewPortMappingProvider(
|
||||||
session,
|
session,
|
||||||
|
|||||||
@@ -6,16 +6,16 @@ import { getMediaMime, MIME_UNKNOWN } from 'vs/base/common/mime';
|
|||||||
import { extname, sep } from 'vs/base/common/path';
|
import { extname, sep } from 'vs/base/common/path';
|
||||||
import { startsWith } from 'vs/base/common/strings';
|
import { startsWith } from 'vs/base/common/strings';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
|
||||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||||
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
|
||||||
export const enum WebviewProtocol {
|
export const enum WebviewProtocol {
|
||||||
CoreResource = 'vscode-core-resource',
|
CoreResource = 'vscode-core-resource',
|
||||||
VsCodeResource = 'vscode-resource',
|
VsCodeResource = 'vscode-resource',
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveContent(fileService: IFileService, resource: URI, mime: string, callback: any): void {
|
function resolveContent(textFileService: ITextFileService, resource: URI, mime: string, callback: any): void {
|
||||||
fileService.resolveContent(resource, { encoding: 'binary' }).then(contents => {
|
textFileService.read(resource, { encoding: 'binary' }).then(contents => {
|
||||||
callback({
|
callback({
|
||||||
data: Buffer.from(contents.value, contents.encoding),
|
data: Buffer.from(contents.value, contents.encoding),
|
||||||
mimeType: mime
|
mimeType: mime
|
||||||
@@ -29,7 +29,7 @@ function resolveContent(fileService: IFileService, resource: URI, mime: string,
|
|||||||
export function registerFileProtocol(
|
export function registerFileProtocol(
|
||||||
contents: Electron.WebContents,
|
contents: Electron.WebContents,
|
||||||
protocol: WebviewProtocol,
|
protocol: WebviewProtocol,
|
||||||
fileService: IFileService,
|
textFileService: ITextFileService,
|
||||||
extensionLocation: URI | undefined,
|
extensionLocation: URI | undefined,
|
||||||
getRoots: () => ReadonlyArray<URI>
|
getRoots: () => ReadonlyArray<URI>
|
||||||
) {
|
) {
|
||||||
@@ -44,7 +44,7 @@ export function registerFileProtocol(
|
|||||||
requestResourcePath: requestUri.path
|
requestResourcePath: requestUri.path
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
resolveContent(fileService, redirectedUri, getMimeType(requestUri), callback);
|
resolveContent(textFileService, redirectedUri, getMimeType(requestUri), callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ export function registerFileProtocol(
|
|||||||
const normalizedPath = URI.file(requestPath);
|
const normalizedPath = URI.file(requestPath);
|
||||||
for (const root of getRoots()) {
|
for (const root of getRoots()) {
|
||||||
if (startsWith(normalizedPath.fsPath, root.fsPath + sep)) {
|
if (startsWith(normalizedPath.fsPath, root.fsPath + sep)) {
|
||||||
resolveContent(fileService, normalizedPath, getMimeType(normalizedPath), callback);
|
resolveContent(textFileService, normalizedPath, getMimeType(normalizedPath), callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export class WalkThroughContentProvider implements ITextModelContentProvider, IW
|
|||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}) : this.textFileService.resolve(URI.file(resource.fsPath)).then(content => content.value));
|
}) : this.textFileService.readStream(URI.file(resource.fsPath)).then(content => content.value));
|
||||||
return content.then(content => {
|
return content.then(content => {
|
||||||
let codeEditorModel = this.modelService.getModel(resource);
|
let codeEditorModel = this.modelService.getModel(resource);
|
||||||
if (!codeEditorModel) {
|
if (!codeEditorModel) {
|
||||||
@@ -61,7 +61,7 @@ export class WalkThroughSnippetContentProvider implements ITextModelContentProvi
|
|||||||
}
|
}
|
||||||
|
|
||||||
public provideTextContent(resource: URI): Promise<ITextModel> {
|
public provideTextContent(resource: URI): Promise<ITextModel> {
|
||||||
return this.textFileService.resolve(URI.file(resource.fsPath)).then(content => {
|
return this.textFileService.readStream(URI.file(resource.fsPath)).then(content => {
|
||||||
let codeEditorModel = this.modelService.getModel(resource);
|
let codeEditorModel = this.modelService.getModel(resource);
|
||||||
if (!codeEditorModel) {
|
if (!codeEditorModel) {
|
||||||
const j = parseInt(resource.fragment);
|
const j = parseInt(resource.fragment);
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-brow
|
|||||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||||
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
import { FileService2 } from 'vs/workbench/services/files2/common/fileService2';
|
import { FileService } from 'vs/workbench/services/files/common/fileService';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { DiskFileSystemProvider } from 'vs/workbench/services/files2/electron-browser/diskFileSystemProvider';
|
import { DiskFileSystemProvider } from 'vs/workbench/services/files/electron-browser/diskFileSystemProvider';
|
||||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel';
|
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel';
|
||||||
import { DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationExportHelper';
|
import { DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationExportHelper';
|
||||||
@@ -190,7 +190,7 @@ class CodeRendererMain extends Disposable {
|
|||||||
serviceCollection.set(IRemoteAgentService, remoteAgentService);
|
serviceCollection.set(IRemoteAgentService, remoteAgentService);
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
const fileService = this._register(new FileService2(logService));
|
const fileService = this._register(new FileService(logService));
|
||||||
serviceCollection.set(IFileService, fileService);
|
serviceCollection.set(IFileService, fileService);
|
||||||
|
|
||||||
const diskFileSystemProvider = this._register(new DiskFileSystemProvider(logService));
|
const diskFileSystemProvider = this._register(new DiskFileSystemProvider(logService));
|
||||||
@@ -295,9 +295,9 @@ class CodeRendererMain extends Disposable {
|
|||||||
}, error => onUnexpectedError(error));
|
}, error => onUnexpectedError(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService2, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
|
private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
|
||||||
const configurationFileService = new ConfigurationFileService();
|
const configurationFileService = new ConfigurationFileService();
|
||||||
fileService.whenReady.then(() => configurationFileService.fileService = fileService);
|
configurationFileService.fileService = fileService;
|
||||||
|
|
||||||
const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService);
|
const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService);
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,10 @@
|
|||||||
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IResolveContentOptions, ITextSnapshot } from 'vs/platform/files/common/files';
|
import { ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model';
|
||||||
import { ITextBufferFactory } from 'vs/editor/common/model';
|
|
||||||
|
|
||||||
export const IBackupFileService = createDecorator<IBackupFileService>('backupFileService');
|
export const IBackupFileService = createDecorator<IBackupFileService>('backupFileService');
|
||||||
|
|
||||||
export const BACKUP_FILE_RESOLVE_OPTIONS: IResolveContentOptions = { acceptTextOnly: true, encoding: 'utf8' };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service that handles any I/O and state associated with the backup system.
|
* A service that handles any I/O and state associated with the backup system.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,15 +8,17 @@ import * as crypto from 'crypto';
|
|||||||
import * as pfs from 'vs/base/node/pfs';
|
import * as pfs from 'vs/base/node/pfs';
|
||||||
import { URI as Uri } from 'vs/base/common/uri';
|
import { URI as Uri } from 'vs/base/common/uri';
|
||||||
import { ResourceQueue } from 'vs/base/common/async';
|
import { ResourceQueue } from 'vs/base/common/async';
|
||||||
import { IBackupFileService, BACKUP_FILE_RESOLVE_OPTIONS } from 'vs/workbench/services/backup/common/backup';
|
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||||
import { IFileService, ITextSnapshot, TextSnapshotReadable } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { readToMatchingString } from 'vs/base/node/stream';
|
import { readToMatchingString } from 'vs/base/node/stream';
|
||||||
import { ITextBufferFactory } from 'vs/editor/common/model';
|
import { ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model';
|
||||||
import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
||||||
import { keys } from 'vs/base/common/map';
|
import { keys } from 'vs/base/common/map';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
|
import { TextSnapshotReadable } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
|
||||||
export interface IBackupFilesModel {
|
export interface IBackupFilesModel {
|
||||||
resolve(backupRoot: string): Promise<IBackupFilesModel>;
|
resolve(backupRoot: string): Promise<IBackupFilesModel>;
|
||||||
@@ -249,19 +251,21 @@ class BackupFileServiceImpl implements IBackupFileService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resolveBackupContent(backup: Uri): Promise<ITextBufferFactory> {
|
resolveBackupContent(backup: Uri): Promise<ITextBufferFactory> {
|
||||||
return this.fileService.resolveStreamContent(backup, BACKUP_FILE_RESOLVE_OPTIONS).then(content => {
|
return this.fileService.readFileStream(backup).then(content => {
|
||||||
|
|
||||||
// Add a filter method to filter out everything until the meta marker
|
// Add a filter method to filter out everything until the meta marker
|
||||||
let metaFound = false;
|
let metaFound = false;
|
||||||
const metaPreambleFilter = (chunk: string) => {
|
const metaPreambleFilter = (chunk: VSBuffer) => {
|
||||||
|
const chunkString = chunk.toString();
|
||||||
|
|
||||||
if (!metaFound && chunk) {
|
if (!metaFound && chunk) {
|
||||||
const metaIndex = chunk.indexOf(BackupFileServiceImpl.META_MARKER);
|
const metaIndex = chunkString.indexOf(BackupFileServiceImpl.META_MARKER);
|
||||||
if (metaIndex === -1) {
|
if (metaIndex === -1) {
|
||||||
return ''; // meta not yet found, return empty string
|
return VSBuffer.fromString(''); // meta not yet found, return empty string
|
||||||
}
|
}
|
||||||
|
|
||||||
metaFound = true;
|
metaFound = true;
|
||||||
return chunk.substr(metaIndex + 1); // meta found, return everything after
|
return VSBuffer.fromString(chunkString.substr(metaIndex + 1)); // meta found, return everything after
|
||||||
}
|
}
|
||||||
|
|
||||||
return chunk;
|
return chunk;
|
||||||
|
|||||||
@@ -12,20 +12,17 @@ import * as path from 'vs/base/common/path';
|
|||||||
import * as pfs from 'vs/base/node/pfs';
|
import * as pfs from 'vs/base/node/pfs';
|
||||||
import { URI as Uri } from 'vs/base/common/uri';
|
import { URI as Uri } from 'vs/base/common/uri';
|
||||||
import { BackupFileService, BackupFilesModel, hashPath } from 'vs/workbench/services/backup/node/backupFileService';
|
import { BackupFileService, BackupFilesModel, hashPath } from 'vs/workbench/services/backup/node/backupFileService';
|
||||||
import { LegacyFileService } from 'vs/workbench/services/files/node/fileService';
|
|
||||||
import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
||||||
import { TestContextService, TestTextResourceConfigurationService, TestEnvironmentService } from 'vs/workbench/test/workbenchTestServices';
|
|
||||||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||||
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
|
||||||
import { DefaultEndOfLine } from 'vs/editor/common/model';
|
import { DefaultEndOfLine } from 'vs/editor/common/model';
|
||||||
import { snapshotToString } from 'vs/platform/files/common/files';
|
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
|
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
|
||||||
import { FileService2 } from 'vs/workbench/services/files2/common/fileService2';
|
import { FileService } from 'vs/workbench/services/files/common/fileService';
|
||||||
import { NullLogService } from 'vs/platform/log/common/log';
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
import { DiskFileSystemProvider } from 'vs/workbench/services/files2/node/diskFileSystemProvider';
|
import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider';
|
||||||
import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService';
|
import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService';
|
||||||
import { parseArgs } from 'vs/platform/environment/node/argv';
|
import { parseArgs } from 'vs/platform/environment/node/argv';
|
||||||
|
import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
|
||||||
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice');
|
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice');
|
||||||
const backupHome = path.join(parentDir, 'Backups');
|
const backupHome = path.join(parentDir, 'Backups');
|
||||||
@@ -58,14 +55,8 @@ class TestBackupEnvironmentService extends WorkbenchEnvironmentService {
|
|||||||
|
|
||||||
class TestBackupFileService extends BackupFileService {
|
class TestBackupFileService extends BackupFileService {
|
||||||
constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) {
|
constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) {
|
||||||
const fileService = new FileService2(new NullLogService());
|
const fileService = new FileService(new NullLogService());
|
||||||
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
|
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
|
||||||
fileService.setLegacyService(new LegacyFileService(
|
|
||||||
fileService,
|
|
||||||
new TestContextService(new Workspace(workspace.fsPath, toWorkspaceFolders([{ path: workspace.fsPath }]))),
|
|
||||||
TestEnvironmentService,
|
|
||||||
new TestTextResourceConfigurationService(),
|
|
||||||
));
|
|
||||||
const environmentService = new TestBackupEnvironmentService(workspaceBackupPath);
|
const environmentService = new TestBackupEnvironmentService(workspaceBackupPath);
|
||||||
|
|
||||||
super(environmentService, fileService);
|
super(environmentService, fileService);
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ export class UserConfiguration extends Disposable {
|
|||||||
|
|
||||||
async reload(): Promise<ConfigurationModel> {
|
async reload(): Promise<ConfigurationModel> {
|
||||||
try {
|
try {
|
||||||
const content = await this.configurationFileService.resolveContent(this.configurationResource);
|
const content = await this.configurationFileService.readFile(this.configurationResource);
|
||||||
this.parser.parseContent(content);
|
this.parser.parseContent(content);
|
||||||
return this.parser.configurationModel;
|
return this.parser.configurationModel;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -379,7 +379,7 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork
|
|||||||
}
|
}
|
||||||
let contents = '';
|
let contents = '';
|
||||||
try {
|
try {
|
||||||
contents = await this.configurationFileService.resolveContent(this._workspaceIdentifier.configPath);
|
contents = await this.configurationFileService.readFile(this._workspaceIdentifier.configPath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const exists = await this.configurationFileService.exists(this._workspaceIdentifier.configPath);
|
const exists = await this.configurationFileService.exists(this._workspaceIdentifier.configPath);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
@@ -547,7 +547,7 @@ class FileServiceBasedFolderConfiguration extends Disposable implements IFolderC
|
|||||||
async loadConfiguration(): Promise<ConfigurationModel> {
|
async loadConfiguration(): Promise<ConfigurationModel> {
|
||||||
const configurationContents = await Promise.all(this.configurationResources.map(async resource => {
|
const configurationContents = await Promise.all(this.configurationResources.map(async resource => {
|
||||||
try {
|
try {
|
||||||
return await this.configurationFileService.resolveContent(resource);
|
return await this.configurationFileService.readFile(resource);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const exists = await this.configurationFileService.exists(resource);
|
const exists = await this.configurationFileService.exists(resource);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user