Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -6,11 +6,12 @@
'use strict';
import * as fs from 'fs';
import * as path from 'path';
import { dirname, basename } from 'path';
import * as objects from 'vs/base/common/objects';
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import Event, { Emitter } from 'vs/base/common/event';
import * as json from 'vs/base/common/json';
import * as extfs from 'vs/base/node/extfs';
export interface IConfigurationChangeEvent<T> {
config: T;
@@ -49,9 +50,11 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
private timeoutHandle: NodeJS.Timer;
private disposables: IDisposable[];
private _onDidUpdateConfiguration: Emitter<IConfigurationChangeEvent<T>>;
private configName: string;
constructor(private _path: string, private options: IConfigOptions<T> = { changeBufferDelay: 0, defaultConfig: Object.create(null), onError: error => console.error(error) }) {
this.disposables = [];
this.configName = basename(this._path);
this._onDidUpdateConfiguration = new Emitter<IConfigurationChangeEvent<T>>();
this.disposables.push(this._onDidUpdateConfiguration);
@@ -121,8 +124,8 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
private registerWatcher(): void {
// Watch the parent of the path so that we detect ADD and DELETES
const parentFolder = path.dirname(this._path);
this.watch(parentFolder);
const parentFolder = dirname(this._path);
this.watch(parentFolder, true);
// Check if the path is a symlink and watch its target if so
fs.lstat(this._path, (err, stat) => {
@@ -137,20 +140,19 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
return; // path is not a valid symlink
}
this.watch(realPath);
this.watch(realPath, false);
});
}
});
}
private watch(path: string): void {
private watch(path: string, isParentFolder: boolean): void {
if (this.disposed) {
return; // avoid watchers that will never get disposed by checking for being disposed
}
try {
const watcher = fs.watch(path);
watcher.on('change', () => this.onConfigFileChange());
const watcher = extfs.watch(path, (type, file) => this.onConfigFileChange(type, file, isParentFolder));
watcher.on('error', (code, signal) => this.options.onError(`Error watching ${path} for configuration changes (${code}, ${signal})`));
this.disposables.push(toDisposable(() => {
@@ -166,7 +168,11 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
}
}
private onConfigFileChange(): void {
private onConfigFileChange(eventType: string, filename: string, isParentFolder: boolean): void {
if (isParentFolder && filename !== this.configName) {
return; // a change to a sibling file that is not our config file
}
if (this.timeoutHandle) {
global.clearTimeout(this.timeoutHandle);
this.timeoutHandle = null;

128
src/vs/base/node/console.ts Normal file
View File

@@ -0,0 +1,128 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
export interface IRemoteConsoleLog {
type: string;
severity: string;
arguments: string;
}
interface IStackArgument {
__$stack: string;
}
export interface IStackFrame {
uri: URI;
line: number;
column: number;
}
export function isRemoteConsoleLog(obj: any): obj is IRemoteConsoleLog {
const entry = obj as IRemoteConsoleLog;
return entry && typeof entry.type === 'string' && typeof entry.severity === 'string';
}
export function parse(entry: IRemoteConsoleLog): { args: any[], stack?: string } {
const args: any[] = [];
let stack: string;
// Parse Entry
try {
const parsedArguments: any[] = JSON.parse(entry.arguments);
// Check for special stack entry as last entry
const stackArgument = parsedArguments[parsedArguments.length - 1] as IStackArgument;
if (stackArgument && stackArgument.__$stack) {
parsedArguments.pop(); // stack is handled specially
stack = stackArgument.__$stack;
}
args.push(...parsedArguments);
} catch (error) {
args.push('Unable to log remote console arguments', entry.arguments);
}
return { args, stack };
}
export function getFirstFrame(entry: IRemoteConsoleLog): IStackFrame;
export function getFirstFrame(stack: string): IStackFrame;
export function getFirstFrame(arg0: IRemoteConsoleLog | string): IStackFrame {
if (typeof arg0 !== 'string') {
return getFirstFrame(parse(arg0).stack);
}
// Parse a source information out of the stack if we have one. Format can be:
// at vscode.commands.registerCommand (/Users/someone/Desktop/test-ts/out/src/extension.js:18:17)
// or
// at /Users/someone/Desktop/test-ts/out/src/extension.js:18:17
// or
// at c:\Users\someone\Desktop\end-js\extension.js:19:17
// or
// at e.$executeContributedCommand(c:\Users\someone\Desktop\end-js\extension.js:19:17)
const stack = arg0;
if (stack) {
const topFrame = stack.split('\n')[0];
// at [^\/]* => line starts with "at" followed by any character except '/' (to not capture unix paths too late)
// (?:(?:[a-zA-Z]+:)|(?:[\/])|(?:\\\\) => windows drive letter OR unix root OR unc root
// (?:.+) => simple pattern for the path, only works because of the line/col pattern after
// :(?:\d+):(?:\d+) => :line:column data
const matches = /at [^\/]*((?:(?:[a-zA-Z]+:)|(?:[\/])|(?:\\\\))(?:.+)):(\d+):(\d+)/.exec(topFrame);
if (matches && matches.length === 4) {
return {
uri: URI.file(matches[1]),
line: Number(matches[2]),
column: Number(matches[3])
} as IStackFrame;
}
}
return void 0;
}
export function log(entry: IRemoteConsoleLog, label: string): void {
const { args, stack } = parse(entry);
const isOneStringArg = typeof args[0] === 'string' && args.length === 1;
let topFrame = stack && stack.split('\n')[0];
if (topFrame) {
topFrame = `(${topFrame.trim()})`;
}
let consoleArgs = [];
// First arg is a string
if (typeof args[0] === 'string') {
if (topFrame && isOneStringArg) {
consoleArgs = [`%c[${label}] %c${args[0]} %c${topFrame}`, color('blue'), color('black'), color('grey')];
} else {
consoleArgs = [`%c[${label}] %c${args[0]}`, color('blue'), color('black'), ...args.slice(1)];
}
}
// First arg is something else, just apply all
else {
consoleArgs = [`%c[${label}]%`, color('blue'), ...args];
}
// Stack: add to args unless already aded
if (topFrame && !isOneStringArg) {
consoleArgs.push(topFrame);
}
// Log it
console[entry.severity].apply(console, consoleArgs);
}
function color(color: string): string {
return `color: ${color}`;
}

View File

@@ -32,7 +32,7 @@ export function checksum(path: string, sha1hash: string): TPromise<void> {
input.once('error', done);
input.once('end', done);
hashStream.once('error', done);
hashStream.once('data', data => done(null, data.toString('hex')));
hashStream.once('data', (data: NodeBuffer) => done(null, data.toString('hex')));
});
return promise.then(hash => {

View File

@@ -95,17 +95,12 @@ export function detectEncodingByBOM(file: string): TPromise<string> {
}
const MINIMUM_THRESHOLD = 0.2;
const IGNORE_ENCODINGS = ['ascii', 'utf-8', 'utf-16', 'utf-32'];
const MAPPED_ENCODINGS = {
'ibm866': 'cp866'
};
/**
* Guesses the encoding from buffer.
*/
export async function guessEncodingByBuffer(buffer: NodeBuffer): TPromise<string> {
const jschardet = await import('jschardet');
jschardet.Constants.MINIMUM_THRESHOLD = MINIMUM_THRESHOLD;
@@ -126,9 +121,14 @@ export async function guessEncodingByBuffer(buffer: NodeBuffer): TPromise<string
return toIconvLiteEncoding(guessed.encoding);
}
const JSCHARDET_TO_ICONV_ENCODINGS: { [name: string]: string } = {
'ibm866': 'cp866',
'big5': 'cp950'
};
function toIconvLiteEncoding(encodingName: string): string {
const normalizedEncodingName = encodingName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
const mapped = MAPPED_ENCODINGS[normalizedEncodingName];
const mapped = JSCHARDET_TO_ICONV_ENCODINGS[normalizedEncodingName];
return mapped || normalizedEncodingName;
}

View File

@@ -42,7 +42,7 @@ export function readdir(path: string, callback: (error: Error, files: string[])
}
export function mkdirp(path: string, mode: number, callback: (error: Error) => void): void {
fs.exists(path, (exists) => {
fs.exists(path, exists => {
if (exists) {
return isDirectory(path, (err: Error, itIs?: boolean) => {
if (err) {
@@ -61,7 +61,7 @@ export function mkdirp(path: string, mode: number, callback: (error: Error) => v
if (err) { callback(err); return; }
if (mode) {
fs.mkdir(path, mode, (error) => {
fs.mkdir(path, mode, error => {
if (error) {
return callback(error);
}
@@ -98,10 +98,10 @@ export function copy(source: string, target: string, callback: (error: Error) =>
copiedSources[source] = true; // remember as copied
}
mkdirp(target, stat.mode & 511, (err) => {
mkdirp(target, stat.mode & 511, err => {
readdir(source, (err, files) => {
loop(files, (file: string, clb: (error: Error, _result) => void) => {
copy(paths.join(source, file), paths.join(target, file), (error: Error) => clb(error, undefined), copiedSources);
loop(files, (file: string, clb: (error: Error, result: string[]) => void) => {
copy(paths.join(source, file), paths.join(target, file), (error: Error) => clb(error, void 0), copiedSources);
}, callback);
});
});
@@ -147,7 +147,7 @@ function pipeFs(source: string, target: string, mode: number, callback: (error:
// will fail in case any file is used by another process. fs.unlink() in node will not bail if a file unlinked is used by another process.
// However, the consequences are bad as outlined in all the related bugs from https://github.com/joyent/node/issues/7164
export function del(path: string, tmpFolder: string, callback: (error: Error) => void, done?: (error: Error) => void): void {
fs.exists(path, (exists) => {
fs.exists(path, exists => {
if (!exists) {
return callback(null);
}
@@ -173,7 +173,7 @@ export function del(path: string, tmpFolder: string, callback: (error: Error) =>
callback(null);
// do the heavy deletion outside the callers callback
rmRecursive(pathInTemp, (error) => {
rmRecursive(pathInTemp, error => {
if (error) {
console.error(error);
}
@@ -192,7 +192,7 @@ function rmRecursive(path: string, callback: (error: Error) => void): void {
return callback(new Error('Will not delete root!'));
}
fs.exists(path, (exists) => {
fs.exists(path, exists => {
if (!exists) {
callback(null);
} else {
@@ -221,7 +221,7 @@ function rmRecursive(path: string, callback: (error: Error) => void): void {
} else {
let firstError: Error = null;
let childrenLeft = children.length;
children.forEach((child) => {
children.forEach(child => {
rmRecursive(paths.join(path, child), (err: Error) => {
childrenLeft--;
if (err) {
@@ -348,13 +348,13 @@ export function writeFileAndFlush(path: string, data: string | NodeBuffer, optio
}
// It is valid to pass a fd handle to fs.writeFile() and this will keep the handle open!
fs.writeFile(fd, data, (writeError) => {
fs.writeFile(fd, data, writeError => {
if (writeError) {
return fs.close(fd, () => callback(writeError)); // still need to close the handle on error!
}
// Flush contents (not metadata) of the file to disk
fs.fdatasync(fd, (syncError) => {
fs.fdatasync(fd, (syncError: Error) => {
// In some exotic setups it is well possible that node fails to sync
// In that case we disable flushing and warn to the console
@@ -363,7 +363,7 @@ export function writeFileAndFlush(path: string, data: string | NodeBuffer, optio
canFlush = false;
}
return fs.close(fd, (closeError) => callback(closeError));
return fs.close(fd, closeError => callback(closeError));
});
});
});
@@ -450,3 +450,19 @@ export function realpath(path: string, callback: (error: Error, realpath: string
function normalizePath(path: string): string {
return strings.rtrim(paths.normalize(path), paths.sep);
}
export function watch(path: string, onChange: (type: string, path: string) => void): fs.FSWatcher {
const watcher = fs.watch(path);
watcher.on('change', (type, raw) => {
let file = raw.toString();
if (platform.isMacintosh) {
// Mac: uses NFD unicode form on disk, but we want NFC
// See also https://github.com/nodejs/node/issues/2165
file = strings.normalizeNFC(file);
}
onChange(type, file);
});
return watcher;
}

View File

@@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import * as errors from 'vs/base/common/errors';
import * as uuid from 'vs/base/common/uuid';
import { networkInterfaces } from 'os';
import { TrieMap } from 'vs/base/common/map';
import { TernarySearchTree } from 'vs/base/common/map';
// http://www.techrepublic.com/blog/data-center/mac-address-scorecard-for-common-virtual-machine-platforms/
// VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69
@@ -23,21 +23,30 @@ import { TrieMap } from 'vs/base/common/map';
// Sun xVM VirtualBox 08-00-27
export const virtualMachineHint: { value(): number } = new class {
private _virtualMachineOUIs: TrieMap<boolean>;
private _virtualMachineOUIs: TernarySearchTree<boolean>;
private _value: number;
private _isVirtualMachineMacAdress(mac: string): boolean {
if (!this._virtualMachineOUIs) {
this._virtualMachineOUIs = new TrieMap<boolean>(s => s.split(/[-:]/));
// this._virtualMachineOUIs.insert('00-00-00', true);
this._virtualMachineOUIs.insert('00-50-56', true);
this._virtualMachineOUIs.insert('00-0C-29', true);
this._virtualMachineOUIs.insert('00-05-69', true);
this._virtualMachineOUIs.insert('00-03-FF', true);
this._virtualMachineOUIs.insert('00-1C-42', true);
this._virtualMachineOUIs.insert('00-16-3E', true);
this._virtualMachineOUIs.insert('08-00-27', true);
this._virtualMachineOUIs = TernarySearchTree.forStrings<boolean>();
// dash-separated
this._virtualMachineOUIs.set('00-50-56', true);
this._virtualMachineOUIs.set('00-0C-29', true);
this._virtualMachineOUIs.set('00-05-69', true);
this._virtualMachineOUIs.set('00-03-FF', true);
this._virtualMachineOUIs.set('00-1C-42', true);
this._virtualMachineOUIs.set('00-16-3E', true);
this._virtualMachineOUIs.set('08-00-27', true);
// colon-separated
this._virtualMachineOUIs.set('00:50:56', true);
this._virtualMachineOUIs.set('00:0C:29', true);
this._virtualMachineOUIs.set('00:05:69', true);
this._virtualMachineOUIs.set('00:03:FF', true);
this._virtualMachineOUIs.set('00:1C:42', true);
this._virtualMachineOUIs.set('00:16:3E', true);
this._virtualMachineOUIs.set('08:00:27', true);
}
return this._virtualMachineOUIs.findSubstr(mac);
}

View File

@@ -56,7 +56,7 @@ const ZERO_BYTE_DETECTION_BUFFER_MAX_LEN = 512; // number of bytes to look at to
const NO_GUESS_BUFFER_MAX_LEN = 512; // when not auto guessing the encoding, small number of bytes are enough
const AUTO_GUESS_BUFFER_MAX_LEN = 512 * 8; // with auto guessing we want a lot more content to be read for guessing
function maxBufferLen(arg1?: DetectMimesOption | boolean): number {
export function maxBufferLen(arg1?: DetectMimesOption | boolean): number {
let autoGuessEncoding: boolean;
if (typeof arg1 === 'boolean') {
autoGuessEncoding = arg1;

View File

@@ -189,3 +189,24 @@ const tmpDir = os.tmpdir();
export function del(path: string, tmp = tmpDir): TPromise<void> {
return nfcall(extfs.del, path, tmp);
}
export function whenDeleted(path: string): TPromise<void> {
// Complete when wait marker file is deleted
return new TPromise<void>(c => {
let running = false;
const interval = setInterval(() => {
if (!running) {
running = true;
fs.exists(path, exists => {
running = false;
if (!exists) {
clearInterval(interval);
c(null);
}
});
}
}, 1000);
});
}

View File

@@ -46,6 +46,10 @@ function doFindFreePort(startPort: number, giveUpAfter: number, clb: (port: numb
return doFindFreePort(startPort + 1, giveUpAfter - 1, clb);
});
client.once('data', () => {
// this listener is required since node.js 8.x
});
client.once('error', (err: Error & { code?: string }) => {
dispose(client);

View File

@@ -455,7 +455,7 @@ export interface IQueuedSender {
// On Windows we always wait for the send() method to return before sending the next message
// to workaround https://github.com/nodejs/node/issues/7657 (IPC can freeze process)
export function createQueuedSender(childProcess: ChildProcess | NodeJS.Process): IQueuedSender {
let msgQueue = [];
let msgQueue: string[] = [];
let useQueue = false;
const send = function (msg: any): void {
@@ -464,7 +464,7 @@ export function createQueuedSender(childProcess: ChildProcess | NodeJS.Process):
return;
}
let result = childProcess.send(msg, error => {
let result = childProcess.send(msg, (error: Error) => {
if (error) {
console.error(error); // unlikely to happen, best we can do is log this error
}

View File

@@ -62,14 +62,14 @@ export function removePiiPaths(profile: Profile) {
}
declare interface Profiler {
startProfiling(name: string);
startProfiling(name: string): void;
stopProfiling(): Profile;
}
export declare interface Profile {
title: string;
export(callback: (err, data) => void);
delete();
export(callback: (err, data) => void): void;
delete(): void;
head: ProfileSample;
}

View File

@@ -144,7 +144,7 @@ export function asText(context: IRequestContext): TPromise<string> {
}
let buffer: string[] = [];
context.stream.on('data', d => buffer.push(d));
context.stream.on('data', (d: string) => buffer.push(d));
context.stream.on('end', () => c(buffer.join('')));
context.stream.on('error', e);
});
@@ -165,7 +165,7 @@ export function asJson<T>(context: IRequestContext): TPromise<T> {
}
const buffer: string[] = [];
context.stream.on('data', d => buffer.push(d));
context.stream.on('data', (d: string) => buffer.push(d));
context.stream.on('end', () => c(JSON.parse(buffer.join(''))));
context.stream.on('error', e);
});

View File

@@ -28,7 +28,7 @@ declare interface TickController {
export function startTimer(name: string): TickController;
export function stopTimer(name: string);
export function stopTimer(name: string): void;
export function ticks(): Tick[];