Skip to content

Commit 6279f98

Browse files
authored
Merge pull request #37029 from armanio123/AddToggleCommentFeature
Add ToggleLineComment and ToggleMultilineComment service
2 parents 3c91133 + 635ee24 commit 6279f98

39 files changed

+1262
-33
lines changed

src/harness/client.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,22 @@ namespace ts.server {
825825
return notImplemented();
826826
}
827827

828+
toggleLineComment(): TextChange[] {
829+
return notImplemented();
830+
}
831+
832+
toggleMultilineComment(): TextChange[] {
833+
return notImplemented();
834+
}
835+
836+
commentSelection(): TextChange[] {
837+
return notImplemented();
838+
}
839+
840+
uncommentSelection(): TextChange[] {
841+
return notImplemented();
842+
}
843+
828844
dispose(): void {
829845
throw new Error("dispose is not available through the server layer.");
830846
}

src/harness/fourslashImpl.ts

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3226,7 +3226,7 @@ namespace FourSlash {
32263226

32273227
this.raiseError(
32283228
`Expected to find a fix with the name '${fixName}', but none exists.` +
3229-
availableFixes.length
3229+
availableFixes.length
32303230
? ` Available fixes: ${availableFixes.map(fix => `${fix.fixName} (${fix.fixId ? "with" : "without"} fix-all)`).join(", ")}`
32313231
: ""
32323232
);
@@ -3465,13 +3465,13 @@ namespace FourSlash {
34653465

34663466
const incomingCalls =
34673467
direction === CallHierarchyItemDirection.Outgoing ? { result: "skip" } as const :
3468-
alreadySeen ? { result: "seen" } as const :
3469-
{ result: "show", values: this.languageService.provideCallHierarchyIncomingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
3468+
alreadySeen ? { result: "seen" } as const :
3469+
{ result: "show", values: this.languageService.provideCallHierarchyIncomingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
34703470

34713471
const outgoingCalls =
34723472
direction === CallHierarchyItemDirection.Incoming ? { result: "skip" } as const :
3473-
alreadySeen ? { result: "seen" } as const :
3474-
{ result: "show", values: this.languageService.provideCallHierarchyOutgoingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
3473+
alreadySeen ? { result: "seen" } as const :
3474+
{ result: "show", values: this.languageService.provideCallHierarchyOutgoingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const;
34753475

34763476
let text = "";
34773477
text += `${prefix}╭ name: ${callHierarchyItem.name}\n`;
@@ -3485,7 +3485,7 @@ namespace FourSlash {
34853485
text += `${prefix}├ selectionSpan:\n`;
34863486
text += this.formatCallHierarchyItemSpan(file, callHierarchyItem.selectionSpan, `${prefix}│ `,
34873487
incomingCalls.result !== "skip" || outgoingCalls.result !== "skip" ? `${prefix}│ ` :
3488-
`${trailingPrefix}╰ `);
3488+
`${trailingPrefix}╰ `);
34893489

34903490
if (incomingCalls.result === "seen") {
34913491
if (outgoingCalls.result === "skip") {
@@ -3514,8 +3514,8 @@ namespace FourSlash {
35143514
text += `${prefix}│ ├ fromSpans:\n`;
35153515
text += this.formatCallHierarchyItemSpans(file, incomingCall.fromSpans, `${prefix}│ │ `,
35163516
i < incomingCalls.values.length - 1 ? `${prefix}│ ╰ ` :
3517-
outgoingCalls.result !== "skip" ? `${prefix}│ ╰ ` :
3518-
`${trailingPrefix}╰ ╰ `);
3517+
outgoingCalls.result !== "skip" ? `${prefix}│ ╰ ` :
3518+
`${trailingPrefix}╰ ╰ `);
35193519
}
35203520
}
35213521
}
@@ -3536,7 +3536,7 @@ namespace FourSlash {
35363536
text += `${prefix}│ ├ fromSpans:\n`;
35373537
text += this.formatCallHierarchyItemSpans(file, outgoingCall.fromSpans, `${prefix}│ │ `,
35383538
i < outgoingCalls.values.length - 1 ? `${prefix}│ ╰ ` :
3539-
`${trailingPrefix}╰ ╰ `);
3539+
`${trailingPrefix}╰ ╰ `);
35403540
}
35413541
}
35423542
}
@@ -3696,6 +3696,50 @@ namespace FourSlash {
36963696
public configurePlugin(pluginName: string, configuration: any): void {
36973697
(<ts.server.SessionClient>this.languageService).configurePlugin(pluginName, configuration);
36983698
}
3699+
3700+
public toggleLineComment(newFileContent: string): void {
3701+
const changes: ts.TextChange[] = [];
3702+
for (const range of this.getRanges()) {
3703+
changes.push.apply(changes, this.languageService.toggleLineComment(this.activeFile.fileName, range));
3704+
}
3705+
3706+
this.applyEdits(this.activeFile.fileName, changes);
3707+
3708+
this.verifyCurrentFileContent(newFileContent);
3709+
}
3710+
3711+
public toggleMultilineComment(newFileContent: string): void {
3712+
const changes: ts.TextChange[] = [];
3713+
for (const range of this.getRanges()) {
3714+
changes.push.apply(changes, this.languageService.toggleMultilineComment(this.activeFile.fileName, range));
3715+
}
3716+
3717+
this.applyEdits(this.activeFile.fileName, changes);
3718+
3719+
this.verifyCurrentFileContent(newFileContent);
3720+
}
3721+
3722+
public commentSelection(newFileContent: string): void {
3723+
const changes: ts.TextChange[] = [];
3724+
for (const range of this.getRanges()) {
3725+
changes.push.apply(changes, this.languageService.commentSelection(this.activeFile.fileName, range));
3726+
}
3727+
3728+
this.applyEdits(this.activeFile.fileName, changes);
3729+
3730+
this.verifyCurrentFileContent(newFileContent);
3731+
}
3732+
3733+
public uncommentSelection(newFileContent: string): void {
3734+
const changes: ts.TextChange[] = [];
3735+
for (const range of this.getRanges()) {
3736+
changes.push.apply(changes, this.languageService.uncommentSelection(this.activeFile.fileName, range));
3737+
}
3738+
3739+
this.applyEdits(this.activeFile.fileName, changes);
3740+
3741+
this.verifyCurrentFileContent(newFileContent);
3742+
}
36993743
}
37003744

37013745
function prefixMessage(message: string | undefined) {

src/harness/fourslashInterfaceImpl.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,22 @@ namespace FourSlashInterface {
214214
public refactorAvailableForTriggerReason(triggerReason: ts.RefactorTriggerReason, name: string, actionName?: string) {
215215
this.state.verifyRefactorAvailable(this.negative, triggerReason, name, actionName);
216216
}
217+
218+
public toggleLineComment(newFileContent: string) {
219+
this.state.toggleLineComment(newFileContent);
220+
}
221+
222+
public toggleMultilineComment(newFileContent: string) {
223+
this.state.toggleMultilineComment(newFileContent);
224+
}
225+
226+
public commentSelection(newFileContent: string) {
227+
this.state.commentSelection(newFileContent);
228+
}
229+
230+
public uncommentSelection(newFileContent: string) {
231+
this.state.uncommentSelection(newFileContent);
232+
}
217233
}
218234

219235
export class Verify extends VerifyNegatable {

src/harness/harnessLanguageService.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,18 @@ namespace Harness.LanguageService {
603603
clearSourceMapperCache(): never {
604604
return ts.notImplemented();
605605
}
606+
toggleLineComment(fileName: string, textRange: ts.TextRange): ts.TextChange[] {
607+
return unwrapJSONCallResult(this.shim.toggleLineComment(fileName, textRange));
608+
}
609+
toggleMultilineComment(fileName: string, textRange: ts.TextRange): ts.TextChange[] {
610+
return unwrapJSONCallResult(this.shim.toggleMultilineComment(fileName, textRange));
611+
}
612+
commentSelection(fileName: string, textRange: ts.TextRange): ts.TextChange[] {
613+
return unwrapJSONCallResult(this.shim.commentSelection(fileName, textRange));
614+
}
615+
uncommentSelection(fileName: string, textRange: ts.TextRange): ts.TextChange[] {
616+
return unwrapJSONCallResult(this.shim.uncommentSelection(fileName, textRange));
617+
}
606618
dispose(): void { this.shim.dispose({}); }
607619
}
608620

src/server/protocol.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,18 @@ namespace ts.server.protocol {
136136
SelectionRange = "selectionRange",
137137
/* @internal */
138138
SelectionRangeFull = "selectionRange-full",
139-
139+
ToggleLineComment = "toggleLineComment",
140+
/* @internal */
141+
ToggleLineCommentFull = "toggleLineComment-full",
142+
ToggleMultilineComment = "toggleMultilineComment",
143+
/* @internal */
144+
ToggleMultilineCommentFull = "toggleMultilineComment-full",
145+
CommentSelection = "commentSelection",
146+
/* @internal */
147+
CommentSelectionFull = "commentSelection-full",
148+
UncommentSelection = "uncommentSelection",
149+
/* @internal */
150+
UncommentSelectionFull = "uncommentSelection-full",
140151
PrepareCallHierarchy = "prepareCallHierarchy",
141152
ProvideCallHierarchyIncomingCalls = "provideCallHierarchyIncomingCalls",
142153
ProvideCallHierarchyOutgoingCalls = "provideCallHierarchyOutgoingCalls",
@@ -1542,6 +1553,26 @@ namespace ts.server.protocol {
15421553
parent?: SelectionRange;
15431554
}
15441555

1556+
export interface ToggleLineCommentRequest extends FileRequest {
1557+
command: CommandTypes.ToggleLineComment;
1558+
arguments: FileRangeRequestArgs;
1559+
}
1560+
1561+
export interface ToggleMultilineCommentRequest extends FileRequest {
1562+
command: CommandTypes.ToggleMultilineComment;
1563+
arguments: FileRangeRequestArgs;
1564+
}
1565+
1566+
export interface CommentSelectionRequest extends FileRequest {
1567+
command: CommandTypes.CommentSelection;
1568+
arguments: FileRangeRequestArgs;
1569+
}
1570+
1571+
export interface UncommentSelectionRequest extends FileRequest {
1572+
command: CommandTypes.UncommentSelection;
1573+
arguments: FileRangeRequestArgs;
1574+
}
1575+
15451576
/**
15461577
* Information found in an "open" request.
15471578
*/

src/server/session.ts

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,8 +2012,7 @@ namespace ts.server {
20122012
position = getPosition(args);
20132013
}
20142014
else {
2015-
const { startPosition, endPosition } = this.getStartAndEndPosition(args, scriptInfo);
2016-
textRange = { pos: startPosition, end: endPosition };
2015+
textRange = this.getRange(args, scriptInfo);
20172016
}
20182017
return Debug.checkDefined(position === undefined ? textRange : position);
20192018

@@ -2022,6 +2021,12 @@ namespace ts.server {
20222021
}
20232022
}
20242023

2024+
private getRange(args: protocol.FileRangeRequestArgs, scriptInfo: ScriptInfo): TextRange {
2025+
const { startPosition, endPosition } = this.getStartAndEndPosition(args, scriptInfo);
2026+
2027+
return { pos: startPosition, end: endPosition };
2028+
}
2029+
20252030
private getApplicableRefactors(args: protocol.GetApplicableRefactorsRequestArgs): protocol.ApplicableRefactorInfo[] {
20262031
const { file, project } = this.getFileAndProject(args);
20272032
const scriptInfo = project.getScriptInfoForNormalizedPath(file)!;
@@ -2251,6 +2256,70 @@ namespace ts.server {
22512256
});
22522257
}
22532258

2259+
private toggleLineComment(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
2260+
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
2261+
const scriptInfo = this.projectService.getScriptInfo(file)!;
2262+
const textRange = this.getRange(args, scriptInfo);
2263+
2264+
const textChanges = languageService.toggleLineComment(file, textRange);
2265+
2266+
if (simplifiedResult) {
2267+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
2268+
2269+
return textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo));
2270+
}
2271+
2272+
return textChanges;
2273+
}
2274+
2275+
private toggleMultilineComment(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
2276+
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
2277+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
2278+
const textRange = this.getRange(args, scriptInfo);
2279+
2280+
const textChanges = languageService.toggleMultilineComment(file, textRange);
2281+
2282+
if (simplifiedResult) {
2283+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
2284+
2285+
return textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo));
2286+
}
2287+
2288+
return textChanges;
2289+
}
2290+
2291+
private commentSelection(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
2292+
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
2293+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
2294+
const textRange = this.getRange(args, scriptInfo);
2295+
2296+
const textChanges = languageService.commentSelection(file, textRange);
2297+
2298+
if (simplifiedResult) {
2299+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
2300+
2301+
return textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo));
2302+
}
2303+
2304+
return textChanges;
2305+
}
2306+
2307+
private uncommentSelection(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] {
2308+
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
2309+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
2310+
const textRange = this.getRange(args, scriptInfo);
2311+
2312+
const textChanges = languageService.uncommentSelection(file, textRange);
2313+
2314+
if (simplifiedResult) {
2315+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
2316+
2317+
return textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo));
2318+
}
2319+
2320+
return textChanges;
2321+
}
2322+
22542323
private mapSelectionRange(selectionRange: SelectionRange, scriptInfo: ScriptInfo): protocol.SelectionRange {
22552324
const result: protocol.SelectionRange = {
22562325
textSpan: toProtocolTextSpan(selectionRange.textSpan, scriptInfo),
@@ -2697,6 +2766,30 @@ namespace ts.server {
26972766
[CommandNames.ProvideCallHierarchyOutgoingCalls]: (request: protocol.ProvideCallHierarchyOutgoingCallsRequest) => {
26982767
return this.requiredResponse(this.provideCallHierarchyOutgoingCalls(request.arguments));
26992768
},
2769+
[CommandNames.ToggleLineComment]: (request: protocol.ToggleLineCommentRequest) => {
2770+
return this.requiredResponse(this.toggleLineComment(request.arguments, /*simplifiedResult*/ true));
2771+
},
2772+
[CommandNames.ToggleLineCommentFull]: (request: protocol.ToggleLineCommentRequest) => {
2773+
return this.requiredResponse(this.toggleLineComment(request.arguments, /*simplifiedResult*/ false));
2774+
},
2775+
[CommandNames.ToggleMultilineComment]: (request: protocol.ToggleMultilineCommentRequest) => {
2776+
return this.requiredResponse(this.toggleMultilineComment(request.arguments, /*simplifiedResult*/ true));
2777+
},
2778+
[CommandNames.ToggleMultilineCommentFull]: (request: protocol.ToggleMultilineCommentRequest) => {
2779+
return this.requiredResponse(this.toggleMultilineComment(request.arguments, /*simplifiedResult*/ false));
2780+
},
2781+
[CommandNames.CommentSelection]: (request: protocol.CommentSelectionRequest) => {
2782+
return this.requiredResponse(this.commentSelection(request.arguments, /*simplifiedResult*/ true));
2783+
},
2784+
[CommandNames.CommentSelectionFull]: (request: protocol.CommentSelectionRequest) => {
2785+
return this.requiredResponse(this.commentSelection(request.arguments, /*simplifiedResult*/ false));
2786+
},
2787+
[CommandNames.UncommentSelection]: (request: protocol.UncommentSelectionRequest) => {
2788+
return this.requiredResponse(this.uncommentSelection(request.arguments, /*simplifiedResult*/ true));
2789+
},
2790+
[CommandNames.UncommentSelectionFull]: (request: protocol.UncommentSelectionRequest) => {
2791+
return this.requiredResponse(this.uncommentSelection(request.arguments, /*simplifiedResult*/ false));
2792+
},
27002793
}));
27012794

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

0 commit comments

Comments
 (0)