diff --git a/src/services/services.ts b/src/services/services.ts index acd845c7979c6..cb2c73939bdd7 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2492,6 +2492,9 @@ export function createLanguageService( const token = findPrecedingToken(position, sourceFile); if (!token || token.parent.kind === SyntaxKind.SourceFile) return undefined; + // matches more than valid tag names to allow linked editing when typing is in progress or tag name is incomplete + const jsxTagWordPattern = "[a-zA-Z0-9:\\-\\._$]*"; + if (isJsxFragment(token.parent.parent)) { const openFragment = token.parent.parent.openingFragment; const closeFragment = token.parent.parent.closingFragment; @@ -2503,7 +2506,10 @@ export function createLanguageService( // only allows linked editing right after opening bracket: <| > if ((position !== openPos) && (position !== closePos)) return undefined; - return { ranges: [{ start: openPos, length: 0 }, { start: closePos, length: 0 }] }; + return { + ranges: [{ start: openPos, length: 0 }, { start: closePos, length: 0 }], + wordPattern: jsxTagWordPattern, + }; } else { // determines if the cursor is in an element tag @@ -2534,6 +2540,7 @@ export function createLanguageService( return { ranges: [{ start: openTagStart, length: openTagEnd - openTagStart }, { start: closeTagStart, length: closeTagEnd - closeTagStart }], + wordPattern: jsxTagWordPattern, }; } } diff --git a/tests/cases/fourslash/linkedEditingJsxTag1.ts b/tests/cases/fourslash/linkedEditingJsxTag1.ts index ab0183c9c1e15..2fe2624231d63 100644 --- a/tests/cases/fourslash/linkedEditingJsxTag1.ts +++ b/tests/cases/fourslash/linkedEditingJsxTag1.ts @@ -20,17 +20,24 @@ //// ////);/*d*/ +// goTo.marker("a"); + +const wordPattern = "[a-zA-Z0-9:\\-\\._$]*"; const linkedCursors1 = { ranges: [{ start: test.markerByName("0").position, length: 3 }, { start: test.markerByName("5").position, length: 3 }], + wordPattern, }; const linkedCursors2 = { ranges: [{ start: test.markerByName("9").position - 1, length: 3 }, { start: test.markerByName("14").position - 1, length: 3 }], + wordPattern, }; const linkedCursors3 = { ranges: [{ start: test.markerByName("10").position - 1, length: 3 }, { start: test.markerByName("13").position - 1, length: 3 }], + wordPattern, }; const linkedCursors4 = { ranges: [{ start: test.markerByName("11").position - 1, length: 1 }, { start: test.markerByName("12").position, length: 1 }], + wordPattern, }; verify.linkedEditing( { diff --git a/tests/cases/fourslash/linkedEditingJsxTag10.ts b/tests/cases/fourslash/linkedEditingJsxTag10.ts index 0cc40d35da978..509f858010e7e 100644 --- a/tests/cases/fourslash/linkedEditingJsxTag10.ts +++ b/tests/cases/fourslash/linkedEditingJsxTag10.ts @@ -48,8 +48,10 @@ // @Filename: /jsx15.tsx ////const jsx = ; +const wordPattern = "[a-zA-Z0-9:\\-\\._$]*"; const linkedCursors9 = { ranges: [{ start: test.markerByName("9").position, length: 3 }, { start: test.markerByName("9a").position, length: 3 }], + wordPattern, }; verify.linkedEditing( { diff --git a/tests/cases/fourslash/linkedEditingJsxTag11.ts b/tests/cases/fourslash/linkedEditingJsxTag11.ts new file mode 100644 index 0000000000000..3755f78a8cb0b --- /dev/null +++ b/tests/cases/fourslash/linkedEditingJsxTag11.ts @@ -0,0 +1,61 @@ +/// + +// for readability +////const jsx = ( +////
+////

+//// +////

+////
+////); + +// @Filename: /customElements.tsx +//// const jsx = +//// ; +//// +//// const customElement = ; +//// +//// const standardElement = +//// +//// +//// Next +//// +//// ; + +const wordPattern = "[a-zA-Z0-9:\\-\\._$]*"; + +const linkedCursors1 = { + ranges: [{ start: test.markerByName("1").position, length: 8 }, { start: test.markerByName("4").position - 1, length: 8 }], + wordPattern, +}; +const linkedCursors2 = { + ranges: [{ start: test.markerByName("6").position, length: 14 }, { start: test.markerByName("9").position - 6, length: 14 }], + wordPattern, +}; +const linkedCursors3 = { + ranges: [{ start: test.markerByName("10").position, length: 4 }, { start: test.markerByName("15").position - 2, length: 4 }], + wordPattern, +}; +const linkedCursors4 = { + ranges: [{ start: test.markerByName("12").position, length: 6 }, { start: test.markerByName("14").position - 3, length: 6 }], + wordPattern, +}; + +verify.linkedEditing( { + "1": linkedCursors1, + "2": linkedCursors1, + "3": linkedCursors1, + "4": linkedCursors1, + "5": linkedCursors1, + "6": linkedCursors2, + "7": linkedCursors2, + "8": linkedCursors2, + "9": linkedCursors2, + "10": linkedCursors3, + "11": linkedCursors3, + "12": linkedCursors4, + "13": linkedCursors4, + "14": linkedCursors4, + "15": linkedCursors3, +}); \ No newline at end of file diff --git a/tests/cases/fourslash/linkedEditingJsxTag2.ts b/tests/cases/fourslash/linkedEditingJsxTag2.ts index 35c5a119653c9..d16821137bc96 100644 --- a/tests/cases/fourslash/linkedEditingJsxTag2.ts +++ b/tests/cases/fourslash/linkedEditingJsxTag2.ts @@ -28,8 +28,10 @@ const startPos = test.markerByName("0").position; const endPos = test.markerByName("6").position - 2; +const wordPattern = "[a-zA-Z0-9:\\-\\._$]*"; const linkedCursors = { ranges: [{ start: startPos, length: 3 }, { start: endPos, length: 3 }], + wordPattern, }; verify.linkedEditing( { diff --git a/tests/cases/fourslash/linkedEditingJsxTag4.ts b/tests/cases/fourslash/linkedEditingJsxTag4.ts index b130c55e024f9..bd4e9f7179119 100644 --- a/tests/cases/fourslash/linkedEditingJsxTag4.ts +++ b/tests/cases/fourslash/linkedEditingJsxTag4.ts @@ -27,8 +27,10 @@ const startPos = test.markerByName("0").position; const endPos = test.markerByName("6").position; +const wordPattern = "[a-zA-Z0-9:\\-\\._$]*"; const linkedCursors = { ranges: [{ start: startPos, length: 3 }, { start: endPos, length: 3 }], + wordPattern, }; verify.linkedEditing( { diff --git a/tests/cases/fourslash/linkedEditingJsxTag5.ts b/tests/cases/fourslash/linkedEditingJsxTag5.ts index 2e7dbe56acea2..87379e19a3e4b 100644 --- a/tests/cases/fourslash/linkedEditingJsxTag5.ts +++ b/tests/cases/fourslash/linkedEditingJsxTag5.ts @@ -20,16 +20,20 @@ //// ////); +const wordPattern = "[a-zA-Z0-9:\\-\\._$]*"; + const startPos1 = test.markerByName("1").position - 3; const endPos1 = test.markerByName("2").position - 3; const linkedCursors1 = { ranges: [{ start: startPos1, length: 3 }, { start: endPos1, length: 3 }], + wordPattern, }; const startPos2 = test.markerByName("6").position - 3; const endPos2 = test.markerByName("7").position - 3; const linkedCursors2 = { ranges: [{ start: startPos2, length: 3 }, { start: endPos2, length: 3 }], + wordPattern, }; verify.linkedEditing( { diff --git a/tests/cases/fourslash/linkedEditingJsxTag6.ts b/tests/cases/fourslash/linkedEditingJsxTag6.ts index 8cac987be18cb..482fec57bb2a7 100644 --- a/tests/cases/fourslash/linkedEditingJsxTag6.ts +++ b/tests/cases/fourslash/linkedEditingJsxTag6.ts @@ -16,16 +16,20 @@ //// +const wordPattern = "[a-zA-Z0-9:\\-\\._$]*"; + const startPos1 = test.markerByName("start").position; const endPos1 = test.markerByName("end").position; const linkedCursors1 = { ranges: [{ start: startPos1, length: 19 }, { start: endPos1, length: 19 }], + wordPattern, }; const startPos2 = test.markerByName("26").position; const endPos2 = test.markerByName("30").position; const linkedCursors2 = { ranges: [{ start: startPos2, length: 21 }, { start: endPos2, length: 21 }], + wordPattern, }; verify.linkedEditing( { diff --git a/tests/cases/fourslash/linkedEditingJsxTag7.ts b/tests/cases/fourslash/linkedEditingJsxTag7.ts index c401de04cb5d0..9a746c04f0fbd 100644 --- a/tests/cases/fourslash/linkedEditingJsxTag7.ts +++ b/tests/cases/fourslash/linkedEditingJsxTag7.ts @@ -30,17 +30,20 @@ //// ////);/*e*/ +const wordPattern = "[a-zA-Z0-9:\\-\\._$]*"; + const startPos1 = test.markerByName("0").position; const endPos1 = test.markerByName("3").position; const linkedCursors1 = { ranges: [{ start: startPos1, length: 0 }, { start: endPos1, length: 0 }], - // wordPattern : undefined + wordPattern, }; const startPos2 = test.markerByName("10").position; const endPos2 = test.markerByName("14").position; const linkedCursors2 = { ranges: [{ start: startPos2, length: 0 }, { start: endPos2, length: 0 }], + wordPattern, }; verify.linkedEditing({ diff --git a/tests/cases/fourslash/linkedEditingJsxTag9.ts b/tests/cases/fourslash/linkedEditingJsxTag9.ts index 67bd28d1fc5e7..7f363a8ed619f 100644 --- a/tests/cases/fourslash/linkedEditingJsxTag9.ts +++ b/tests/cases/fourslash/linkedEditingJsxTag9.ts @@ -28,15 +28,20 @@ //// ////); +const wordPattern = "[a-zA-Z0-9:\\-\\._$]*"; + const markers = test.markers(); const linkedCursors1 = { ranges: [{ start: markers[1].position, length: 3 }, { start: markers[5].position, length: 3 }], + wordPattern, }; const linkedCursors2 = { ranges: [{ start: markers[7].position, length: 3 }, { start: markers[10].position, length: 3 }], + wordPattern, }; const linkedCursors3 = { ranges: [{ start: markers[20].position - 2, length: 3 }, { start: markers[28].position - 1, length: 3 }], + wordPattern, }; verify.linkedEditing( {