try to detect terminal encoding when reading from stdin (for #6161)

This commit is contained in:
Benjamin Pasero
2017-12-04 12:00:25 +01:00
parent 0c8542b8e4
commit 3f9b66c2cd
3 changed files with 71 additions and 3 deletions
+45
View File
@@ -8,6 +8,8 @@
import stream = require('vs/base/node/stream');
import iconv = require('iconv-lite');
import { TPromise } from 'vs/base/common/winjs.base';
import { isLinux, isMacintosh } from 'vs/base/common/platform';
import { exec } from 'child_process';
export const UTF8 = 'utf8';
export const UTF8_with_bom = 'utf8bom';
@@ -165,3 +167,46 @@ export function toCanonicalName(enc: string): string {
return enc;
}
}
export function resolveTerminalEncoding(verbose?: boolean): TPromise<string> {
let rawEncodingPromise: TPromise<string>;
// Support a global environment variable to win over other mechanics
const cliEncodingEnv = process.env['VSCODE_CLI_ENCODING'];
if (cliEncodingEnv) {
rawEncodingPromise = TPromise.as(cliEncodingEnv);
}
// Linux/Mac: use "locale charmap" command
else if (isLinux || isMacintosh) {
rawEncodingPromise = new TPromise<string>(c => {
if (verbose) {
console.log('Running "locale charmap" to detect terminal encoding...');
}
exec('locale charmap', (err, stdout, stderr) => c(stdout));
});
}
// Windows: educated guess
else {
rawEncodingPromise = TPromise.as('cp850');
}
return rawEncodingPromise.then(rawEncoding => {
if (verbose) {
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;
}
return UTF8;
});
}
@@ -8,6 +8,7 @@
import assert = require('assert');
import encoding = require('vs/base/node/encoding');
import { encodingExists } from 'vs/base/node/encoding';
suite('Encoding', () => {
test('detectBOM UTF-8', (done: (err?: any) => void) => {
@@ -54,4 +55,21 @@ suite('Encoding', () => {
done();
}, done);
});
test('resolve terminal encoding (detect)', function (done: (err?: any) => void) {
encoding.resolveTerminalEncoding().then(encoding => {
assert.ok(encodingExists(encoding));
done();
}, done);
});
test('resolve terminal encoding (environment)', function (done: (err?: any) => void) {
process.env['VSCODE_CLI_ENCODING'] = 'utf16le';
encoding.resolveTerminalEncoding().then(encoding => {
assert.ok(encodingExists(encoding));
assert.equal(encoding, 'utf16le');
done();
}, done);
});
});
+8 -3
View File
@@ -15,6 +15,8 @@ import * as os from 'os';
import * as fs from 'fs';
import { whenDeleted } from 'vs/base/node/pfs';
import { findFreePort } from 'vs/base/node/ports';
import { resolveTerminalEncoding } from 'vs/base/node/encoding';
import * as iconv from 'iconv-lite';
function shouldSpawnCliProcess(argv: ParsedArgs): boolean {
return !!argv['install-source']
@@ -93,10 +95,13 @@ export async function main(argv: string[]): TPromise<any> {
let stdinFileError: Error;
stdinFilePath = paths.join(os.tmpdir(), `stdin-${Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 6)}.txt`);
try {
const stdinFileStream = fs.createWriteStream(stdinFilePath);
resolveTerminalEncoding(verbose).done(encoding => {
// Pipe into tmp file
process.stdin.setEncoding('utf8');
process.stdin.pipe(fs.createWriteStream(stdinFilePath));
// Pipe into tmp file using terminals encoding
const converterStream = iconv.decodeStream(encoding);
process.stdin.pipe(converterStream).pipe(stdinFileStream);
});
// Make sure to open tmp file
argv.push(stdinFilePath);