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 = *15*/div> *15a*/> /*15b*/div> /*15c*/>;
+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 = *1*/fbt/*2*/:en/*3*/um knownProp="accepted"
+//// unknownProp="rejected">
+//// ;
+////
+//// const customElement = *6*/custom/*7*/-element/*8*/>;
+////
+//// const standardElement =
+//// *10*/Link/*11*/ href="/hello" passHref>
+//// *12*/But/*13*/ton component="a">
+//// 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 @@
//// *12*/ //*13*/div>
////);
+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 @@
//// /*30*/foo /*31*/ .// hi/*32*/
//// /*33*/bar>
+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 @@
//// /*23*/ /*24*///*25*/* even/*26*/ more comment *//*27*/ d/*28*/iv /* b/*29*/ye */>
////);
+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( {