Skip to content

Commit ee37d8e

Browse files
author
Armando Aguirre
committed
Added comment and uncomment selection
1 parent fe91f31 commit ee37d8e

20 files changed

+2177
-1845
lines changed

src/harness/client.ts

Lines changed: 835 additions & 827 deletions
Large diffs are not rendered by default.

src/harness/fourslashImpl.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3679,6 +3679,28 @@ namespace FourSlash {
36793679

36803680
this.verifyCurrentFileContent(newFileContent);
36813681
}
3682+
3683+
public commentSelection(newFileContent: string): void {
3684+
let changes: ts.TextChange[] = [];
3685+
for (let range of this.getRanges()) {
3686+
changes.push.apply(changes, this.languageService.commentSelection(this.activeFile.fileName, range));
3687+
}
3688+
3689+
this.applyEdits(this.activeFile.fileName, changes);
3690+
3691+
this.verifyCurrentFileContent(newFileContent);
3692+
}
3693+
3694+
public uncommentSelection(newFileContent: string): void {
3695+
let changes: ts.TextChange[] = [];
3696+
for (let range of this.getRanges()) {
3697+
changes.push.apply(changes, this.languageService.uncommentSelection(this.activeFile.fileName, range));
3698+
}
3699+
3700+
this.applyEdits(this.activeFile.fileName, changes);
3701+
3702+
this.verifyCurrentFileContent(newFileContent);
3703+
}
36823704
}
36833705

36843706
function prefixMessage(message: string | undefined) {

src/harness/fourslashInterfaceImpl.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,14 @@ namespace FourSlashInterface {
218218
public toggleMultilineComment(newFileContent: string) {
219219
this.state.toggleMultilineComment(newFileContent);
220220
}
221+
222+
public commentSelection(newFileContent: string) {
223+
this.state.commentSelection(newFileContent);
224+
}
225+
226+
public uncommentSelection(newFileContent: string) {
227+
this.state.uncommentSelection(newFileContent);
228+
}
221229
}
222230

223231
export class Verify extends VerifyNegatable {

src/harness/harnessLanguageService.ts

Lines changed: 991 additions & 985 deletions
Large diffs are not rendered by default.

src/server/protocol.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,17 @@ namespace ts.server.protocol {
137137
/* @internal */
138138
SelectionRangeFull = "selectionRange-full",
139139
ToggleLineComment = "toggleLineComment",
140+
/* @internal */
140141
ToggleLineCommentFull = "toggleLineComment-full",
141142
ToggleMultilineComment = "toggleMultilineComment",
143+
/* @internal */
142144
ToggleMultilineCommentFull = "toggleMultilineComment-full",
143-
145+
CommentSelection = "commentSelection",
146+
/* @internal */
147+
CommentSelectionFull = "commentSelection-full",
148+
UncommentSelection = "uncommentSelection",
149+
/* @internal */
150+
UncommentSelectionFull = "uncommentSelection-full",
144151
PrepareCallHierarchy = "prepareCallHierarchy",
145152
ProvideCallHierarchyIncomingCalls = "provideCallHierarchyIncomingCalls",
146153
ProvideCallHierarchyOutgoingCalls = "provideCallHierarchyOutgoingCalls",
@@ -1547,6 +1554,16 @@ namespace ts.server.protocol {
15471554
arguments: FileRangeRequestArgs;
15481555
}
15491556

1557+
export interface CommentSelectionRequest extends FileRequest {
1558+
command: CommandTypes.CommentSelection;
1559+
arguments: FileRangeRequestArgs;
1560+
}
1561+
1562+
export interface UncommentSelectionRequest extends FileRequest {
1563+
command: CommandTypes.UncommentSelection;
1564+
arguments: FileRangeRequestArgs;
1565+
}
1566+
15501567
/**
15511568
* Information found in an "open" request.
15521569
*/

src/server/session.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2233,6 +2233,38 @@ namespace ts.server {
22332233
return textChanges;
22342234
}
22352235

2236+
private commentSelection(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
2237+
const { file, project } = this.getFileAndProject(args);
2238+
const scriptInfo = project.getScriptInfoForNormalizedPath(file)!;
2239+
const textRange = this.getRange(args, scriptInfo);
2240+
2241+
const textChanges = project.getLanguageService().commentSelection(file, textRange);
2242+
2243+
if (simplifiedResult) {
2244+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
2245+
2246+
return textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo));
2247+
}
2248+
2249+
return textChanges;
2250+
}
2251+
2252+
private uncommentSelection(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
2253+
const { file, project } = this.getFileAndProject(args);
2254+
const scriptInfo = project.getScriptInfoForNormalizedPath(file)!;
2255+
const textRange = this.getRange(args, scriptInfo);
2256+
2257+
const textChanges = project.getLanguageService().uncommentSelection(file, textRange);
2258+
2259+
if (simplifiedResult) {
2260+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
2261+
2262+
return textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo));
2263+
}
2264+
2265+
return textChanges;
2266+
}
2267+
22362268
private mapSelectionRange(selectionRange: SelectionRange, scriptInfo: ScriptInfo): protocol.SelectionRange {
22372269
const result: protocol.SelectionRange = {
22382270
textSpan: toProtocolTextSpan(selectionRange.textSpan, scriptInfo),
@@ -2690,6 +2722,18 @@ namespace ts.server {
26902722
[CommandNames.ToggleMultilineCommentFull]: (request: protocol.ToggleMultilineCommentRequest) => {
26912723
return this.requiredResponse(this.toggleMultilineComment(request.arguments, /*simplifiedResult*/false));
26922724
},
2725+
[CommandNames.CommentSelection]: (request: protocol.CommentSelectionRequest) => {
2726+
return this.requiredResponse(this.commentSelection(request.arguments, /*simplifiedResult*/true));
2727+
},
2728+
[CommandNames.CommentSelectionFull]: (request: protocol.CommentSelectionRequest) => {
2729+
return this.requiredResponse(this.commentSelection(request.arguments, /*simplifiedResult*/false));
2730+
},
2731+
[CommandNames.UncommentSelection]: (request: protocol.UncommentSelectionRequest) => {
2732+
return this.requiredResponse(this.uncommentSelection(request.arguments, /*simplifiedResult*/true));
2733+
},
2734+
[CommandNames.UncommentSelectionFull]: (request: protocol.UncommentSelectionRequest) => {
2735+
return this.requiredResponse(this.uncommentSelection(request.arguments, /*simplifiedResult*/false));
2736+
},
26932737
});
26942738

26952739
public addProtocolHandler(command: string, handler: (request: protocol.Request) => HandlerResponse) {

src/services/services.ts

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,12 +1985,12 @@ namespace ts {
19851985
}
19861986
}
19871987

1988-
function toggleLineComment(fileName: string, textRange: TextRange): TextChange[] {
1988+
function toggleLineComment(fileName: string, textRange: TextRange, insertComment?: boolean): TextChange[] {
19891989
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
19901990
const textChanges: TextChange[] = [];
19911991
const { lineStarts, firstLine, lastLine } = getLinesForRange(sourceFile, textRange);
19921992

1993-
let isCommenting = false;
1993+
let isCommenting = insertComment || false;
19941994
let leftMostPosition = Number.MAX_VALUE;
19951995
let lineTextStarts = new Map<number>();
19961996
const whiteSpaceRegex = new RegExp(/\S/);
@@ -2008,7 +2008,7 @@ namespace ts {
20082008
lineTextStarts.set(i.toString(), regExec.index);
20092009

20102010
if (lineText.substr(regExec.index, openComment.length) !== openComment) {
2011-
isCommenting = true;
2011+
isCommenting = insertComment !== undefined ? insertComment : true;
20122012
}
20132013
}
20142014
}
@@ -2029,7 +2029,7 @@ namespace ts {
20292029
start: lineStarts[i] + leftMostPosition
20302030
}
20312031
});
2032-
} else {
2032+
} else if (sourceFile.text.substr(lineStarts[i] + lineTextStart, openComment.length) === openComment) {
20332033
textChanges.push({
20342034
newText: "",
20352035
span: {
@@ -2049,7 +2049,7 @@ namespace ts {
20492049
const textChanges: TextChange[] = [];
20502050
const { text } = sourceFile;
20512051

2052-
let isCommenting = insertComment !== undefined ? insertComment : false;
2052+
let isCommenting = insertComment || false;
20532053
const positions = [] as number[] as SortedArray<number>;
20542054

20552055
let pos = textRange.pos;
@@ -2083,7 +2083,9 @@ namespace ts {
20832083
} else { // If it's not in a comment range, then we need to comment the uncommented portions.
20842084
let newPos = text.substring(pos, textRange.end).search(`(${openMultilineRegex})|(${closeMultilineRegex})`);
20852085

2086-
isCommenting = isCommenting || !isTextWhiteSpaceLike(text, pos, newPos === -1 ? textRange.end : pos + newPos);
2086+
isCommenting = insertComment !== undefined
2087+
? insertComment
2088+
: isCommenting || !isTextWhiteSpaceLike(text, pos, newPos === -1 ? textRange.end : pos + newPos); // If isCommenting is already true we don't need to check whitespace again.
20872089
pos = newPos === -1 ? textRange.end + 1 : pos + newPos + closeMultiline.length;
20882090
}
20892091
}
@@ -2157,6 +2159,31 @@ namespace ts {
21572159
return textChanges;
21582160
}
21592161

2162+
function commentSelection(fileName: string, textRange: TextRange): TextChange[] {
2163+
return toggleLineComment(fileName, textRange, true);
2164+
}
2165+
function uncommentSelection(fileName: string, textRange: TextRange): TextChange[] {
2166+
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
2167+
const textChanges: TextChange[] = [];
2168+
2169+
for (let i = textRange.pos; i <= textRange.end; i++) {
2170+
let commentRange = isInComment(sourceFile, i);
2171+
if (commentRange) {
2172+
switch (commentRange.kind) {
2173+
case SyntaxKind.SingleLineCommentTrivia:
2174+
textChanges.push.apply(textChanges, toggleLineComment(fileName, { end: commentRange.end, pos: commentRange.pos + 1 }, false));
2175+
break;
2176+
case SyntaxKind.MultiLineCommentTrivia:
2177+
textChanges.push.apply(textChanges, toggleMultilineComment(fileName, { end: commentRange.end, pos: commentRange.pos + 1 }, false));
2178+
}
2179+
2180+
i = commentRange.end + 1;
2181+
}
2182+
}
2183+
2184+
return textChanges;
2185+
}
2186+
21602187
function isUnclosedTag({ openingElement, closingElement, parent }: JsxElement): boolean {
21612188
return !tagNamesAreEquivalent(openingElement.tagName, closingElement.tagName) ||
21622189
isJsxElement(parent) && tagNamesAreEquivalent(openingElement.tagName, parent.openingElement.tagName) && isUnclosedTag(parent);
@@ -2437,7 +2464,9 @@ namespace ts {
24372464
provideCallHierarchyIncomingCalls,
24382465
provideCallHierarchyOutgoingCalls,
24392466
toggleLineComment,
2440-
toggleMultilineComment
2467+
toggleMultilineComment,
2468+
commentSelection,
2469+
uncommentSelection,
24412470
};
24422471
}
24432472

src/services/shims.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ namespace ts {
280280

281281
toggleLineComment(fileName: string, textChange: ts.TextRange): string;
282282
toggleMultilineComment(fileName: string, textChange: ts.TextRange): string;
283+
commentSelection(fileName: string, textChange: ts.TextRange): string;
284+
uncommentSelection(fileName: string, textChange: ts.TextRange): string;
283285
}
284286

285287
export interface ClassifierShim extends Shim {
@@ -1083,6 +1085,20 @@ namespace ts {
10831085
() => this.languageService.toggleMultilineComment(fileName, textRange)
10841086
);
10851087
}
1088+
1089+
public commentSelection(fileName: string, textRange: ts.TextRange): string {
1090+
return this.forwardJSONCall(
1091+
`commentSelection('${fileName}', '${JSON.stringify(textRange)}')`,
1092+
() => this.languageService.commentSelection(fileName, textRange)
1093+
);
1094+
}
1095+
1096+
public uncommentSelection(fileName: string, textRange: ts.TextRange): string {
1097+
return this.forwardJSONCall(
1098+
`uncommentSelection('${fileName}', '${JSON.stringify(textRange)}')`,
1099+
() => this.languageService.uncommentSelection(fileName, textRange)
1100+
);
1101+
}
10861102
}
10871103

10881104
function convertClassifications(classifications: Classifications): { spans: string, endOfLineState: EndOfLineState } {

src/services/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ namespace ts {
488488

489489
toggleLineComment(fileName: string, textRanges: TextRange): TextChange[];
490490
toggleMultilineComment(fileName: string, textRanges: TextRange): TextChange[];
491+
commentSelection(fileName: string, textRanges: TextRange): TextChange[];
492+
uncommentSelection(fileName: string, textRanges: TextRange): TextChange[];
491493

492494
dispose(): void;
493495
}

src/testRunner/unittests/tsserver/session.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,9 @@ namespace ts.server {
273273
CommandNames.ProvideCallHierarchyIncomingCalls,
274274
CommandNames.ProvideCallHierarchyOutgoingCalls,
275275
CommandNames.ToggleLineComment,
276-
CommandNames.ToggleMultilineComment
276+
CommandNames.ToggleMultilineComment,
277+
CommandNames.CommentSelection,
278+
CommandNames.UncommentSelection,
277279
];
278280

279281
it("should not throw when commands are executed with invalid arguments", () => {

0 commit comments

Comments
 (0)