Added comment and uncomment selection

This commit is contained in:
Armando Aguirre
2020-05-22 16:56:57 -07:00
parent fe91f317de
commit ee37d8e8d3
20 changed files with 2177 additions and 1845 deletions
+835 -827
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -3679,6 +3679,28 @@ namespace FourSlash {
this.verifyCurrentFileContent(newFileContent);
}
public commentSelection(newFileContent: string): void {
let changes: ts.TextChange[] = [];
for (let range of this.getRanges()) {
changes.push.apply(changes, this.languageService.commentSelection(this.activeFile.fileName, range));
}
this.applyEdits(this.activeFile.fileName, changes);
this.verifyCurrentFileContent(newFileContent);
}
public uncommentSelection(newFileContent: string): void {
let changes: ts.TextChange[] = [];
for (let range of this.getRanges()) {
changes.push.apply(changes, this.languageService.uncommentSelection(this.activeFile.fileName, range));
}
this.applyEdits(this.activeFile.fileName, changes);
this.verifyCurrentFileContent(newFileContent);
}
}
function prefixMessage(message: string | undefined) {
+8
View File
@@ -218,6 +218,14 @@ namespace FourSlashInterface {
public toggleMultilineComment(newFileContent: string) {
this.state.toggleMultilineComment(newFileContent);
}
public commentSelection(newFileContent: string) {
this.state.commentSelection(newFileContent);
}
public uncommentSelection(newFileContent: string) {
this.state.uncommentSelection(newFileContent);
}
}
export class Verify extends VerifyNegatable {
File diff suppressed because it is too large Load Diff
+18 -1
View File
@@ -137,10 +137,17 @@ namespace ts.server.protocol {
/* @internal */
SelectionRangeFull = "selectionRange-full",
ToggleLineComment = "toggleLineComment",
/* @internal */
ToggleLineCommentFull = "toggleLineComment-full",
ToggleMultilineComment = "toggleMultilineComment",
/* @internal */
ToggleMultilineCommentFull = "toggleMultilineComment-full",
CommentSelection = "commentSelection",
/* @internal */
CommentSelectionFull = "commentSelection-full",
UncommentSelection = "uncommentSelection",
/* @internal */
UncommentSelectionFull = "uncommentSelection-full",
PrepareCallHierarchy = "prepareCallHierarchy",
ProvideCallHierarchyIncomingCalls = "provideCallHierarchyIncomingCalls",
ProvideCallHierarchyOutgoingCalls = "provideCallHierarchyOutgoingCalls",
@@ -1547,6 +1554,16 @@ namespace ts.server.protocol {
arguments: FileRangeRequestArgs;
}
export interface CommentSelectionRequest extends FileRequest {
command: CommandTypes.CommentSelection;
arguments: FileRangeRequestArgs;
}
export interface UncommentSelectionRequest extends FileRequest {
command: CommandTypes.UncommentSelection;
arguments: FileRangeRequestArgs;
}
/**
* Information found in an "open" request.
*/
+44
View File
@@ -2233,6 +2233,38 @@ namespace ts.server {
return textChanges;
}
private commentSelection(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().commentSelection(file, textRange);
if (simplifiedResult) {
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
return textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo));
}
return textChanges;
}
private uncommentSelection(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().uncommentSelection(file, textRange);
if (simplifiedResult) {
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
return textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo));
}
return textChanges;
}
private mapSelectionRange(selectionRange: SelectionRange, scriptInfo: ScriptInfo): protocol.SelectionRange {
const result: protocol.SelectionRange = {
textSpan: toProtocolTextSpan(selectionRange.textSpan, scriptInfo),
@@ -2690,6 +2722,18 @@ namespace ts.server {
[CommandNames.ToggleMultilineCommentFull]: (request: protocol.ToggleMultilineCommentRequest) => {
return this.requiredResponse(this.toggleMultilineComment(request.arguments, /*simplifiedResult*/false));
},
[CommandNames.CommentSelection]: (request: protocol.CommentSelectionRequest) => {
return this.requiredResponse(this.commentSelection(request.arguments, /*simplifiedResult*/true));
},
[CommandNames.CommentSelectionFull]: (request: protocol.CommentSelectionRequest) => {
return this.requiredResponse(this.commentSelection(request.arguments, /*simplifiedResult*/false));
},
[CommandNames.UncommentSelection]: (request: protocol.UncommentSelectionRequest) => {
return this.requiredResponse(this.uncommentSelection(request.arguments, /*simplifiedResult*/true));
},
[CommandNames.UncommentSelectionFull]: (request: protocol.UncommentSelectionRequest) => {
return this.requiredResponse(this.uncommentSelection(request.arguments, /*simplifiedResult*/false));
},
});
public addProtocolHandler(command: string, handler: (request: protocol.Request) => HandlerResponse) {
+36 -7
View File
@@ -1985,12 +1985,12 @@ namespace ts {
}
}
function toggleLineComment(fileName: string, textRange: TextRange): TextChange[] {
function toggleLineComment(fileName: string, textRange: TextRange, insertComment?: boolean): TextChange[] {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const textChanges: TextChange[] = [];
const { lineStarts, firstLine, lastLine } = getLinesForRange(sourceFile, textRange);
let isCommenting = false;
let isCommenting = insertComment || false;
let leftMostPosition = Number.MAX_VALUE;
let lineTextStarts = new Map<number>();
const whiteSpaceRegex = new RegExp(/\S/);
@@ -2008,7 +2008,7 @@ namespace ts {
lineTextStarts.set(i.toString(), regExec.index);
if (lineText.substr(regExec.index, openComment.length) !== openComment) {
isCommenting = true;
isCommenting = insertComment !== undefined ? insertComment : true;
}
}
}
@@ -2029,7 +2029,7 @@ namespace ts {
start: lineStarts[i] + leftMostPosition
}
});
} else {
} else if (sourceFile.text.substr(lineStarts[i] + lineTextStart, openComment.length) === openComment) {
textChanges.push({
newText: "",
span: {
@@ -2049,7 +2049,7 @@ namespace ts {
const textChanges: TextChange[] = [];
const { text } = sourceFile;
let isCommenting = insertComment !== undefined ? insertComment : false;
let isCommenting = insertComment || false;
const positions = [] as number[] as SortedArray<number>;
let pos = textRange.pos;
@@ -2083,7 +2083,9 @@ namespace ts {
} else { // If it's not in a comment range, then we need to comment the uncommented portions.
let newPos = text.substring(pos, textRange.end).search(`(${openMultilineRegex})|(${closeMultilineRegex})`);
isCommenting = isCommenting || !isTextWhiteSpaceLike(text, pos, newPos === -1 ? textRange.end : pos + newPos);
isCommenting = insertComment !== undefined
? insertComment
: isCommenting || !isTextWhiteSpaceLike(text, pos, newPos === -1 ? textRange.end : pos + newPos); // If isCommenting is already true we don't need to check whitespace again.
pos = newPos === -1 ? textRange.end + 1 : pos + newPos + closeMultiline.length;
}
}
@@ -2157,6 +2159,31 @@ namespace ts {
return textChanges;
}
function commentSelection(fileName: string, textRange: TextRange): TextChange[] {
return toggleLineComment(fileName, textRange, true);
}
function uncommentSelection(fileName: string, textRange: TextRange): TextChange[] {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const textChanges: TextChange[] = [];
for (let i = textRange.pos; i <= textRange.end; i++) {
let commentRange = isInComment(sourceFile, i);
if (commentRange) {
switch (commentRange.kind) {
case SyntaxKind.SingleLineCommentTrivia:
textChanges.push.apply(textChanges, toggleLineComment(fileName, { end: commentRange.end, pos: commentRange.pos + 1 }, false));
break;
case SyntaxKind.MultiLineCommentTrivia:
textChanges.push.apply(textChanges, toggleMultilineComment(fileName, { end: commentRange.end, pos: commentRange.pos + 1 }, false));
}
i = commentRange.end + 1;
}
}
return textChanges;
}
function isUnclosedTag({ openingElement, closingElement, parent }: JsxElement): boolean {
return !tagNamesAreEquivalent(openingElement.tagName, closingElement.tagName) ||
isJsxElement(parent) && tagNamesAreEquivalent(openingElement.tagName, parent.openingElement.tagName) && isUnclosedTag(parent);
@@ -2437,7 +2464,9 @@ namespace ts {
provideCallHierarchyIncomingCalls,
provideCallHierarchyOutgoingCalls,
toggleLineComment,
toggleMultilineComment
toggleMultilineComment,
commentSelection,
uncommentSelection,
};
}
+16
View File
@@ -280,6 +280,8 @@ namespace ts {
toggleLineComment(fileName: string, textChange: ts.TextRange): string;
toggleMultilineComment(fileName: string, textChange: ts.TextRange): string;
commentSelection(fileName: string, textChange: ts.TextRange): string;
uncommentSelection(fileName: string, textChange: ts.TextRange): string;
}
export interface ClassifierShim extends Shim {
@@ -1083,6 +1085,20 @@ namespace ts {
() => this.languageService.toggleMultilineComment(fileName, textRange)
);
}
public commentSelection(fileName: string, textRange: ts.TextRange): string {
return this.forwardJSONCall(
`commentSelection('${fileName}', '${JSON.stringify(textRange)}')`,
() => this.languageService.commentSelection(fileName, textRange)
);
}
public uncommentSelection(fileName: string, textRange: ts.TextRange): string {
return this.forwardJSONCall(
`uncommentSelection('${fileName}', '${JSON.stringify(textRange)}')`,
() => this.languageService.uncommentSelection(fileName, textRange)
);
}
}
function convertClassifications(classifications: Classifications): { spans: string, endOfLineState: EndOfLineState } {
+2
View File
@@ -488,6 +488,8 @@ namespace ts {
toggleLineComment(fileName: string, textRanges: TextRange): TextChange[];
toggleMultilineComment(fileName: string, textRanges: TextRange): TextChange[];
commentSelection(fileName: string, textRanges: TextRange): TextChange[];
uncommentSelection(fileName: string, textRanges: TextRange): TextChange[];
dispose(): void;
}
+3 -1
View File
@@ -273,7 +273,9 @@ namespace ts.server {
CommandNames.ProvideCallHierarchyIncomingCalls,
CommandNames.ProvideCallHierarchyOutgoingCalls,
CommandNames.ToggleLineComment,
CommandNames.ToggleMultilineComment
CommandNames.ToggleMultilineComment,
CommandNames.CommentSelection,
CommandNames.UncommentSelection,
];
it("should not throw when commands are executed with invalid arguments", () => {
+18 -21
View File
@@ -5315,8 +5315,10 @@ declare namespace ts {
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean): EmitOutput;
getProgram(): Program | undefined;
toggleLineComment(fileName: string, textRanges: TextRange[]): TextChange[];
toggleMultilineComment(fileName: string, textRanges: TextRange[]): TextChange[];
toggleLineComment(fileName: string, textRanges: TextRange): TextChange[];
toggleMultilineComment(fileName: string, textRanges: TextRange): TextChange[];
commentSelection(fileName: string, textRanges: TextRange): TextChange[];
uncommentSelection(fileName: string, textRanges: TextRange): TextChange[];
dispose(): void;
}
interface JsxClosingTagInfo {
@@ -6303,9 +6305,9 @@ declare namespace ts.server.protocol {
ConfigurePlugin = "configurePlugin",
SelectionRange = "selectionRange",
ToggleLineComment = "toggleLineComment",
ToggleLineCommentFull = "toggleLineComment-full",
ToggleMultilineComment = "toggleMultilineComment",
ToggleMultilineCommentFull = "toggleMultilineComment-full",
CommentSelection = "commentSelection",
UncommentSelection = "uncommentSelection",
PrepareCallHierarchy = "prepareCallHierarchy",
ProvideCallHierarchyIncomingCalls = "provideCallHierarchyIncomingCalls",
ProvideCallHierarchyOutgoingCalls = "provideCallHierarchyOutgoingCalls"
@@ -6881,16 +6883,6 @@ declare namespace ts.server.protocol {
*/
end: Location;
}
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.
*/
@@ -7342,17 +7334,19 @@ declare namespace ts.server.protocol {
}
interface ToggleLineCommentRequest extends FileRequest {
command: CommandTypes.ToggleLineComment;
arguments: ToggleLineCommentRequestArgs;
}
interface ToggleLineCommentRequestArgs extends FileRequestArgs {
textRanges: TextRange[];
arguments: FileRangeRequestArgs;
}
interface ToggleMultilineCommentRequest extends FileRequest {
command: CommandTypes.ToggleMultilineComment;
arguments: ToggleMultilineCommentRequestArgs;
arguments: FileRangeRequestArgs;
}
interface ToggleMultilineCommentRequestArgs extends FileRequestArgs {
textRanges: TextRange[];
interface CommentSelectionRequest extends FileRequest {
command: CommandTypes.CommentSelection;
arguments: FileRangeRequestArgs;
}
interface UncommentSelectionRequest extends FileRequest {
command: CommandTypes.UncommentSelection;
arguments: FileRangeRequestArgs;
}
/**
* Information found in an "open" request.
@@ -9690,6 +9684,7 @@ declare namespace ts.server {
private getSupportedCodeFixes;
private isLocation;
private extractPositionOrRange;
private getRange;
private getApplicableRefactors;
private getEditsForRefactor;
private organizeImports;
@@ -9709,6 +9704,8 @@ declare namespace ts.server {
private getSmartSelectionRange;
private toggleLineComment;
private toggleMultilineComment;
private commentSelection;
private uncommentSelection;
private mapSelectionRange;
private getScriptInfoFromProjectService;
private toProtocolCallHierarchyItem;
+4 -2
View File
@@ -5315,8 +5315,10 @@ declare namespace ts {
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean): EmitOutput;
getProgram(): Program | undefined;
toggleLineComment(fileName: string, textRanges: TextRange[]): TextChange[];
toggleMultilineComment(fileName: string, textRanges: TextRange[]): TextChange[];
toggleLineComment(fileName: string, textRanges: TextRange): TextChange[];
toggleMultilineComment(fileName: string, textRanges: TextRange): TextChange[];
commentSelection(fileName: string, textRanges: TextRange): TextChange[];
uncommentSelection(fileName: string, textRanges: TextRange): TextChange[];
dispose(): void;
}
interface JsxClosingTagInfo {
@@ -0,0 +1,18 @@
// Simple comment selection cases.
//// let var1[| = 1;
//// let var2 = 2;
//// let var3 |]= 3;
////
//// //let var4[| = 4;
//// //let var5 = 5;
//// //let var6 |]= 6;
verify.commentSelection(
`//let var1 = 1;
//let var2 = 2;
//let var3 = 3;
////let var4 = 4;
////let var5 = 5;
////let var6 = 6;`);
@@ -0,0 +1,29 @@
// Common jsx insert comment.
//@Filename: file.tsx
//// const a = <MyContainer>
//// [|<MyFirstComponent />
//// <MySecondComponent />|]
//// </MyContainer>;
//// const b = <MyContainer>
//// {/*<MyF[|irstComponent />*/}
//// {/*<MySec|]ondComponent />*/}
//// </MyContainer>;
//// const c = <MyContainer>[|
//// <MyFirstComponent />
//// <MySecondCompo|]nent />
//// </MyContainer>;
verify.commentSelection(
`const a = <MyContainer>
{/*<MyFirstComponent />*/}
{/*<MySecondComponent />*/}
</MyContainer>;
const b = <MyContainer>
{/*<MyFirstComponent />*/}
{/*<MySecondComponent />*/}
</MyContainer>;
//const c = <MyContainer>
// <MyFirstComponent />
// <MySecondComponent />
</MyContainer>;`);
+2
View File
@@ -399,6 +399,8 @@ declare namespace FourSlashInterface {
toggleLineComment(newFileContent: string): void;
toggleMultilineComment(newFileContent: string): void;
commentSelection(newFileContent: string): void;
uncommentSelection(newFileContent: string): void;
}
class edit {
backspace(count?: number): void;
@@ -1,4 +1,4 @@
// If selection is outside of a block comment then insert comment
// If selection is outside of a multiline comment then insert comment
// instead of removing.
//// let var1/* = 1;
@@ -0,0 +1,30 @@
// Simple comment selection cases.
//// //let var1[| = 1;
//// //let var2 = 2;
//// //let var3 |]= 3;
////
//// //let var4[| = 4;
//// /*let var5 = 5;*/
//// //let var6 = 6;
////
//// let var7 |]= 7;
////
//// let var8/* = 1;
//// let var9 [||]= 2;
//// let var10 */= 3;
verify.uncommentSelection(
`let var1 = 1;
let var2 = 2;
let var3 = 3;
let var4 = 4;
let var5 = 5;
let var6 = 6;
let var7 = 7;
let var8 = 1;
let var9 = 2;
let var10 = 3;`);
@@ -0,0 +1,26 @@
// Common uncomment jsx cases
//@Filename: file.tsx
//// const a = <MyContainer>
//// {/*<MyF[|irstComponent />*/}
//// {/*<MySec|]ondComponent />*/}
//// </MyContainer>;
////
//// const b = <div>
//// {/*[|<div>*/}
//// SomeText
//// {/*</div>|]*/}
//// </div>;
verify.uncommentSelection(
`const a = <MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>;
const b = <div>
<div>
SomeText
</div>
</div>;`);
@@ -0,0 +1,34 @@
// Remove all comments within the selection
//// let var1/* = 1;
//// let var2 [|= 2;
//// let var3 */= 3;|]
////
//// [|let var4/* = 1;
//// let var5 |]= 2;
//// let var6 */= 3;
////
//// [|let var7/* = 1;
//// let var8 = 2;
//// let var9 */= 3;|]
////
//// /*let va[|r10 = 1;*/
//// let var11 = 2;
//// /*let var12|] = 3;*/
verify.uncommentSelection(
`let var1 = 1;
let var2 = 2;
let var3 = 3;
let var4 = 1;
let var5 = 2;
let var6 = 3;
let var7 = 1;
let var8 = 2;
let var9 = 3;
let var10 = 1;
let var11 = 2;
let var12 = 3;`);
@@ -0,0 +1,40 @@
// Remove all comments in jsx.
//@Filename: file.tsx
//// const var1 = <div>Tex{/*t1</div>;
//// const var2 = <div>Text2[|</div>;
//// const var3 = <div>Tex*/}t3</div>;|]
////
//// [|const var4 = <div>Tex{/*t4</div>;
//// const var5 = <div|]>Text5</div>;
//// const var6 = <div>Tex*/}t6</div>;
////
//// [|const var7 = <div>Tex{/*t7</div>;
//// const var8 = <div>Text8</div>;
//// const var9 = <div>Tex*/}t9</div>;|]
////
//// const var10 = <div>
//// {/*<div>T[|ext</div>*/}
//// <div>Text</div>
//// {/*<div>Text|]</div>*/}
//// </div>;
verify.uncommentSelection(
`const var1 = <div>Text1</div>;
const var2 = <div>Text2</div>;
const var3 = <div>Text3</div>;
const var4 = <div>Text4</div>;
const var5 = <div>Text5</div>;
const var6 = <div>Text6</div>;
const var7 = <div>Text7</div>;
const var8 = <div>Text8</div>;
const var9 = <div>Text9</div>;
const var10 = <div>
<div>Text</div>
<div>Text</div>
<div>Text</div>
</div>;`
);