diff --git a/src/services/services.ts b/src/services/services.ts index d87d638bf1..03bf020acd 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1997,43 +1997,67 @@ namespace ts { let leftMostPosition = Number.MAX_VALUE; let lineTextStarts = new Map(); const whiteSpaceRegex = new RegExp(/\S/); + const isJsx = isInsideJsxElement(sourceFile, lineStarts[firstLine]) + const openComment = isJsx ? "{/*" : "//"; + const closeComment = "*/}"; // First check the lines before any text changes. for (let i = firstLine; i <= lastLine; i++) { - const lineText = sourceFile.text.substring(lineStarts[i], lineStarts[i + 1]); // TODO: Validate the end of line it might go outside of range. + 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); - // let sourceFilePosition = lineStarts[i] + leftMostPosition; - if (lineText.substr(regExec.index, 3) !== "// ") { // TODO: Validate when it is inside a comment. It can only uncomment if it's inside a comment. // TODO: Check when not finishing on empty space. + + if (lineText.substr(regExec.index, openComment.length) !== openComment) { // TODO: Validate when it is inside a comment. It can only uncomment if it's inside a comment. // TODO: Check when not finishing on empty space. 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 (isCommenting) { textChanges.push({ - newText: "// ", + newText: openComment, span: { length: 0, start: lineStarts[i] + leftMostPosition } }); + + if (isJsx) { + textChanges.push({ + newText: closeComment, + span: { + length: 0, + start: sourceFile.getLineEndOfPosition(lineStarts[i]) + } + }); + } } else { textChanges.push({ newText: "", span: { - length: 3, + length: openComment.length, start: lineStarts[i] + lineTextStart } }); + + if (isJsx) { + textChanges.push({ + newText: "", + span: { + length: closeComment.length, + start: sourceFile.getLineEndOfPosition(lineStarts[i]) - closeComment.length + } + }); + } } } } @@ -2052,7 +2076,7 @@ namespace ts { const positions = [] as number[] as SortedArray; let pos = textRange.pos; - const isJsx = isInsideJsxTags(sourceFile, pos); + const isJsx = isInsideJsxElement(sourceFile, pos); const openMultiline = isJsx ? "{/*" : "/*"; const closeMultiline = isJsx ? "*/}" : "*/"; diff --git a/src/services/utilities.ts b/src/services/utilities.ts index ed20ed7365..d692099186 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1320,23 +1320,29 @@ namespace ts { return false; } - export function isInsideJsxTags(sourceFile: SourceFile, position: number) { - const token = getTokenAtPosition(sourceFile, position); + export function isInsideJsxElement(sourceFile: SourceFile, position: number): boolean { + function isInsideJsxElementRecursion(node: Node): boolean { + while (node) { + if (node.kind >= SyntaxKind.JsxSelfClosingElement && node.kind <= SyntaxKind.JsxExpression + || node.kind === SyntaxKind.JsxText + || node.kind === SyntaxKind.LessThanToken + || node.kind === SyntaxKind.GreaterThanToken + || node.kind === SyntaxKind.Identifier + || node.kind === SyntaxKind.CloseBraceToken + || node.kind === SyntaxKind.OpenBraceToken + || node.kind === SyntaxKind.SlashToken) { + node = node.parent; + } else if (node.kind === SyntaxKind.JsxElement) { + return position > node.getStart(sourceFile) || isInsideJsxElementRecursion(node.parent); + } else { + return false; + } + } - switch (token.kind) { - case SyntaxKind.JsxText: - return true; - case SyntaxKind.LessThanToken: - case SyntaxKind.Identifier: - return token.parent.kind === SyntaxKind.JsxText //
Hello |
- || token.parent.kind === SyntaxKind.JsxClosingElement //
|
- || isJsxOpeningLikeElement(token.parent) && isJsxElement(token.parent.parent) //
|
or
- case SyntaxKind.CloseBraceToken: - case SyntaxKind.OpenBraceToken: - return isJsxExpression(token.parent) && isJsxElement(token.parent.parent); //
{|}
or
|{}
+ return false; } - return false; + return isInsideJsxElementRecursion(getTokenAtPosition(sourceFile, position)); } export function findPrecedingMatchingToken(token: Node, matchingTokenKind: SyntaxKind, sourceFile: SourceFile) { diff --git a/tests/cases/fourslash/toggleLineComment1.ts b/tests/cases/fourslash/toggleLineComment1.ts index 8e634c84d0..1f72de7b40 100644 --- a/tests/cases/fourslash/toggleLineComment1.ts +++ b/tests/cases/fourslash/toggleLineComment1.ts @@ -4,14 +4,14 @@ //// let var2 = 2; //// let var3 |]= 3; //// -//// // let var4[| = 1; -//// // let var5 = 2; -//// // let var6 |]= 3; +//// //let var4[| = 1; +//// //let var5 = 2; +//// //let var6 |]= 3; verify.toggleLineComment( - `// let var1 = 1; -// let var2 = 2; -// let var3 = 3; + `//let var1 = 1; +//let var2 = 2; +//let var3 = 3; let var4 = 1; let var5 = 2; diff --git a/tests/cases/fourslash/toggleLineComment2.ts b/tests/cases/fourslash/toggleLineComment2.ts index ead331a289..710bd5ef3f 100644 --- a/tests/cases/fourslash/toggleLineComment2.ts +++ b/tests/cases/fourslash/toggleLineComment2.ts @@ -6,15 +6,15 @@ //// let var2 = 2; //// let var3 |]= 3; //// -//// // let var4[| = 1; -//// // let var5 = 2; -//// // let var6 |]= 3; +//// // let var4[| = 1; +//// //let var5 = 2; +//// // let var6 |]= 3; verify.toggleLineComment( - `// let var1 = 1; -// let var2 = 2; -// let var3 = 3; + ` // let var1 = 1; + //let var2 = 2; + // let var3 = 3; - let var4 = 1; - let var5 = 2; - let var6 = 3;`); \ No newline at end of file + let var4 = 1; +let var5 = 2; + let var6 = 3;`); \ No newline at end of file diff --git a/tests/cases/fourslash/toggleLineComment3.ts b/tests/cases/fourslash/toggleLineComment3.ts index e498bb4ea0..d8f9aeabb9 100644 --- a/tests/cases/fourslash/toggleLineComment3.ts +++ b/tests/cases/fourslash/toggleLineComment3.ts @@ -6,18 +6,18 @@ //// //// let var3 |]= 3; //// -//// // let var4[| = 1; +//// //let var4[| = 1; //// -//// // let var5 = 2; +//// //let var5 = 2; //// -//// // let var6 |]= 3; +//// //let var6 |]= 3; verify.toggleLineComment( - `// let var1 = 1; + `//let var1 = 1; -// let var2 = 2; +//let var2 = 2; -// let var3 = 3; +//let var3 = 3; let var4 = 1; diff --git a/tests/cases/fourslash/toggleLineComment4.ts b/tests/cases/fourslash/toggleLineComment4.ts index 72ebd7b5e0..1d162ca7be 100644 --- a/tests/cases/fourslash/toggleLineComment4.ts +++ b/tests/cases/fourslash/toggleLineComment4.ts @@ -1,18 +1,18 @@ // If at least one line is uncomment then comment all lines again. -//// // let var1[| = 1; -//// let var2 = 2; -//// // let var3 |]= 3; +//// //const a[| = 1; +//// const b = 2 +//// //const c =|] 3; //// -//// // // let var4[| = 1; -//// // let var5 = 2; -//// // // let var6 |]= 3; +//// ////const d[| = 4; +//// //const e = 5; +//// ////const e =|] 6; verify.toggleLineComment( - `// // let var1 = 1; -// let var2 = 2; -// // let var3 = 3; + `// //const a = 1; +//const b = 2 +// //const c = 3; -// let var4 = 1; -let var5 = 2; -// let var6 = 3;`); \ No newline at end of file +//const d = 4; +const e = 5; +//const e = 6;`); \ No newline at end of file diff --git a/tests/cases/fourslash/toggleLineComment5.ts b/tests/cases/fourslash/toggleLineComment5.ts index c5e20dd27b..bec00a9233 100644 --- a/tests/cases/fourslash/toggleLineComment5.ts +++ b/tests/cases/fourslash/toggleLineComment5.ts @@ -1,8 +1,8 @@ // Comments inside strings are still considered comments. //// let var1 = ` -//// // some stri[|ng -//// // some other|] string +//// //some stri[|ng +//// //some other|] string //// `; //// //// let var2 = ` @@ -17,6 +17,6 @@ some other string \`; let var2 = \` -// some string -// some other string +//some string +//some other string \`;`); \ No newline at end of file diff --git a/tests/cases/fourslash/toggleLineComment6.ts b/tests/cases/fourslash/toggleLineComment6.ts index a3b3d9e4a6..4274cc1830 100644 --- a/tests/cases/fourslash/toggleLineComment6.ts +++ b/tests/cases/fourslash/toggleLineComment6.ts @@ -1,20 +1,15 @@ -// Selection is at the start of jsx it's still considered js. +// Selection is at the start of jsx its still js. -//// function a() { -//// let foo = "bar"; -//// return ( -//// [|
-//// {foo}|] -////
-//// ); -//// } +//@Filename: file.tsx +//// let a = ( +//// [|
+//// some text|] +////
+//// ); verify.toggleLineComment( - `function a() { - let foo = "bar"; - return ( - //
- // {foo} -
- ); -}`); \ No newline at end of file + `let a = ( + //
+ // some text +
+);`); \ No newline at end of file diff --git a/tests/cases/fourslash/toggleLineComment7.ts b/tests/cases/fourslash/toggleLineComment7.ts new file mode 100644 index 0000000000..5a6cbb002f --- /dev/null +++ b/tests/cases/fourslash/toggleLineComment7.ts @@ -0,0 +1,29 @@ +// Common comment line cases. + +//@Filename: file.tsx +//// const a = +//// [| +//// |] +//// ; +//// const b = +//// {/**/} +//// {/**/} +//// ; +//// const c = [| +//// +//// +//// ; + +verify.toggleLineComment( + `const a = + {/**/} + {/**/} +; +const b = + + +; +//const c = +// +// +;`); \ No newline at end of file diff --git a/tests/cases/fourslash/toggleLineComment8.ts b/tests/cases/fourslash/toggleLineComment8.ts new file mode 100644 index 0000000000..1c3bed3fd8 --- /dev/null +++ b/tests/cases/fourslash/toggleLineComment8.ts @@ -0,0 +1,30 @@ +// When indentation is different between lines it should get the left most indentation +// and use that for all lines. +// When uncommeting, doesn't matter what indentation the line has. + +//@Filename: file.tsx +//// const a =
+//// [|
+//// SomeText +////
|] +////
; +//// +//// const b =
+//// {/*[|
*/} +//// {/* SomeText*/} +//// {/*
|]*/} +////
; + + +verify.toggleLineComment( + `const a =
+ {/*
*/} + {/* SomeText*/} + {/*
*/} +
; + +const b =
+
+ SomeText +
+
;`); \ No newline at end of file diff --git a/tests/cases/fourslash/toggleMultilineComment4.ts b/tests/cases/fourslash/toggleMultilineComment4.ts index 1764c5a08e..216a308ae4 100644 --- a/tests/cases/fourslash/toggleMultilineComment4.ts +++ b/tests/cases/fourslash/toggleMultilineComment4.ts @@ -1,5 +1,5 @@ -// This is an edgecase. The string contains a multiline comment syntax and because it is a string, -// is not actually a comment. When toggling it doesn't get escaped or appended comments. +// This is an edgecase. The string contains a multiline comment syntax but it is a string +// and not actually a comment. When toggling it doesn't get escaped or appended comments. // The result would be a portion of the selection to be "not commented". //// /*let s[|omeLongVa*/riable = "Some other /*long th*/in|]g"; diff --git a/tests/cases/fourslash/toggleMultilineComment5.ts b/tests/cases/fourslash/toggleMultilineComment5.ts index e516b0b04f..0dea4ebbff 100644 --- a/tests/cases/fourslash/toggleMultilineComment5.ts +++ b/tests/cases/fourslash/toggleMultilineComment5.ts @@ -14,6 +14,8 @@ //// |] //// ; //// const e = [|{'foo'}|]; +//// const f =
Some text;|] +//// const g =
Some text<[|/div>;|] verify.toggleMultilineComment( `const a =
{/*
;*/} @@ -26,5 +28,7 @@ const d = */} ; -const e = {/*{'foo'}*/};` +const e = {/*{'foo'}*/}; +const f =
Some text;*/} +const g =
Some text<{/*/div>;*/}` ); \ No newline at end of file diff --git a/tests/cases/fourslash/toggleMultilineComment7.ts b/tests/cases/fourslash/toggleMultilineComment7.ts new file mode 100644 index 0000000000..d4c711aee6 --- /dev/null +++ b/tests/cases/fourslash/toggleMultilineComment7.ts @@ -0,0 +1,33 @@ +// Cases where the cursor is inside JSX like sintax but it's actually js. + +//@Filename: file.tsx +//// const a = ( +//// [|
+//// some text|] +////
+//// ); +//// const b = ; +//// const c = ; +//// const d = ; +//// const e = ;|] +//// const f = [ +//// [|
  • First item
  • , +////
  • Second item
  • ,|] +////
  • Third item
  • , +//// ]; + +verify.toggleMultilineComment( + `const a = ( + /*
    + some text*/ +
    +); +const b = ; +const c = ; +const d = ; +const e = ;*/ +const f = [ + /*
  • First item
  • , +
  • Second item
  • ,*/ +
  • Third item
  • , +];`); \ No newline at end of file