mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:19:30 -06:00
Breakpoint span in variable declarations in new language service
Also updates the fourslash breakpoints baseline to be more readable
This commit is contained in:
parent
a6eb698f5b
commit
06d29a00f2
1
Jakefile
1
Jakefile
@ -55,6 +55,7 @@ var servicesSources = [
|
||||
].map(function (f) {
|
||||
return path.join(compilerDirectory, f);
|
||||
}).concat([
|
||||
"breakpoints.ts",
|
||||
"services.ts",
|
||||
"shims.ts",
|
||||
"signatureHelp.ts",
|
||||
|
||||
@ -985,13 +985,23 @@ module FourSlash {
|
||||
return item.parameters[currentParam];
|
||||
}
|
||||
|
||||
public getBreakpointStatementLocation(pos: number) {
|
||||
private alignmentForExtraInfo = 50;
|
||||
|
||||
public getBreakpointStatementLocation(pos: number, prefixString: string) {
|
||||
this.taoInvalidReason = 'getBreakpointStatementLocation NYI';
|
||||
|
||||
var spanInfo = this.languageService.getBreakpointStatementAtPosition(this.activeFile.fileName, pos);
|
||||
var resultString = "\n**Pos: " + pos + " SpanInfo: " + JSON.stringify(spanInfo) + "\n** Statement: ";
|
||||
if (spanInfo !== null) {
|
||||
resultString = resultString + this.activeFile.content.substr(spanInfo.start(), spanInfo.length());
|
||||
var resultString = "SpanInfo: " + JSON.stringify(spanInfo);
|
||||
if (spanInfo) {
|
||||
var spanString = this.activeFile.content.substr(spanInfo.start(), spanInfo.length());
|
||||
var spanLineMap = ts.getLineStarts(spanString);
|
||||
for (var i = 0; i < spanLineMap.length; i++) {
|
||||
if (!i) {
|
||||
resultString += "\n";
|
||||
}
|
||||
resultString += prefixString + spanString.substring(spanLineMap[i], spanLineMap[i + 1]);
|
||||
}
|
||||
resultString += "\n" + prefixString + ":=> (" + this.getLineColStringAtPosition(spanInfo.start()) + ") to (" + this.getLineColStringAtPosition(spanInfo.end()) + ")";
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
@ -1003,12 +1013,60 @@ module FourSlash {
|
||||
"Breakpoint Locations for " + this.activeFile.fileName,
|
||||
this.testData.globalOptions[testOptMetadataNames.baselineFile],
|
||||
() => {
|
||||
var fileLength = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength();
|
||||
var fileLineMap = ts.getLineStarts(this.activeFile.content);
|
||||
var nextLine = 0;
|
||||
var resultString = "";
|
||||
for (var pos = 0; pos < fileLength; pos++) {
|
||||
resultString = resultString + this.getBreakpointStatementLocation(pos);
|
||||
var currentLine: string;
|
||||
var previousSpanInfo: string;
|
||||
var startColumn: number;
|
||||
var length: number;
|
||||
var prefixString = " >";
|
||||
|
||||
var addSpanInfoString = () => {
|
||||
if (previousSpanInfo) {
|
||||
resultString += currentLine;
|
||||
var thisLineMarker = repeatString(startColumn, " ") + repeatString(length, "~");
|
||||
thisLineMarker += repeatString(this.alignmentForExtraInfo - thisLineMarker.length - prefixString.length + 1, " ");
|
||||
resultString += thisLineMarker;
|
||||
resultString += "=> Pos: (" + (pos - length) + " to " + (pos - 1) + ") ";
|
||||
resultString += " " + previousSpanInfo;
|
||||
previousSpanInfo = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
for (var pos = 0; pos < this.activeFile.content.length; pos++) {
|
||||
if (pos === 0 || pos === fileLineMap[nextLine]) {
|
||||
nextLine++;
|
||||
addSpanInfoString();
|
||||
if (resultString.length) {
|
||||
resultString += "\n--------------------------------";
|
||||
}
|
||||
currentLine = "\n" + nextLine.toString() + repeatString(3 - nextLine.toString().length, " ") + ">" + this.activeFile.content.substring(pos, fileLineMap[nextLine]) + "\n ";
|
||||
startColumn = 0;
|
||||
length = 0;
|
||||
}
|
||||
var spanInfo = this.getBreakpointStatementLocation(pos, prefixString);
|
||||
if (previousSpanInfo && previousSpanInfo !== spanInfo) {
|
||||
addSpanInfoString();
|
||||
previousSpanInfo = spanInfo;
|
||||
startColumn = startColumn + length;
|
||||
length = 1;
|
||||
}
|
||||
else {
|
||||
previousSpanInfo = spanInfo;
|
||||
length++;
|
||||
}
|
||||
}
|
||||
addSpanInfoString();
|
||||
return resultString;
|
||||
|
||||
function repeatString(count: number, char: string) {
|
||||
var result = "";
|
||||
for (var i = 0; i < count; i++) {
|
||||
result += char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
true /* run immediately */);
|
||||
}
|
||||
@ -1056,7 +1114,7 @@ module FourSlash {
|
||||
}
|
||||
|
||||
public printBreakpointLocation(pos: number) {
|
||||
Harness.IO.log(this.getBreakpointStatementLocation(pos));
|
||||
Harness.IO.log("\n**Pos: " + pos + " " + this.getBreakpointStatementLocation(pos, " "));
|
||||
}
|
||||
|
||||
public printBreakpointAtCurrentLocation() {
|
||||
@ -1502,7 +1560,7 @@ module FourSlash {
|
||||
throw new Error('verifyCaretAtMarker failed - expected to be in file "' + pos.fileName + '", but was in file "' + this.activeFile.fileName + '"');
|
||||
}
|
||||
if (pos.position !== this.currentCaretPosition) {
|
||||
throw new Error('verifyCaretAtMarker failed - expected to be at marker "/*' + markerName + '*/, but was at position ' + this.currentCaretPosition + '(' + this.getLineColStringAtCaret() + ')');
|
||||
throw new Error('verifyCaretAtMarker failed - expected to be at marker "/*' + markerName + '*/, but was at position ' + this.currentCaretPosition + '(' + this.getLineColStringAtPosition(this.currentCaretPosition) + ')');
|
||||
}
|
||||
}
|
||||
|
||||
@ -2102,8 +2160,8 @@ module FourSlash {
|
||||
return this.languageServiceShimHost.positionToZeroBasedLineCol(this.activeFile.fileName, this.currentCaretPosition).line + 1;
|
||||
}
|
||||
|
||||
private getLineColStringAtCaret() {
|
||||
var pos = this.languageServiceShimHost.positionToZeroBasedLineCol(this.activeFile.fileName, this.currentCaretPosition);
|
||||
private getLineColStringAtPosition(position: number) {
|
||||
var pos = this.languageServiceShimHost.positionToZeroBasedLineCol(this.activeFile.fileName, position);
|
||||
return 'line ' + (pos.line + 1) + ', col ' + pos.character;
|
||||
}
|
||||
|
||||
|
||||
@ -1082,4 +1082,93 @@ module TypeScript.Services.Breakpoints {
|
||||
var breakpointResolver = new BreakpointResolver(posLine, lineMap);
|
||||
return breakpointResolver.breakpointSpanOf(positionedToken);
|
||||
}
|
||||
}
|
||||
|
||||
module ts.Breakpoints {
|
||||
/**
|
||||
* Get the breakpoint span in given sourceFile
|
||||
*/
|
||||
export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: number) {
|
||||
// Cannot set breakpoint in dts file
|
||||
if (sourceFile.flags & NodeFlags.DeclarationFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
var tokenAtLocation = getTokenAtPosition(sourceFile, position);
|
||||
var lineOfPosition = sourceFile.getLineAndCharacterFromPosition(position).line;
|
||||
if (sourceFile.getLineAndCharacterFromPosition(tokenAtLocation.getStart()).line > lineOfPosition) {
|
||||
// Get previous token if the token is returned starts on new line
|
||||
// eg: var x =10; |--- curser is here
|
||||
// var y = 10;
|
||||
// token at position will return var keyword on second line as the token but we would like to use
|
||||
// token on same line if trailing trivia (comments or white spaces on same line) part of the last token on that line
|
||||
tokenAtLocation = findPrecedingToken(tokenAtLocation.pos, sourceFile);
|
||||
}
|
||||
|
||||
// Cannot set breakpoint in ambient declarations
|
||||
if (isInAmbientContext(tokenAtLocation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the span in the node based on its syntax
|
||||
return spanInNode(tokenAtLocation);
|
||||
|
||||
function textSpan(startNode: Node, endNode?: Node) {
|
||||
return TypeScript.TextSpan.fromBounds(startNode.getStart(), (endNode || startNode).getEnd());
|
||||
}
|
||||
|
||||
function spanInNodeIfStartsOnSameLine(node: Node): TypeScript.TextSpan {
|
||||
if (node && sourceFile.getLineAndCharacterFromPosition(position).line === sourceFile.getLineAndCharacterFromPosition(node.getStart()).line) {
|
||||
return spanInNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
function spanInNode(node: Node): TypeScript.TextSpan {
|
||||
if (node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.VariableStatement:
|
||||
return spanInVariableStatement(<VariableStatement>node);
|
||||
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return spanInVariableDeclaration(<VariableDeclaration>node);
|
||||
|
||||
case SyntaxKind.SemicolonToken:
|
||||
case SyntaxKind.EndOfFileToken:
|
||||
return spanInNodeIfStartsOnSameLine(findPrecedingToken(node.pos, sourceFile));
|
||||
|
||||
default:
|
||||
// Default go to parent to set the breakpoint
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
}
|
||||
|
||||
function spanInVariableDeclaration(variableDeclaration: VariableDeclaration): TypeScript.TextSpan {
|
||||
var isParentVariableStatement = variableDeclaration.parent.kind === SyntaxKind.VariableStatement;
|
||||
var isfirstDeclarationOfVariableStatement = isParentVariableStatement &&
|
||||
(<VariableStatement>variableDeclaration.parent).declarations[0] === variableDeclaration;
|
||||
|
||||
// Breakpoint is possible in variableDeclaration only if there is initialization
|
||||
if (variableDeclaration.initializer) {
|
||||
if (isfirstDeclarationOfVariableStatement) {
|
||||
// First declaration - include var keyword
|
||||
return textSpan(variableDeclaration.parent, variableDeclaration);
|
||||
}
|
||||
else {
|
||||
// Span only on this declaration
|
||||
return textSpan(variableDeclaration);
|
||||
}
|
||||
}
|
||||
else if (!isfirstDeclarationOfVariableStatement && isParentVariableStatement) {
|
||||
// If we cant set breakpoint on this declaration, set it on previous one
|
||||
var variableStatement = <VariableStatement>variableDeclaration.parent;
|
||||
var indexOfCurrentDeclaration = indexOf(variableStatement.declarations, variableDeclaration);
|
||||
return spanInVariableDeclaration(variableStatement.declarations[indexOfCurrentDeclaration - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
function spanInVariableStatement(variableStatement: VariableStatement): TypeScript.TextSpan {
|
||||
return spanInVariableDeclaration(variableStatement.declarations[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4737,9 +4737,7 @@ module ts {
|
||||
function getBreakpointStatementAtPosition(filename: string, position: number) {
|
||||
// doesn't use compiler - no need to synchronize with host
|
||||
filename = TypeScript.switchToForwardSlashes(filename);
|
||||
|
||||
var syntaxtree = getSyntaxTree(filename);
|
||||
return TypeScript.Services.Breakpoints.getBreakpointLocation(syntaxtree, position);
|
||||
return Breakpoints.spanInSourceFileAtLocation(getCurrentSourceFile(filename), position);
|
||||
}
|
||||
|
||||
function getNavigationBarItems(filename: string): NavigationBarItem[] {
|
||||
|
||||
23
tests/baselines/reference/bpSpan_variables.baseline
Normal file
23
tests/baselines/reference/bpSpan_variables.baseline
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
1 >var a = 10;
|
||||
|
||||
~~~~~~~~~~~~ => Pos: (0 to 11) SpanInfo: {"start":0,"length":10}
|
||||
>var a = 10
|
||||
>:=> (line 1, col 0) to (line 1, col 10)
|
||||
--------------------------------
|
||||
2 >var b;
|
||||
|
||||
~~~~~~~ => Pos: (12 to 18) SpanInfo: undefined
|
||||
--------------------------------
|
||||
3 >var c = 10, d, e;
|
||||
|
||||
~~~~~~~~~~~~~~~~~~ => Pos: (19 to 36) SpanInfo: {"start":19,"length":10}
|
||||
>var c = 10
|
||||
>:=> (line 3, col 0) to (line 3, col 10)
|
||||
--------------------------------
|
||||
4 >var c2, d2 = 10;
|
||||
~~~~~~~ => Pos: (37 to 43) SpanInfo: undefined
|
||||
4 >var c2, d2 = 10;
|
||||
~~~~~~~~~ => Pos: (44 to 52) SpanInfo: {"start":45,"length":7}
|
||||
>d2 = 10
|
||||
>:=> (line 4, col 8) to (line 4, col 15)
|
||||
Loading…
x
Reference in New Issue
Block a user