Recover from git corruption

This commit is contained in:
Mohamed Hegazy 2015-02-14 15:12:06 -08:00
parent 99373dbd89
commit a0b557e1e2
6 changed files with 601 additions and 1167 deletions

View file

@ -128,7 +128,9 @@ module Harness.LanguageService {
protected settings = ts.getDefaultCompilerOptions()) {
}
public getNewLine(): string { return "\r\n"; }
public getNewLine(): string {
return "\r\n";
}
public getFilenames(): string[] {
var fileNames: string[] = [];
@ -435,17 +437,26 @@ module Harness.LanguageService {
}
// Server adapter
class ServerLanguageServiceHost extends NativeLanguageServiceHost {
class SessionClientHost extends NativeLanguageServiceHost implements ts.server.SessionClientHost {
private client: ts.server.SessionClient;
constructor(cancellationToken: ts.CancellationToken, settings: ts.CompilerOptions) {
super(cancellationToken, settings);
}
setClient(client: ts.server.SessionClient) {
onMessage(message: string): void {
}
writeMessage(message: string): void {
}
setClient(client: ts.server.SessionClient) {
this.client = client;
}
openFile(fileName: string): void {
openFile(fileName: string): void {
super.openFile(fileName);
this.client.openFile(fileName);
}
@ -456,15 +467,135 @@ module Harness.LanguageService {
}
}
class SessionServerHost implements ts.server.ServerHost, ts.server.Logger {
args: string[] = [];
newLine: string;
useCaseSensitiveFileNames: boolean = false;
constructor(private host: NativeLanguageServiceHost) {
this.newLine = this.host.getNewLine();
}
onMessage(message: string): void {
}
writeMessage(message: string): void {
}
write(message: string): void {
this.writeMessage(message);
}
readFile(fileName: string): string {
var snapshot = this.host.getScriptSnapshot(fileName);
return snapshot && snapshot.getText(0, snapshot.getLength());
}
writeFile(name: string, text: string, writeByteOrderMark: boolean): void {
}
resolvePath(path: string): string {
return path;
}
fileExists(path: string): boolean {
return !!this.host.getScriptSnapshot(path);
}
directoryExists(path: string): boolean {
return false;
}
getExecutingFilePath(): string {
return "";
}
exit(exitCode: number): void {
}
createDirectory(directoryName: string): void {
throw new Error("Not Implemented Yet.");
}
getCurrentDirectory(): string {
return this.host.getCurrentDirectory();
}
readDirectory(path: string, extension?: string): string[] {
throw new Error("Not implemented Yet.");
}
getModififedTime(fileName: string): Date {
return new Date();
}
stat(path: string, callback?: (err: any, stats: any) => any) {
return 0;
}
lineColToPosition(fileName: string, line: number, col: number): number {
return this.host.lineColToPosition(fileName, line, col);
}
positionToZeroBasedLineCol(fileName: string, position: number): ts.LineAndCharacter {
return this.host.positionToZeroBasedLineCol(fileName, position);
}
getFileLength(fileName: string): number {
return this.host.getScriptSnapshot(fileName).getLength();
}
getFileNames(): string[] {
return this.host.getScriptFileNames();
}
close(): void {
}
info(message: string): void {
return this.host.log(message);
}
msg(message: string) {
return this.host.log(message);
}
endGroup(): void {
}
perftrc(message: string): void {
return this.host.log(message);
}
startGroup(): void {
}
}
export class ServerLanugageServiceAdapter implements LanguageServiceAdapter {
private host: ServerLanguageServiceHost;
private host: SessionClientHost;
private client: ts.server.SessionClient;
constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) {
debugger;
// This is the main host that tests use to direct tests
var clientHost = new SessionClientHost(cancellationToken, options);
var client = new ts.server.SessionClient(clientHost);
this.host = new ServerLanguageServiceHost(cancellationToken, options);
this.client = new ts.server.SessionClient(this.host, /*abbreviate*/ true);
this.host.setClient(this.client);
// This host is just a proxy for the clientHost, it uses the client
// host to answer server queries about files on disk
var serverHost = new SessionServerHost(clientHost);
var server = new ts.server.Session(serverHost, serverHost, /*useProtocol*/ true, /*prettyJSON*/ false);
// Fake the connection between the client and the server
serverHost.writeMessage = client.onMessage.bind(client);
clientHost.writeMessage = server.onMessage.bind(server);
// Wire the client to the host to get notifications when a file is open
// or edited.
clientHost.setClient(client);
// Set the properties
this.client = client;
this.host = clientHost;
}
getHost() { return this.host; }
getLanguageService(): ts.LanguageService { return this.client; }

View file

@ -1,177 +1,49 @@
/// <reference path="protocol.ts" />
module ts.server {
export interface SessionClientHost extends LanguageServiceHost {
lineColToPosition(fileName: string, line: number, col: number): number;
positionToZeroBasedLineCol(fileName: string, position: number): ts.LineAndCharacter;
}
class SessionClientHostProxy implements ServerHost, Logger {
args: string[] = [];
newLine: string;
useCaseSensitiveFileNames: boolean = false;
lastReply: string;
constructor(private host: SessionClientHost) {
this.newLine = this.host.getNewLine();
}
/// <reference path="protocol.ts" />
write(message: string): void {
this.lastReply = message;
}
module ts.server {
readFile(fileName: string): string {
var snapshot = this.host.getScriptSnapshot(fileName);
return snapshot && snapshot.getText(0, snapshot.getLength());
}
writeFile(name: string, text:string, writeByteOrderMark: boolean): void {
}
resolvePath(path: string): string {
return path;
}
fileExists(path: string): boolean {
return !!this.host.getScriptSnapshot(path);
}
directoryExists(path: string): boolean {
return false;
}
getExecutingFilePath(): string {
return "";
}
exit(exitCode: number): void {
}
createDirectory(directoryName: string): void {
throw new Error("Not Implemented Yet.");
}
getCurrentDirectory(): string {
return this.host.getCurrentDirectory();
}
readDirectory(path: string, extension?: string): string[] {
throw new Error("Not implemented Yet.");
}
getModififedTime(fileName: string): Date {
return new Date();
}
stat(path: string, callback?: (err: any, stats: any) => any) {
return 0;
}
lineColToPosition(fileName: string, line: number, col: number): number {
return this.host.lineColToPosition(fileName, line, col);
}
positionToZeroBasedLineCol(fileName: string, position: number): ts.LineAndCharacter {
return this.host.positionToZeroBasedLineCol(fileName, position);
}
getFileLength(fileName: string): number {
return this.host.getScriptSnapshot(fileName).getLength();
}
getFileNames(): string[] {
return this.host.getScriptFileNames();
}
close(): void {
}
info(message: string): void {
return this.host.log(message);
}
msg(message: string) {
return this.host.log(message);
}
endGroup(): void {
}
perftrc(message: string): void {
return this.host.log(message);
}
startGroup(): void {
}
export interface SessionClientHost extends LanguageServiceHost {
writeMessage(message: string): void;
}
export class SessionClient implements LanguageService {
private session: Session;
private sequence: number = 0;
private host: SessionClientHostProxy;
private expantionTable: ts.Map<string>;
private fileMapping: ts.Map<string> = {};
constructor(host: SessionClientHost, abbreviate: boolean) {
this.sequence = 0;
this.host = new SessionClientHostProxy(host);
this.session = new Session(this.host, this.host, /* useProtocol */ true, /*prettyJSON*/ false);
// Setup the abbreviation table
if (abbreviate) {
this.setupExpantionTable()
}
}
private setupExpantionTable(): void {
var request = this.processRequest<ServerProtocol.AbbrevRequest>(CommandNames.Abbrev);
var response = this.processResponse<ServerProtocol.AbbrevResponse>(request);
var abbriviationTable = response.body;
Debug.assert(!!abbriviationTable, "Could not setup abbreviation. Abbreviation table was empty.");
var expantionTable: ts.Map<string> = {};
for (var p in abbriviationTable) {
if (abbriviationTable.hasOwnProperty(p)) {
expantionTable[abbriviationTable[p]] = p;
}
}
this.expantionTable = expantionTable;
}
private expand<T>(obj: T): T {
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
if (typeof (<any>obj)[p] === "object") {
// Expand the property value
(<any>obj)[p] = this.expand((<any>obj)[p]);
}
// Substitute the name if applicaple
var substitution = ts.lookUp(this.expantionTable, p);
if (substitution) {
(<any>obj)[substitution] = (<any>obj)[p];
(<any>obj)[p] = undefined;
}
}
}
return obj;
}
private lineColToPosition(fileName: string, lineCol: ServerProtocol.LineCol): number {
return this.host.lineColToPosition(fileName, lineCol.line, lineCol.col);
export class SessionClient implements LanguageService {
private sequence: number = 0;
private fileMapping: ts.Map<string> = {};
private lineMaps: ts.Map<number[]> = {};
private messages: string[] = [];
constructor(private host: SessionClientHost) {
}
private positionToOneBasedLineCol(fileName: string, position: number): ServerProtocol.LineCol {
var lineCol = this.host.positionToZeroBasedLineCol(fileName, position);
public onMessage(message: string): void {
this.messages.push(message);
}
private writeMessage(message: string): void {
this.host.writeMessage(message);
}
private getLineMap(fileName: string): number[] {
var lineMap = ts.lookUp(this.lineMaps, fileName);
if (!lineMap) {
var scriptSnapshot = this.host.getScriptSnapshot(fileName);
lineMap = this.lineMaps[fileName] = ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength()));
}
return lineMap;
}
private lineColToPosition(fileName: string, lineCol: ServerProtocol.LineCol): number {
return ts.computePositionFromLineAndCharacter(this.getLineMap(fileName), lineCol.line, lineCol.col);
}
private positionToOneBasedLineCol(fileName: string, position: number): ServerProtocol.LineCol {
var lineCol = ts.computeLineAndCharacterOfPosition(this.getLineMap(fileName), position);
return {
line: lineCol.line + 1,
col: lineCol.character + 1
line: lineCol.line,
col: lineCol.character
};
}
}
private convertCodeEditsToTextChange(fileName: string, codeEdit: ServerProtocol.CodeEdit): ts.TextChange {
var start = this.lineColToPosition(fileName, codeEdit.start);
var end = this.lineColToPosition(fileName, codeEdit.end);
@ -180,8 +52,8 @@ module ts.server {
span: ts.createTextSpanFromBounds(start, end),
newText: codeEdit.newText
};
}
}
private getFileNameFromEncodedFile(fileId: ServerProtocol.EncodedFile): string {
var fileName: string;
if (typeof fileId === "object") {
@ -196,9 +68,9 @@ module ts.server {
Debug.fail("Got unexpedted fileId type.");
}
return fileName;
}
private processRequest<T extends ServerProtocol.Request>(command: string, arguments?: any): T {
}
private processRequest<T extends ServerProtocol.Request>(command: string, arguments?: any): T {
var request: ServerProtocol.Request = {
seq: this.sequence++,
type: "request",
@ -206,34 +78,33 @@ module ts.server {
arguments: arguments
};
this.session.executeJSONcmd(JSON.stringify(request));
return <T>request;
}
private processResponse<T extends ServerProtocol.Response>(request: ServerProtocol.Request): T {
debugger;
var lastMessage = this.host.lastReply;
this.host.lastReply = undefined;
Debug.assert(!!lastMessage, "Did not recieve any responses.");
// Read the content length
var contentLengthPrefix = "Content-Length: ";
var lines = lastMessage.split("\r\n");
Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response.");
var contentLengthText = lines[0];
Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header.");
var contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length));
// Read the body
var responseBody = lines[2];
// Verify content length
Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length.");
try {
this.writeMessage(JSON.stringify(request));
return <T>request;
}
private processResponse<T extends ServerProtocol.Response>(request: ServerProtocol.Request): T {
debugger;
var lastMessage = this.messages.shift();
Debug.assert(!!lastMessage, "Did not recieve any responses.");
// Read the content length
var contentLengthPrefix = "Content-Length: ";
var lines = lastMessage.split("\r\n");
Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response.");
var contentLengthText = lines[0];
Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header.");
var contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length));
// Read the body
var responseBody = lines[2];
// Verify content length
Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length.");
try {
var response: T = JSON.parse(responseBody);
}
catch (e) {
@ -250,13 +121,9 @@ module ts.server {
Debug.assert(!!response.body, "Malformed response: Unexpected empty response body.");
if (this.expantionTable) {
// Expand the response if abbreviated
return this.expand(response);
}
return response;
}
}
openFile(fileName: string): void {
var args: ServerProtocol.FileRequestArgs = { file: fileName };
this.processRequest(CommandNames.Open, args);
@ -268,6 +135,9 @@ module ts.server {
}
changeFile(fileName: string, start: number, end: number, newText: string): void {
// clear the line map after an edit
this.lineMaps[fileName] = undefined;
var lineCol = this.positionToOneBasedLineCol(fileName, start);
var args: ServerProtocol.ChangeRequestArgs = {
file: fileName,
@ -326,7 +196,7 @@ module ts.server {
getNavigateToItems(searchTerm: string): NavigateToItem[] {
var args: ServerProtocol.NavtoRequestArgs = {
searchTerm,
file: this.host.getFileNames()[0]
file: this.host.getScriptFileNames()[0]
};
var request = this.processRequest<ServerProtocol.NavtoRequest>(CommandNames.Navto, args);
@ -357,7 +227,7 @@ module ts.server {
file: fileName,
line: startLineCol.line,
col: startLineCol.col,
endLine: endLineCol.line,
endLine: endLineCol.line,
endCol: endLineCol.col,
};
@ -369,7 +239,7 @@ module ts.server {
}
getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): ts.TextChange[] {
return this.getFormattingEditsForRange(fileName, 0, this.host.getFileLength(fileName), options);
return this.getFormattingEditsForRange(fileName, 0, this.host.getScriptSnapshot(fileName).getLength(), options);
}
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): ts.TextChange[] {
@ -537,7 +407,7 @@ module ts.server {
}
dispose(): void {
throw new Error("dispose is not available through the server layer.");
}
}
}
throw new Error("dispose is not available through the server layer.");
}
}
}

View file

@ -425,7 +425,8 @@ module ts.server {
if (projectOptions.compilerOptions) {
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
}
// TODO: format code options }
// TODO: format code options
}
}
export interface ProjectOpenResult {

File diff suppressed because it is too large Load diff

View file

@ -188,18 +188,6 @@ declare module ServerProtocol {
}
}
/**
Type request; value of command field is "type". Return response
giving the code locations that define the type of the symbol
found in file at location line, col.
*/
export interface TypeRequest extends CodeLocationRequest {
}
export interface TypeResponse extends Response {
body?: CodeSpan[];
}
/**
Open request; value of command field is "open". Notify the
server that the client has file open. The server will not
@ -483,8 +471,8 @@ declare module ServerProtocol {
kindModifiers?: string;
/**
The file in which the symbol is found; the value of this
field will always be a string unless the client opts-in to
file encoding by sending the "abbrev" request.
field will always be a string, number of a mapping between
a string and a number.
*/
file: EncodedFile;
/** The location within file at which the symbol is found*/
@ -528,27 +516,6 @@ declare module ServerProtocol {
arguments: ChangeRequestArgs;
}
/*
The following messages describe an OPTIONAL compression scheme
that clients can choose to use. If a client does not opt-in to
this scheme by sending an "abbrev" request, the server will not
compress messages.
*/
/**
Abbrev request message; value of command field is "abbrev".
Server returns an array of mappings from common message field
names and common message field string values to shortened
versions of these strings. Once a client opts-in by requesting
the abbreviations, the server may send responses whose field
names are shortened. The server may also send file names as
instances of AssignFileId, or as file ids, if the corresponding
id assignment had been previously returned. Currently, only
responses to the "navto" request can be encoded.
*/
export interface AbbrevRequest extends Request {
}
/**
If an object of this type is returned in place of a string as
the value of a file field in a response message, add the
@ -572,25 +539,6 @@ declare module ServerProtocol {
*/
export type EncodedFile = number | IdFile | string;
/**
Response to abbrev opt-in request message. This is a map of
string field names and common string field values to shortened
strings. Once the server sends this response, it will assume
that it can use the shortened field names and field values. In
addition, the server will assume it can assign ids to file
names by returning an AssignFileId instance in place of a file
name. Once an AssignFileId instance is returned, the server
may send the file id (a number) in place of the file name.
*/
export interface AbbrevResponse extends Response {
body?: {
/** Map from full string (either field name or string
field value) to shortened string */
[fullString: string]: string;
}
}
/** Response to "brace" request. */
export interface BraceResponse extends Response {
body?: TextSpan[];

View file

@ -1,18 +1,18 @@
/// <reference path="node.d.ts" />
/// <reference path="protocol.ts" />
module ts.server {
/// <reference path="node.d.ts" />
/// <reference path="protocol.ts" />
module ts.server {
var nodeproto: typeof NodeJS._debugger = require('_debugger');
var readline: NodeJS.ReadLine = require('readline');
var path: NodeJS.Path = require('path');
var path: NodeJS.Path = require('path');
var fs: typeof NodeJS.fs = require('fs');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false,
});
});
class Logger implements ts.server.Logger {
fd = -1;
seq = 0;
@ -71,17 +71,17 @@ module ts.server {
}
}
}
class IOSession extends Session {
protocol: NodeJS._debugger.Protocol;
constructor(host: ServerHost, logger: ts.server.Logger, useProtocol: boolean, prettyJSON: boolean) {
super(host, logger, useProtocol, prettyJSON);
class IOSession extends Session {
protocol: NodeJS._debugger.Protocol;
constructor(host: ServerHost, logger: ts.server.Logger, useProtocol: boolean, prettyJSON: boolean) {
super(host, logger, useProtocol, prettyJSON);
if (useProtocol) {
this.initProtocol();
}
}
}
}
initProtocol() {
this.protocol = new nodeproto.Protocol();
// note: onResponse was named by nodejs authors; we are re-purposing the Protocol
@ -89,25 +89,16 @@ module ts.server {
this.protocol.onResponse = (pkt) => {
this.handleRequest(pkt);
};
}
}
handleRequest(req: NodeJS._debugger.Packet) {
this.projectService.log("Got JSON msg:\n" + req.raw);
}
}
listen() {
rl.on('line',(input: string) => {
var cmd = input.trim();
if (cmd.indexOf("{") == 0) {
// assumption is JSON on single line
// plan is to also carry this protocol
// over tcp, in which case JSON would
// have a Content-Length header
this.executeJSONcmd(cmd);
}
else {
this.executeCmd(cmd);
}
var message = input.trim();
this.onMessage(message);
});
rl.on('close',() => {
@ -115,20 +106,13 @@ module ts.server {
this.projectService.log("Exiting...");
process.exit(0);
});
}
}
}
}
// 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 host: ServerHost = ts.sys;
// Wire the debugging interface
if (!host.getDebuggerClient) {
host.getDebuggerClient = () => new nodeproto.Client();
}
// Start listening
new IOSession(host, logger, /* useProtocol */ true, /* prettyJSON */ false).listen();
var logger = new Logger(__dirname + "/.log" + process.pid.toString());
// Start listening
new IOSession(ts.sys, logger, /* useProtocol */ true, /* prettyJSON */ false).listen();
}