Removed TextRange and added FileRangeRequestArgs

This commit is contained in:
Armando Aguirre
2020-02-27 12:57:51 -08:00
parent 090b38daa1
commit 381dd8427a
7 changed files with 180 additions and 195 deletions

View File

@@ -3190,7 +3190,7 @@ namespace FourSlash {
this.raiseError(
`Expected to find a fix with the name '${fixName}', but none exists.` +
availableFixes.length
availableFixes.length
? ` Available fixes: ${availableFixes.map(fix => `${fix.fixName} (${fix.fixId ? "with" : "without"} fix-all)`).join(", ")}`
: ""
);
@@ -3429,13 +3429,13 @@ namespace FourSlash {
const incomingCalls =
direction === CallHierarchyItemDirection.Outgoing ? { result: "skip" } as const :
alreadySeen ? { result: "seen" } as const :
{ result: "show", values: this.languageService.provideCallHierarchyIncomingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
alreadySeen ? { result: "seen" } as const :
{ result: "show", values: this.languageService.provideCallHierarchyIncomingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
const outgoingCalls =
direction === CallHierarchyItemDirection.Incoming ? { result: "skip" } as const :
alreadySeen ? { result: "seen" } as const :
{ result: "show", values: this.languageService.provideCallHierarchyOutgoingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
alreadySeen ? { result: "seen" } as const :
{ result: "show", values: this.languageService.provideCallHierarchyOutgoingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
let text = "";
text += `${prefix}╭ name: ${callHierarchyItem.name}\n`;
@@ -3446,7 +3446,7 @@ namespace FourSlash {
text += `${prefix}├ selectionSpan:\n`;
text += this.formatCallHierarchyItemSpan(file, callHierarchyItem.selectionSpan, `${prefix}`,
incomingCalls.result !== "skip" || outgoingCalls.result !== "skip" ? `${prefix}` :
`${trailingPrefix}`);
`${trailingPrefix}`);
if (incomingCalls.result === "seen") {
if (outgoingCalls.result === "skip") {
@@ -3475,8 +3475,8 @@ namespace FourSlash {
text += `${prefix}│ ├ fromSpans:\n`;
text += this.formatCallHierarchyItemSpans(file, incomingCall.fromSpans, `${prefix}│ │ `,
i < incomingCalls.values.length - 1 ? `${prefix}│ ╰ ` :
outgoingCalls.result !== "skip" ? `${prefix}│ ╰ ` :
`${trailingPrefix}╰ ╰ `);
outgoingCalls.result !== "skip" ? `${prefix}│ ╰ ` :
`${trailingPrefix}╰ ╰ `);
}
}
}
@@ -3497,7 +3497,7 @@ namespace FourSlash {
text += `${prefix}│ ├ fromSpans:\n`;
text += this.formatCallHierarchyItemSpans(file, outgoingCall.fromSpans, `${prefix}│ │ `,
i < outgoingCalls.values.length - 1 ? `${prefix}│ ╰ ` :
`${trailingPrefix}╰ ╰ `);
`${trailingPrefix}╰ ╰ `);
}
}
}
@@ -3659,20 +3659,22 @@ namespace FourSlash {
}
public toggleLineComment(newFileContent: string): void {
const ranges = this.getRanges();
assert(ranges.length);
const changes = this.languageService.toggleLineComment(this.activeFile.fileName, ranges);
let changes: ts.TextChange[] = [];
for (let range of this.getRanges()) {
changes.push.apply(changes, this.languageService.toggleLineComment(this.activeFile.fileName, range));
}
this.applyEdits(this.activeFile.fileName, changes);
this.verifyCurrentFileContent(newFileContent);
}
public toggleMultilineComment(newFileContent: string): void {
const ranges = this.getRanges();
assert(ranges.length);
const changes = this.languageService.toggleMultilineComment(this.activeFile.fileName, ranges);
let changes: ts.TextChange[] = [];
for (let range of this.getRanges()) {
changes.push.apply(changes, this.languageService.toggleMultilineComment(this.activeFile.fileName, range));
}
this.applyEdits(this.activeFile.fileName, changes);
this.verifyCurrentFileContent(newFileContent);

View File

@@ -600,11 +600,11 @@ namespace Harness.LanguageService {
clearSourceMapperCache(): never {
return ts.notImplemented();
}
toggleLineComment(fileName: string, textRanges: ts.TextRange[]): ts.TextChange[] {
return unwrapJSONCallResult(this.shim.toggleLineComment(fileName, textRanges));
toggleLineComment(fileName: string, textRange: ts.TextRange): ts.TextChange[] {
return unwrapJSONCallResult(this.shim.toggleLineComment(fileName, textRange));
}
toggleMultilineComment(fileName: string, textRanges: ts.TextRange[]): ts.TextChange[] {
return unwrapJSONCallResult(this.shim.toggleMultilineComment(fileName, textRanges));
toggleMultilineComment(fileName: string, textRange: ts.TextRange): ts.TextChange[] {
return unwrapJSONCallResult(this.shim.toggleMultilineComment(fileName, textRange));
}
dispose(): void { this.shim.dispose({}); }
}

View File

@@ -923,18 +923,6 @@ namespace ts.server.protocol {
end: Location;
}
export interface TextRange {
/**
* Position of the first character.
*/
pos: number;
/**
* Position of the last character.
*/
end: number;
}
/**
* Object found in response messages defining a span of text in a specific source file.
*/
@@ -1551,20 +1539,12 @@ namespace ts.server.protocol {
export interface ToggleLineCommentRequest extends FileRequest {
command: CommandTypes.ToggleLineComment;
arguments: ToggleLineCommentRequestArgs;
}
export interface ToggleLineCommentRequestArgs extends FileRequestArgs {
textRanges: TextRange[];
arguments: FileRangeRequestArgs;
}
export interface ToggleMultilineCommentRequest extends FileRequest {
command: CommandTypes.ToggleMultilineComment;
arguments: ToggleMultilineCommentRequestArgs;
}
export interface ToggleMultilineCommentRequestArgs extends FileRequestArgs {
textRanges: TextRange[];
arguments: FileRangeRequestArgs;
}
/**

View File

@@ -1957,8 +1957,7 @@ namespace ts.server {
position = getPosition(args);
}
else {
const { startPosition, endPosition } = this.getStartAndEndPosition(args, scriptInfo);
textRange = { pos: startPosition, end: endPosition };
textRange = this.getRange(args, scriptInfo);
}
return Debug.checkDefined(position === undefined ? textRange : position);
@@ -1967,6 +1966,12 @@ namespace ts.server {
}
}
private getRange(args: protocol.FileRangeRequestArgs, scriptInfo: ScriptInfo): TextRange {
const { startPosition, endPosition } = this.getStartAndEndPosition(args, scriptInfo);
return { pos: startPosition, end: endPosition };
}
private getApplicableRefactors(args: protocol.GetApplicableRefactorsRequestArgs): protocol.ApplicableRefactorInfo[] {
const { file, project } = this.getFileAndProject(args);
const scriptInfo = project.getScriptInfoForNormalizedPath(file)!;
@@ -2196,10 +2201,12 @@ namespace ts.server {
});
}
private toggleLineComment(args: protocol.ToggleLineCommentRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
private toggleLineComment(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
const { file, project } = this.getFileAndProject(args);
const scriptInfo = project.getScriptInfoForNormalizedPath(file)!;
const textRange = this.getRange(args, scriptInfo);
const textChanges = project.getLanguageService().toggleLineComment(file, args.textRanges);
const textChanges = project.getLanguageService().toggleLineComment(file, textRange);
if (simplifiedResult) {
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
@@ -2210,10 +2217,12 @@ namespace ts.server {
return textChanges;
}
private toggleMultilineComment(args: protocol.ToggleMultilineCommentRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
private toggleMultilineComment(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
const { file, project } = this.getFileAndProject(args);
const scriptInfo = project.getScriptInfoForNormalizedPath(file)!;
const textRange = this.getRange(args, scriptInfo);
const textChanges = project.getLanguageService().toggleMultilineComment(file, args.textRanges);
const textChanges = project.getLanguageService().toggleMultilineComment(file, textRange);
if (simplifiedResult) {
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
@@ -2678,7 +2687,7 @@ namespace ts.server {
[CommandNames.ToggleMultilineComment]: (request: protocol.ToggleMultilineCommentRequest) => {
return this.requiredResponse(this.toggleMultilineComment(request.arguments, /*simplifiedResult*/true));
},
[CommandNames.ToggleMultilineComment]: (request: protocol.ToggleMultilineCommentRequest) => {
[CommandNames.ToggleMultilineCommentFull]: (request: protocol.ToggleMultilineCommentRequest) => {
return this.requiredResponse(this.toggleMultilineComment(request.arguments, /*simplifiedResult*/false));
},
});

View File

@@ -5,8 +5,8 @@ namespace ts {
function createNode<TKind extends SyntaxKind>(kind: TKind, pos: number, end: number, parent: Node): NodeObject | TokenObject<TKind> | IdentifierObject | PrivateIdentifierObject {
const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) :
kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) :
kind === SyntaxKind.PrivateIdentifier ? new PrivateIdentifierObject(SyntaxKind.PrivateIdentifier, pos, end) :
new TokenObject(kind, pos, end);
kind === SyntaxKind.PrivateIdentifier ? new PrivateIdentifierObject(SyntaxKind.PrivateIdentifier, pos, end) :
new TokenObject(kind, pos, end);
node.parent = parent;
node.flags = parent.flags & NodeFlags.ContextFlags;
return node;
@@ -1985,62 +1985,58 @@ namespace ts {
}
}
function toggleLineComment(fileName: string, textRanges: TextRange[]): TextChange[] {
function toggleLineComment(fileName: string, textRange: TextRange): TextChange[] {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const textChanges: TextChange[] = [];
const { lineStarts, firstLine, lastLine } = getLinesForRange(sourceFile, textRange);
for (const textRange of textRanges) {
const { lineStarts, firstLine, lastLine } = getLinesForRange(sourceFile, textRange);
let isCommenting = false;
let leftMostPosition = Number.MAX_VALUE;
let lineTextStarts = new Map<number>();
const whiteSpaceRegex = new RegExp(/\S/);
const isJsx = isInsideJsxElement(sourceFile, lineStarts[firstLine])
const openComment = isJsx ? "{/*" : "//";
let isCommenting = false;
let leftMostPosition = Number.MAX_VALUE;
let lineTextStarts = new Map<number>();
const whiteSpaceRegex = new RegExp(/\S/);
const isJsx = isInsideJsxElement(sourceFile, lineStarts[firstLine])
const openComment = isJsx ? "{/*" : "//";
// Check each line before any text changes.
for (let i = firstLine; i <= lastLine; i++) {
const lineText = sourceFile.text.substring(lineStarts[i], sourceFile.getLineEndOfPosition(lineStarts[i]));
// Check each line before any text changes.
for (let i = firstLine; i <= lastLine; i++) {
const lineText = sourceFile.text.substring(lineStarts[i], sourceFile.getLineEndOfPosition(lineStarts[i]));
// Find the start of text and the left-most character. No-op on empty lines.
const regExec = whiteSpaceRegex.exec(lineText);
if (regExec) {
leftMostPosition = Math.min(leftMostPosition, regExec.index);
lineTextStarts.set(i.toString(), regExec.index);
// Find the start of text and the left-most character. No-op on empty lines.
const regExec = whiteSpaceRegex.exec(lineText);
if (regExec) {
leftMostPosition = Math.min(leftMostPosition, regExec.index);
lineTextStarts.set(i.toString(), regExec.index);
if (lineText.substr(regExec.index, openComment.length) !== openComment) {
isCommenting = true;
}
if (lineText.substr(regExec.index, openComment.length) !== openComment) {
isCommenting = true;
}
}
}
// Push all text changes.
for (let i = firstLine; i <= lastLine; i++) {
const lineTextStart = lineTextStarts.get(i.toString());
// If the line is not an empty line; otherwise no-op.
if (lineTextStart !== undefined) {
if (isJsx) {
textChanges.push(...toggleMultilineComment(fileName, [{ pos: lineStarts[i] + leftMostPosition, end: sourceFile.getLineEndOfPosition(lineStarts[i]) }], isCommenting, isJsx));
} else if (isCommenting) {
textChanges.push({
newText: openComment,
span: {
length: 0,
start: lineStarts[i] + leftMostPosition
}
});
} else {
textChanges.push({
newText: "",
span: {
length: openComment.length,
start: lineStarts[i] + lineTextStart
}
});
}
// Push all text changes.
for (let i = firstLine; i <= lastLine; i++) {
const lineTextStart = lineTextStarts.get(i.toString());
// If the line is not an empty line; otherwise no-op.
if (lineTextStart !== undefined) {
if (isJsx) {
textChanges.push.apply(textChanges, toggleMultilineComment(fileName, { pos: lineStarts[i] + leftMostPosition, end: sourceFile.getLineEndOfPosition(lineStarts[i]) }, isCommenting, isJsx));
} else if (isCommenting) {
textChanges.push({
newText: openComment,
span: {
length: 0,
start: lineStarts[i] + leftMostPosition
}
});
} else {
textChanges.push({
newText: "",
span: {
length: openComment.length,
start: lineStarts[i] + lineTextStart
}
});
}
}
}
@@ -2048,116 +2044,114 @@ namespace ts {
return textChanges;
}
function toggleMultilineComment(fileName: string, textRanges: TextRange[], insertComment?: boolean, isInsideJsx?: boolean): TextChange[] {
function toggleMultilineComment(fileName: string, textRange: TextRange, insertComment?: boolean, isInsideJsx?: boolean): TextChange[] {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const textChanges: TextChange[] = [];
const { text } = sourceFile;
for (const textRange of textRanges) {
let isCommenting = insertComment !== undefined ? insertComment : false;
const positions = [] as number[] as SortedArray<number>;
let isCommenting = insertComment !== undefined ? insertComment : false;
const positions = [] as number[] as SortedArray<number>;
let pos = textRange.pos;
const isJsx = isInsideJsx !== undefined ? isInsideJsx : isInsideJsxElement(sourceFile, pos);
let pos = textRange.pos;
const isJsx = isInsideJsx !== undefined ? isInsideJsx : isInsideJsxElement(sourceFile, pos);
const openMultiline = isJsx ? "{/*" : "/*";
const closeMultiline = isJsx ? "*/}" : "*/";
const openMultilineRegex = isJsx ? "\\{\\/\\*" : "\\/\\*";
const closeMultilineRegex = isJsx ? "\\*\\/\\}" : "\\*\\/";
const openMultiline = isJsx ? "{/*" : "/*";
const closeMultiline = isJsx ? "*/}" : "*/";
const openMultilineRegex = isJsx ? "\\{\\/\\*" : "\\/\\*";
const closeMultilineRegex = isJsx ? "\\*\\/\\}" : "\\*\\/";
// Get all comment positions
while (pos <= textRange.end) {
// Start of comment is considered inside comment.
const offset = text.substr(pos, openMultiline.length) === openMultiline ? openMultiline.length : 0;
const commentRange = isInComment(sourceFile, pos + offset);
// Get all comment positions
while (pos <= textRange.end) {
// Start of comment is considered inside comment.
const offset = text.substr(pos, openMultiline.length) === openMultiline ? openMultiline.length : 0;
const commentRange = isInComment(sourceFile, pos + offset);
// If position is in a comment add it to the positions array.
if (commentRange) {
// Comment range doesn't include the brace character. Increase it to include them.
if (isJsx) {
commentRange.pos--;
commentRange.end++;
}
positions.push(commentRange.pos);
if (commentRange.kind === SyntaxKind.MultiLineCommentTrivia) {
positions.push(commentRange.end);
}
pos = commentRange.end + 1;
} else { // If it's not in a comment range, then we need to comment the uncommented portions.
isCommenting = true;
const newPos = text.substring(pos, textRange.end).search(`(${openMultilineRegex})|(${closeMultilineRegex})`);
pos = newPos === -1 ? textRange.end + 1 : pos + newPos + closeMultiline.length;
// If position is in a comment add it to the positions array.
if (commentRange) {
// Comment range doesn't include the brace character. Increase it to include them.
if (isJsx) {
commentRange.pos--;
commentRange.end++;
}
positions.push(commentRange.pos);
if (commentRange.kind === SyntaxKind.MultiLineCommentTrivia) {
positions.push(commentRange.end);
}
pos = commentRange.end + 1;
} else { // If it's not in a comment range, then we need to comment the uncommented portions.
isCommenting = true;
const newPos = text.substring(pos, textRange.end).search(`(${openMultilineRegex})|(${closeMultilineRegex})`);
pos = newPos === -1 ? textRange.end + 1 : pos + newPos + closeMultiline.length;
}
}
if (isCommenting) {
if (isInComment(sourceFile, textRange.pos)?.kind !== SyntaxKind.SingleLineCommentTrivia) {
insertSorted(positions, textRange.pos, compareValues);
}
insertSorted(positions, textRange.end, compareValues);
// Insert open comment if the first position is not a comment already.
const firstPos = positions[0];
if (text.substr(firstPos, openMultiline.length) !== openMultiline) {
textChanges.push({
newText: openMultiline,
span: {
length: 0,
start: firstPos
}
});
}
if (isCommenting) {
if (isInComment(sourceFile, textRange.pos)?.kind !== SyntaxKind.SingleLineCommentTrivia) {
insertSorted(positions, textRange.pos, compareValues);
}
insertSorted(positions, textRange.end, compareValues);
// Insert open comment if the first position is not a comment already.
const firstPos = positions[0];
if (text.substr(firstPos, openMultiline.length) !== openMultiline) {
textChanges.push({
newText: openMultiline,
span: {
length: 0,
start: firstPos
}
});
}
// Insert open and close comment to all positions between first and last. Exclusive.
for (let i = 1; i < positions.length - 1; i++) {
if (text.substr(positions[i] - closeMultiline.length, closeMultiline.length) !== closeMultiline) {
textChanges.push({
newText: closeMultiline,
span: {
length: 0,
start: positions[i]
}
});
}
if (text.substr(positions[i], openMultiline.length) !== openMultiline) {
textChanges.push({
newText: openMultiline,
span: {
length: 0,
start: positions[i]
}
});
}
}
// Insert open comment if the last position is not a comment already.
const lastPos = positions[positions.length - 1];
if (text.substr(lastPos - closeMultiline.length, closeMultiline.length) !== closeMultiline) {
// Insert open and close comment to all positions between first and last. Exclusive.
for (let i = 1; i < positions.length - 1; i++) {
if (text.substr(positions[i] - closeMultiline.length, closeMultiline.length) !== closeMultiline) {
textChanges.push({
newText: closeMultiline,
span: {
length: 0,
start: lastPos
start: positions[i]
}
});
}
} else {
// If is not commenting then remove all comments found.
for (let i = 0; i < positions.length; i++) {
const offset = text.substr(positions[i] - closeMultiline.length, closeMultiline.length) === closeMultiline ? closeMultiline.length : 0;
if (text.substr(positions[i], openMultiline.length) !== openMultiline) {
textChanges.push({
newText: "",
newText: openMultiline,
span: {
length: openMultiline.length,
start: positions[i] - offset
length: 0,
start: positions[i]
}
});
}
}
// Insert open comment if the last position is not a comment already.
const lastPos = positions[positions.length - 1];
if (text.substr(lastPos - closeMultiline.length, closeMultiline.length) !== closeMultiline) {
textChanges.push({
newText: closeMultiline,
span: {
length: 0,
start: lastPos
}
});
}
} else {
// If is not commenting then remove all comments found.
for (let i = 0; i < positions.length; i++) {
const offset = text.substr(positions[i] - closeMultiline.length, closeMultiline.length) === closeMultiline ? closeMultiline.length : 0;
textChanges.push({
newText: "",
span: {
length: openMultiline.length,
start: positions[i] - offset
}
});
}
}
return textChanges;

View File

@@ -278,8 +278,8 @@ namespace ts {
getEmitOutput(fileName: string): string;
getEmitOutputObject(fileName: string): EmitOutput;
toggleLineComment(fileName: string, textChanges: ts.TextRange[]): string;
toggleMultilineComment(fileName: string, textChanges: ts.TextRange[]): string;
toggleLineComment(fileName: string, textChange: ts.TextRange): string;
toggleMultilineComment(fileName: string, textChange: ts.TextRange): string;
}
export interface ClassifierShim extends Shim {
@@ -1070,17 +1070,17 @@ namespace ts {
this.logPerformance) as EmitOutput;
}
public toggleLineComment(fileName: string, textRanges: ts.TextRange[]): string {
public toggleLineComment(fileName: string, textRange: ts.TextRange): string {
return this.forwardJSONCall(
`toggleLineComment('${fileName}', '${JSON.stringify(textRanges)}')`,
() => this.languageService.toggleLineComment(fileName, textRanges)
`toggleLineComment('${fileName}', '${JSON.stringify(textRange)}')`,
() => this.languageService.toggleLineComment(fileName, textRange)
);
}
public toggleMultilineComment(fileName: string, textRanges: ts.TextRange[]): string {
public toggleMultilineComment(fileName: string, textRange: ts.TextRange): string {
return this.forwardJSONCall(
`toggleMultilineComment('${fileName}', '${JSON.stringify(textRanges)}')`,
() => this.languageService.toggleMultilineComment(fileName, textRanges)
`toggleMultilineComment('${fileName}', '${JSON.stringify(textRange)}')`,
() => this.languageService.toggleMultilineComment(fileName, textRange)
);
}
}

View File

@@ -486,8 +486,8 @@ namespace ts {
/* @internal */ getNonBoundSourceFile(fileName: string): SourceFile;
toggleLineComment(fileName: string, textRanges: TextRange[]): TextChange[];
toggleMultilineComment(fileName: string, textRanges: TextRange[]): TextChange[];
toggleLineComment(fileName: string, textRanges: TextRange): TextChange[];
toggleMultilineComment(fileName: string, textRanges: TextRange): TextChange[];
dispose(): void;
}