mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Merge branch 'master' of https://github.com/Microsoft/TypeScript into for-ofES5
This commit is contained in:
commit
1349a196a0
@ -1600,16 +1600,16 @@ module ts {
|
||||
var emitLeadingCommentsOfPosition = compilerOptions.removeComments ? (pos: number) => { } : emitLeadingCommentsOfLocalPosition;
|
||||
|
||||
var detachedCommentsInfo: { nodePos: number; detachedCommentEndPos: number }[];
|
||||
|
||||
/** Emit detached comments of the node */
|
||||
var emitDetachedComments = compilerOptions.removeComments ? (node: TextRange) => { } : emitDetachedCommentsAtPosition;
|
||||
|
||||
/** Emits /// or pinned which is comment starting with /*! comments */
|
||||
var emitPinnedOrTripleSlashComments = compilerOptions.removeComments ? (node: Node) => { } : emitPinnedOrTripleSlashCommentsOfNode;
|
||||
|
||||
var writeComment = writeCommentRange;
|
||||
|
||||
/** Emit a node */
|
||||
var emit = emitNode;
|
||||
var emitNodeWithoutSourceMap = compilerOptions.removeComments ? emitNodeWithoutSourceMapWithoutComments : emitNodeWithoutSourceMapWithComments;
|
||||
var emit = emitNodeWithoutSourceMap;
|
||||
var emitWithoutComments = emitNodeWithoutSourceMapWithoutComments;
|
||||
|
||||
/** Called just before starting emit of a node */
|
||||
var emitStart = function (node: Node) { };
|
||||
@ -2071,25 +2071,34 @@ module ts {
|
||||
sourceMapDir = getDirectoryPath(normalizePath(jsFilePath));
|
||||
}
|
||||
|
||||
function emitNodeWithMap(node: Node) {
|
||||
function emitNodeWithSourceMap(node: Node) {
|
||||
if (node) {
|
||||
if (nodeIsSynthesized(node)) {
|
||||
return emitNode(node);
|
||||
}
|
||||
if (node.kind != SyntaxKind.SourceFile) {
|
||||
recordEmitNodeStartSpan(node);
|
||||
emitNode(node);
|
||||
emitNodeWithoutSourceMap(node);
|
||||
recordEmitNodeEndSpan(node);
|
||||
}
|
||||
else {
|
||||
recordNewSourceFileStart(<SourceFile>node);
|
||||
emitNode(node);
|
||||
emitNodeWithoutSourceMap(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitNodeWithSourceMapWithoutComments(node: Node) {
|
||||
if (node) {
|
||||
recordEmitNodeStartSpan(node);
|
||||
emitNodeWithoutSourceMapWithoutComments(node);
|
||||
recordEmitNodeEndSpan(node);
|
||||
}
|
||||
}
|
||||
|
||||
writeEmittedFiles = writeJavaScriptAndSourceMapFile;
|
||||
emit = emitNodeWithMap;
|
||||
emit = emitNodeWithSourceMap;
|
||||
emitWithoutComments = emitNodeWithSourceMapWithoutComments;
|
||||
emitStart = recordEmitNodeStartSpan;
|
||||
emitEnd = recordEmitNodeEndSpan;
|
||||
emitToken = writeTextWithSpanRecord;
|
||||
@ -3058,8 +3067,10 @@ module ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function indentIfOnDifferentLines(parent: Node, node1: Node, node2: Node) {
|
||||
// Use a newline for existing code if the original had one, and we're preserving formatting.
|
||||
// Returns 'true' if the code was actually indented, false otherwise.
|
||||
// If the code is not indented, an optional valueToWriteWhenNotIndenting will be
|
||||
// emitted instead.
|
||||
function indentIfOnDifferentLines(parent: Node, node1: Node, node2: Node, valueToWriteWhenNotIndenting?: string): boolean {
|
||||
var realNodesAreOnDifferentLines = preserveNewLines && !nodeIsSynthesized(parent) && !nodeEndIsOnSameLineAsNodeStart(node1, node2);
|
||||
|
||||
// Always use a newline for synthesized code if the synthesizer desires it.
|
||||
@ -3070,8 +3081,12 @@ module ts {
|
||||
writeLine();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
else {
|
||||
if (valueToWriteWhenNotIndenting) {
|
||||
write(valueToWriteWhenNotIndenting);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function emitPropertyAccess(node: PropertyAccessExpression) {
|
||||
@ -3080,18 +3095,11 @@ module ts {
|
||||
}
|
||||
|
||||
emit(node.expression);
|
||||
|
||||
var indented = indentIfOnDifferentLines(node, node.expression, node.dotToken);
|
||||
|
||||
var indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken);
|
||||
write(".");
|
||||
|
||||
indented = indented || indentIfOnDifferentLines(node, node.dotToken, node.name);
|
||||
|
||||
var indentedAfterDot = indentIfOnDifferentLines(node, node.dotToken, node.name);
|
||||
emit(node.name);
|
||||
|
||||
if (indented) {
|
||||
decreaseIndent();
|
||||
}
|
||||
decreaseIndentIf(indentedBeforeDot, indentedAfterDot);
|
||||
}
|
||||
|
||||
function emitQualifiedName(node: QualifiedName) {
|
||||
@ -3324,33 +3332,11 @@ module ts {
|
||||
}
|
||||
else {
|
||||
emit(node.left);
|
||||
|
||||
// If there was a newline between the left side of the binary expression and the
|
||||
// operator, then try to preserve that.
|
||||
var indented1 = indentIfOnDifferentLines(node, node.left, node.operatorToken);
|
||||
|
||||
// Otherwise just emit the operator right afterwards. For everything but
|
||||
// comma, emit a space before the operator.
|
||||
if (!indented1 && node.operatorToken.kind !== SyntaxKind.CommaToken) {
|
||||
write(" ");
|
||||
}
|
||||
|
||||
var indentedBeforeOperator = indentIfOnDifferentLines(node, node.left, node.operatorToken, node.operatorToken.kind !== SyntaxKind.CommaToken ? " " : undefined);
|
||||
write(tokenToString(node.operatorToken.kind));
|
||||
|
||||
if (!indented1) {
|
||||
var indented2 = indentIfOnDifferentLines(node, node.operatorToken, node.right);
|
||||
}
|
||||
|
||||
if (!indented2) {
|
||||
write(" ");
|
||||
}
|
||||
|
||||
var indentedAfterOperator = indentIfOnDifferentLines(node, node.operatorToken, node.right, " ");
|
||||
emit(node.right);
|
||||
|
||||
// If we indented the left or the right side, then dedent now.
|
||||
if (indented1 || indented2) {
|
||||
decreaseIndent();
|
||||
}
|
||||
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3360,43 +3346,27 @@ module ts {
|
||||
|
||||
function emitConditionalExpression(node: ConditionalExpression) {
|
||||
emit(node.condition);
|
||||
var indent1 = indentIfOnDifferentLines(node, node.condition, node.questionToken);
|
||||
if (!indent1) {
|
||||
write(" ");
|
||||
}
|
||||
|
||||
var indentedBeforeQuestion = indentIfOnDifferentLines(node, node.condition, node.questionToken, " ");
|
||||
write("?");
|
||||
|
||||
if (!indent1) {
|
||||
var indent2 = indentIfOnDifferentLines(node, node.questionToken, node.whenTrue);
|
||||
}
|
||||
|
||||
if (!indent2) {
|
||||
write(" ");
|
||||
}
|
||||
|
||||
var indentedAfterQuestion = indentIfOnDifferentLines(node, node.questionToken, node.whenTrue, " ");
|
||||
emit(node.whenTrue);
|
||||
decreaseIndentIf(indentedBeforeQuestion, indentedAfterQuestion);
|
||||
var indentedBeforeColon = indentIfOnDifferentLines(node, node.whenTrue, node.colonToken, " ");
|
||||
write(":");
|
||||
var indentedAfterColon = indentIfOnDifferentLines(node, node.colonToken, node.whenFalse, " ");
|
||||
emit(node.whenFalse);
|
||||
decreaseIndentIf(indentedBeforeColon, indentedAfterColon);
|
||||
}
|
||||
|
||||
if (indent1 || indent2) {
|
||||
// Helper function to decrease the indent if we previously indented. Allows multiple
|
||||
// previous indent values to be considered at a time. This also allows caller to just
|
||||
// call this once, passing in all their appropriate indent values, instead of needing
|
||||
// to call this helper function multiple times.
|
||||
function decreaseIndentIf(value1: boolean, value2?: boolean) {
|
||||
if (value1) {
|
||||
decreaseIndent();
|
||||
}
|
||||
|
||||
var indent3 = indentIfOnDifferentLines(node, node.whenTrue, node.colonToken);
|
||||
if (!indent3) {
|
||||
write(" ");
|
||||
}
|
||||
|
||||
write(":");
|
||||
if (!indent3) {
|
||||
var indent4 = indentIfOnDifferentLines(node, node.colonToken, node.whenFalse);
|
||||
}
|
||||
|
||||
if (!indent4) {
|
||||
write(" ");
|
||||
}
|
||||
|
||||
emit(node.whenFalse);
|
||||
if (indent3 || indent4) {
|
||||
if (value2) {
|
||||
decreaseIndent();
|
||||
}
|
||||
}
|
||||
@ -3839,7 +3809,7 @@ module ts {
|
||||
emitContainingModuleName(node);
|
||||
write(".");
|
||||
}
|
||||
emitNode(node.name);
|
||||
emitNodeWithoutSourceMap(node.name);
|
||||
emitEnd(node.name);
|
||||
}
|
||||
|
||||
@ -3858,10 +3828,10 @@ module ts {
|
||||
emitStart(specifier.name);
|
||||
emitContainingModuleName(specifier);
|
||||
write(".");
|
||||
emitNode(specifier.name);
|
||||
emitNodeWithoutSourceMap(specifier.name);
|
||||
emitEnd(specifier.name);
|
||||
write(" = ");
|
||||
emitNode(name);
|
||||
emitNodeWithoutSourceMap(name);
|
||||
write(";");
|
||||
});
|
||||
}
|
||||
@ -4267,14 +4237,14 @@ module ts {
|
||||
writeLine();
|
||||
emitStart(p);
|
||||
write("if (");
|
||||
emitNode(p.name);
|
||||
emitNodeWithoutSourceMap(p.name);
|
||||
write(" === void 0)");
|
||||
emitEnd(p);
|
||||
write(" { ");
|
||||
emitStart(p);
|
||||
emitNode(p.name);
|
||||
emitNodeWithoutSourceMap(p.name);
|
||||
write(" = ");
|
||||
emitNode(p.initializer);
|
||||
emitNodeWithoutSourceMap(p.initializer);
|
||||
emitEnd(p);
|
||||
write("; }");
|
||||
}
|
||||
@ -4291,7 +4261,7 @@ module ts {
|
||||
emitLeadingComments(restParam);
|
||||
emitStart(restParam);
|
||||
write("var ");
|
||||
emitNode(restParam.name);
|
||||
emitNodeWithoutSourceMap(restParam.name);
|
||||
write(" = [];");
|
||||
emitEnd(restParam);
|
||||
emitTrailingComments(restParam);
|
||||
@ -4312,7 +4282,7 @@ module ts {
|
||||
increaseIndent();
|
||||
writeLine();
|
||||
emitStart(restParam);
|
||||
emitNode(restParam.name);
|
||||
emitNodeWithoutSourceMap(restParam.name);
|
||||
write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];");
|
||||
emitEnd(restParam);
|
||||
decreaseIndent();
|
||||
@ -4333,7 +4303,7 @@ module ts {
|
||||
|
||||
function emitDeclarationName(node: Declaration) {
|
||||
if (node.name) {
|
||||
emitNode(node.name);
|
||||
emitNodeWithoutSourceMap(node.name);
|
||||
}
|
||||
else {
|
||||
write(resolver.getGeneratedNameForNode(node));
|
||||
@ -4494,7 +4464,7 @@ module ts {
|
||||
|
||||
// Don't emit comments on this body. We'll have already taken care of it above
|
||||
// when we called emitDetachedComments.
|
||||
emitNode(body, /*disableComments:*/ true);
|
||||
emitWithoutComments(body);
|
||||
emitEnd(body);
|
||||
write(";");
|
||||
emitTempDeclarations(/*newLine*/ false);
|
||||
@ -4505,7 +4475,10 @@ module ts {
|
||||
writeLine();
|
||||
emitLeadingComments(node.body);
|
||||
write("return ");
|
||||
emit(node.body, /*disableComments:*/ true);
|
||||
|
||||
// Don't emit comments on this body. We'll have already taken care of it above
|
||||
// when we called emitDetachedComments.
|
||||
emitWithoutComments(node.body);
|
||||
write(";");
|
||||
emitTrailingComments(node.body);
|
||||
|
||||
@ -4583,7 +4556,7 @@ module ts {
|
||||
emitStart(param);
|
||||
emitStart(param.name);
|
||||
write("this.");
|
||||
emitNode(param.name);
|
||||
emitNodeWithoutSourceMap(param.name);
|
||||
emitEnd(param.name);
|
||||
write(" = ");
|
||||
emit(param.name);
|
||||
@ -4597,7 +4570,7 @@ module ts {
|
||||
// TODO: (jfreeman,drosen): comment on why this is emitNode instead of emit here.
|
||||
if (memberName.kind === SyntaxKind.StringLiteral || memberName.kind === SyntaxKind.NumericLiteral) {
|
||||
write("[");
|
||||
emitNode(memberName);
|
||||
emitNodeWithoutSourceMap(memberName);
|
||||
write("]");
|
||||
}
|
||||
else if (memberName.kind === SyntaxKind.ComputedPropertyName) {
|
||||
@ -4605,7 +4578,7 @@ module ts {
|
||||
}
|
||||
else {
|
||||
write(".");
|
||||
emitNode(memberName);
|
||||
emitNodeWithoutSourceMap(memberName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5098,11 +5071,11 @@ module ts {
|
||||
emitStart(specifier);
|
||||
emitContainingModuleName(specifier);
|
||||
write(".");
|
||||
emitNode(specifier.name);
|
||||
emitNodeWithoutSourceMap(specifier.name);
|
||||
write(" = ");
|
||||
write(generatedName);
|
||||
write(".");
|
||||
emitNode(specifier.propertyName || specifier.name);
|
||||
emitNodeWithoutSourceMap(specifier.propertyName || specifier.name);
|
||||
write(";");
|
||||
emitEnd(specifier);
|
||||
});
|
||||
@ -5366,7 +5339,7 @@ module ts {
|
||||
emitLeadingComments(node.endOfFileToken);
|
||||
}
|
||||
|
||||
function emitNode(node: Node, disableComments?:boolean): void {
|
||||
function emitNodeWithoutSourceMapWithComments(node: Node): void {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
@ -5375,7 +5348,7 @@ module ts {
|
||||
return emitPinnedOrTripleSlashComments(node);
|
||||
}
|
||||
|
||||
var emitComments = !disableComments && shouldEmitLeadingAndTrailingComments(node);
|
||||
var emitComments = shouldEmitLeadingAndTrailingComments(node);
|
||||
if (emitComments) {
|
||||
emitLeadingComments(node);
|
||||
}
|
||||
@ -5387,6 +5360,18 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitNodeWithoutSourceMapWithoutComments(node: Node): void {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.flags & NodeFlags.Ambient) {
|
||||
return emitPinnedOrTripleSlashComments(node);
|
||||
}
|
||||
|
||||
emitJavaScriptWorker(node);
|
||||
}
|
||||
|
||||
function shouldEmitLeadingAndTrailingComments(node: Node) {
|
||||
switch (node.kind) {
|
||||
// All of these entities are emitted in a specialized fashion. As such, we allow
|
||||
@ -5681,7 +5666,8 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitPinnedOrTripleSlashCommentsOfNode(node: Node) {
|
||||
/** Emits /// or pinned which is comment starting with /*! comments */
|
||||
function emitPinnedOrTripleSlashComments(node: Node) {
|
||||
var pinnedComments = ts.filter(getLeadingCommentsToEmit(node), isPinnedOrTripleSlashComment);
|
||||
|
||||
function isPinnedOrTripleSlashComment(comment: CommentRange) {
|
||||
|
||||
@ -152,7 +152,6 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
if (this.errors) {
|
||||
Harness.Baseline.runBaseline('Correct errors for ' + fileName, justName.replace(/\.ts$/, '.errors.txt'), (): string => {
|
||||
if (result.errors.length === 0) return null;
|
||||
|
||||
return getErrorBaseline(toBeCompiled, otherFiles, result);
|
||||
});
|
||||
}
|
||||
|
||||
@ -835,7 +835,7 @@ module Harness {
|
||||
// Register input files
|
||||
function register(file: { unitName: string; content: string; }) {
|
||||
if (file.content !== undefined) {
|
||||
var fileName = ts.normalizeSlashes(file.unitName);
|
||||
var fileName = ts.normalizePath(file.unitName);
|
||||
filemap[getCanonicalFileName(fileName)] = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget);
|
||||
}
|
||||
};
|
||||
@ -844,6 +844,7 @@ module Harness {
|
||||
return {
|
||||
getCurrentDirectory,
|
||||
getSourceFile: (fn, languageVersion) => {
|
||||
fn = ts.normalizePath(fn);
|
||||
if (Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(fn))) {
|
||||
return filemap[getCanonicalFileName(fn)];
|
||||
}
|
||||
@ -1078,16 +1079,6 @@ module Harness {
|
||||
}
|
||||
});
|
||||
|
||||
var filemap: { [name: string]: ts.SourceFile; } = {};
|
||||
var register = (file: { unitName: string; content: string; }) => {
|
||||
if (file.content !== undefined) {
|
||||
var fileName = ts.normalizeSlashes(file.unitName);
|
||||
filemap[getCanonicalFileName(fileName)] = createSourceFileAndAssertInvariants(fileName, file.content, options.target, assertInvariants);
|
||||
}
|
||||
};
|
||||
inputFiles.forEach(register);
|
||||
otherFiles.forEach(register);
|
||||
|
||||
var fileOutputs: GeneratedFile[] = [];
|
||||
|
||||
var programFiles = inputFiles.map(file => file.unitName);
|
||||
|
||||
@ -469,6 +469,7 @@ module Harness.LanguageService {
|
||||
this.writeMessage(message);
|
||||
}
|
||||
|
||||
|
||||
readFile(fileName: string): string {
|
||||
if (fileName.indexOf(Harness.Compiler.defaultLibFileName) >= 0) {
|
||||
fileName = Harness.Compiler.defaultLibFileName;
|
||||
@ -526,6 +527,15 @@ module Harness.LanguageService {
|
||||
msg(message: string) {
|
||||
return this.host.log(message);
|
||||
}
|
||||
|
||||
loggingEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
isVerbose() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
endGroup(): void {
|
||||
}
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
module ts.server {
|
||||
export interface Logger {
|
||||
close(): void;
|
||||
isVerbose(): boolean;
|
||||
loggingEnabled(): boolean;
|
||||
perftrc(s: string): void;
|
||||
info(s: string): void;
|
||||
startGroup(): void;
|
||||
@ -1071,6 +1073,7 @@ module ts.server {
|
||||
|
||||
static changeNumberThreshold = 8;
|
||||
static changeLengthThreshold = 256;
|
||||
static maxVersions = 8;
|
||||
|
||||
// REVIEW: can optimize by coalescing simple edits
|
||||
edit(pos: number, deleteLen: number, insertedText?: string) {
|
||||
@ -1131,6 +1134,13 @@ module ts.server {
|
||||
this.currentVersion = snap.version;
|
||||
this.versions[snap.version] = snap;
|
||||
this.changes = [];
|
||||
if ((this.currentVersion - this.minVersion) >= ScriptVersionCache.maxVersions) {
|
||||
var oldMin = this.minVersion;
|
||||
this.minVersion = (this.currentVersion - ScriptVersionCache.maxVersions) + 1;
|
||||
for (var j = oldMin; j < this.minVersion; j++) {
|
||||
this.versions[j] = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return snap;
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ module ts.server {
|
||||
inGroup = false;
|
||||
firstInGroup = true;
|
||||
|
||||
constructor(public logFilename: string) {
|
||||
constructor(public logFilename: string, public level: string) {
|
||||
}
|
||||
|
||||
static padStringRight(str: string, padding: string) {
|
||||
@ -51,9 +51,20 @@ module ts.server {
|
||||
this.firstInGroup = true;
|
||||
}
|
||||
|
||||
loggingEnabled() {
|
||||
return !!this.logFilename;
|
||||
}
|
||||
|
||||
isVerbose() {
|
||||
return this.loggingEnabled() && (this.level == "verbose");
|
||||
}
|
||||
|
||||
|
||||
msg(s: string, type = "Err") {
|
||||
if (this.fd < 0) {
|
||||
this.fd = fs.openSync(this.logFilename, "w");
|
||||
if (this.logFilename) {
|
||||
this.fd = fs.openSync(this.logFilename, "w");
|
||||
}
|
||||
}
|
||||
if (this.fd >= 0) {
|
||||
s = s + "\n";
|
||||
@ -173,17 +184,61 @@ module ts.server {
|
||||
});
|
||||
|
||||
rl.on('close',() => {
|
||||
this.projectService.closeLog();
|
||||
this.projectService.log("Exiting...");
|
||||
this.projectService.closeLog();
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface LogOptions {
|
||||
file?: string;
|
||||
detailLevel?: string;
|
||||
}
|
||||
|
||||
function parseLoggingEnvironmentString(logEnvStr: string): LogOptions {
|
||||
var logEnv: LogOptions = {};
|
||||
var args = logEnvStr.split(' ');
|
||||
for (var i = 0, len = args.length; i < (len - 1); i += 2) {
|
||||
var option = args[i];
|
||||
var value = args[i + 1];
|
||||
if (option && value) {
|
||||
switch (option) {
|
||||
case "-file":
|
||||
logEnv.file = value;
|
||||
break;
|
||||
case "-level":
|
||||
logEnv.detailLevel = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return logEnv;
|
||||
}
|
||||
|
||||
// TSS_LOG "{ level: "normal | verbose | terse", file?: string}"
|
||||
function createLoggerFromEnv() {
|
||||
var fileName: string = undefined;
|
||||
var detailLevel = "normal";
|
||||
var logEnvStr = process.env["TSS_LOG"];
|
||||
if (logEnvStr) {
|
||||
var logEnv = parseLoggingEnvironmentString(logEnvStr);
|
||||
if (logEnv.file) {
|
||||
fileName = logEnv.file;
|
||||
}
|
||||
else {
|
||||
fileName = __dirname + "/.log" + process.pid.toString();
|
||||
}
|
||||
if (logEnv.detailLevel) {
|
||||
detailLevel = logEnv.detailLevel;
|
||||
}
|
||||
}
|
||||
return new Logger(fileName, detailLevel);
|
||||
}
|
||||
// This places log file in the directory containing editorServices.js
|
||||
// TODO: check that this location is writable
|
||||
var logger = new Logger(__dirname + "/.log" + process.pid.toString());
|
||||
|
||||
var logger = createLoggerFromEnv();
|
||||
|
||||
// REVIEW: for now this implementation uses polling.
|
||||
// The advantage of polling is that it works reliably
|
||||
|
||||
@ -145,6 +145,9 @@ module ts.server {
|
||||
|
||||
send(msg: NodeJS._debugger.Message) {
|
||||
var json = JSON.stringify(msg);
|
||||
if (this.logger.isVerbose()) {
|
||||
this.logger.info(msg.type + ": " + json);
|
||||
}
|
||||
this.sendLineToClient('Content-Length: ' + (1 + Buffer.byteLength(json, 'utf8')) +
|
||||
'\r\n\r\n' + json);
|
||||
}
|
||||
@ -461,19 +464,49 @@ module ts.server {
|
||||
var compilerService = project.compilerService;
|
||||
var position = compilerService.host.lineColToPosition(file, line, col);
|
||||
var edits = compilerService.languageService.getFormattingEditsAfterKeystroke(file, position, key,
|
||||
compilerService.formatCodeOptions);
|
||||
compilerService.formatCodeOptions);
|
||||
// Check whether we should auto-indent. This will be when
|
||||
// the position is on a line containing only whitespace.
|
||||
// This should leave the edits returned from
|
||||
// getFormattingEditsAfterKeytroke either empty or pertaining
|
||||
// only to the previous line. If all this is true, then
|
||||
// add edits necessary to properly indent the current line.
|
||||
if ((key == "\n") && ((!edits) || (edits.length == 0) || allEditsBeforePos(edits, position))) {
|
||||
// TODO: get these options from host
|
||||
var editorOptions: ts.EditorOptions = {
|
||||
IndentSize: 4,
|
||||
TabSize: 4,
|
||||
NewLineCharacter: "\n",
|
||||
ConvertTabsToSpaces: true,
|
||||
};
|
||||
var indentPosition = compilerService.languageService.getIndentationAtPosition(file, position, editorOptions);
|
||||
var spaces = generateSpaces(indentPosition);
|
||||
if (indentPosition > 0) {
|
||||
edits.push({ span: ts.createTextSpanFromBounds(position, position), newText: spaces });
|
||||
var scriptInfo = compilerService.host.getScriptInfo(file);
|
||||
if (scriptInfo) {
|
||||
var lineInfo = scriptInfo.getLineInfo(line);
|
||||
if (lineInfo && (lineInfo.leaf) && (lineInfo.leaf.text)) {
|
||||
var lineText = lineInfo.leaf.text;
|
||||
if (lineText.search("\\S") < 0) {
|
||||
// TODO: get these options from host
|
||||
var editorOptions: ts.EditorOptions = {
|
||||
IndentSize: 4,
|
||||
TabSize: 4,
|
||||
NewLineCharacter: "\n",
|
||||
ConvertTabsToSpaces: true,
|
||||
};
|
||||
var indentPosition =
|
||||
compilerService.languageService.getIndentationAtPosition(file, position, editorOptions);
|
||||
for (var i = 0, len = lineText.length; i < len; i++) {
|
||||
if (lineText.charAt(i) == " ") {
|
||||
indentPosition--;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (indentPosition > 0) {
|
||||
var spaces = generateSpaces(indentPosition);
|
||||
edits.push({ span: ts.createTextSpanFromBounds(position, position), newText: spaces });
|
||||
}
|
||||
else if (indentPosition < 0) {
|
||||
edits.push({
|
||||
span: ts.createTextSpanFromBounds(position, position - indentPosition),
|
||||
newText: ""
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,7 +524,7 @@ module ts.server {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getCompletions(line: number, col: number, prefix: string, fileName: string): protocol.CompletionEntry[] {
|
||||
if (!prefix) {
|
||||
prefix = "";
|
||||
@ -693,6 +726,10 @@ module ts.server {
|
||||
}
|
||||
|
||||
onMessage(message: string) {
|
||||
if (this.logger.isVerbose()) {
|
||||
this.logger.info("request: " + message);
|
||||
var start = process.hrtime();
|
||||
}
|
||||
try {
|
||||
var request = <protocol.Request>JSON.parse(message);
|
||||
var response: any;
|
||||
@ -798,13 +835,23 @@ module ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.logger.isVerbose()) {
|
||||
var elapsed = process.hrtime(start);
|
||||
var seconds = elapsed[0]
|
||||
var nanoseconds = elapsed[1];
|
||||
var elapsedMs = ((1e9 * seconds) + nanoseconds)/1000000.0;
|
||||
var leader = "Elapsed time (in milliseconds)";
|
||||
if (!responseRequired) {
|
||||
leader = "Async elapsed time (in milliseconds)";
|
||||
}
|
||||
this.logger.msg(leader + ": " + elapsedMs.toFixed(4).toString(), "Perf");
|
||||
}
|
||||
if (response) {
|
||||
this.output(response, request.command, request.seq);
|
||||
}
|
||||
else if (responseRequired) {
|
||||
this.output(undefined, request.command, request.seq, "No content available.");
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
if (err instanceof OperationCanceledException) {
|
||||
// Handle cancellation exceptions
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user