mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
1310 lines
56 KiB
TypeScript
1310 lines
56 KiB
TypeScript
/// <reference path="..\compiler\commandLineParser.ts" />
|
|
/// <reference path="..\services\services.ts" />
|
|
/// <reference path="node.d.ts" />
|
|
/// <reference path="protodef.d.ts" />
|
|
/// <reference path="editorServices.ts" />
|
|
|
|
module ts {
|
|
export interface NavigationBarItem {
|
|
displayString?: string;
|
|
docString?: string;
|
|
}
|
|
|
|
export interface System {
|
|
getModififedTime? (fileName: string): Date;
|
|
stat? (path: string, callback?: (err: any, stats: any) => any): void;
|
|
}
|
|
}
|
|
|
|
module ts.server {
|
|
var paddedLength = 8;
|
|
|
|
var typeNames = ["interface", "class", "enum", "module", "alias", "type"];
|
|
|
|
var spaceCache = [" ", " ", " ", " "];
|
|
|
|
interface StackTraceError extends Error {
|
|
stack?: string;
|
|
}
|
|
|
|
function generateSpaces(n: number): string {
|
|
if (!spaceCache[n]) {
|
|
var strBuilder = "";
|
|
for (var i = 0; i < n; i++) {
|
|
strBuilder += " ";
|
|
}
|
|
spaceCache[n] = strBuilder;
|
|
}
|
|
return spaceCache[n];
|
|
}
|
|
|
|
function isTypeName(name: string, suffix?: string) {
|
|
for (var i = 0, len = typeNames.length; i < len; i++) {
|
|
if (typeNames[i] == name) {
|
|
return true;
|
|
}
|
|
else if (suffix && ((typeNames[i] + suffix) == name)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function parseTypeName(displayParts: ts.SymbolDisplayPart[]) {
|
|
var len = displayParts.length;
|
|
for (var i = len - 1; i >= 0; i--) {
|
|
if (isTypeName(displayParts[i].kind, "Name")) {
|
|
return displayParts[i].text;
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
function findExactMatchType(items: ts.NavigateToItem[]) {
|
|
for (var i = 0, len = items.length; i < len; i++) {
|
|
var navItem = items[i];
|
|
if (navItem.matchKind == "exact") {
|
|
if (isTypeName(navItem.kind)) {
|
|
return navItem;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
interface FileStart {
|
|
file: string;
|
|
start: ILineInfo;
|
|
}
|
|
|
|
function compareNumber(a: number, b: number) {
|
|
if (a < b) {
|
|
return -1;
|
|
}
|
|
else if (a == b) {
|
|
return 0;
|
|
}
|
|
else return 1;
|
|
}
|
|
|
|
function printObject(obj: any) {
|
|
for (var p in obj) {
|
|
if (obj.hasOwnProperty(p)) {
|
|
console.log(p + ": " + obj[p]);
|
|
}
|
|
}
|
|
}
|
|
|
|
function compareFileStart(a: FileStart, b: FileStart) {
|
|
if (a.file < b.file) {
|
|
return -1;
|
|
}
|
|
else if (a.file == b.file) {
|
|
var n = compareNumber(a.start.line, b.start.line);
|
|
if (n == 0) {
|
|
return compareNumber(a.start.col, b.start.col);
|
|
}
|
|
else return n;
|
|
}
|
|
else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
function sortNavItems(items: ts.NavigateToItem[]) {
|
|
return items.sort((a, b) => {
|
|
if (a.matchKind < b.matchKind) {
|
|
return -1;
|
|
}
|
|
else if (a.matchKind == b.matchKind) {
|
|
var lowa = a.name.toLowerCase();
|
|
var lowb = b.name.toLowerCase();
|
|
if (lowa < lowb) {
|
|
return -1;
|
|
}
|
|
else if (lowa == lowb) {
|
|
return 0;
|
|
}
|
|
else {
|
|
return 1;
|
|
}
|
|
}
|
|
else {
|
|
return 1;
|
|
}
|
|
})
|
|
}
|
|
|
|
//function SourceInfo(body: NodeJS._debugger.BreakResponse) {
|
|
// var result = body.exception ? 'exception in ' : 'break in ';
|
|
|
|
// if (body.script) {
|
|
// if (body.script.name) {
|
|
// var name = body.script.name,
|
|
// dir = path.resolve() + '/';
|
|
|
|
// // Change path to relative, if possible
|
|
// if (name.indexOf(dir) === 0) {
|
|
// name = name.slice(dir.length);
|
|
// }
|
|
|
|
// result += name;
|
|
// } else {
|
|
// result += '[unnamed]';
|
|
// }
|
|
// }
|
|
// result += ':';
|
|
// result += body.sourceLine + 1;
|
|
|
|
// if (body.exception) result += '\n' + body.exception.text;
|
|
|
|
// return result;
|
|
//}
|
|
|
|
class JsDebugSession {
|
|
host = 'localhost';
|
|
port = 5858;
|
|
|
|
constructor(public client: NodeJS._debugger.Client) {
|
|
this.init();
|
|
}
|
|
|
|
cont(cb: NodeJS._debugger.RequestHandler) {
|
|
this.client.reqContinue(cb);
|
|
}
|
|
|
|
listSrc() {
|
|
this.client.reqScripts((err: any) => {
|
|
if (err) {
|
|
console.log("rscr error: " + err);
|
|
}
|
|
else {
|
|
console.log("req scripts");
|
|
for (var id in this.client.scripts) {
|
|
var script = this.client.scripts[id];
|
|
if ((typeof script === "object") && script.name) {
|
|
console.log(id + ": " + script.name);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
findScript(file: string) {
|
|
if (file) {
|
|
var script: NodeJS._debugger.ScriptDesc;
|
|
var scripts = this.client.scripts;
|
|
var keys: any[] = Object.keys(scripts);
|
|
var ambiguous = false;
|
|
for (var v = 0; v < keys.length; v++) {
|
|
var id = keys[v];
|
|
if (scripts[id] &&
|
|
scripts[id].name &&
|
|
scripts[id].name.indexOf(file) !== -1) {
|
|
if (script) {
|
|
ambiguous = true;
|
|
}
|
|
script = scripts[id];
|
|
}
|
|
}
|
|
return { script: script, ambiguous: ambiguous };
|
|
}
|
|
}
|
|
|
|
// TODO: condition
|
|
setBreakpointOnLine(line: number, file?: string) {
|
|
if (!file) {
|
|
file = this.client.currentScript;
|
|
}
|
|
var script: NodeJS._debugger.ScriptDesc;
|
|
var scriptResult = this.findScript(file);
|
|
if (scriptResult) {
|
|
if (scriptResult.ambiguous) {
|
|
// TODO: send back error
|
|
script = undefined;
|
|
}
|
|
else {
|
|
script = scriptResult.script;
|
|
}
|
|
}
|
|
// TODO: set breakpoint when script not loaded
|
|
if (script) {
|
|
var brkmsg: NodeJS._debugger.BreakpointMessageBody = {
|
|
type: 'scriptId',
|
|
target: script.id,
|
|
line: line - 1,
|
|
}
|
|
this.client.setBreakpoint(brkmsg,(err, bod) => {
|
|
// TODO: remember breakpoint
|
|
if (err) {
|
|
console.log("Error: set breakpoint: " + err);
|
|
}
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
init() {
|
|
var connectionAttempts = 0;
|
|
this.client.on('break',(res: NodeJS._debugger.Event) => {
|
|
this.handleBreak(res.body);
|
|
});
|
|
this.client.on('exception',(res: NodeJS._debugger.Event) => {
|
|
this.handleBreak(res.body);
|
|
});
|
|
this.client.on('error',() => {
|
|
setTimeout(() => {
|
|
++connectionAttempts;
|
|
this.client.connect(this.port, this.host);
|
|
}, 500);
|
|
});
|
|
this.client.once('ready',() => {
|
|
});
|
|
this.client.on('unhandledResponse',() => {
|
|
});
|
|
this.client.connect(this.port, this.host);
|
|
}
|
|
|
|
evaluate(code: string) {
|
|
var frame = this.client.currentFrame;
|
|
this.client.reqFrameEval(code, frame,(err, bod) => {
|
|
if (err) {
|
|
console.log("Error: evaluate: " + err);
|
|
return;
|
|
}
|
|
|
|
console.log("Value: " + bod.toString());
|
|
if (typeof bod === "object") {
|
|
printObject(bod);
|
|
}
|
|
|
|
// Request object by handles (and it's sub-properties)
|
|
this.client.mirrorObject(bod, 3,(err, mirror) => {
|
|
if (mirror) {
|
|
if (typeof mirror === "object") {
|
|
printObject(mirror);
|
|
}
|
|
console.log(mirror.toString());
|
|
}
|
|
else {
|
|
console.log("undefined");
|
|
}
|
|
});
|
|
|
|
});
|
|
}
|
|
|
|
handleBreak(breakInfo: NodeJS._debugger.BreakResponse) {
|
|
this.client.currentSourceLine = breakInfo.sourceLine;
|
|
this.client.currentSourceLineText = breakInfo.sourceLineText;
|
|
this.client.currentSourceColumn = breakInfo.sourceColumn;
|
|
this.client.currentFrame = 0;
|
|
this.client.currentScript = breakInfo.script && breakInfo.script.name;
|
|
|
|
//console.log(SourceInfo(breakInfo));
|
|
// TODO: watchers
|
|
}
|
|
}
|
|
|
|
interface FileRange {
|
|
file?: string;
|
|
start: ILineInfo;
|
|
end: ILineInfo;
|
|
}
|
|
|
|
interface FileRanges {
|
|
file: string;
|
|
locs: FileRange[];
|
|
}
|
|
|
|
function formatDiag(file: string, project: Project, diag: ts.Diagnostic) {
|
|
return {
|
|
start: project.compilerService.host.positionToLineCol(file, diag.start),
|
|
len: diag.length,
|
|
text: diag.messageText,
|
|
};
|
|
}
|
|
|
|
interface PendingErrorCheck {
|
|
filename: string;
|
|
project: Project;
|
|
}
|
|
|
|
function allEditsBeforePos(edits: ts.TextChange[], pos: number) {
|
|
for (var i = 0, len = edits.length; i < len; i++) {
|
|
if (ts.textSpanEnd(edits[i].span) >= pos) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
module CommandNames {
|
|
export var Abbrev = "abbrev";
|
|
export var Change = "change";
|
|
export var Close = "close";
|
|
export var Completions = "completions";
|
|
export var Definition = "definition";
|
|
export var Format = "format";
|
|
export var Formatonkey = "formatonkey";
|
|
export var Geterr = "geterr";
|
|
export var Navto = "navto";
|
|
export var Open = "open";
|
|
export var Quickinfo = "quickinfo";
|
|
export var References = "references";
|
|
export var Reload = "reload";
|
|
export var Rename = "rename";
|
|
export var Saveto = "saveto";
|
|
export var Type = "type";
|
|
export var Unknown = "unknown";
|
|
}
|
|
|
|
export interface ServerHost extends ts.System {
|
|
getDebuggerClient? (): NodeJS._debugger.Client;
|
|
}
|
|
|
|
export class Session {
|
|
projectService: ProjectService;
|
|
debugSession: JsDebugSession;
|
|
pendingOperation = false;
|
|
fileHash: ts.Map<number> = {};
|
|
abbrevTable: ts.Map<string>;
|
|
fetchedAbbrev = false;
|
|
nextFileId = 1;
|
|
errorTimer: NodeJS.Timer;
|
|
immediateId: any;
|
|
changeSeq = 0;
|
|
|
|
constructor(private host: ServerHost, private logger: Logger, protected useProtocol: boolean, protected prettyJSON: boolean) {
|
|
this.projectService = new ProjectService(host, logger);
|
|
this.initAbbrevTable();
|
|
}
|
|
|
|
logError(err: Error, cmd: string) {
|
|
var typedErr = <StackTraceError>err;
|
|
var msg = "Exception on executing command " + cmd;
|
|
if (typedErr.message) {
|
|
msg += ":\n" + typedErr.message;
|
|
if (typedErr.stack) {
|
|
msg += "\n" + typedErr.stack;
|
|
}
|
|
}
|
|
this.projectService.log(msg);
|
|
}
|
|
|
|
sendLineToClient(line: string) {
|
|
this.host.write(line + this.host.newLine);
|
|
}
|
|
|
|
send(msg: NodeJS._debugger.Message) {
|
|
var json: string;
|
|
if (this.prettyJSON) {
|
|
json = JSON.stringify(msg, null, " ");
|
|
}
|
|
else {
|
|
json = JSON.stringify(msg);
|
|
}
|
|
this.sendLineToClient('Content-Length: ' + (1 + Buffer.byteLength(json, 'utf8')) +
|
|
'\r\n\r\n' + json);
|
|
}
|
|
|
|
event(info: any, eventName: string) {
|
|
var ev: NodeJS._debugger.Event = {
|
|
seq: 0,
|
|
type: "event",
|
|
event: eventName,
|
|
body: info,
|
|
};
|
|
this.send(ev);
|
|
}
|
|
|
|
response(info: any, cmdName: string, reqSeq = 0, errorMsg?: string) {
|
|
var res: ServerProtocol.Response = {
|
|
seq: 0,
|
|
type: "response",
|
|
command: cmdName,
|
|
request_seq: reqSeq,
|
|
success: !errorMsg,
|
|
}
|
|
if (!errorMsg) {
|
|
res.body = info;
|
|
}
|
|
else {
|
|
res.message = errorMsg;
|
|
}
|
|
this.send(res);
|
|
}
|
|
|
|
initAbbrevTable() {
|
|
this.abbrevTable = {
|
|
name: "n",
|
|
kind: "k",
|
|
fileName: "f",
|
|
containerName: "cn",
|
|
containerKind: "ck",
|
|
kindModifiers: "km",
|
|
start: "s",
|
|
end: "e",
|
|
line: "l",
|
|
col: "c",
|
|
"interface": "i",
|
|
"function": "fn",
|
|
};
|
|
}
|
|
|
|
encodeFilename(filename: string): ServerProtocol.EncodedFile {
|
|
if (!this.fetchedAbbrev) {
|
|
return filename;
|
|
}
|
|
else {
|
|
var id = ts.lookUp(this.fileHash, filename);
|
|
if (!id) {
|
|
id = this.nextFileId++;
|
|
this.fileHash[filename] = id;
|
|
return { id: id, file: filename };
|
|
}
|
|
else {
|
|
return id;
|
|
}
|
|
}
|
|
}
|
|
|
|
abbreviate(obj: any) {
|
|
if (this.fetchedAbbrev && (!this.prettyJSON)) {
|
|
for (var p in obj) {
|
|
if (obj.hasOwnProperty(p)) {
|
|
var sub = ts.lookUp(this.abbrevTable, p);
|
|
if (sub) {
|
|
obj[sub] = obj[p];
|
|
obj[p] = undefined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
output(info: any, cmdName: string, reqSeq = 0, errorMsg?: string) {
|
|
if (this.useProtocol) {
|
|
this.response(info, cmdName, reqSeq, errorMsg);
|
|
}
|
|
else if (this.prettyJSON) {
|
|
if (!errorMsg) {
|
|
this.sendLineToClient(JSON.stringify(info, null, " ").trim());
|
|
}
|
|
else {
|
|
this.sendLineToClient(JSON.stringify(errorMsg));
|
|
}
|
|
} else {
|
|
if (!errorMsg) {
|
|
var infoStr = JSON.stringify(info).trim();
|
|
// [8 digits of length,infoStr] + '\n'
|
|
var len = infoStr.length + paddedLength + 4;
|
|
var lenStr = len.toString();
|
|
var padLen = paddedLength - lenStr.length;
|
|
for (var i = 0; i < padLen; i++) {
|
|
lenStr = '0' + lenStr;
|
|
}
|
|
this.sendLineToClient("[" + lenStr + "," + infoStr + "]");
|
|
}
|
|
else {
|
|
this.sendLineToClient(JSON.stringify("error: " + errorMsg));
|
|
}
|
|
}
|
|
}
|
|
|
|
semanticCheck(file: string, project: Project) {
|
|
var diags = project.compilerService.languageService.getSemanticDiagnostics(file);
|
|
if (diags) {
|
|
var bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
|
|
this.event({ file: file, diagnostics: bakedDiags }, "semanticDiag");
|
|
}
|
|
}
|
|
|
|
syntacticCheck(file: string, project: Project) {
|
|
var diags = project.compilerService.languageService.getSyntacticDiagnostics(file);
|
|
if (diags) {
|
|
var bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
|
|
this.event({ file: file, diagnostics: bakedDiags }, "syntaxDiag");
|
|
}
|
|
}
|
|
|
|
errorCheck(file: string, project: Project) {
|
|
this.syntacticCheck(file, project);
|
|
this.semanticCheck(file, project);
|
|
}
|
|
|
|
updateErrorCheck(checkList: PendingErrorCheck[], seq: number,
|
|
matchSeq: (seq: number) => boolean, ms = 1500, followMs = 200) {
|
|
if (followMs > ms) {
|
|
followMs = ms;
|
|
}
|
|
if (this.errorTimer) {
|
|
clearTimeout(this.errorTimer);
|
|
}
|
|
if (this.immediateId) {
|
|
clearImmediate(this.immediateId);
|
|
this.immediateId = undefined;
|
|
}
|
|
var index = 0;
|
|
var checkOne = () => {
|
|
if (matchSeq(seq)) {
|
|
var checkSpec = checkList[index++];
|
|
if (checkSpec.project.getSourceFileFromName(checkSpec.filename)) {
|
|
this.syntacticCheck(checkSpec.filename, checkSpec.project);
|
|
this.immediateId = setImmediate(() => {
|
|
this.semanticCheck(checkSpec.filename, checkSpec.project);
|
|
this.immediateId = undefined;
|
|
if (checkList.length > index) {
|
|
this.errorTimer = setTimeout(checkOne, followMs);
|
|
}
|
|
else {
|
|
this.errorTimer = undefined;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if ((checkList.length > index) && (matchSeq(seq))) {
|
|
this.errorTimer = setTimeout(checkOne, ms);
|
|
}
|
|
}
|
|
|
|
goToDefinition(line: number, col: number, rawfile: string, reqSeq = 0) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var pos = compilerService.host.lineColToPosition(file, line, col);
|
|
var locs = compilerService.languageService.getDefinitionAtPosition(file, pos);
|
|
if (locs) {
|
|
var info: ServerProtocol.CodeSpan[] = locs.map(def => ({
|
|
file: def && def.fileName,
|
|
start: def &&
|
|
compilerService.host.positionToLineCol(def.fileName, def.textSpan.start),
|
|
end: def &&
|
|
compilerService.host.positionToLineCol(def.fileName, ts.textSpanEnd(def.textSpan))
|
|
}));
|
|
this.output(info, CommandNames.Definition, reqSeq);
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Definition, reqSeq, "could not find def");
|
|
}
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Definition, reqSeq, "no project for " + file);
|
|
}
|
|
}
|
|
|
|
rename(line: number, col: number, rawfile: string, reqSeq = 0) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var pos = compilerService.host.lineColToPosition(file, line, col);
|
|
var renameInfo = compilerService.languageService.getRenameInfo(file, pos);
|
|
if (renameInfo) {
|
|
if (renameInfo.canRename) {
|
|
var renameLocs = compilerService.languageService.findRenameLocations(file, pos, false, false);
|
|
if (renameLocs) {
|
|
var bakedRenameLocs = renameLocs.map(loc=> ({
|
|
file: loc.fileName,
|
|
start: compilerService.host.positionToLineCol(loc.fileName, loc.textSpan.start),
|
|
end: compilerService.host.positionToLineCol(loc.fileName, ts.textSpanEnd(loc.textSpan)),
|
|
})).sort((a, b) => {
|
|
if (a.file < b.file) {
|
|
return -1;
|
|
}
|
|
else if (a.file > b.file) {
|
|
return 1;
|
|
}
|
|
else {
|
|
// reverse sort assuming no overlap
|
|
if (a.start.line < b.start.line) {
|
|
return 1;
|
|
}
|
|
else if (a.start.line > b.start.line) {
|
|
return -1;
|
|
}
|
|
else {
|
|
return b.start.col - a.start.col;
|
|
}
|
|
}
|
|
}).reduce<FileRanges[]>((accum: FileRanges[], cur: FileRange) => {
|
|
var curFileAccum: FileRanges;
|
|
if (accum.length > 0) {
|
|
curFileAccum = accum[accum.length - 1];
|
|
if (curFileAccum.file != cur.file) {
|
|
curFileAccum = undefined;
|
|
}
|
|
}
|
|
if (!curFileAccum) {
|
|
curFileAccum = { file: cur.file, locs: [] };
|
|
accum.push(curFileAccum);
|
|
}
|
|
curFileAccum.locs.push({ start: cur.start, end: cur.end });
|
|
return accum;
|
|
}, []);
|
|
this.output({ info: renameInfo, locs: bakedRenameLocs }, CommandNames.Rename, reqSeq);
|
|
}
|
|
else {
|
|
this.output({ info: renameInfo, locs: [] }, CommandNames.Rename, reqSeq);
|
|
}
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Rename, reqSeq, renameInfo.localizedErrorMessage);
|
|
}
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Rename, reqSeq, "no rename information at cursor");
|
|
}
|
|
}
|
|
}
|
|
|
|
findReferences(line: number, col: number, rawfile: string, reqSeq = 0) {
|
|
// TODO: get all projects for this file; report refs for all projects deleting duplicates
|
|
// can avoid duplicates by eliminating same ref file from subsequent projects
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var pos = compilerService.host.lineColToPosition(file, line, col);
|
|
var refs = compilerService.languageService.getReferencesAtPosition(file, pos);
|
|
if (refs) {
|
|
var nameInfo = compilerService.languageService.getQuickInfoAtPosition(file, pos);
|
|
if (nameInfo) {
|
|
var displayString = ts.displayPartsToString(nameInfo.displayParts);
|
|
var nameSpan = nameInfo.textSpan;
|
|
var nameColStart =
|
|
compilerService.host.positionToLineCol(file, nameSpan.start).col;
|
|
var nameText =
|
|
compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan));
|
|
var bakedRefs: ServerProtocol.ReferencesResponseItem[] = refs.map((ref) => {
|
|
var start = compilerService.host.positionToLineCol(ref.fileName, ref.textSpan.start);
|
|
var refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1);
|
|
var snap = compilerService.host.getScriptSnapshot(ref.fileName);
|
|
var lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
|
|
return {
|
|
file: ref.fileName,
|
|
start: start,
|
|
lineText: lineText,
|
|
end: compilerService.host.positionToLineCol(ref.fileName, ts.textSpanEnd(ref.textSpan)),
|
|
};
|
|
}).sort(compareFileStart);
|
|
var response: ServerProtocol.ReferencesResponseBody = {
|
|
refs: bakedRefs,
|
|
symbolName: nameText,
|
|
symbolStartCol: nameColStart,
|
|
symbolDisplayString: displayString
|
|
};
|
|
this.output(response, CommandNames.References, reqSeq);
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.References, reqSeq, "no references at this position");
|
|
}
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.References, reqSeq, "no references at this position");
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: implement this as ls api that can return multiple def sites
|
|
goToType(line: number, col: number, rawfile: string, reqSeq = 0) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var pos = compilerService.host.lineColToPosition(file, line, col);
|
|
var quickInfo = compilerService.languageService.getQuickInfoAtPosition(file, pos);
|
|
var typeLoc: any;
|
|
|
|
if (quickInfo && (quickInfo.kind == "var") || (quickInfo.kind == "local var")) {
|
|
var typeName = parseTypeName(quickInfo.displayParts);
|
|
if (typeName) {
|
|
var navItems = compilerService.languageService.getNavigateToItems(typeName);
|
|
var navItem = findExactMatchType(navItems);
|
|
if (navItem) {
|
|
typeLoc = {
|
|
file: navItem.fileName,
|
|
start: compilerService.host.positionToLineCol(navItem.fileName,
|
|
navItem.textSpan.start),
|
|
end: compilerService.host.positionToLineCol(navItem.fileName,
|
|
ts.textSpanEnd(navItem.textSpan)),
|
|
};
|
|
}
|
|
}
|
|
}
|
|
if (typeLoc) {
|
|
this.output([typeLoc], CommandNames.Type, reqSeq);
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Type, reqSeq, "no info at this location");
|
|
}
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Type, reqSeq, "no project for " + file);
|
|
}
|
|
}
|
|
|
|
openClientFile(rawfile: string) {
|
|
var file = ts.normalizePath(rawfile);
|
|
this.projectService.openClientFile(file);
|
|
}
|
|
|
|
quickInfo(line: number, col: number, rawfile: string, reqSeq = 0) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var pos = compilerService.host.lineColToPosition(file, line, col);
|
|
var quickInfo = compilerService.languageService.getQuickInfoAtPosition(file, pos);
|
|
if (quickInfo) {
|
|
var displayString = ts.displayPartsToString(quickInfo.displayParts);
|
|
var docString = ts.displayPartsToString(quickInfo.documentation);
|
|
var qi: ServerProtocol.QuickInfoResponseBody = {
|
|
kind: quickInfo.kind,
|
|
kindModifiers: quickInfo.kindModifiers,
|
|
start: compilerService.host.positionToLineCol(file, quickInfo.textSpan.start),
|
|
end: compilerService.host.positionToLineCol(file, ts.textSpanEnd(quickInfo.textSpan)),
|
|
displayString: displayString,
|
|
documentation: docString,
|
|
};
|
|
this.output(qi, CommandNames.Quickinfo, reqSeq);
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Quickinfo, reqSeq, "no info")
|
|
}
|
|
}
|
|
}
|
|
|
|
format(line: number, col: number, endLine: number, endCol: number, rawfile: string, cmd: string, reqSeq = 0) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var pos = compilerService.host.lineColToPosition(file, line, col);
|
|
var endPos = compilerService.host.lineColToPosition(file, endLine, endCol);
|
|
var edits: ts.TextChange[];
|
|
// TODO: avoid duplicate code (with formatonkey)
|
|
try {
|
|
edits = compilerService.languageService.getFormattingEditsForRange(file, pos, endPos,
|
|
compilerService.formatCodeOptions);
|
|
}
|
|
catch (err) {
|
|
this.logError(err, cmd);
|
|
edits = undefined;
|
|
}
|
|
if (edits) {
|
|
var bakedEdits: ServerProtocol.CodeEdit[] = edits.map((edit) => {
|
|
return {
|
|
start: compilerService.host.positionToLineCol(file,
|
|
edit.span.start),
|
|
end: compilerService.host.positionToLineCol(file,
|
|
ts.textSpanEnd(edit.span)),
|
|
newText: edit.newText ? edit.newText : ""
|
|
};
|
|
});
|
|
this.output(bakedEdits, CommandNames.Format, reqSeq);
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Format, reqSeq, "no edits")
|
|
}
|
|
}
|
|
}
|
|
|
|
formatOnKey(line: number, col: number, key: string, rawfile: string, cmd: string, reqSeq = 0) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var pos = compilerService.host.lineColToPosition(file, line, col);
|
|
var edits: ts.TextChange[];
|
|
try {
|
|
edits = compilerService.languageService.getFormattingEditsAfterKeystroke(file, pos, key,
|
|
compilerService.formatCodeOptions);
|
|
if ((key == "\n") && ((!edits) || (edits.length == 0) || allEditsBeforePos(edits, pos))) {
|
|
// TODO: get these options from host
|
|
var editorOptions: ts.EditorOptions = {
|
|
IndentSize: 4,
|
|
TabSize: 4,
|
|
NewLineCharacter: "\n",
|
|
ConvertTabsToSpaces: true,
|
|
};
|
|
var indentPosition = compilerService.languageService.getIndentationAtPosition(file, pos, editorOptions);
|
|
var spaces = generateSpaces(indentPosition);
|
|
if (indentPosition > 0) {
|
|
edits.push({ span: ts.createTextSpanFromBounds(pos, pos), newText: spaces });
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
this.logError(err, cmd);
|
|
edits = undefined;
|
|
}
|
|
if (edits) {
|
|
var bakedEdits: ServerProtocol.CodeEdit[] = edits.map((edit) => {
|
|
return {
|
|
start: compilerService.host.positionToLineCol(file,
|
|
edit.span.start),
|
|
end: compilerService.host.positionToLineCol(file,
|
|
ts.textSpanEnd(edit.span)),
|
|
newText: edit.newText ? edit.newText : ""
|
|
};
|
|
});
|
|
this.output(bakedEdits, CommandNames.Formatonkey, reqSeq);
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Formatonkey, reqSeq, "no edits")
|
|
}
|
|
}
|
|
}
|
|
|
|
completions(line: number, col: number, prefix: string, rawfile: string, cmd: string, reqSeq = 0) {
|
|
if (!prefix) {
|
|
prefix = "";
|
|
}
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
var completions: ts.CompletionInfo = undefined;
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var pos = compilerService.host.lineColToPosition(file, line, col);
|
|
if (pos >= 0) {
|
|
try {
|
|
completions = compilerService.languageService.getCompletionsAtPosition(file, pos);
|
|
}
|
|
catch (err) {
|
|
this.logError(err, cmd);
|
|
completions = undefined;
|
|
}
|
|
if (completions) {
|
|
var compressedEntries: ServerProtocol.CompletionItem[] =
|
|
completions.entries.reduce((accum: ts.CompletionEntryDetails[], entry: ts.CompletionEntry) => {
|
|
if (entry.name.indexOf(prefix) == 0) {
|
|
var protoEntry = <ts.CompletionEntryDetails>{};
|
|
protoEntry.name = entry.name;
|
|
protoEntry.kind = entry.kind;
|
|
if (entry.kindModifiers && (entry.kindModifiers.length > 0)) {
|
|
protoEntry.kindModifiers = entry.kindModifiers;
|
|
}
|
|
var details = compilerService.languageService.getCompletionEntryDetails(file, pos, entry.name);
|
|
if (details && (details.documentation) && (details.documentation.length > 0)) {
|
|
protoEntry.documentation = details.documentation;
|
|
}
|
|
if (details && (details.displayParts) && (details.displayParts.length > 0)) {
|
|
protoEntry.displayParts = details.documentation;
|
|
}
|
|
accum.push(protoEntry);
|
|
}
|
|
return accum;
|
|
}, []);
|
|
this.output(compressedEntries, CommandNames.Completions, reqSeq);
|
|
}
|
|
}
|
|
}
|
|
if (!completions) {
|
|
this.output(undefined, CommandNames.Completions, reqSeq, "no completions");
|
|
}
|
|
}
|
|
|
|
geterr(ms: number, files: string[]) {
|
|
var checkList = files.reduce((accum: PendingErrorCheck[], filename: string) => {
|
|
filename = ts.normalizePath(filename);
|
|
var project = this.projectService.getProjectForFile(filename);
|
|
if (project) {
|
|
accum.push({ filename: filename, project: project });
|
|
}
|
|
return accum;
|
|
}, []);
|
|
if (checkList.length > 0) {
|
|
this.updateErrorCheck(checkList, this.changeSeq,(n) => n == this.changeSeq, ms)
|
|
}
|
|
}
|
|
|
|
change(line: number, col: number, deleteLen: number, insertString: string, rawfile: string) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var pos = compilerService.host.lineColToPosition(file, line, col);
|
|
if (pos >= 0) {
|
|
var end = pos;
|
|
if (deleteLen) {
|
|
end += deleteLen;
|
|
}
|
|
compilerService.host.editScript(file, pos, end, insertString);
|
|
this.changeSeq++;
|
|
}
|
|
}
|
|
}
|
|
|
|
reload(rawfile: string, rawtmpfile: string, reqSeq = 0) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var tmpfile = ts.normalizePath(rawtmpfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
this.changeSeq++;
|
|
// make sure no changes happen before this one is finished
|
|
project.compilerService.host.reloadScript(file, tmpfile,() => {
|
|
this.output(undefined, CommandNames.Reload, reqSeq);
|
|
});
|
|
}
|
|
}
|
|
|
|
saveToTmp(rawfile: string, rawtmpfile: string) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var tmpfile = ts.normalizePath(rawtmpfile);
|
|
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
project.compilerService.host.saveTo(file, tmpfile);
|
|
}
|
|
}
|
|
|
|
closeClientFile(rawfile: string) {
|
|
var file = ts.normalizePath(rawfile);
|
|
this.projectService.closeClientFile(file);
|
|
}
|
|
|
|
decorateNavBarItem(navBarItem: ts.NavigationBarItem, compilerService: CompilerService, file: string) {
|
|
if (navBarItem.spans.length == 1) {
|
|
var span = navBarItem.spans[0];
|
|
var offset = span.start;
|
|
var textForSpan = compilerService.host.getScriptSnapshot(file).getText(offset, offset + span.length);
|
|
var adj = textForSpan.indexOf(navBarItem.text);
|
|
if (adj > 0) {
|
|
offset += adj;
|
|
}
|
|
var quickInfo = compilerService.languageService.getQuickInfoAtPosition(file,
|
|
offset + (navBarItem.text.length / 2));
|
|
if (quickInfo) {
|
|
var displayString = ts.displayPartsToString(quickInfo.displayParts);
|
|
var docString = ts.displayPartsToString(quickInfo.documentation);
|
|
navBarItem.displayString = displayString;
|
|
navBarItem.docString = docString;
|
|
}
|
|
}
|
|
if (navBarItem.childItems.length > 0) {
|
|
navBarItem.childItems =
|
|
navBarItem.childItems.map(navBarItem => this.decorateNavBarItem(navBarItem, compilerService, file));
|
|
}
|
|
return navBarItem;
|
|
}
|
|
|
|
navbar(rawfile: string, reqSeq = 0) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var navBarItems = compilerService.languageService.getNavigationBarItems(file);
|
|
var bakedNavBarItems = navBarItems.map(navBarItem => this.decorateNavBarItem(navBarItem, compilerService, file));
|
|
this.sendLineToClient(JSON.stringify(bakedNavBarItems, null, " "));
|
|
}
|
|
}
|
|
|
|
navto(searchTerm: string, rawfile: string, cmd: string, reqSeq = 0) {
|
|
var file = ts.normalizePath(rawfile);
|
|
var project = this.projectService.getProjectForFile(file);
|
|
if (project) {
|
|
var compilerService = project.compilerService;
|
|
var navItems: ts.NavigateToItem[];
|
|
var cancellationToken = <CancellationToken>compilerService.host.getCancellationToken();
|
|
if (this.pendingOperation) {
|
|
cancellationToken.cancel();
|
|
cancellationToken.reset();
|
|
}
|
|
try {
|
|
this.pendingOperation = true;
|
|
navItems = sortNavItems(compilerService.languageService.getNavigateToItems(searchTerm));
|
|
}
|
|
catch (err) {
|
|
this.logError(err, cmd);
|
|
navItems = undefined;
|
|
}
|
|
this.pendingOperation = false;
|
|
if (navItems) {
|
|
var bakedNavItems: ServerProtocol.NavtoItem[] = navItems.map((navItem) => {
|
|
var start = compilerService.host.positionToLineCol(navItem.fileName,
|
|
navItem.textSpan.start);
|
|
var end = compilerService.host.positionToLineCol(navItem.fileName, ts.textSpanEnd(navItem.textSpan));
|
|
this.abbreviate(start);
|
|
var bakedItem: ServerProtocol.NavtoItem = {
|
|
name: navItem.name,
|
|
kind: navItem.kind,
|
|
file: this.encodeFilename(navItem.fileName),
|
|
start: start,
|
|
end: end,
|
|
};
|
|
if (navItem.kindModifiers && (navItem.kindModifiers != "")) {
|
|
bakedItem.kindModifiers = navItem.kindModifiers;
|
|
}
|
|
if (navItem.matchKind != 'none') {
|
|
bakedItem.matchKind = navItem.matchKind;
|
|
}
|
|
if (navItem.containerName && (navItem.containerName.length > 0)) {
|
|
bakedItem.containerName = navItem.containerName;
|
|
}
|
|
if (navItem.containerKind && (navItem.containerKind.length > 0)) {
|
|
bakedItem.containerKind = navItem.containerKind;
|
|
}
|
|
this.abbreviate(bakedItem);
|
|
return bakedItem;
|
|
});
|
|
|
|
this.output(bakedNavItems, CommandNames.Navto, reqSeq);
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Navto, reqSeq, "no nav items");
|
|
}
|
|
}
|
|
}
|
|
|
|
executeJSONcmd(cmd: string) {
|
|
try {
|
|
var req = <ServerProtocol.Request>JSON.parse(cmd);
|
|
switch (req.command) {
|
|
case CommandNames.Definition: {
|
|
var defArgs = <ServerProtocol.CodeLocationRequestArgs>req.arguments;
|
|
this.goToDefinition(defArgs.line, defArgs.col, defArgs.file, req.seq);
|
|
break;
|
|
}
|
|
case CommandNames.References: {
|
|
var refArgs = <ServerProtocol.CodeLocationRequestArgs>req.arguments;
|
|
this.findReferences(refArgs.line, refArgs.col, refArgs.file, req.seq);
|
|
break;
|
|
}
|
|
case CommandNames.Rename: {
|
|
var renameArgs = <ServerProtocol.CodeLocationRequestArgs>req.arguments;
|
|
this.rename(renameArgs.line, renameArgs.col, renameArgs.file, req.seq);
|
|
break;
|
|
}
|
|
case CommandNames.Type: {
|
|
var typeArgs = <ServerProtocol.CodeLocationRequestArgs>req.arguments;
|
|
this.goToType(typeArgs.line, typeArgs.col, typeArgs.file, req.seq);
|
|
break;
|
|
}
|
|
case CommandNames.Open: {
|
|
var openArgs = <ServerProtocol.FileRequestArgs>req.arguments;
|
|
this.openClientFile(openArgs.file);
|
|
break;
|
|
}
|
|
case CommandNames.Quickinfo: {
|
|
var quickinfoArgs = <ServerProtocol.CodeLocationRequestArgs>req.arguments;
|
|
this.quickInfo(quickinfoArgs.line, quickinfoArgs.col, quickinfoArgs.file, req.seq);
|
|
break;
|
|
}
|
|
case CommandNames.Format: {
|
|
var formatArgs = <ServerProtocol.FormatRequestArgs>req.arguments;
|
|
this.format(formatArgs.line, formatArgs.col, formatArgs.endLine, formatArgs.endCol, formatArgs.file,
|
|
cmd, req.seq);
|
|
break;
|
|
}
|
|
case CommandNames.Formatonkey: {
|
|
var formatOnKeyArgs = <ServerProtocol.FormatOnKeyRequestArgs>req.arguments;
|
|
this.formatOnKey(formatOnKeyArgs.line, formatOnKeyArgs.col, formatOnKeyArgs.key, formatOnKeyArgs.file,
|
|
cmd, req.seq);
|
|
break;
|
|
}
|
|
case CommandNames.Completions: {
|
|
var completionsArgs = <ServerProtocol.CompletionsRequestArgs>req.arguments;
|
|
this.completions(req.arguments.line, req.arguments.col, completionsArgs.prefix, req.arguments.file,
|
|
cmd, req.seq);
|
|
break;
|
|
}
|
|
case CommandNames.Geterr: {
|
|
var geterrArgs = <ServerProtocol.GeterrRequestArgs>req.arguments;
|
|
this.geterr(geterrArgs.delay, geterrArgs.files);
|
|
break;
|
|
}
|
|
case CommandNames.Change: {
|
|
var changeArgs = <ServerProtocol.ChangeRequestArgs>req.arguments;
|
|
this.change(changeArgs.line, changeArgs.col, changeArgs.deleteLen, changeArgs.insertString,
|
|
changeArgs.file);
|
|
break;
|
|
}
|
|
case CommandNames.Reload: {
|
|
var reloadArgs = <ServerProtocol.ReloadRequestArgs>req.arguments;
|
|
this.reload(reloadArgs.file, reloadArgs.tmpfile, req.seq);
|
|
break;
|
|
}
|
|
case CommandNames.Saveto: {
|
|
var savetoArgs = <ServerProtocol.SavetoRequestArgs>req.arguments;
|
|
this.saveToTmp(savetoArgs.file, savetoArgs.tmpfile);
|
|
break;
|
|
}
|
|
case CommandNames.Close: {
|
|
var closeArgs = <ServerProtocol.FileRequestArgs>req.arguments;
|
|
this.closeClientFile(closeArgs.file);
|
|
break;
|
|
}
|
|
case CommandNames.Navto: {
|
|
var navtoArgs = <ServerProtocol.NavtoRequestArgs>req.arguments;
|
|
this.navto(navtoArgs.searchTerm, navtoArgs.file, cmd, req.seq);
|
|
break;
|
|
}
|
|
default: {
|
|
this.projectService.log("Unrecognized JSON command: " + cmd);
|
|
break;
|
|
}
|
|
}
|
|
} catch (err) {
|
|
this.logError(err, cmd);
|
|
}
|
|
}
|
|
|
|
sendAbbrev(reqSeq = 0) {
|
|
if (!this.fetchedAbbrev) {
|
|
this.output(this.abbrevTable, CommandNames.Abbrev, reqSeq);
|
|
}
|
|
this.fetchedAbbrev = true;
|
|
}
|
|
|
|
executeCmd(cmd: string) {
|
|
var line: number, col: number, file: string;
|
|
var m: string[];
|
|
|
|
try {
|
|
if (m = cmd.match(/^dbg start$/)) {
|
|
this.debugSession = new JsDebugSession(this.host.getDebuggerClient());
|
|
}
|
|
else if (m = cmd.match(/^dbg cont$/)) {
|
|
if (this.debugSession) {
|
|
this.debugSession.cont((err, body, res) => {
|
|
});
|
|
}
|
|
}
|
|
else if (m = cmd.match(/^dbg src$/)) {
|
|
if (this.debugSession) {
|
|
this.debugSession.listSrc();
|
|
}
|
|
}
|
|
else if (m = cmd.match(/^dbg brk (\d+) (.*)$/)) {
|
|
line = parseInt(m[1]);
|
|
file = ts.normalizePath(m[2]);
|
|
if (this.debugSession) {
|
|
this.debugSession.setBreakpointOnLine(line, file);
|
|
}
|
|
}
|
|
else if (m = cmd.match(/^dbg eval (.*)$/)) {
|
|
var code = m[1];
|
|
if (this.debugSession) {
|
|
this.debugSession.evaluate(code);
|
|
}
|
|
}
|
|
else if (m = cmd.match(/^definition (\d+) (\d+) (.*)$/)) {
|
|
line = parseInt(m[1]);
|
|
col = parseInt(m[2]);
|
|
file = m[3];
|
|
this.goToDefinition(line, col, file);
|
|
}
|
|
else if (m = cmd.match(/^rename (\d+) (\d+) (.*)$/)) {
|
|
line = parseInt(m[1]);
|
|
col = parseInt(m[2]);
|
|
file = m[3];
|
|
this.rename(line, col, file);
|
|
}
|
|
else if (m = cmd.match(/^type (\d+) (\d+) (.*)$/)) {
|
|
line = parseInt(m[1]);
|
|
col = parseInt(m[2]);
|
|
file = m[3];
|
|
this.goToType(line, col, file);
|
|
}
|
|
else if (m = cmd.match(/^open (.*)$/)) {
|
|
file = m[1];
|
|
this.openClientFile(file);
|
|
}
|
|
else if (m = cmd.match(/^references (\d+) (\d+) (.*)$/)) {
|
|
line = parseInt(m[1]);
|
|
col = parseInt(m[2]);
|
|
file = m[3];
|
|
this.findReferences(line, col, file);
|
|
}
|
|
else if (m = cmd.match(/^quickinfo (\d+) (\d+) (.*)$/)) {
|
|
line = parseInt(m[1]);
|
|
col = parseInt(m[2]);
|
|
file = m[3];
|
|
this.quickInfo(line, col, file);
|
|
}
|
|
else if (m = cmd.match(/^format (\d+) (\d+) (\d+) (\d+) (.*)$/)) {
|
|
// format line col endLine endCol file
|
|
line = parseInt(m[1]);
|
|
col = parseInt(m[2]);
|
|
var endLine = parseInt(m[3]);
|
|
var endCol = parseInt(m[4]);
|
|
file = m[5];
|
|
this.format(line, col, endLine, endCol, file, cmd);
|
|
}
|
|
else if (m = cmd.match(/^formatonkey (\d+) (\d+) (\{\".*\"\})\s* (.*)$/)) {
|
|
line = parseInt(m[1]);
|
|
col = parseInt(m[2]);
|
|
var key = JSON.parse(m[3].substring(1, m[3].length - 1));
|
|
file = m[4];
|
|
this.formatOnKey(line, col, key, file, cmd);
|
|
}
|
|
else if (m = cmd.match(/^completions (\d+) (\d+) (\{.*\})?\s*(.*)$/)) {
|
|
line = parseInt(m[1]);
|
|
col = parseInt(m[2]);
|
|
var prefix = "";
|
|
file = m[4];
|
|
if (m[3]) {
|
|
prefix = m[3].substring(1, m[3].length - 1);
|
|
}
|
|
this.completions(line, col, prefix, file, cmd);
|
|
}
|
|
else if (m = cmd.match(/^geterr (\d+) (.*)$/)) {
|
|
var ms = parseInt(m[1]);
|
|
var rawFiles = m[2];
|
|
this.geterr(ms, rawFiles.split(';'));
|
|
}
|
|
else if (m = cmd.match(/^change (\d+) (\d+) (\d+) (\d+) (\{\".*\"\})?\s*(.*)$/)) {
|
|
line = parseInt(m[1]);
|
|
col = parseInt(m[2]);
|
|
var deleteLen = parseInt(m[3]);
|
|
var insertLen = parseInt(m[4]);
|
|
var insertString: string;
|
|
if (insertLen) {
|
|
insertString = JSON.parse(m[5].substring(1, m[5].length - 1));
|
|
}
|
|
file = m[6];
|
|
this.change(line, col, deleteLen, insertString, file);
|
|
}
|
|
else if (m = cmd.match(/^reload (.*) from (.*)$/)) {
|
|
this.reload(m[1], m[2]);
|
|
}
|
|
// TODO: change this to saveto
|
|
else if (m = cmd.match(/^save (.*) to (.*)$/)) {
|
|
this.saveToTmp(m[1], m[2]);
|
|
}
|
|
else if (m = cmd.match(/^close (.*)$/)) {
|
|
this.closeClientFile(m[1]);
|
|
}
|
|
else if (m = cmd.match(/^navto (\{.*\}) (.*)$/)) {
|
|
var searchTerm = m[1];
|
|
searchTerm = searchTerm.substring(1, searchTerm.length - 1);
|
|
this.navto(searchTerm, m[2], cmd);
|
|
}
|
|
else if (m = cmd.match(/^navbar (.*)$/)) {
|
|
this.navbar(m[1]);
|
|
}
|
|
else if (m = cmd.match(/^abbrev/)) {
|
|
this.sendAbbrev();
|
|
}
|
|
else if (m = cmd.match(/^pretty/)) {
|
|
this.prettyJSON = true;
|
|
}
|
|
else if (m = cmd.match(/^printproj/)) {
|
|
this.projectService.printProjects();
|
|
}
|
|
else if (m = cmd.match(/^fileproj (.*)$/)) {
|
|
file = ts.normalizePath(m[1]);
|
|
this.projectService.printProjectsForFile(file);
|
|
}
|
|
else {
|
|
this.output(undefined, CommandNames.Unknown, 0, "Unrecognized command " + cmd);
|
|
}
|
|
} catch (err) {
|
|
this.logError(err, cmd);
|
|
}
|
|
}
|
|
}
|
|
}
|