Merge pull request #2258 from Microsoft/formatLine
TS Server format line fixes
This commit is contained in:
commit
5556683227
4 changed files with 140 additions and 18 deletions
|
@ -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…
Reference in a new issue