From 409d9495301d284b336155312eb9d02921f213f3 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 8 Mar 2023 17:38:17 -0800
Subject: [PATCH 01/32] add tests and fourslash framework
---
src/harness/fourslashImpl.ts | 9 ++++
src/harness/fourslashInterfaceImpl.ts | 5 ++
src/services/services.ts | 7 +++
src/services/types.ts | 9 ++++
tests/cases/fourslash/mirrorCursor.ts | 78 +++++++++++++++++++++++++++
5 files changed, 108 insertions(+)
create mode 100644 tests/cases/fourslash/mirrorCursor.ts
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index 7c7c43db639e7..e3fef1cec9259 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -3444,6 +3444,15 @@ export class TestState {
}
}
+ public verifyJsxMirrorCursor(map: {[markerName:string]:ts.JsxMirrorCursorInfo | undefined}):void {
+ for (const markerName in map) {
+ this.goToMarker(markerName);
+ // const actual = {};
+ const actual = this.languageService.getJsxMirrorCursorAtPosition(this.activeFile.fileName, this.currentCaretPosition);
+ assert.deepEqual(actual, map[markerName], markerName);
+ }
+ }
+
public verifyMatchingBracePosition(bracePosition: number, expectedMatchPosition: number) {
const actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition);
diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts
index 4cf5c58d542b7..22541648c28d5 100644
--- a/src/harness/fourslashInterfaceImpl.ts
+++ b/src/harness/fourslashInterfaceImpl.ts
@@ -189,6 +189,11 @@ export class VerifyNegatable {
this.state.verifyJsxClosingTag(map);
}
+ public jsxMirrorCursor(map: { [markerName: string]: ts.JsxMirrorCursorInfo | undefined }): void {
+ this.state.verifyJsxMirrorCursor(map);
+ }
+
+
public isInCommentAtPosition(onlyMultiLineDiverges?: boolean) {
this.state.verifySpanOfEnclosingComment(this.negative, onlyMultiLineDiverges);
}
diff --git a/src/services/services.ts b/src/services/services.ts
index 4bf03927fb3bf..80358a97a501e 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -189,6 +189,7 @@ import {
JsxElement,
JsxEmit,
JsxFragment,
+ JsxMirrorCursorInfo,
LanguageService,
LanguageServiceHost,
LanguageServiceMode,
@@ -2478,6 +2479,11 @@ export function createLanguageService(
}
}
+ function getJsxMirrorCursorAtPosition(fileName: string, position: number): JsxMirrorCursorInfo[] | undefined {
+ return undefined;
+ // ISABEL unimplemented
+ }
+
function getLinesForRange(sourceFile: SourceFile, textRange: TextRange) {
return {
lineStarts: sourceFile.getLineStarts(),
@@ -3009,6 +3015,7 @@ export function createLanguageService(
getDocCommentTemplateAtPosition,
isValidBraceCompletionAtPosition,
getJsxClosingTagAtPosition,
+ getJsxMirrorCursorAtPosition,
getSpanOfEnclosingComment,
getCodeFixesAtPosition,
getCombinedCodeFix,
diff --git a/src/services/types.ts b/src/services/types.ts
index de17b02ac2c4d..afbbcfc8f0b50 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -607,6 +607,8 @@ export interface LanguageService {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
+ getJsxMirrorCursorAtPosition(fileName: string, currentCaretPosition: number): JsxMirrorCursorInfo | unknown;
+ //ISABEL incorrect return type
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
@@ -661,6 +663,13 @@ export interface JsxClosingTagInfo {
readonly newText: string;
}
+export interface JsxMirrorCursorInfo {
+ readonly startLine : number;
+ readonly startCharacter : number;
+ readonly endLine : number;
+ readonly endCharacter : number;
+}
+
export interface CombinedCodeFixScope { type: "file"; fileName: string; }
export const enum OrganizeImportsMode {
diff --git a/tests/cases/fourslash/mirrorCursor.ts b/tests/cases/fourslash/mirrorCursor.ts
new file mode 100644
index 0000000000000..e73164c948652
--- /dev/null
+++ b/tests/cases/fourslash/mirrorCursor.ts
@@ -0,0 +1,78 @@
+///
+
+// @Filename: /basic.tsx
+//// const jsx = (
+////
+////
+//// );
+
+// @Filename: /attrs.tsx
+//// const jsx = (
+////
+////
+////
+////
+////
+//// );
+
+// @Filename: /selfClosing.tsx
+//// const jsx = (
+////
+////
+////
+////
+////
+//// );
+
+// @Filename: /longName.tsx
+//// const jsx = (
+////
+////
+//// );
+
+// @FileName: /invalid1.tsx
+//// const jsx = (
+////
+////
+////
+//// );
+
+// @FileName: /invalid2.tsx
+//// const jsx = (
+////
+//// );
+
+// @FileName: /fragment.tsx
+//// const jsx = (
+//// *6*/>
+////
+//// >
+//// );
+
+// @FileName: /mismatchedNames.tsx
+//// const A = thing;
+//// const B = thing;
+//// const jsx = (
+//// **/A>
+////
+//// );
+
+
+
+verify.jsxMirrorCursor( {
+ "0": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
+ {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 9}],
+ "1": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
+ {startLine: 5, startCharacter: 6, endLine: 5, endCharacter: 9}],
+ "2": [],
+ "3": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 25},
+ {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 26}],
+ "4": [],
+ "5": [{startLine: 2, startCharacter: 9, endLine: 2, endCharacter: 12},
+ {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 9}],
+ "6": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 5},
+ {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 6}],
+ "7": [],
+})
\ No newline at end of file
From 94c4b6506ab052f6c9397d3aa674e19de1798c8f Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Fri, 10 Mar 2023 16:32:05 -0800
Subject: [PATCH 02/32] cd
---
lib/tsserverlibrary.d.ts | 16 +++++++++
src/harness/harnessLanguageService.ts | 3 ++
src/server/protocol.ts | 10 ++++++
src/server/session.ts | 9 +++++
src/services/services.ts | 35 +++++++++++++++++--
src/services/types.ts | 5 +++
.../reference/api/tsserverlibrary.d.ts | 4 +++
tests/baselines/reference/api/typescript.d.ts | 8 +++++
tests/cases/fourslash/fourslash.ts | 5 +++
tests/cases/fourslash/mirrorCursor.ts | 24 +++++++------
10 files changed, 106 insertions(+), 13 deletions(-)
diff --git a/lib/tsserverlibrary.d.ts b/lib/tsserverlibrary.d.ts
index 0884b10602045..7fab75b0aeb81 100644
--- a/lib/tsserverlibrary.d.ts
+++ b/lib/tsserverlibrary.d.ts
@@ -92,6 +92,7 @@ declare namespace ts {
*/
enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
+ JsxMirrorCursor = "jsxMirrorCursor",
Brace = "brace",
BraceCompletion = "braceCompletion",
GetSpanOfEnclosingComment = "getSpanOfEnclosingComment",
@@ -882,6 +883,14 @@ declare namespace ts {
interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
+ // ISABEL correct extends??
+ interface JsxMirrorCursorRequest extends FileLocationRequest {
+ readonly command: CommandTypes.JsxMirrorCursor;
+ //ISABEL arguments?
+ }
+ interface JsxMirrorCursorResponse extends Response {
+ readonly mirrorCursors: [JsxMirrorCursorInfo];
+ }
/**
* @deprecated
* Get occurrences request; value of command field is
@@ -3839,6 +3848,7 @@ declare namespace ts {
private getSemanticDiagnosticsSync;
private getSuggestionDiagnosticsSync;
private getJsxClosingTag;
+ private getJsxMirrorCursor
private getDocumentHighlights;
private provideInlayHints;
private setCompilerOptionsForInferredProjects;
@@ -10084,6 +10094,12 @@ declare namespace ts {
interface JsxClosingTagInfo {
readonly newText: string;
}
+ interface JsxMirrorCursorInfo {
+ readonly startLine : number;
+ readonly startCharacter : number;
+ readonly endLine : number;
+ readonly endCharacter : number;
+ }
interface CombinedCodeFixScope {
type: "file";
fileName: string;
diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts
index 84eb84e330af6..0f0eea5ea00dc 100644
--- a/src/harness/harnessLanguageService.ts
+++ b/src/harness/harnessLanguageService.ts
@@ -593,6 +593,9 @@ class LanguageServiceShimProxy implements ts.LanguageService {
getJsxClosingTagAtPosition(): never {
throw new Error("Not supported on the shim.");
}
+ getJsxMirrorCursorAtPosition(): never {
+ throw new Error("Not supported on the shim.");
+ }
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan {
return unwrapJSONCallResult(this.shim.getSpanOfEnclosingComment(fileName, position, onlyMultiLine));
}
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index 50546bb8dce8f..da01b3354ebac 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -23,6 +23,7 @@ import {
export const enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
+ JsxMirrorCursor = "jsxMirrorCursor",
Brace = "brace",
/** @internal */
BraceFull = "brace-full",
@@ -1101,6 +1102,15 @@ export interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
+export interface JsxMirrorCursorRequest extends FileLocationRequest {
+ readonly command: CommandTypes.JsxMirrorCursor;
+ // ISABEL?
+}
+
+export interface JsxMirrorCursorResponse extends Response {
+ // ISABEL?
+}
+
/**
* Get document highlights request; value of command field is
diff --git a/src/server/session.ts b/src/server/session.ts
index f7e37522a8719..74153bb08d741 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -1802,6 +1802,11 @@ export class Session implements EventSender {
return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 };
}
+ private getJsxMirrorCursor(args): undefined{
+ return undefined;
+ //ISABEL stub
+ }
+
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
@@ -3389,6 +3394,10 @@ export class Session implements EventSender {
[protocol.CommandTypes.JsxClosingTag]: (request: protocol.JsxClosingTagRequest) => {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
},
+ [protocol.CommandTypes.JsxMirrorCursor]: (request: protocol.JsxMirrorCursorRequest) => {
+ return this.requiredResponse(this.getJsxClosingTag(request.arguments));
+ // ISABEL what ;
+ },
[protocol.CommandTypes.GetCodeFixes]: (request: protocol.CodeFixRequest) => {
return this.requiredResponse(this.getCodeFixes(request.arguments, /*simplifiedResult*/ true));
},
diff --git a/src/services/services.ts b/src/services/services.ts
index 80358a97a501e..7aa2f000190dc 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -1,3 +1,4 @@
+import { findArgument } from "../jsTyping/shared";
import * as ts from "./_namespaces/ts";
import {
__String,
@@ -189,6 +190,7 @@ import {
JsxElement,
JsxEmit,
JsxFragment,
+ JsxLinkedEditInfo,
JsxMirrorCursorInfo,
LanguageService,
LanguageServiceHost,
@@ -2479,8 +2481,37 @@ export function createLanguageService(
}
}
- function getJsxMirrorCursorAtPosition(fileName: string, position: number): JsxMirrorCursorInfo[] | undefined {
- return undefined;
+ function getJsxMirrorCursorAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined {
+ const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
+ const token = findPrecedingToken(position, sourceFile);
+ if (!token) return undefined;
+
+ // if it is not in a jsx element
+ if (token.parent.parent.kind !== SyntaxKind.JsxElement && token.parent.parent.kind !== SyntaxKind.JsxFragment) return undefined;
+
+ //opening element
+ if (token.parent.kind === SyntaxKind.JsxOpeningElement){
+ const nameSpan = {start : token.pos, length : token.pos - token.end};
+ const name = "";
+ return {ranges:nameSpan, wordPattern : name};
+ }
+ //losing element
+ if (token.parent.kind === SyntaxKind.JsxClosingElement){
+ return undefined;
+ }
+
+ //opening fragment
+ if (token.parent.kind === SyntaxKind.JsxOpeningFragment){
+ return undefined;
+ }
+ //losing element
+ if (token.parent.kind === SyntaxKind.JsxClosingFragment){
+ return undefined;
+ }
+
+
+ //neither
+ return undefined
// ISABEL unimplemented
}
diff --git a/src/services/types.ts b/src/services/types.ts
index afbbcfc8f0b50..19d17e9970687 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -670,6 +670,11 @@ export interface JsxMirrorCursorInfo {
readonly endCharacter : number;
}
+export interface JsxLinkedEditInfo {
+ readonly ranges : TextSpan;
+ wordPattern? : string;
+}
+
export interface CombinedCodeFixScope { type: "file"; fileName: string; }
export const enum OrganizeImportsMode {
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 6f8b2365c3511..14187beea9385 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -89,6 +89,7 @@ declare namespace ts {
namespace protocol {
enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
+ JsxMirrorCursor = "jsxMirrorCursor",
Brace = "brace",
BraceCompletion = "braceCompletion",
GetSpanOfEnclosingComment = "getSpanOfEnclosingComment",
@@ -877,6 +878,8 @@ declare namespace ts {
interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
+ interface mirrror {}
+ // ISABEL
/**
* Get document highlights request; value of command field is
* "documentHighlights". Return response giving spans that are relevant
@@ -3847,6 +3850,7 @@ declare namespace ts {
private getSemanticDiagnosticsSync;
private getSuggestionDiagnosticsSync;
private getJsxClosingTag;
+ private getJsxMirrorCursor;
private getDocumentHighlights;
private provideInlayHints;
private setCompilerOptionsForInferredProjects;
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index 35f824d416f0b..70518ff7b751e 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -6111,6 +6111,8 @@ declare namespace ts {
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
+ // ISABEL change name?
+ getMirrorCursorPosition(fileName: string, position: number): JsxMirrorCursorInfo | undefined;
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise;
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise;
@@ -6136,6 +6138,12 @@ declare namespace ts {
interface JsxClosingTagInfo {
readonly newText: string;
}
+ interface JsxMirrorCursorInfo {
+ readonly startLine : number;
+ readonly startCharacter : number;
+ readonly endLine : number;
+ readonly endCharacter : number;
+ }
interface CombinedCodeFixScope {
type: "file";
fileName: string;
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 53352c8573dc1..bffeb276b2a49 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -260,6 +260,11 @@ declare namespace FourSlashInterface {
implementationListIsEmpty(): void;
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
+ jsxMirrorCursor(map: { [markerName: string]: {
+ readonly startLine : number;
+ readonly startCharacter : number;
+ readonly endLine : number;
+ readonly endCharacter : number;}[] | undefined }): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
codeFix(options: {
description: string | [string, ...(string | number)[]] | DiagnosticIgnoredInterpolations,
diff --git a/tests/cases/fourslash/mirrorCursor.ts b/tests/cases/fourslash/mirrorCursor.ts
index e73164c948652..65ad9b54ef6dc 100644
--- a/tests/cases/fourslash/mirrorCursor.ts
+++ b/tests/cases/fourslash/mirrorCursor.ts
@@ -6,6 +6,7 @@
////
//// );
+
// @Filename: /attrs.tsx
//// const jsx = (
////
@@ -61,18 +62,19 @@
+
verify.jsxMirrorCursor( {
"0": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
{startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 9}],
- "1": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
- {startLine: 5, startCharacter: 6, endLine: 5, endCharacter: 9}],
- "2": [],
- "3": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 25},
- {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 26}],
- "4": [],
- "5": [{startLine: 2, startCharacter: 9, endLine: 2, endCharacter: 12},
- {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 9}],
- "6": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 5},
- {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 6}],
- "7": [],
+ // "1": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
+ // {startLine: 5, startCharacter: 6, endLine: 5, endCharacter: 9}],
+ // "2": [],
+ // "3": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 25},
+ // {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 26}],
+ // "4": [],
+ // "5": [{startLine: 2, startCharacter: 9, endLine: 2, endCharacter: 12},
+ // {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 9}],
+ // "6": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 5},
+ // {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 6}],
+ // "7": [],
})
\ No newline at end of file
From a5192e8823f92a1cac81e3b8f2007dc8277fe389 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Fri, 10 Mar 2023 23:45:32 -0800
Subject: [PATCH 03/32] first implementation, all tests except 3 (namespace)
passes
---
src/harness/fourslashInterfaceImpl.ts | 2 +-
src/services/services.ts | 69 +++++++++++-----
src/services/types.ts | 2 +-
tests/cases/fourslash/mirrorCursor.ts | 115 +++++++++++++-------------
4 files changed, 110 insertions(+), 78 deletions(-)
diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts
index 22541648c28d5..89768d69200c9 100644
--- a/src/harness/fourslashInterfaceImpl.ts
+++ b/src/harness/fourslashInterfaceImpl.ts
@@ -189,7 +189,7 @@ export class VerifyNegatable {
this.state.verifyJsxClosingTag(map);
}
- public jsxMirrorCursor(map: { [markerName: string]: ts.JsxMirrorCursorInfo | undefined }): void {
+ public jsxMirrorCursor(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined }): void {
this.state.verifyJsxMirrorCursor(map);
}
diff --git a/src/services/services.ts b/src/services/services.ts
index 7aa2f000190dc..7c29ebc11b813 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -1,4 +1,3 @@
-import { findArgument } from "../jsTyping/shared";
import * as ts from "./_namespaces/ts";
import {
__String,
@@ -154,6 +153,7 @@ import {
isJSDocCommentContainingNode,
isJsxAttributes,
isJsxClosingElement,
+ isJsxClosingFragment,
isJsxElement,
isJsxFragment,
isJsxOpeningElement,
@@ -2486,33 +2486,62 @@ export function createLanguageService(
const token = findPrecedingToken(position, sourceFile);
if (!token) return undefined;
- // if it is not in a jsx element
- if (token.parent.parent.kind !== SyntaxKind.JsxElement && token.parent.parent.kind !== SyntaxKind.JsxFragment) return undefined;
+ let wordPattern : string | undefined;
+ // if it is not in a jsx element/fragment, or if the tags do not match
+ if (isJsxElement(token.parent.parent)){
+ if (token.parent.parent.openingElement.tagName.getText() !== token.parent.parent.closingElement.tagName.getText()) {
+ return undefined;
+ }
+ wordPattern = token.parent.parent.openingElement.tagName.getText();
+ }
+ else if (isJsxFragment(token.parent.parent)) {
+ wordPattern = undefined;
+ }
+ else return undefined;
+ let ranges : {start: number, end: number};
//opening element
- if (token.parent.kind === SyntaxKind.JsxOpeningElement){
- const nameSpan = {start : token.pos, length : token.pos - token.end};
- const name = "";
- return {ranges:nameSpan, wordPattern : name};
+ if (isJsxOpeningElement(token.parent)){
+ ranges = {start : token.parent.parent.closingElement.tagName.pos, end : token.parent.parent.closingElement.tagName.end};
}
- //losing element
- if (token.parent.kind === SyntaxKind.JsxClosingElement){
- return undefined;
+ else if (isJsxClosingElement(token.parent)){
+ ranges = {start : token.parent.parent.openingElement.tagName.pos, end : token.parent.parent.openingElement.tagName.end};
}
-
- //opening fragment
- if (token.parent.kind === SyntaxKind.JsxOpeningFragment){
- return undefined;
+ else if (isJsxOpeningFragment(token.parent)){
+ const pos = token.parent.parent.closingFragment.pos + 1;
+ ranges = {start : pos, end : pos};
}
- //losing element
- if (token.parent.kind === SyntaxKind.JsxClosingFragment){
+ else if (isJsxClosingFragment(token.parent)){
+ const pos = token.parent.parent.openingFragment.pos + 1;
+ ranges = {start : pos, end : pos};
+ }
+ else {
return undefined;
}
-
- //neither
- return undefined
- // ISABEL unimplemented
+ return {ranges, wordPattern};
+
+ // is this cursed?
+ // it doesnt even work -> it errors types
+ // switch (true) {
+ // case isJsxOpeningElement(token.parent):
+ // // const nameSpan = {start : token.parent.parent.closingElement.pos, end : token.parent.parent.closingElement.end};
+ // case isJsxClosingElement(token.parent):
+ // case isJsxOpeningFragment(token.parent):
+ // case isJsxClosingFragment(token.parent):
+ // return undefined
+ // }
+
+ // switch (token.parent.kind) {
+ // case SyntaxKind.JsxOpeningElement:
+ // // const nameSpan = {start : token.parent.parent.closingElement.pos, end : token.parent.parent.closingElement.end};
+ // case SyntaxKind.JsxClosingElement:
+ // case SyntaxKind.JsxOpeningFragment:
+ // case SyntaxKind.JsxClosingFragment:
+ // return undefined
+ // }
+
+ // ISABEL delete extras
}
function getLinesForRange(sourceFile: SourceFile, textRange: TextRange) {
diff --git a/src/services/types.ts b/src/services/types.ts
index 19d17e9970687..13e72c7bf5a6b 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -671,7 +671,7 @@ export interface JsxMirrorCursorInfo {
}
export interface JsxLinkedEditInfo {
- readonly ranges : TextSpan;
+ readonly ranges : {start: number, end: number};
wordPattern? : string;
}
diff --git a/tests/cases/fourslash/mirrorCursor.ts b/tests/cases/fourslash/mirrorCursor.ts
index 65ad9b54ef6dc..21353dcd949e4 100644
--- a/tests/cases/fourslash/mirrorCursor.ts
+++ b/tests/cases/fourslash/mirrorCursor.ts
@@ -1,80 +1,83 @@
///
// @Filename: /basic.tsx
-//// const jsx = (
-////
-////
-//// );
+////const jsx = (
+////
+////
+////);
// @Filename: /attrs.tsx
-//// const jsx = (
-////
-////
-////
-////
-////
-//// );
+////const jsx = (
+////
+////
+////
+////
+////
+////);
// @Filename: /selfClosing.tsx
-//// const jsx = (
-////
-////
-////
-////
-////
-//// );
+////const jsx = (
+////
+////
+////
+////
+////
+////);
-// @Filename: /longName.tsx
-//// const jsx = (
-////
-////
-//// );
+// @Filename: /namespace.tsx
+////const jsx = (
+////
+////
+////);
// @FileName: /invalid1.tsx
-//// const jsx = (
-////
-////
-////
-//// );
+////const jsx = (
+////
+////
+////
+////);
// @FileName: /invalid2.tsx
-//// const jsx = (
-////
-//// );
+////const jsx = (
+////
+////);
// @FileName: /fragment.tsx
-//// const jsx = (
-//// *6*/>
-////
-//// >
-//// );
+////const jsx = (
+//// *6*/>
+////
+//// >
+////);
// @FileName: /mismatchedNames.tsx
-//// const A = thing;
-//// const B = thing;
-//// const jsx = (
-//// **/A>
-////
-//// );
-
-
-
+////const A = thing;
+////const B = thing;
+////const jsx = (
+//// *7*/A>
+////
+////);
verify.jsxMirrorCursor( {
- "0": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
- {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 9}],
- // "1": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
+ // "0": {ranges: {start: 28, end: 31}, wordPattern : 'div'},
+ // [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
+ // {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 9}],
+ // "1": {ranges: {start: 91, end: 94}, wordPattern : 'div'},
+ // [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
// {startLine: 5, startCharacter: 6, endLine: 5, endCharacter: 9}],
- // "2": [],
- // "3": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 25},
+ // "2": undefined,
+ // "3": {ranges: {start: 0, end: 0}, wordPattern : 'div'}, // FAILS
+ // [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 25},
// {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 26}],
- // "4": [],
- // "5": [{startLine: 2, startCharacter: 9, endLine: 2, endCharacter: 12},
+ // "4": undefined,
+ // "5": {ranges: {start: 44, end: 47}, wordPattern : 'div'},
+ // [{startLine: 2, startCharacter: 9, endLine: 2, endCharacter: 12},
// {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 9}],
- // "6": [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 5},
+ "6": {ranges: {start: 42, end: 42}, wordPattern : undefined}, // if you dont define wordpattern in 6, it has issues
+ // [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 5},
// {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 6}],
- // "7": [],
+ "7": undefined,
+ // "8": undefined,
})
\ No newline at end of file
From 21aa9e76bfca2ad0c3173557b5eb6620b5fd59a4 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Fri, 10 Mar 2023 23:47:54 -0800
Subject: [PATCH 04/32] forgot to include into last commit
---
tests/cases/fourslash/fourslash.ts | 6 ++----
tests/cases/fourslash/mirrorCursor.ts | 12 ++++++------
2 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index bffeb276b2a49..ec327371e1be6 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -261,10 +261,8 @@ declare namespace FourSlashInterface {
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
jsxMirrorCursor(map: { [markerName: string]: {
- readonly startLine : number;
- readonly startCharacter : number;
- readonly endLine : number;
- readonly endCharacter : number;}[] | undefined }): void;
+ readonly ranges : TextSpan;
+ wordPattern? : string ;} | undefined }): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
codeFix(options: {
description: string | [string, ...(string | number)[]] | DiagnosticIgnoredInterpolations,
diff --git a/tests/cases/fourslash/mirrorCursor.ts b/tests/cases/fourslash/mirrorCursor.ts
index 21353dcd949e4..6220c638f78fc 100644
--- a/tests/cases/fourslash/mirrorCursor.ts
+++ b/tests/cases/fourslash/mirrorCursor.ts
@@ -61,18 +61,18 @@
////);
verify.jsxMirrorCursor( {
- // "0": {ranges: {start: 28, end: 31}, wordPattern : 'div'},
+ "0": {ranges: {start: 28, end: 31}, wordPattern : 'div'},
// [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
// {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 9}],
- // "1": {ranges: {start: 91, end: 94}, wordPattern : 'div'},
+ "1": {ranges: {start: 91, end: 94}, wordPattern : 'div'},
// [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
// {startLine: 5, startCharacter: 6, endLine: 5, endCharacter: 9}],
- // "2": undefined,
- // "3": {ranges: {start: 0, end: 0}, wordPattern : 'div'}, // FAILS
+ "2": undefined,
+ "3": {ranges: {start: 0, end: 0}, wordPattern : 'div'}, // FAILS
// [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 25},
// {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 26}],
- // "4": undefined,
- // "5": {ranges: {start: 44, end: 47}, wordPattern : 'div'},
+ "4": undefined,
+ "5": {ranges: {start: 44, end: 47}, wordPattern : 'div'},
// [{startLine: 2, startCharacter: 9, endLine: 2, endCharacter: 12},
// {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 9}],
"6": {ranges: {start: 42, end: 42}, wordPattern : undefined}, // if you dont define wordpattern in 6, it has issues
From 398f6739720bd3dea87791033ae95808a89ca867 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Mon, 13 Mar 2023 16:24:37 -0700
Subject: [PATCH 05/32] passes tests!
---
src/services/services.ts | 81 ++++++++++++++++++---------
tests/cases/fourslash/mirrorCursor.ts | 2 +-
2 files changed, 54 insertions(+), 29 deletions(-)
diff --git a/src/services/services.ts b/src/services/services.ts
index 7c29ebc11b813..7a5f25f8a92bf 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -71,6 +71,7 @@ import {
filter,
find,
FindAllReferences,
+ findAncestor,
findChildOfKind,
findPrecedingToken,
first,
@@ -152,6 +153,7 @@ import {
isIntrinsicJsxName,
isJSDocCommentContainingNode,
isJsxAttributes,
+ isJsxChild,
isJsxClosingElement,
isJsxClosingFragment,
isJsxElement,
@@ -2487,38 +2489,61 @@ export function createLanguageService(
if (!token) return undefined;
let wordPattern : string | undefined;
+ let ranges : {start: number, end: number};
+
// if it is not in a jsx element/fragment, or if the tags do not match
- if (isJsxElement(token.parent.parent)){
- if (token.parent.parent.openingElement.tagName.getText() !== token.parent.parent.closingElement.tagName.getText()) {
- return undefined;
- }
- wordPattern = token.parent.parent.openingElement.tagName.getText();
- }
- else if (isJsxFragment(token.parent.parent)) {
+ if (isJsxFragment(token.parent.parent)) {
wordPattern = undefined;
- }
- else return undefined;
-
- let ranges : {start: number, end: number};
- //opening element
- if (isJsxOpeningElement(token.parent)){
- ranges = {start : token.parent.parent.closingElement.tagName.pos, end : token.parent.parent.closingElement.tagName.end};
- }
- else if (isJsxClosingElement(token.parent)){
- ranges = {start : token.parent.parent.openingElement.tagName.pos, end : token.parent.parent.openingElement.tagName.end};
- }
- else if (isJsxOpeningFragment(token.parent)){
- const pos = token.parent.parent.closingFragment.pos + 1;
- ranges = {start : pos, end : pos};
- }
- else if (isJsxClosingFragment(token.parent)){
- const pos = token.parent.parent.openingFragment.pos + 1;
- ranges = {start : pos, end : pos};
- }
+ if (isJsxOpeningFragment(token.parent)){
+ const pos = token.parent.parent.closingFragment.pos + 1;
+ ranges = {start : pos, end : pos};
+ }
+ else if (isJsxClosingFragment(token.parent)){
+ const pos = token.parent.parent.openingFragment.pos + 1;
+ ranges = {start : pos, end : pos};
+ }
+ else return undefined;
+ }
+ // else if (isJsxElement(token.parent.parent)){
+ // if (token.parent.parent.openingElement.tagName.getText() !== token.parent.parent.closingElement.tagName.getText()) {
+ // return undefined;
+ // }
+ // wordPattern = token.parent.parent.openingElement.tagName.getText();
+ // if (isJsxOpeningElement(token.parent)){
+ // ranges = {start : token.parent.parent.closingElement.tagName.pos, end : token.parent.parent.closingElement.tagName.end};
+ // }
+ // else if (isJsxClosingElement(token.parent)){
+ // ranges = {start : token.parent.parent.openingElement.tagName.pos, end : token.parent.parent.openingElement.tagName.end};
+ // }
+ // else return undefined;
+ // }
else {
- return undefined;
- }
+ const tag = findAncestor(token,
+ (n) => {
+ // refactor case of?
+ if (isJsxOpeningElement(n)) return true;
+ else if (isJsxClosingElement(n)) return true;
+ else if (isJsxAttributes(n)) return "quit";
+ else if (isJsxChild(n)) return "quit";
+ return false;
+ }
+ );
+ if (!tag) return undefined;
+ if (isJsxOpeningElement(tag)){
+ ranges = {start : tag.parent.closingElement.tagName.pos, end : tag.parent.closingElement.tagName.end};
+ }
+ else if (isJsxClosingElement(tag)){
+ ranges = {start : tag.parent.openingElement.tagName.pos, end : tag.parent.openingElement.tagName.end};
+ }
+ else return undefined;
+
+ if (tag.parent.openingElement.tagName.getText() === tag.parent.closingElement.tagName.getText()) {
+ wordPattern = tag.tagName.getText();
+ }
+ else return undefined;
+ }
+
return {ranges, wordPattern};
// is this cursed?
diff --git a/tests/cases/fourslash/mirrorCursor.ts b/tests/cases/fourslash/mirrorCursor.ts
index 6220c638f78fc..29fe466bbe672 100644
--- a/tests/cases/fourslash/mirrorCursor.ts
+++ b/tests/cases/fourslash/mirrorCursor.ts
@@ -68,7 +68,7 @@ verify.jsxMirrorCursor( {
// [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
// {startLine: 5, startCharacter: 6, endLine: 5, endCharacter: 9}],
"2": undefined,
- "3": {ranges: {start: 0, end: 0}, wordPattern : 'div'}, // FAILS
+ "3": {ranges: {start: 46, end: 65}, wordPattern : 'someNamespace.Thing'}, // FAILS
// [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 25},
// {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 26}],
"4": undefined,
From 2bafe8da2de82643ea5f4b8d062588c5b31d26a6 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 15 Mar 2023 12:57:41 -0700
Subject: [PATCH 06/32] change testing structure
---
tests/cases/fourslash/jsxTagLinkedEdit1.ts | 7 ++
tests/cases/fourslash/jsxTagLinkedEdit2.ts | 10 +++
tests/cases/fourslash/jsxTagLinkedEdit3.ts | 10 +++
tests/cases/fourslash/jsxTagLinkedEdit4.ts | 7 ++
tests/cases/fourslash/jsxTagLinkedEdit5.ts | 8 +++
tests/cases/fourslash/jsxTagLinkedEdit6.ts | 8 +++
tests/cases/fourslash/jsxTagLinkedEdit7.ts | 8 +++
tests/cases/fourslash/jsxTagLinkedEdit8.ts | 12 ++++
tests/cases/fourslash/mirrorCursor.ts | 83 ----------------------
9 files changed, 70 insertions(+), 83 deletions(-)
create mode 100644 tests/cases/fourslash/jsxTagLinkedEdit1.ts
create mode 100644 tests/cases/fourslash/jsxTagLinkedEdit2.ts
create mode 100644 tests/cases/fourslash/jsxTagLinkedEdit3.ts
create mode 100644 tests/cases/fourslash/jsxTagLinkedEdit4.ts
create mode 100644 tests/cases/fourslash/jsxTagLinkedEdit5.ts
create mode 100644 tests/cases/fourslash/jsxTagLinkedEdit6.ts
create mode 100644 tests/cases/fourslash/jsxTagLinkedEdit7.ts
create mode 100644 tests/cases/fourslash/jsxTagLinkedEdit8.ts
delete mode 100644 tests/cases/fourslash/mirrorCursor.ts
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
new file mode 100644
index 0000000000000..a113cc757b600
--- /dev/null
+++ b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
@@ -0,0 +1,7 @@
+///
+
+// @Filename: /basic.tsx
+////const jsx = (
+//// *00*/d/*01*/iv/*02*/>
+//// /*03*/di/*04*/v/*05*/>
+////);
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit2.ts b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
new file mode 100644
index 0000000000000..335482fa12ac6
--- /dev/null
+++ b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
@@ -0,0 +1,10 @@
+///
+
+// @Filename: /attrs.tsx
+////const jsx = (
+////
+////
+////
+////
+////
+////);
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit3.ts b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
new file mode 100644
index 0000000000000..306c4584eef6b
--- /dev/null
+++ b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
@@ -0,0 +1,10 @@
+///
+
+// @Filename: /selfClosing.tsx
+////const jsx = (
+////
+////
+////
+////
+////
+////);
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit4.ts b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
new file mode 100644
index 0000000000000..013550daccc71
--- /dev/null
+++ b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
@@ -0,0 +1,7 @@
+///
+
+// @Filename: /namespace.tsx
+////const jsx = (
+////
+////
+////);
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit5.ts b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
new file mode 100644
index 0000000000000..490459440b4ed
--- /dev/null
+++ b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
@@ -0,0 +1,8 @@
+///
+
+// @FileName: /invalid1.tsx
+////const jsx = (
+////
+////
+////
+////);
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit6.ts b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
new file mode 100644
index 0000000000000..e242efea77e9d
--- /dev/null
+++ b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
@@ -0,0 +1,8 @@
+///
+
+// @FileName: /invalid2.tsx
+////const jsx = (
+////
+////);
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit7.ts b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
new file mode 100644
index 0000000000000..46df2a4a76055
--- /dev/null
+++ b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
@@ -0,0 +1,8 @@
+///
+
+// @FileName: /fragment.tsx
+////const jsx = (
+//// *6*/>
+////
+//// >
+////);
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit8.ts b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
new file mode 100644
index 0000000000000..8c6221a424031
--- /dev/null
+++ b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
@@ -0,0 +1,12 @@
+///
+
+// @FileName: /mismatchedNames.tsx
+////const A = thing;
+////const B = thing;
+////const jsx = (
+//// *7*/A>
+////
+////);
+
+// verify.jsxMirrorCursor( {
+// "0": {ranges: {start: 28, end: 31}, wordPattern : 'div'}} );
\ No newline at end of file
diff --git a/tests/cases/fourslash/mirrorCursor.ts b/tests/cases/fourslash/mirrorCursor.ts
deleted file mode 100644
index 29fe466bbe672..0000000000000
--- a/tests/cases/fourslash/mirrorCursor.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-///
-
-// @Filename: /basic.tsx
-////const jsx = (
-////
-////
-////);
-
-
-// @Filename: /attrs.tsx
-////const jsx = (
-////
-////
-////
-////
-////
-////);
-
-// @Filename: /selfClosing.tsx
-////const jsx = (
-////
-////
-////
-////
-////
-////);
-
-// @Filename: /namespace.tsx
-////const jsx = (
-////
-////
-////);
-
-// @FileName: /invalid1.tsx
-////const jsx = (
-////
-////
-////
-////);
-
-// @FileName: /invalid2.tsx
-////const jsx = (
-////
-////);
-
-// @FileName: /fragment.tsx
-////const jsx = (
-//// *6*/>
-////
-//// >
-////);
-
-// @FileName: /mismatchedNames.tsx
-////const A = thing;
-////const B = thing;
-////const jsx = (
-//// *7*/A>
-////
-////);
-
-verify.jsxMirrorCursor( {
- "0": {ranges: {start: 28, end: 31}, wordPattern : 'div'},
- // [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
- // {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 9}],
- "1": {ranges: {start: 91, end: 94}, wordPattern : 'div'},
- // [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8},
- // {startLine: 5, startCharacter: 6, endLine: 5, endCharacter: 9}],
- "2": undefined,
- "3": {ranges: {start: 46, end: 65}, wordPattern : 'someNamespace.Thing'}, // FAILS
- // [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 25},
- // {startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 26}],
- "4": undefined,
- "5": {ranges: {start: 44, end: 47}, wordPattern : 'div'},
- // [{startLine: 2, startCharacter: 9, endLine: 2, endCharacter: 12},
- // {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 9}],
- "6": {ranges: {start: 42, end: 42}, wordPattern : undefined}, // if you dont define wordpattern in 6, it has issues
- // [{startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 5},
- // {startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 6}],
- "7": undefined,
- // "8": undefined,
-})
\ No newline at end of file
From da0ddf1457830994497c34a4d7f178383ea21a92 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 15 Mar 2023 23:29:10 -0700
Subject: [PATCH 07/32] change testing structure
---
tests/cases/fourslash/jsxTagLinkedEdit1.ts | 40 ++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
index a113cc757b600..9d295cc57d7c2 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit1.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
@@ -1,7 +1,43 @@
///
+// the content of basic.tsx
+//const jsx = (
+//
+//
+//);
+
+
// @Filename: /basic.tsx
////const jsx = (
-//// *00*/d/*01*/iv/*02*/>
-//// /*03*/di/*04*/v/*05*/>
+//// *0*/d/*1*/iv/*2*/>/*7*/
+//// *6*///*3*/di/*4*/v/*5*/>/*9*/
+////);
+////const jsx2 = (
+////
+//// < /*8*/ /div>
+////);
+////const jsx3 = (
+//// *10*/ div>
+////
////);
+
+
+const linkedCursors = {ranges: [{start: 19, end: 22},
+ {start: 30, end: 33}],
+ wordPattern : 'div'};
+
+verify.jsxMirrorCursor( {
+ "0": linkedCursors,
+ "1": linkedCursors,
+ "2": linkedCursors,
+ "3": linkedCursors,
+ "4": linkedCursors,
+ "5": linkedCursors,
+ "6": undefined,
+ "7": undefined,
+ "8": undefined,
+ "9": undefined,
+ // "10":undefined, // if still a comment, this case doesnt yet work !!!!
+ }
+ );
+
From 9d7f32cd2b062271a04dab4d1c56bb4ab462cf83 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 15 Mar 2023 23:37:14 -0700
Subject: [PATCH 08/32] add correct content into tests (and some more test
cases)
---
tests/cases/fourslash/fourslash.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit1.ts | 23 ++++++++--------
tests/cases/fourslash/jsxTagLinkedEdit2.ts | 18 ++++++++++--
tests/cases/fourslash/jsxTagLinkedEdit3.ts | 10 ++++++-
tests/cases/fourslash/jsxTagLinkedEdit4.ts | 32 ++++++++++++++++++++--
tests/cases/fourslash/jsxTagLinkedEdit5.ts | 14 ++++++++--
tests/cases/fourslash/jsxTagLinkedEdit6.ts | 17 +++++++++---
tests/cases/fourslash/jsxTagLinkedEdit7.ts | 29 ++++++++++++++++++--
tests/cases/fourslash/jsxTagLinkedEdit8.ts | 11 ++++++--
tests/cases/fourslash/test.jsx | 2 ++
10 files changed, 128 insertions(+), 30 deletions(-)
create mode 100644 tests/cases/fourslash/test.jsx
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index ec327371e1be6..c0ebbbd49caf4 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -261,7 +261,7 @@ declare namespace FourSlashInterface {
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
jsxMirrorCursor(map: { [markerName: string]: {
- readonly ranges : TextSpan;
+ readonly ranges : {start:number, end:number}[],
wordPattern? : string ;} | undefined }): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
codeFix(options: {
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
index 9d295cc57d7c2..5c622448d91a4 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit1.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
@@ -22,22 +22,21 @@
////);
-const linkedCursors = {ranges: [{start: 19, end: 22},
- {start: 30, end: 33}],
- wordPattern : 'div'};
+const linkedCursors1 = {ranges: [{start: 19, end: 22},
+ {start: 30, end: 33}],
+ wordPattern : 'div'};
verify.jsxMirrorCursor( {
- "0": linkedCursors,
- "1": linkedCursors,
- "2": linkedCursors,
- "3": linkedCursors,
- "4": linkedCursors,
- "5": linkedCursors,
+ "0": linkedCursors1,
+ "1": linkedCursors1,
+ "2": linkedCursors1,
+ "3": linkedCursors1,
+ "4": linkedCursors1,
+ "5": linkedCursors1,
"6": undefined,
"7": undefined,
"8": undefined,
"9": undefined,
- // "10":undefined, // if still a comment, this case doesnt yet work !!!!
- }
- );
+ // "10":undefined, // if still a comment, case doesnt yet work !!!!
+ });
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit2.ts b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
index 335482fa12ac6..7b451b6cfcb54 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit2.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
@@ -2,9 +2,23 @@
// @Filename: /attrs.tsx
////const jsx = (
-////
+//// *0*/div/*1*/ /*5*/styl/*2*/e={{ color: 'red' }}/*6*/>/*4*/
////
////
////
-////
+////
////);
+
+const linkedCursors2 = {ranges: [{start: 18, end: 21},
+ {start: 91, end: 94}],
+ wordPattern : 'div'};
+
+verify.jsxMirrorCursor( {
+ "0": linkedCursors2,
+ "1": linkedCursors2,
+ "2": undefined,
+ "3": linkedCursors2,
+ "4": undefined,
+ // "5": undefined, // if still a comment, case doesnt yet work !!!!
+ "6": undefined,
+});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit3.ts b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
index 306c4584eef6b..2554855e8816a 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit3.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
@@ -7,4 +7,12 @@
////
////
////
-////);
\ No newline at end of file
+////);
+
+// const linkedCursors3 = {ranges: [{start: 18, end: 21},
+// {start: 91, end: 94}],
+// wordPattern : 'div'};
+
+verify.jsxMirrorCursor( {
+ "2": undefined,
+});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit4.ts b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
index 013550daccc71..37d2018a5629a 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit4.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
@@ -1,7 +1,33 @@
///
-// @Filename: /namespace.tsx
+// for readability purposes
+//const jsx = (
+// >
+//
+//
+//
+//
+//);
+
+
+// @Filename: /typeTag.tsx
////const jsx = (
-////
-////
+//// *0*/div/*1*/*2*/T/*3*/>/*4*/>
+////
+////
+////
+////
////);
+
+const linkedCursors4 = {ranges: [{start: 18, end: 21},
+ {start: 69, end: 72}],
+ wordPattern : 'div'};
+
+verify.jsxMirrorCursor( {
+ "0": linkedCursors4,
+ "1": linkedCursors4,
+ // "2": undefined,
+ "3": undefined,
+ "4": undefined,
+ "5": linkedCursors4, // if still a comment, this case doesnt yet work !!!!
+});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit5.ts b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
index 490459440b4ed..4ed030a590333 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit5.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
@@ -3,6 +3,16 @@
// @FileName: /invalid1.tsx
////const jsx = (
////
-////
-////
+////
+////
////);
+
+const linkedCursors5 = {ranges: [{start: 33, end: 36},
+ {start: 44, end: 47}],
+ wordPattern : 'div'};
+
+verify.jsxMirrorCursor( {
+ "4": undefined,
+ "5": linkedCursors5,
+ "6": linkedCursors5,
+});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit6.ts b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
index e242efea77e9d..1f3978a5fb298 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit6.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
@@ -1,8 +1,17 @@
///
-// @FileName: /invalid2.tsx
+// @Filename: /namespace.tsx
////const jsx = (
-////
+////
+////
////);
+
+const linkedCursors6 = {ranges: [{start: 19, end: 38},
+ {start: 46, end: 65}],
+ wordPattern : 'someNamespace.Thing'};
+
+verify.jsxMirrorCursor( {
+ "1": linkedCursors6,
+ "2": linkedCursors6,
+ "3": linkedCursors6,
+});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit7.ts b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
index 46df2a4a76055..30bb859258df4 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit7.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
@@ -2,7 +2,32 @@
// @FileName: /fragment.tsx
////const jsx = (
-//// *6*/>
+//// /*7*/*0*/>/*1*/
////
+//// /*8*/*2*///*3*/>/*4*/
+////);
+////const jsx2 = (
+//// <>/*5*/
+//// >
+////);
+////const jsx3 = (
+//// *6*/>
+////
//// >
-////);
\ No newline at end of file
+////);
+
+const linkedCursors7 = {ranges: [{start: 14, end: 14},
+ {start: 43, end: 43}],
+ wordPattern : undefined};
+
+verify.jsxMirrorCursor( {
+ "0": linkedCursors7,
+ "1": undefined,
+ "2": undefined,
+ "3": linkedCursors7,
+ "4": undefined,
+ "5": undefined,
+ // "6": linkedCursors7, // I don't know what's supposed to happen in this case
+ "7": undefined,
+ "8": undefined,
+});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit8.ts b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
index 8c6221a424031..97a337540af85 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit8.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
@@ -4,9 +4,14 @@
////const A = thing;
////const B = thing;
////const jsx = (
-//// *7*/A>
+//// *8*/A>
////
////);
-// verify.jsxMirrorCursor( {
-// "0": {ranges: {start: 28, end: 31}, wordPattern : 'div'}} );
\ No newline at end of file
+// const linkedCursors8 = {ranges: [{start: 14, end: 14},
+// {start: 43, end: 43}],
+// wordPattern : };
+
+verify.jsxMirrorCursor( {
+ "8": undefined,
+});
\ No newline at end of file
diff --git a/tests/cases/fourslash/test.jsx b/tests/cases/fourslash/test.jsx
new file mode 100644
index 0000000000000..759c99865a518
--- /dev/null
+++ b/tests/cases/fourslash/test.jsx
@@ -0,0 +1,2 @@
+const c = (< div>
+
)
\ No newline at end of file
From 1fff99dceeae756853d5efc7a140f686411bb6e6 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 15 Mar 2023 23:41:10 -0700
Subject: [PATCH 09/32] changes to getLinkedEdit.., saving some extra code in
comments as well
---
src/services/services.ts | 88 ++++++++++++++++++++--------------------
1 file changed, 44 insertions(+), 44 deletions(-)
diff --git a/src/services/services.ts b/src/services/services.ts
index 7a5f25f8a92bf..800abfed8c4ef 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -153,13 +153,14 @@ import {
isIntrinsicJsxName,
isJSDocCommentContainingNode,
isJsxAttributes,
- isJsxChild,
isJsxClosingElement,
isJsxClosingFragment,
isJsxElement,
isJsxFragment,
isJsxOpeningElement,
isJsxOpeningFragment,
+ isJsxSelfClosingElement,
+ isJSXTagName,
isJsxText,
isLabelName,
isLiteralComputedPropertyDeclarationName,
@@ -188,12 +189,13 @@ import {
JSDocTagInfo,
JsonSourceFile,
JsxAttributes,
+ JsxClosingElement,
JsxClosingTagInfo,
JsxElement,
JsxEmit,
JsxFragment,
JsxLinkedEditInfo,
- JsxMirrorCursorInfo,
+ JsxOpeningElement,
LanguageService,
LanguageServiceHost,
LanguageServiceMode,
@@ -2489,55 +2491,53 @@ export function createLanguageService(
if (!token) return undefined;
let wordPattern : string | undefined;
- let ranges : {start: number, end: number};
+ let ranges : {start: number, end: number}[] = [];
- // if it is not in a jsx element/fragment, or if the tags do not match
- if (isJsxFragment(token.parent.parent)) {
+ // check edge cases <| and >|
+ if (token.kind===SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent)) return undefined;
+ if (token.kind===SyntaxKind.LessThanToken && isJsxClosingElement(token.parent)) return undefined;
+
+ if ((isJsxOpeningFragment(token.parent) && token.kind===SyntaxKind.LessThanToken)
+ || (isJsxClosingFragment(token.parent) && token.kind===SyntaxKind.SlashToken)){
+
+ const openPos = token.parent.parent.openingFragment.pos + 1;
+ const closePos = token.parent.parent.closingFragment.pos + 2;
+
+ ranges = ranges.concat({start : openPos, end : openPos});
+ ranges = ranges.concat({start : closePos, end : closePos});
wordPattern = undefined;
- if (isJsxOpeningFragment(token.parent)){
- const pos = token.parent.parent.closingFragment.pos + 1;
- ranges = {start : pos, end : pos};
- }
- else if (isJsxClosingFragment(token.parent)){
- const pos = token.parent.parent.openingFragment.pos + 1;
- ranges = {start : pos, end : pos};
- }
- else return undefined;
}
- // else if (isJsxElement(token.parent.parent)){
- // if (token.parent.parent.openingElement.tagName.getText() !== token.parent.parent.closingElement.tagName.getText()) {
- // return undefined;
- // }
- // wordPattern = token.parent.parent.openingElement.tagName.getText();
- // if (isJsxOpeningElement(token.parent)){
- // ranges = {start : token.parent.parent.closingElement.tagName.pos, end : token.parent.parent.closingElement.tagName.end};
- // }
- // else if (isJsxClosingElement(token.parent)){
- // ranges = {start : token.parent.parent.openingElement.tagName.pos, end : token.parent.parent.openingElement.tagName.end};
- // }
- // else return undefined;
- // }
+ else if (isJsxFragment(token.parent.parent)) {
+ return undefined;
+ }
else {
- const tag = findAncestor(token,
+ const tag =
+ // findAncestor(token,
+ // (n) => {
+ // if (isJsxOpeningElement(n) || isJsxClosingElement(n)) return true;
+ // else if (n.kind===SyntaxKind.LessThanToken || isIdentifier(n) || n.kind === SyntaxKind.ThisKeyword || isPropertyAccessExpression(n)) return false;
+ // return "quit"; });
+
+ findAncestor(token,
(n) => {
- // refactor case of?
- if (isJsxOpeningElement(n)) return true;
- else if (isJsxClosingElement(n)) return true;
- else if (isJsxAttributes(n)) return "quit";
- else if (isJsxChild(n)) return "quit";
- return false;
+ if (!n.parent.parent) return "quit";
+ else if (isJsxElement(n.parent.parent)) {
+ if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent) )|| n.kind===SyntaxKind.LessThanToken || n.kind===SyntaxKind.SlashToken) return true;
+ return "quit";
+ }
+ // return true;
+ // else if (isJsxClosingElement(n.parent)) return true;
+ // else if (isJsxAttributes(n)) return "quit";
+ // else if (isJsxChild(n)) return "quit";
+ else return false;
+ // else if (n.kind === SyntaxKind.JsxTagNameExpression || n.kind === SyntaxKind.JsxTagNamePropertyAccess)
}
- );
+ )?.parent as JsxOpeningElement | JsxClosingElement | undefined;
if (!tag) return undefined;
- if (isJsxOpeningElement(tag)){
- ranges = {start : tag.parent.closingElement.tagName.pos, end : tag.parent.closingElement.tagName.end};
- }
- else if (isJsxClosingElement(tag)){
- ranges = {start : tag.parent.openingElement.tagName.pos, end : tag.parent.openingElement.tagName.end};
- }
- else return undefined;
-
+ ranges = ranges.concat({start : tag.parent.openingElement.tagName.pos, end : tag.parent.openingElement.tagName.end});
+ ranges = ranges.concat({start : tag.parent.closingElement.tagName.pos, end : tag.parent.closingElement.tagName.end});
+
if (tag.parent.openingElement.tagName.getText() === tag.parent.closingElement.tagName.getText()) {
wordPattern = tag.tagName.getText();
}
@@ -2545,7 +2545,7 @@ export function createLanguageService(
}
return {ranges, wordPattern};
-
+ // return {ranges: }};
// is this cursed?
// it doesnt even work -> it errors types
// switch (true) {
From 0b0541db5e9ede2568f6dfcbb5ebfe0995be0249 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 15 Mar 2023 23:51:39 -0700
Subject: [PATCH 10/32] remove comments, extra code, rename functions
---
src/harness/fourslashImpl.ts | 5 +--
src/harness/fourslashInterfaceImpl.ts | 4 +-
src/harness/harnessLanguageService.ts | 2 +-
src/server/protocol.ts | 8 ++--
src/server/session.ts | 7 +---
src/services/services.ts | 43 +++-------------------
src/services/types.ts | 12 +-----
tests/cases/fourslash/fourslash.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit1.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit2.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit3.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit4.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit5.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit6.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit7.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit8.ts | 2 +-
16 files changed, 26 insertions(+), 73 deletions(-)
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index e3fef1cec9259..6afc33345521e 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -3444,11 +3444,10 @@ export class TestState {
}
}
- public verifyJsxMirrorCursor(map: {[markerName:string]:ts.JsxMirrorCursorInfo | undefined}):void {
+ public verifyJsxLinkedEdit(map: {[markerName:string]:ts.JsxLinkedEditInfo | undefined}):void {
for (const markerName in map) {
this.goToMarker(markerName);
- // const actual = {};
- const actual = this.languageService.getJsxMirrorCursorAtPosition(this.activeFile.fileName, this.currentCaretPosition);
+ const actual = this.languageService.getJsxLinkedEditAtPosition(this.activeFile.fileName, this.currentCaretPosition);
assert.deepEqual(actual, map[markerName], markerName);
}
}
diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts
index 89768d69200c9..d6a56c9280a48 100644
--- a/src/harness/fourslashInterfaceImpl.ts
+++ b/src/harness/fourslashInterfaceImpl.ts
@@ -189,8 +189,8 @@ export class VerifyNegatable {
this.state.verifyJsxClosingTag(map);
}
- public jsxMirrorCursor(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined }): void {
- this.state.verifyJsxMirrorCursor(map);
+ public jsxLinkedEdit(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined }): void {
+ this.state.verifyJsxLinkedEdit(map);
}
diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts
index 0f0eea5ea00dc..2ad1a313cb15c 100644
--- a/src/harness/harnessLanguageService.ts
+++ b/src/harness/harnessLanguageService.ts
@@ -593,7 +593,7 @@ class LanguageServiceShimProxy implements ts.LanguageService {
getJsxClosingTagAtPosition(): never {
throw new Error("Not supported on the shim.");
}
- getJsxMirrorCursorAtPosition(): never {
+ getJsxLinkedEditAtPosition(): never {
throw new Error("Not supported on the shim.");
}
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan {
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index da01b3354ebac..2f079372761d2 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -23,7 +23,7 @@ import {
export const enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
- JsxMirrorCursor = "jsxMirrorCursor",
+ JsxLinkedEdit = "jsxLinkedEdit",
Brace = "brace",
/** @internal */
BraceFull = "brace-full",
@@ -1102,12 +1102,12 @@ export interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
-export interface JsxMirrorCursorRequest extends FileLocationRequest {
- readonly command: CommandTypes.JsxMirrorCursor;
+export interface JsxLinkedEditRequest extends FileLocationRequest {
+ readonly command: CommandTypes.JsxLinkedEdit;
// ISABEL?
}
-export interface JsxMirrorCursorResponse extends Response {
+export interface JsxLinkedEditResponse extends Response {
// ISABEL?
}
diff --git a/src/server/session.ts b/src/server/session.ts
index 74153bb08d741..4f4f89d2fb7c1 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -1802,11 +1802,6 @@ export class Session implements EventSender {
return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 };
}
- private getJsxMirrorCursor(args): undefined{
- return undefined;
- //ISABEL stub
- }
-
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
@@ -3394,7 +3389,7 @@ export class Session implements EventSender {
[protocol.CommandTypes.JsxClosingTag]: (request: protocol.JsxClosingTagRequest) => {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
},
- [protocol.CommandTypes.JsxMirrorCursor]: (request: protocol.JsxMirrorCursorRequest) => {
+ [protocol.CommandTypes.JsxLinkedEdit]: (request: protocol.JsxLinkedEditRequest) => {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
// ISABEL what ;
},
diff --git a/src/services/services.ts b/src/services/services.ts
index 800abfed8c4ef..403a4183dd099 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2485,7 +2485,7 @@ export function createLanguageService(
}
}
- function getJsxMirrorCursorAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined {
+ function getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const token = findPrecedingToken(position, sourceFile);
if (!token) return undefined;
@@ -2511,26 +2511,15 @@ export function createLanguageService(
return undefined;
}
else {
- const tag =
- // findAncestor(token,
- // (n) => {
- // if (isJsxOpeningElement(n) || isJsxClosingElement(n)) return true;
- // else if (n.kind===SyntaxKind.LessThanToken || isIdentifier(n) || n.kind === SyntaxKind.ThisKeyword || isPropertyAccessExpression(n)) return false;
- // return "quit"; });
-
- findAncestor(token,
+ const tag = findAncestor(token,
(n) => {
if (!n.parent.parent) return "quit";
else if (isJsxElement(n.parent.parent)) {
- if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent) )|| n.kind===SyntaxKind.LessThanToken || n.kind===SyntaxKind.SlashToken) return true;
+ if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent)) || n.kind===SyntaxKind.LessThanToken || n.kind===SyntaxKind.SlashToken) {
+ return true };
return "quit";
}
- // return true;
- // else if (isJsxClosingElement(n.parent)) return true;
- // else if (isJsxAttributes(n)) return "quit";
- // else if (isJsxChild(n)) return "quit";
else return false;
- // else if (n.kind === SyntaxKind.JsxTagNameExpression || n.kind === SyntaxKind.JsxTagNamePropertyAccess)
}
)?.parent as JsxOpeningElement | JsxClosingElement | undefined;
if (!tag) return undefined;
@@ -2545,28 +2534,6 @@ export function createLanguageService(
}
return {ranges, wordPattern};
- // return {ranges: }};
- // is this cursed?
- // it doesnt even work -> it errors types
- // switch (true) {
- // case isJsxOpeningElement(token.parent):
- // // const nameSpan = {start : token.parent.parent.closingElement.pos, end : token.parent.parent.closingElement.end};
- // case isJsxClosingElement(token.parent):
- // case isJsxOpeningFragment(token.parent):
- // case isJsxClosingFragment(token.parent):
- // return undefined
- // }
-
- // switch (token.parent.kind) {
- // case SyntaxKind.JsxOpeningElement:
- // // const nameSpan = {start : token.parent.parent.closingElement.pos, end : token.parent.parent.closingElement.end};
- // case SyntaxKind.JsxClosingElement:
- // case SyntaxKind.JsxOpeningFragment:
- // case SyntaxKind.JsxClosingFragment:
- // return undefined
- // }
-
- // ISABEL delete extras
}
function getLinesForRange(sourceFile: SourceFile, textRange: TextRange) {
@@ -3100,7 +3067,7 @@ export function createLanguageService(
getDocCommentTemplateAtPosition,
isValidBraceCompletionAtPosition,
getJsxClosingTagAtPosition,
- getJsxMirrorCursorAtPosition,
+ getJsxLinkedEditAtPosition: getJsxLinkedEditAtPosition,
getSpanOfEnclosingComment,
getCodeFixesAtPosition,
getCombinedCodeFix,
diff --git a/src/services/types.ts b/src/services/types.ts
index 13e72c7bf5a6b..50511ee86619d 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -607,8 +607,7 @@ export interface LanguageService {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxMirrorCursorAtPosition(fileName: string, currentCaretPosition: number): JsxMirrorCursorInfo | unknown;
- //ISABEL incorrect return type
+ getJsxLinkedEditAtPosition(fileName: string, currentCaretPosition: number): JsxLinkedEditInfo | unknown;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
@@ -663,15 +662,8 @@ export interface JsxClosingTagInfo {
readonly newText: string;
}
-export interface JsxMirrorCursorInfo {
- readonly startLine : number;
- readonly startCharacter : number;
- readonly endLine : number;
- readonly endCharacter : number;
-}
-
export interface JsxLinkedEditInfo {
- readonly ranges : {start: number, end: number};
+ readonly ranges : {start: number, end: number}[];
wordPattern? : string;
}
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index c0ebbbd49caf4..60de39bd77ffa 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -260,7 +260,7 @@ declare namespace FourSlashInterface {
implementationListIsEmpty(): void;
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
- jsxMirrorCursor(map: { [markerName: string]: {
+ jsxLinkedEdit(map: { [markerName: string]: {
readonly ranges : {start:number, end:number}[],
wordPattern? : string ;} | undefined }): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
index 5c622448d91a4..61455ad90ea58 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit1.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
@@ -26,7 +26,7 @@ const linkedCursors1 = {ranges: [{start: 19, end: 22},
{start: 30, end: 33}],
wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"0": linkedCursors1,
"1": linkedCursors1,
"2": linkedCursors1,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit2.ts b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
index 7b451b6cfcb54..ab0cbc0e5edde 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit2.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
@@ -13,7 +13,7 @@ const linkedCursors2 = {ranges: [{start: 18, end: 21},
{start: 91, end: 94}],
wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"0": linkedCursors2,
"1": linkedCursors2,
"2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit3.ts b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
index 2554855e8816a..f149f0237e519 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit3.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
@@ -13,6 +13,6 @@
// {start: 91, end: 94}],
// wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"2": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit4.ts b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
index 37d2018a5629a..ae48b86e8db45 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit4.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
@@ -23,7 +23,7 @@ const linkedCursors4 = {ranges: [{start: 18, end: 21},
{start: 69, end: 72}],
wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"0": linkedCursors4,
"1": linkedCursors4,
// "2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit5.ts b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
index 4ed030a590333..5d92f9196c615 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit5.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
@@ -11,7 +11,7 @@ const linkedCursors5 = {ranges: [{start: 33, end: 36},
{start: 44, end: 47}],
wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"4": undefined,
"5": linkedCursors5,
"6": linkedCursors5,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit6.ts b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
index 1f3978a5fb298..81138025a9122 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit6.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
@@ -10,7 +10,7 @@ const linkedCursors6 = {ranges: [{start: 19, end: 38},
{start: 46, end: 65}],
wordPattern : 'someNamespace.Thing'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"1": linkedCursors6,
"2": linkedCursors6,
"3": linkedCursors6,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit7.ts b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
index 30bb859258df4..9d7eea3996857 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit7.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
@@ -20,7 +20,7 @@ const linkedCursors7 = {ranges: [{start: 14, end: 14},
{start: 43, end: 43}],
wordPattern : undefined};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"0": linkedCursors7,
"1": undefined,
"2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit8.ts b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
index 97a337540af85..f9617c1fcd4cd 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit8.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
@@ -12,6 +12,6 @@
// {start: 43, end: 43}],
// wordPattern : };
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"8": undefined,
});
\ No newline at end of file
From b70ee9048c297e3fd9339d9169bdcbd6996ed9f0 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 15 Mar 2023 23:51:39 -0700
Subject: [PATCH 11/32] remove commented code and todos, also renames functions
---
src/harness/fourslashImpl.ts | 5 +--
src/harness/fourslashInterfaceImpl.ts | 4 +-
src/harness/harnessLanguageService.ts | 2 +-
src/server/protocol.ts | 8 ++--
src/server/session.ts | 7 +---
src/services/services.ts | 43 +++-------------------
src/services/types.ts | 12 +-----
tests/cases/fourslash/fourslash.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit1.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit2.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit3.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit4.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit5.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit6.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit7.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit8.ts | 2 +-
16 files changed, 26 insertions(+), 73 deletions(-)
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index e3fef1cec9259..6afc33345521e 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -3444,11 +3444,10 @@ export class TestState {
}
}
- public verifyJsxMirrorCursor(map: {[markerName:string]:ts.JsxMirrorCursorInfo | undefined}):void {
+ public verifyJsxLinkedEdit(map: {[markerName:string]:ts.JsxLinkedEditInfo | undefined}):void {
for (const markerName in map) {
this.goToMarker(markerName);
- // const actual = {};
- const actual = this.languageService.getJsxMirrorCursorAtPosition(this.activeFile.fileName, this.currentCaretPosition);
+ const actual = this.languageService.getJsxLinkedEditAtPosition(this.activeFile.fileName, this.currentCaretPosition);
assert.deepEqual(actual, map[markerName], markerName);
}
}
diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts
index 89768d69200c9..d6a56c9280a48 100644
--- a/src/harness/fourslashInterfaceImpl.ts
+++ b/src/harness/fourslashInterfaceImpl.ts
@@ -189,8 +189,8 @@ export class VerifyNegatable {
this.state.verifyJsxClosingTag(map);
}
- public jsxMirrorCursor(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined }): void {
- this.state.verifyJsxMirrorCursor(map);
+ public jsxLinkedEdit(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined }): void {
+ this.state.verifyJsxLinkedEdit(map);
}
diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts
index 0f0eea5ea00dc..2ad1a313cb15c 100644
--- a/src/harness/harnessLanguageService.ts
+++ b/src/harness/harnessLanguageService.ts
@@ -593,7 +593,7 @@ class LanguageServiceShimProxy implements ts.LanguageService {
getJsxClosingTagAtPosition(): never {
throw new Error("Not supported on the shim.");
}
- getJsxMirrorCursorAtPosition(): never {
+ getJsxLinkedEditAtPosition(): never {
throw new Error("Not supported on the shim.");
}
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan {
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index da01b3354ebac..2f079372761d2 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -23,7 +23,7 @@ import {
export const enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
- JsxMirrorCursor = "jsxMirrorCursor",
+ JsxLinkedEdit = "jsxLinkedEdit",
Brace = "brace",
/** @internal */
BraceFull = "brace-full",
@@ -1102,12 +1102,12 @@ export interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
-export interface JsxMirrorCursorRequest extends FileLocationRequest {
- readonly command: CommandTypes.JsxMirrorCursor;
+export interface JsxLinkedEditRequest extends FileLocationRequest {
+ readonly command: CommandTypes.JsxLinkedEdit;
// ISABEL?
}
-export interface JsxMirrorCursorResponse extends Response {
+export interface JsxLinkedEditResponse extends Response {
// ISABEL?
}
diff --git a/src/server/session.ts b/src/server/session.ts
index 74153bb08d741..4f4f89d2fb7c1 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -1802,11 +1802,6 @@ export class Session implements EventSender {
return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 };
}
- private getJsxMirrorCursor(args): undefined{
- return undefined;
- //ISABEL stub
- }
-
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
@@ -3394,7 +3389,7 @@ export class Session implements EventSender {
[protocol.CommandTypes.JsxClosingTag]: (request: protocol.JsxClosingTagRequest) => {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
},
- [protocol.CommandTypes.JsxMirrorCursor]: (request: protocol.JsxMirrorCursorRequest) => {
+ [protocol.CommandTypes.JsxLinkedEdit]: (request: protocol.JsxLinkedEditRequest) => {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
// ISABEL what ;
},
diff --git a/src/services/services.ts b/src/services/services.ts
index 800abfed8c4ef..403a4183dd099 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2485,7 +2485,7 @@ export function createLanguageService(
}
}
- function getJsxMirrorCursorAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined {
+ function getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const token = findPrecedingToken(position, sourceFile);
if (!token) return undefined;
@@ -2511,26 +2511,15 @@ export function createLanguageService(
return undefined;
}
else {
- const tag =
- // findAncestor(token,
- // (n) => {
- // if (isJsxOpeningElement(n) || isJsxClosingElement(n)) return true;
- // else if (n.kind===SyntaxKind.LessThanToken || isIdentifier(n) || n.kind === SyntaxKind.ThisKeyword || isPropertyAccessExpression(n)) return false;
- // return "quit"; });
-
- findAncestor(token,
+ const tag = findAncestor(token,
(n) => {
if (!n.parent.parent) return "quit";
else if (isJsxElement(n.parent.parent)) {
- if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent) )|| n.kind===SyntaxKind.LessThanToken || n.kind===SyntaxKind.SlashToken) return true;
+ if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent)) || n.kind===SyntaxKind.LessThanToken || n.kind===SyntaxKind.SlashToken) {
+ return true };
return "quit";
}
- // return true;
- // else if (isJsxClosingElement(n.parent)) return true;
- // else if (isJsxAttributes(n)) return "quit";
- // else if (isJsxChild(n)) return "quit";
else return false;
- // else if (n.kind === SyntaxKind.JsxTagNameExpression || n.kind === SyntaxKind.JsxTagNamePropertyAccess)
}
)?.parent as JsxOpeningElement | JsxClosingElement | undefined;
if (!tag) return undefined;
@@ -2545,28 +2534,6 @@ export function createLanguageService(
}
return {ranges, wordPattern};
- // return {ranges: }};
- // is this cursed?
- // it doesnt even work -> it errors types
- // switch (true) {
- // case isJsxOpeningElement(token.parent):
- // // const nameSpan = {start : token.parent.parent.closingElement.pos, end : token.parent.parent.closingElement.end};
- // case isJsxClosingElement(token.parent):
- // case isJsxOpeningFragment(token.parent):
- // case isJsxClosingFragment(token.parent):
- // return undefined
- // }
-
- // switch (token.parent.kind) {
- // case SyntaxKind.JsxOpeningElement:
- // // const nameSpan = {start : token.parent.parent.closingElement.pos, end : token.parent.parent.closingElement.end};
- // case SyntaxKind.JsxClosingElement:
- // case SyntaxKind.JsxOpeningFragment:
- // case SyntaxKind.JsxClosingFragment:
- // return undefined
- // }
-
- // ISABEL delete extras
}
function getLinesForRange(sourceFile: SourceFile, textRange: TextRange) {
@@ -3100,7 +3067,7 @@ export function createLanguageService(
getDocCommentTemplateAtPosition,
isValidBraceCompletionAtPosition,
getJsxClosingTagAtPosition,
- getJsxMirrorCursorAtPosition,
+ getJsxLinkedEditAtPosition: getJsxLinkedEditAtPosition,
getSpanOfEnclosingComment,
getCodeFixesAtPosition,
getCombinedCodeFix,
diff --git a/src/services/types.ts b/src/services/types.ts
index 13e72c7bf5a6b..50511ee86619d 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -607,8 +607,7 @@ export interface LanguageService {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxMirrorCursorAtPosition(fileName: string, currentCaretPosition: number): JsxMirrorCursorInfo | unknown;
- //ISABEL incorrect return type
+ getJsxLinkedEditAtPosition(fileName: string, currentCaretPosition: number): JsxLinkedEditInfo | unknown;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
@@ -663,15 +662,8 @@ export interface JsxClosingTagInfo {
readonly newText: string;
}
-export interface JsxMirrorCursorInfo {
- readonly startLine : number;
- readonly startCharacter : number;
- readonly endLine : number;
- readonly endCharacter : number;
-}
-
export interface JsxLinkedEditInfo {
- readonly ranges : {start: number, end: number};
+ readonly ranges : {start: number, end: number}[];
wordPattern? : string;
}
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index c0ebbbd49caf4..60de39bd77ffa 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -260,7 +260,7 @@ declare namespace FourSlashInterface {
implementationListIsEmpty(): void;
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
- jsxMirrorCursor(map: { [markerName: string]: {
+ jsxLinkedEdit(map: { [markerName: string]: {
readonly ranges : {start:number, end:number}[],
wordPattern? : string ;} | undefined }): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
index 5c622448d91a4..61455ad90ea58 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit1.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
@@ -26,7 +26,7 @@ const linkedCursors1 = {ranges: [{start: 19, end: 22},
{start: 30, end: 33}],
wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"0": linkedCursors1,
"1": linkedCursors1,
"2": linkedCursors1,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit2.ts b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
index 7b451b6cfcb54..ab0cbc0e5edde 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit2.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
@@ -13,7 +13,7 @@ const linkedCursors2 = {ranges: [{start: 18, end: 21},
{start: 91, end: 94}],
wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"0": linkedCursors2,
"1": linkedCursors2,
"2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit3.ts b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
index 2554855e8816a..f149f0237e519 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit3.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
@@ -13,6 +13,6 @@
// {start: 91, end: 94}],
// wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"2": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit4.ts b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
index 37d2018a5629a..ae48b86e8db45 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit4.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
@@ -23,7 +23,7 @@ const linkedCursors4 = {ranges: [{start: 18, end: 21},
{start: 69, end: 72}],
wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"0": linkedCursors4,
"1": linkedCursors4,
// "2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit5.ts b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
index 4ed030a590333..5d92f9196c615 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit5.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
@@ -11,7 +11,7 @@ const linkedCursors5 = {ranges: [{start: 33, end: 36},
{start: 44, end: 47}],
wordPattern : 'div'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"4": undefined,
"5": linkedCursors5,
"6": linkedCursors5,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit6.ts b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
index 1f3978a5fb298..81138025a9122 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit6.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
@@ -10,7 +10,7 @@ const linkedCursors6 = {ranges: [{start: 19, end: 38},
{start: 46, end: 65}],
wordPattern : 'someNamespace.Thing'};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"1": linkedCursors6,
"2": linkedCursors6,
"3": linkedCursors6,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit7.ts b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
index 30bb859258df4..9d7eea3996857 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit7.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
@@ -20,7 +20,7 @@ const linkedCursors7 = {ranges: [{start: 14, end: 14},
{start: 43, end: 43}],
wordPattern : undefined};
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"0": linkedCursors7,
"1": undefined,
"2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit8.ts b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
index 97a337540af85..f9617c1fcd4cd 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit8.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
@@ -12,6 +12,6 @@
// {start: 43, end: 43}],
// wordPattern : };
-verify.jsxMirrorCursor( {
+verify.jsxLinkedEdit( {
"8": undefined,
});
\ No newline at end of file
From 25393f11eb21227b6de46c0b9e242f6a117465c4 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Thu, 16 Mar 2023 00:13:45 -0700
Subject: [PATCH 12/32] revert changes to lib
---
lib/tsserverlibrary.d.ts | 16 ----------------
tests/cases/fourslash/test.jsx | 2 --
2 files changed, 18 deletions(-)
delete mode 100644 tests/cases/fourslash/test.jsx
diff --git a/lib/tsserverlibrary.d.ts b/lib/tsserverlibrary.d.ts
index 7fab75b0aeb81..0884b10602045 100644
--- a/lib/tsserverlibrary.d.ts
+++ b/lib/tsserverlibrary.d.ts
@@ -92,7 +92,6 @@ declare namespace ts {
*/
enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
- JsxMirrorCursor = "jsxMirrorCursor",
Brace = "brace",
BraceCompletion = "braceCompletion",
GetSpanOfEnclosingComment = "getSpanOfEnclosingComment",
@@ -883,14 +882,6 @@ declare namespace ts {
interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
- // ISABEL correct extends??
- interface JsxMirrorCursorRequest extends FileLocationRequest {
- readonly command: CommandTypes.JsxMirrorCursor;
- //ISABEL arguments?
- }
- interface JsxMirrorCursorResponse extends Response {
- readonly mirrorCursors: [JsxMirrorCursorInfo];
- }
/**
* @deprecated
* Get occurrences request; value of command field is
@@ -3848,7 +3839,6 @@ declare namespace ts {
private getSemanticDiagnosticsSync;
private getSuggestionDiagnosticsSync;
private getJsxClosingTag;
- private getJsxMirrorCursor
private getDocumentHighlights;
private provideInlayHints;
private setCompilerOptionsForInferredProjects;
@@ -10094,12 +10084,6 @@ declare namespace ts {
interface JsxClosingTagInfo {
readonly newText: string;
}
- interface JsxMirrorCursorInfo {
- readonly startLine : number;
- readonly startCharacter : number;
- readonly endLine : number;
- readonly endCharacter : number;
- }
interface CombinedCodeFixScope {
type: "file";
fileName: string;
diff --git a/tests/cases/fourslash/test.jsx b/tests/cases/fourslash/test.jsx
deleted file mode 100644
index 759c99865a518..0000000000000
--- a/tests/cases/fourslash/test.jsx
+++ /dev/null
@@ -1,2 +0,0 @@
-const c = (< div>
-)
\ No newline at end of file
From 6ba63211f87629d02bc31cdf4f2a8a1a33415499 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Thu, 16 Mar 2023 13:19:17 -0700
Subject: [PATCH 13/32] link everything together (fix session client)
---
src/harness/client.ts | 4 ++++
src/server/protocol.ts | 4 ++--
src/server/session.ts | 1 -
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/harness/client.ts b/src/harness/client.ts
index 22db85eb4be92..89e6293ce6e7c 100644
--- a/src/harness/client.ts
+++ b/src/harness/client.ts
@@ -726,6 +726,10 @@ export class SessionClient implements LanguageService {
return notImplemented();
}
+ getJsxLinkedEditAtPosition(_fileName: string, _currentCaretPosition: number): unknown {
+ return notImplemented();
+ }
+
getSpanOfEnclosingComment(_fileName: string, _position: number, _onlyMultiLine: boolean): TextSpan {
return notImplemented();
}
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index 2f079372761d2..f02dcf5d14e32 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -4,6 +4,7 @@ import {
EndOfLineState,
FileExtensionInfo,
HighlightSpanKind,
+ JsxLinkedEditInfo,
MapLike,
OutliningSpanKind,
OutputFile,
@@ -1104,11 +1105,10 @@ export interface JsxClosingTagResponse extends Response {
export interface JsxLinkedEditRequest extends FileLocationRequest {
readonly command: CommandTypes.JsxLinkedEdit;
- // ISABEL?
}
export interface JsxLinkedEditResponse extends Response {
- // ISABEL?
+ readonly info: JsxLinkedEditInfo;
}
diff --git a/src/server/session.ts b/src/server/session.ts
index 4f4f89d2fb7c1..18936cf128d73 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -3391,7 +3391,6 @@ export class Session implements EventSender {
},
[protocol.CommandTypes.JsxLinkedEdit]: (request: protocol.JsxLinkedEditRequest) => {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
- // ISABEL what ;
},
[protocol.CommandTypes.GetCodeFixes]: (request: protocol.CodeFixRequest) => {
return this.requiredResponse(this.getCodeFixes(request.arguments, /*simplifiedResult*/ true));
From 92875ce464bd8bfb9de5d4945bf2b4b579b61d78 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Thu, 16 Mar 2023 14:05:57 -0700
Subject: [PATCH 14/32] missed renames
---
tests/baselines/reference/api/tsserverlibrary.d.ts | 4 ++--
tests/baselines/reference/api/typescript.d.ts | 11 ++++-------
2 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 14187beea9385..c663970c6a7b5 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -89,7 +89,7 @@ declare namespace ts {
namespace protocol {
enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
- JsxMirrorCursor = "jsxMirrorCursor",
+ JsxLinkedEdit = "jsxLinkedEdit",
Brace = "brace",
BraceCompletion = "braceCompletion",
GetSpanOfEnclosingComment = "getSpanOfEnclosingComment",
@@ -3850,7 +3850,7 @@ declare namespace ts {
private getSemanticDiagnosticsSync;
private getSuggestionDiagnosticsSync;
private getJsxClosingTag;
- private getJsxMirrorCursor;
+ private getJsxLinkedEdit;
private getDocumentHighlights;
private provideInlayHints;
private setCompilerOptionsForInferredProjects;
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index 70518ff7b751e..9867c22b5837c 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -6107,12 +6107,11 @@ declare namespace ts {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
+ getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
- // ISABEL change name?
- getMirrorCursorPosition(fileName: string, position: number): JsxMirrorCursorInfo | undefined;
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise;
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise;
@@ -6138,11 +6137,9 @@ declare namespace ts {
interface JsxClosingTagInfo {
readonly newText: string;
}
- interface JsxMirrorCursorInfo {
- readonly startLine : number;
- readonly startCharacter : number;
- readonly endLine : number;
- readonly endCharacter : number;
+ interface JsxLinkedEditInfo {
+ ranges : {start: number, end: number}[];
+ wordPattern? : string;
}
interface CombinedCodeFixScope {
type: "file";
From 57ef9b8e900205436cf864d0c5a49eba538a2f83 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Thu, 16 Mar 2023 14:42:05 -0700
Subject: [PATCH 15/32] linted
---
src/harness/fourslashImpl.ts | 2 +-
src/services/services.ts | 26 +++++++++++++-------------
src/services/types.ts | 4 ++--
3 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index 6afc33345521e..fa3e0ec8d0686 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -3444,7 +3444,7 @@ export class TestState {
}
}
- public verifyJsxLinkedEdit(map: {[markerName:string]:ts.JsxLinkedEditInfo | undefined}):void {
+ public verifyJsxLinkedEdit(map: {[markerName: string]: ts.JsxLinkedEditInfo | undefined}): void {
for (const markerName in map) {
this.goToMarker(markerName);
const actual = this.languageService.getJsxLinkedEditAtPosition(this.activeFile.fileName, this.currentCaretPosition);
diff --git a/src/services/services.ts b/src/services/services.ts
index 403a4183dd099..975b74018188c 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2490,8 +2490,8 @@ export function createLanguageService(
const token = findPrecedingToken(position, sourceFile);
if (!token) return undefined;
- let wordPattern : string | undefined;
- let ranges : {start: number, end: number}[] = [];
+ let wordPattern: string | undefined;
+ let ranges: {start: number, end: number}[] = [];
// check edge cases <| and >|
if (token.kind===SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent)) return undefined;
@@ -2503,37 +2503,37 @@ export function createLanguageService(
const openPos = token.parent.parent.openingFragment.pos + 1;
const closePos = token.parent.parent.closingFragment.pos + 2;
- ranges = ranges.concat({start : openPos, end : openPos});
- ranges = ranges.concat({start : closePos, end : closePos});
+ ranges = ranges.concat({ start : openPos, end : openPos });
+ ranges = ranges.concat({ start : closePos, end : closePos });
wordPattern = undefined;
}
else if (isJsxFragment(token.parent.parent)) {
return undefined;
}
else {
- const tag = findAncestor(token,
+ const tag = findAncestor(token,
(n) => {
if (!n.parent.parent) return "quit";
else if (isJsxElement(n.parent.parent)) {
if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent)) || n.kind===SyntaxKind.LessThanToken || n.kind===SyntaxKind.SlashToken) {
- return true };
+ return true;
+ }
return "quit";
}
- else return false;
+ return false;
}
)?.parent as JsxOpeningElement | JsxClosingElement | undefined;
if (!tag) return undefined;
- ranges = ranges.concat({start : tag.parent.openingElement.tagName.pos, end : tag.parent.openingElement.tagName.end});
- ranges = ranges.concat({start : tag.parent.closingElement.tagName.pos, end : tag.parent.closingElement.tagName.end});
-
+ ranges = ranges.concat({ start : tag.parent.openingElement.tagName.pos, end : tag.parent.openingElement.tagName.end });
+ ranges = ranges.concat({ start : tag.parent.closingElement.tagName.pos, end : tag.parent.closingElement.tagName.end });
+
if (tag.parent.openingElement.tagName.getText() === tag.parent.closingElement.tagName.getText()) {
wordPattern = tag.tagName.getText();
}
else return undefined;
}
-
- return {ranges, wordPattern};
+ return { ranges, wordPattern };
}
function getLinesForRange(sourceFile: SourceFile, textRange: TextRange) {
@@ -3067,7 +3067,7 @@ export function createLanguageService(
getDocCommentTemplateAtPosition,
isValidBraceCompletionAtPosition,
getJsxClosingTagAtPosition,
- getJsxLinkedEditAtPosition: getJsxLinkedEditAtPosition,
+ getJsxLinkedEditAtPosition,
getSpanOfEnclosingComment,
getCodeFixesAtPosition,
getCombinedCodeFix,
diff --git a/src/services/types.ts b/src/services/types.ts
index 50511ee86619d..5efc0cd06aee9 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -663,8 +663,8 @@ export interface JsxClosingTagInfo {
}
export interface JsxLinkedEditInfo {
- readonly ranges : {start: number, end: number}[];
- wordPattern? : string;
+ readonly ranges: {start: number, end: number}[];
+ wordPattern?: string;
}
export interface CombinedCodeFixScope { type: "file"; fileName: string; }
From 06afbbd8d4c37e034c9ac8c0d708ca1ca5c7588e Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Thu, 16 Mar 2023 16:11:05 -0700
Subject: [PATCH 16/32] update baselines
---
.../reference/api/tsserverlibrary.d.ts | 17 ++++++++++++++---
tests/baselines/reference/api/typescript.d.ts | 13 ++++++++-----
2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index c663970c6a7b5..a060a5a833a0b 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -878,8 +878,12 @@ declare namespace ts {
interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
- interface mirrror {}
- // ISABEL
+ interface JsxLinkedEditRequest extends FileLocationRequest {
+ readonly command: CommandTypes.JsxLinkedEdit;
+ }
+ interface JsxLinkedEditResponse extends Response {
+ readonly info: JsxLinkedEditInfo;
+ }
/**
* Get document highlights request; value of command field is
* "documentHighlights". Return response giving spans that are relevant
@@ -3850,7 +3854,6 @@ declare namespace ts {
private getSemanticDiagnosticsSync;
private getSuggestionDiagnosticsSync;
private getJsxClosingTag;
- private getJsxLinkedEdit;
private getDocumentHighlights;
private provideInlayHints;
private setCompilerOptionsForInferredProjects;
@@ -9981,6 +9984,7 @@ declare namespace ts {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
+ getJsxLinkedEditAtPosition(fileName: string, currentCaretPosition: number): JsxLinkedEditInfo | unknown;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
@@ -10010,6 +10014,13 @@ declare namespace ts {
interface JsxClosingTagInfo {
readonly newText: string;
}
+ interface JsxLinkedEditInfo {
+ readonly ranges: {
+ start: number;
+ end: number;
+ }[];
+ wordPattern?: string;
+ }
interface CombinedCodeFixScope {
type: "file";
fileName: string;
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index 9867c22b5837c..07c32976070a4 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -6107,7 +6107,7 @@ declare namespace ts {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined;
+ getJsxLinkedEditAtPosition(fileName: string, currentCaretPosition: number): JsxLinkedEditInfo | unknown;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
@@ -6137,10 +6137,13 @@ declare namespace ts {
interface JsxClosingTagInfo {
readonly newText: string;
}
- interface JsxLinkedEditInfo {
- ranges : {start: number, end: number}[];
- wordPattern? : string;
- }
+ interface JsxLinkedEditInfo {
+ readonly ranges: {
+ start: number;
+ end: number;
+ }[];
+ wordPattern?: string;
+ }
interface CombinedCodeFixScope {
type: "file";
fileName: string;
From f4ec7bd3e0921739b8aac07b4c3835a11b153170 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Fri, 17 Mar 2023 01:04:32 -0700
Subject: [PATCH 17/32] debugged whitespace issues
---
src/services/services.ts | 16 ++++++------
tests/cases/fourslash/jsxTagLinkedEdit1.ts | 29 ++++++++++++++++------
tests/cases/fourslash/jsxTagLinkedEdit2.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit3.ts | 17 +++++++++----
tests/cases/fourslash/jsxTagLinkedEdit4.ts | 9 ++++---
5 files changed, 48 insertions(+), 25 deletions(-)
diff --git a/src/services/services.ts b/src/services/services.ts
index 975b74018188c..87dd6fea8580b 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -73,6 +73,7 @@ import {
FindAllReferences,
findAncestor,
findChildOfKind,
+ findNextToken,
findPrecedingToken,
first,
firstDefined,
@@ -2493,16 +2494,13 @@ export function createLanguageService(
let wordPattern: string | undefined;
let ranges: {start: number, end: number}[] = [];
- // check edge cases <| and >|
- if (token.kind===SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent)) return undefined;
- if (token.kind===SyntaxKind.LessThanToken && isJsxClosingElement(token.parent)) return undefined;
-
if ((isJsxOpeningFragment(token.parent) && token.kind===SyntaxKind.LessThanToken)
|| (isJsxClosingFragment(token.parent) && token.kind===SyntaxKind.SlashToken)){
const openPos = token.parent.parent.openingFragment.pos + 1;
const closePos = token.parent.parent.closingFragment.pos + 2;
+ //TODO: fragments with whitespace?
ranges = ranges.concat({ start : openPos, end : openPos });
ranges = ranges.concat({ start : closePos, end : closePos });
wordPattern = undefined;
@@ -2515,7 +2513,9 @@ export function createLanguageService(
(n) => {
if (!n.parent.parent) return "quit";
else if (isJsxElement(n.parent.parent)) {
- if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent)) || n.kind===SyntaxKind.LessThanToken || n.kind===SyntaxKind.SlashToken) {
+ if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent))
+ || (n.kind===SyntaxKind.LessThanToken && isJSXTagName(findNextToken(n,n.parent,sourceFile) ?? n))
+ || n.kind===SyntaxKind.SlashToken) {
return true;
}
return "quit";
@@ -2525,8 +2525,10 @@ export function createLanguageService(
)?.parent as JsxOpeningElement | JsxClosingElement | undefined;
if (!tag) return undefined;
- ranges = ranges.concat({ start : tag.parent.openingElement.tagName.pos, end : tag.parent.openingElement.tagName.end });
- ranges = ranges.concat({ start : tag.parent.closingElement.tagName.pos, end : tag.parent.closingElement.tagName.end });
+ ranges = ranges.concat({ start : tag.parent.openingElement.tagName.getStart(), end : tag.parent.openingElement.tagName.end });
+ ranges = ranges.concat({ start : tag.parent.closingElement.tagName.getStart(), end : tag.parent.closingElement.tagName.end });
+
+ if (!(ranges[0].start <= position && position <= ranges[0].end || ranges[1].start <= position && position <= ranges[1].end)) return undefined;
if (tag.parent.openingElement.tagName.getText() === tag.parent.closingElement.tagName.getText()) {
wordPattern = tag.tagName.getText();
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
index 61455ad90ea58..4b0b82add7777 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit1.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
@@ -6,21 +6,31 @@
//
//);
-
// @Filename: /basic.tsx
////const jsx = (
//// *0*/d/*1*/iv/*2*/>/*7*/
-//// *6*///*3*/di/*4*/v/*5*/>/*9*/
+//// *6*///*3*/di/*4*/v/*5*/>/*8*/
////);
-////const jsx2 = (
+
+// @Filename: /whitespaceInvalidClosing.tsx
+////const jsx = (
////
-//// < /*8*/ /div>
+//// < /*9*/ /div>
////);
+
+// @Filename: /whitespaceOpening.tsx
////const jsx3 = (
-//// *10*/ div>
-////
+//// *10*/ /*11*/div/*12*/ /*13*/> /*14*/
+////
////);
+// @Filename: /whitespaceClosing.tsx
+////const jsx = (
+////
+//// /*15*/ /*16*/div/*17*/ /*18*/> /*19*/
+////);
+
+
const linkedCursors1 = {ranges: [{start: 19, end: 22},
{start: 30, end: 33}],
@@ -36,7 +46,10 @@ verify.jsxLinkedEdit( {
"6": undefined,
"7": undefined,
"8": undefined,
- "9": undefined,
- // "10":undefined, // if still a comment, case doesnt yet work !!!!
+ "9": undefined, // I believe this should be an invalid tag
+ "10": undefined,
+ "13": undefined,
+ "15": undefined,
+ "18": undefined,
});
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit2.ts b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
index ab0cbc0e5edde..c7e15e1bbf662 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit2.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
@@ -19,6 +19,6 @@ verify.jsxLinkedEdit( {
"2": undefined,
"3": linkedCursors2,
"4": undefined,
- // "5": undefined, // if still a comment, case doesnt yet work !!!!
+ "5": undefined,
"6": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit3.ts b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
index f149f0237e519..e58fb9a262dc7 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit3.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
@@ -2,11 +2,11 @@
// @Filename: /selfClosing.tsx
////const jsx = (
-////
-////
-////
-////
-////
+//// /*1*/
+////
/*4*/
+//// /*5*/
+//// /*6*/
/*8*/
+//// /*7*/
////);
// const linkedCursors3 = {ranges: [{start: 18, end: 21},
@@ -14,5 +14,12 @@
// wordPattern : 'div'};
verify.jsxLinkedEdit( {
+ "1": undefined,
"2": undefined,
+ "3": undefined,
+ "4": undefined,
+ "5": undefined,
+ "6": undefined,
+ "7": undefined,
+ "8": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit4.ts b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
index ae48b86e8db45..85bcb63bfab9b 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit4.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
@@ -12,11 +12,11 @@
// @Filename: /typeTag.tsx
////const jsx = (
-//// *0*/div/*1*/*2*/T/*3*/>/*4*/>
+//// *0*/div/*1*/*2*/T/*3*/>/*4*/>/*5*/
////
////
////
-////
+////
////);
const linkedCursors4 = {ranges: [{start: 18, end: 21},
@@ -26,8 +26,9 @@ const linkedCursors4 = {ranges: [{start: 18, end: 21},
verify.jsxLinkedEdit( {
"0": linkedCursors4,
"1": linkedCursors4,
- // "2": undefined,
+ "2": undefined,
"3": undefined,
"4": undefined,
- "5": linkedCursors4, // if still a comment, this case doesnt yet work !!!!
+ "5": undefined,
+ "6": linkedCursors4,
});
\ No newline at end of file
From 803b2920eb1da85fdd39f58d25ec69c805e97613 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Mon, 20 Mar 2023 14:11:13 -0700
Subject: [PATCH 18/32] fixed some whitespace in code
---
src/harness/fourslashImpl.ts | 2 +-
src/harness/fourslashInterfaceImpl.ts | 1 -
src/server/protocol.ts | 1 -
src/services/services.ts | 18 +++++++++---------
4 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index fa3e0ec8d0686..f50f1b75b0989 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -3444,7 +3444,7 @@ export class TestState {
}
}
- public verifyJsxLinkedEdit(map: {[markerName: string]: ts.JsxLinkedEditInfo | undefined}): void {
+ public verifyJsxLinkedEdit(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined } ): void {
for (const markerName in map) {
this.goToMarker(markerName);
const actual = this.languageService.getJsxLinkedEditAtPosition(this.activeFile.fileName, this.currentCaretPosition);
diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts
index d6a56c9280a48..70b459733d40a 100644
--- a/src/harness/fourslashInterfaceImpl.ts
+++ b/src/harness/fourslashInterfaceImpl.ts
@@ -193,7 +193,6 @@ export class VerifyNegatable {
this.state.verifyJsxLinkedEdit(map);
}
-
public isInCommentAtPosition(onlyMultiLineDiverges?: boolean) {
this.state.verifySpanOfEnclosingComment(this.negative, onlyMultiLineDiverges);
}
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index f02dcf5d14e32..5d250cf8a36b9 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -1111,7 +1111,6 @@ export interface JsxLinkedEditResponse extends Response {
readonly info: JsxLinkedEditInfo;
}
-
/**
* Get document highlights request; value of command field is
* "documentHighlights". Return response giving spans that are relevant
diff --git a/src/services/services.ts b/src/services/services.ts
index 87dd6fea8580b..63e364cb339eb 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2494,15 +2494,15 @@ export function createLanguageService(
let wordPattern: string | undefined;
let ranges: {start: number, end: number}[] = [];
- if ((isJsxOpeningFragment(token.parent) && token.kind===SyntaxKind.LessThanToken)
- || (isJsxClosingFragment(token.parent) && token.kind===SyntaxKind.SlashToken)){
+ if ((isJsxOpeningFragment(token.parent) && token.kind === SyntaxKind.LessThanToken)
+ || (isJsxClosingFragment(token.parent) && token.kind === SyntaxKind.SlashToken)){
const openPos = token.parent.parent.openingFragment.pos + 1;
const closePos = token.parent.parent.closingFragment.pos + 2;
//TODO: fragments with whitespace?
- ranges = ranges.concat({ start : openPos, end : openPos });
- ranges = ranges.concat({ start : closePos, end : closePos });
+ ranges = ranges.concat({ start: openPos, end: openPos });
+ ranges = ranges.concat({ start: closePos, end: closePos });
wordPattern = undefined;
}
else if (isJsxFragment(token.parent.parent)) {
@@ -2510,12 +2510,12 @@ export function createLanguageService(
}
else {
const tag = findAncestor(token,
- (n) => {
+ n => {
if (!n.parent.parent) return "quit";
else if (isJsxElement(n.parent.parent)) {
if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent))
- || (n.kind===SyntaxKind.LessThanToken && isJSXTagName(findNextToken(n,n.parent,sourceFile) ?? n))
- || n.kind===SyntaxKind.SlashToken) {
+ || (n.kind === SyntaxKind.LessThanToken && isJSXTagName(findNextToken(n, n.parent, sourceFile) ?? n))
+ || n.kind === SyntaxKind.SlashToken) {
return true;
}
return "quit";
@@ -2525,8 +2525,8 @@ export function createLanguageService(
)?.parent as JsxOpeningElement | JsxClosingElement | undefined;
if (!tag) return undefined;
- ranges = ranges.concat({ start : tag.parent.openingElement.tagName.getStart(), end : tag.parent.openingElement.tagName.end });
- ranges = ranges.concat({ start : tag.parent.closingElement.tagName.getStart(), end : tag.parent.closingElement.tagName.end });
+ ranges = ranges.concat({ start: tag.parent.openingElement.tagName.getStart(sourceFile), end: tag.parent.openingElement.tagName.end });
+ ranges = ranges.concat({ start: tag.parent.closingElement.tagName.getStart(sourceFile), end: tag.parent.closingElement.tagName.end });
if (!(ranges[0].start <= position && position <= ranges[0].end || ranges[1].start <= position && position <= ranges[1].end)) return undefined;
From 34f5e40bee0c9fc4fc605dfe15c0f20af5882bb5 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 22 Mar 2023 12:54:38 -0700
Subject: [PATCH 19/32] adds better behavior for whitespace and trivia in
fragments
---
src/harness/fourslashImpl.ts | 2 +-
src/services/services.ts | 12 +++---
tests/cases/fourslash/jsxTagLinkedEdit7.ts | 50 +++++++++++++++++++---
3 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index f50f1b75b0989..e79354c462d5b 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -3444,7 +3444,7 @@ export class TestState {
}
}
- public verifyJsxLinkedEdit(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined } ): void {
+ public verifyJsxLinkedEdit(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined }): void {
for (const markerName in map) {
this.goToMarker(markerName);
const actual = this.languageService.getJsxLinkedEditAtPosition(this.activeFile.fileName, this.currentCaretPosition);
diff --git a/src/services/services.ts b/src/services/services.ts
index 63e364cb339eb..dc510250adb4c 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2497,13 +2497,15 @@ export function createLanguageService(
if ((isJsxOpeningFragment(token.parent) && token.kind === SyntaxKind.LessThanToken)
|| (isJsxClosingFragment(token.parent) && token.kind === SyntaxKind.SlashToken)){
- const openPos = token.parent.parent.openingFragment.pos + 1;
- const closePos = token.parent.parent.closingFragment.pos + 2;
+ const openPos = token.parent.parent.openingFragment.getStart(sourceFile) + "<".length;
+ const closePos = token.parent.parent.closingFragment.getStart(sourceFile) + "".length;
- //TODO: fragments with whitespace?
- ranges = ranges.concat({ start: openPos, end: openPos });
- ranges = ranges.concat({ start: closePos, end: closePos });
+ // only allows mirroring right after opening bracket: <| >| >
+ if ((position !== openPos) && (position !== closePos)) return undefined;
+
+ ranges = [{ start: openPos, end: openPos }, { start: closePos, end: closePos }];
wordPattern = undefined;
+ return { ranges, wordPattern };
}
else if (isJsxFragment(token.parent.parent)) {
return undefined;
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit7.ts b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
index 9d7eea3996857..425178534a70d 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit7.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
@@ -1,33 +1,69 @@
///
+// plaintext
+// const jsx = (
+// <>
+//
+// >
+// );
+// const jsx2 = (
+// <>
+// >
+// );
+// const jsx3 = (
+// /* this is comment */* more comment */>Hello
+// /* even more comment */>
+// );
+
// @FileName: /fragment.tsx
////const jsx = (
-//// /*7*/*0*/>/*1*/
+//// /*5*/*0*/>/*1*/
////
-//// /*8*/*2*///*3*/>/*4*/
+//// /*6*/*2*///*3*/>/*4*/
////);
////const jsx2 = (
-//// <>/*5*/
+//// <>/*7*/
//// >
////);
////const jsx3 = (
-//// *6*/>
+//// /* this is comment *//*13*/*10*//* /*11*/more comment *//*12*/>/*8*/Hello/*9*/
+//// /*14*/ /*18*///*17*/* even/*15*/ more comment *//*16*/>
+////);
+
+// @FileName: /mismatchedFragment.tsx
+////const jsx3 = (
+//// *A*/>
////
//// >
////);
-const linkedCursors7 = {ranges: [{start: 14, end: 14},
+const linkedCursors7 = {ranges: [{start: 19, end: 19},
{start: 43, end: 43}],
wordPattern : undefined};
-verify.jsxLinkedEdit( {
+const linkedCursors7jsx3 = {ranges: [{start: 122, end: 122},
+ {start: 153, end: 153}],
+ wordPattern : undefined};
+
+verify.jsxLinkedEdit({
"0": linkedCursors7,
"1": undefined,
"2": undefined,
"3": linkedCursors7,
"4": undefined,
"5": undefined,
- // "6": linkedCursors7, // I don't know what's supposed to happen in this case
+ "6": undefined,
"7": undefined,
"8": undefined,
+ "9": undefined,
+ "10": linkedCursors7jsx3,
+ "11": undefined,
+ "12": undefined,
+ "13": undefined,
+ "14": linkedCursors7jsx3,
+ "15": undefined,
+ "16": undefined,
+ "17": undefined,
+ "18": undefined,
+ // "A": undefined // I don't know what's supposed to happen in this case
});
\ No newline at end of file
From 03fa5bb9cbabd5313293c182cbdd9ca3ce598bcd Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 22 Mar 2023 14:28:55 -0700
Subject: [PATCH 20/32] refactor getJsxLinkedEditAtPosition
---
src/services/services.ts | 30 +++++++++++++-----------------
1 file changed, 13 insertions(+), 17 deletions(-)
diff --git a/src/services/services.ts b/src/services/services.ts
index dc510250adb4c..2ca062ebb5c98 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2491,20 +2491,17 @@ export function createLanguageService(
const token = findPrecedingToken(position, sourceFile);
if (!token) return undefined;
- let wordPattern: string | undefined;
- let ranges: {start: number, end: number}[] = [];
-
if ((isJsxOpeningFragment(token.parent) && token.kind === SyntaxKind.LessThanToken)
|| (isJsxClosingFragment(token.parent) && token.kind === SyntaxKind.SlashToken)){
- const openPos = token.parent.parent.openingFragment.getStart(sourceFile) + "<".length;
- const closePos = token.parent.parent.closingFragment.getStart(sourceFile) + "".length;
+ const openPos = token.parent.parent.openingFragment.getStart(sourceFile) + 1; // "<".length
+ const closePos = token.parent.parent.closingFragment.getStart(sourceFile) + 2; // "".length
// only allows mirroring right after opening bracket: <| >| >
if ((position !== openPos) && (position !== closePos)) return undefined;
- ranges = [{ start: openPos, end: openPos }, { start: closePos, end: closePos }];
- wordPattern = undefined;
+ const ranges = [{ start: openPos, end: openPos }, { start: closePos, end: closePos }];
+ const wordPattern = undefined;
return { ranges, wordPattern };
}
else if (isJsxFragment(token.parent.parent)) {
@@ -2523,21 +2520,20 @@ export function createLanguageService(
return "quit";
}
return false;
- }
- )?.parent as JsxOpeningElement | JsxClosingElement | undefined;
+ });
if (!tag) return undefined;
- ranges = ranges.concat({ start: tag.parent.openingElement.tagName.getStart(sourceFile), end: tag.parent.openingElement.tagName.end });
- ranges = ranges.concat({ start: tag.parent.closingElement.tagName.getStart(sourceFile), end: tag.parent.closingElement.tagName.end });
+ const element = tag.parent as JsxOpeningElement | JsxClosingElement;
+ const openTag = { start: element.parent.openingElement.tagName.getStart(sourceFile), end: element.parent.openingElement.tagName.end };
+ const endTag = { start: element.parent.closingElement.tagName.getStart(sourceFile), end: element.parent.closingElement.tagName.end };
- if (!(ranges[0].start <= position && position <= ranges[0].end || ranges[1].start <= position && position <= ranges[1].end)) return undefined;
+ if (!(openTag.start <= position && position <= openTag.end || endTag.start <= position && position <= endTag.end)) return undefined;
+ if (element.parent.openingElement.tagName.getText(sourceFile) !== element.parent.closingElement.tagName.getText(sourceFile)) return undefined;
- if (tag.parent.openingElement.tagName.getText() === tag.parent.closingElement.tagName.getText()) {
- wordPattern = tag.tagName.getText();
- }
- else return undefined;
+ const ranges = [openTag, endTag];
+ const wordPattern = element.tagName.getText(sourceFile);
+ return { ranges, wordPattern };
}
- return { ranges, wordPattern };
}
function getLinesForRange(sourceFile: SourceFile, textRange: TextRange) {
From 4faee9927942b6a222a89dc93354f7d8bb46fd13 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Wed, 22 Mar 2023 15:32:47 -0700
Subject: [PATCH 21/32] change type to TextSpan
---
src/services/services.ts | 4 ++--
src/services/types.ts | 2 +-
tests/baselines/reference/api/tsserverlibrary.d.ts | 5 +----
tests/baselines/reference/api/typescript.d.ts | 5 +----
tests/cases/fourslash/fourslash.ts | 2 +-
5 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/src/services/services.ts b/src/services/services.ts
index 2ca062ebb5c98..73311f85274b3 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2500,7 +2500,7 @@ export function createLanguageService(
// only allows mirroring right after opening bracket: <| >| >
if ((position !== openPos) && (position !== closePos)) return undefined;
- const ranges = [{ start: openPos, end: openPos }, { start: closePos, end: closePos }];
+ const ranges = [{ start: openPos, length: 0 }, { start: closePos, length: 0 }];
const wordPattern = undefined;
return { ranges, wordPattern };
}
@@ -2530,7 +2530,7 @@ export function createLanguageService(
if (!(openTag.start <= position && position <= openTag.end || endTag.start <= position && position <= endTag.end)) return undefined;
if (element.parent.openingElement.tagName.getText(sourceFile) !== element.parent.closingElement.tagName.getText(sourceFile)) return undefined;
- const ranges = [openTag, endTag];
+ const ranges = [{ start: openTag.start, length: openTag.end - openTag.start }, { start: endTag.start, length: endTag.end - endTag.start }];
const wordPattern = element.tagName.getText(sourceFile);
return { ranges, wordPattern };
}
diff --git a/src/services/types.ts b/src/services/types.ts
index 5efc0cd06aee9..dc19e4ad841e2 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -663,7 +663,7 @@ export interface JsxClosingTagInfo {
}
export interface JsxLinkedEditInfo {
- readonly ranges: {start: number, end: number}[];
+ readonly ranges: TextSpan[];
wordPattern?: string;
}
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index a060a5a833a0b..5af2b6eb01e2c 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -10015,10 +10015,7 @@ declare namespace ts {
readonly newText: string;
}
interface JsxLinkedEditInfo {
- readonly ranges: {
- start: number;
- end: number;
- }[];
+ readonly ranges: TextSpan[];
wordPattern?: string;
}
interface CombinedCodeFixScope {
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index 07c32976070a4..79047d331fd30 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -6138,10 +6138,7 @@ declare namespace ts {
readonly newText: string;
}
interface JsxLinkedEditInfo {
- readonly ranges: {
- start: number;
- end: number;
- }[];
+ readonly ranges: TextSpan[];
wordPattern?: string;
}
interface CombinedCodeFixScope {
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 60de39bd77ffa..9d218e52ba3c6 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -261,7 +261,7 @@ declare namespace FourSlashInterface {
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
jsxLinkedEdit(map: { [markerName: string]: {
- readonly ranges : {start:number, end:number}[],
+ readonly ranges : TextSpan[],
wordPattern? : string ;} | undefined }): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
codeFix(options: {
From 6a1d3dd7af2035f6861d07deaabbbc0a56b2b3f3 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Thu, 23 Mar 2023 16:35:25 -0700
Subject: [PATCH 22/32] updated tests to have textspan
---
tests/cases/fourslash/fourslash.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit1.ts | 6 ++----
tests/cases/fourslash/jsxTagLinkedEdit2.ts | 4 ++--
tests/cases/fourslash/jsxTagLinkedEdit3.ts | 4 ++--
tests/cases/fourslash/jsxTagLinkedEdit4.ts | 5 ++---
tests/cases/fourslash/jsxTagLinkedEdit5.ts | 4 ++--
tests/cases/fourslash/jsxTagLinkedEdit6.ts | 4 ++--
tests/cases/fourslash/jsxTagLinkedEdit7.ts | 8 ++++----
8 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 9d218e52ba3c6..55dc2573701ab 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -261,7 +261,7 @@ declare namespace FourSlashInterface {
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
jsxLinkedEdit(map: { [markerName: string]: {
- readonly ranges : TextSpan[],
+ readonly ranges : { start: number, length: number }[],
wordPattern? : string ;} | undefined }): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
codeFix(options: {
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
index 4b0b82add7777..efa6cf133ded3 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit1.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
@@ -30,10 +30,8 @@
//// /*15*/ /*16*/div/*17*/ /*18*/> /*19*/
////);
-
-
-const linkedCursors1 = {ranges: [{start: 19, end: 22},
- {start: 30, end: 33}],
+const linkedCursors1 = {ranges: [{start: 19, length: 3},
+ {start: 30, length: 3}],
wordPattern : 'div'};
verify.jsxLinkedEdit( {
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit2.ts b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
index c7e15e1bbf662..95f4fcf84977a 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit2.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
@@ -9,8 +9,8 @@
////
////);
-const linkedCursors2 = {ranges: [{start: 18, end: 21},
- {start: 91, end: 94}],
+const linkedCursors2 = {ranges: [{start: 18, length: 3},
+ {start: 91, length: 3}],
wordPattern : 'div'};
verify.jsxLinkedEdit( {
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit3.ts b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
index e58fb9a262dc7..b056a9534ab00 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit3.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
@@ -9,8 +9,8 @@
//// /*7*/
////);
-// const linkedCursors3 = {ranges: [{start: 18, end: 21},
-// {start: 91, end: 94}],
+// const linkedCursors3 = {ranges: [{start: 18, length: 3},
+// {start: 91, length: 3}],
// wordPattern : 'div'};
verify.jsxLinkedEdit( {
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit4.ts b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
index 85bcb63bfab9b..4f26b52275dd3 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit4.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
@@ -9,7 +9,6 @@
//
//);
-
// @Filename: /typeTag.tsx
////const jsx = (
//// *0*/div/*1*/*2*/T/*3*/>/*4*/>/*5*/
@@ -19,8 +18,8 @@
////
////);
-const linkedCursors4 = {ranges: [{start: 18, end: 21},
- {start: 69, end: 72}],
+const linkedCursors4 = {ranges: [{start: 18, length: 3},
+ {start: 69, length: 3}],
wordPattern : 'div'};
verify.jsxLinkedEdit( {
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit5.ts b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
index 5d92f9196c615..8860b7b0f0767 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit5.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
@@ -7,8 +7,8 @@
////
////);
-const linkedCursors5 = {ranges: [{start: 33, end: 36},
- {start: 44, end: 47}],
+const linkedCursors5 = {ranges: [{start: 33, length: 3},
+ {start: 44, length: 3}],
wordPattern : 'div'};
verify.jsxLinkedEdit( {
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit6.ts b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
index 81138025a9122..169a3cccd27b3 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit6.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
@@ -6,8 +6,8 @@
////
////);
-const linkedCursors6 = {ranges: [{start: 19, end: 38},
- {start: 46, end: 65}],
+const linkedCursors6 = {ranges: [{start: 19, length: 19},
+ {start: 46, length: 19}],
wordPattern : 'someNamespace.Thing'};
verify.jsxLinkedEdit( {
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit7.ts b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
index 425178534a70d..0f80a753c8995 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit7.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
@@ -37,12 +37,12 @@
//// >
////);
-const linkedCursors7 = {ranges: [{start: 19, end: 19},
- {start: 43, end: 43}],
+const linkedCursors7 = {ranges: [{start: 19, length: 0},
+ {start: 43, length: 0}],
wordPattern : undefined};
-const linkedCursors7jsx3 = {ranges: [{start: 122, end: 122},
- {start: 153, end: 153}],
+const linkedCursors7jsx3 = {ranges: [{start: 122, length: 0},
+ {start: 153, length: 0}],
wordPattern : undefined};
verify.jsxLinkedEdit({
From c8ea55908027e5d2d08eb92e7335475e9854438b Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Mon, 27 Mar 2023 14:11:07 -0700
Subject: [PATCH 23/32] fix names
---
src/harness/client.ts | 2 +-
src/server/session.ts | 7 +++++++
src/services/types.ts | 2 +-
3 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/harness/client.ts b/src/harness/client.ts
index 89e6293ce6e7c..07b24a123cdca 100644
--- a/src/harness/client.ts
+++ b/src/harness/client.ts
@@ -726,7 +726,7 @@ export class SessionClient implements LanguageService {
return notImplemented();
}
- getJsxLinkedEditAtPosition(_fileName: string, _currentCaretPosition: number): unknown {
+ getJsxLinkedEditAtPosition(_fileName: string, _position: number): never {
return notImplemented();
}
diff --git a/src/server/session.ts b/src/server/session.ts
index 18936cf128d73..6429d4c3c9e7d 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -81,6 +81,7 @@ import {
isStringLiteralLike,
JSDocLinkDisplayPart,
JSDocTagInfo,
+ JsxLinkedEditInfo,
LanguageServiceMode,
LineAndCharacter,
map,
@@ -1802,6 +1803,12 @@ export class Session implements EventSender {
return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 };
}
+ private getJsxLinkedEdit(args: protocol.FileLocationRequestArgs): JsxLinkedEditInfo | undefined {
+ const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
+ const position = this.getPositionInFile(args, file);
+ return languageService.getJsxLinkedEditAtPosition(file, position);
+ }
+
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
diff --git a/src/services/types.ts b/src/services/types.ts
index dc19e4ad841e2..090045b7c141a 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -607,7 +607,7 @@ export interface LanguageService {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxLinkedEditAtPosition(fileName: string, currentCaretPosition: number): JsxLinkedEditInfo | unknown;
+ getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
From fef7ab6b0dc4a1586dd7e479ddcbef957d1ac7be Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Mon, 27 Mar 2023 14:11:07 -0700
Subject: [PATCH 24/32] fix names
---
src/harness/client.ts | 2 +-
src/server/session.ts | 9 ++++++++-
src/services/types.ts | 2 +-
tests/baselines/reference/api/tsserverlibrary.d.ts | 3 ++-
tests/baselines/reference/api/typescript.d.ts | 2 +-
5 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/src/harness/client.ts b/src/harness/client.ts
index 89e6293ce6e7c..07b24a123cdca 100644
--- a/src/harness/client.ts
+++ b/src/harness/client.ts
@@ -726,7 +726,7 @@ export class SessionClient implements LanguageService {
return notImplemented();
}
- getJsxLinkedEditAtPosition(_fileName: string, _currentCaretPosition: number): unknown {
+ getJsxLinkedEditAtPosition(_fileName: string, _position: number): never {
return notImplemented();
}
diff --git a/src/server/session.ts b/src/server/session.ts
index 18936cf128d73..bcfe7e7af2256 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -81,6 +81,7 @@ import {
isStringLiteralLike,
JSDocLinkDisplayPart,
JSDocTagInfo,
+ JsxLinkedEditInfo,
LanguageServiceMode,
LineAndCharacter,
map,
@@ -1802,6 +1803,12 @@ export class Session implements EventSender {
return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 };
}
+ private getJsxLinkedEdit(args: protocol.FileLocationRequestArgs): JsxLinkedEditInfo | undefined {
+ const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
+ const position = this.getPositionInFile(args, file);
+ return languageService.getJsxLinkedEditAtPosition(file, position);
+ }
+
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
@@ -3390,7 +3397,7 @@ export class Session implements EventSender {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
},
[protocol.CommandTypes.JsxLinkedEdit]: (request: protocol.JsxLinkedEditRequest) => {
- return this.requiredResponse(this.getJsxClosingTag(request.arguments));
+ return this.requiredResponse(this.getJsxLinkedEdit(request.arguments));
},
[protocol.CommandTypes.GetCodeFixes]: (request: protocol.CodeFixRequest) => {
return this.requiredResponse(this.getCodeFixes(request.arguments, /*simplifiedResult*/ true));
diff --git a/src/services/types.ts b/src/services/types.ts
index dc19e4ad841e2..090045b7c141a 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -607,7 +607,7 @@ export interface LanguageService {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxLinkedEditAtPosition(fileName: string, currentCaretPosition: number): JsxLinkedEditInfo | unknown;
+ getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 5af2b6eb01e2c..6c985630f0fad 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -3854,6 +3854,7 @@ declare namespace ts {
private getSemanticDiagnosticsSync;
private getSuggestionDiagnosticsSync;
private getJsxClosingTag;
+ private getJsxLinkedEdit;
private getDocumentHighlights;
private provideInlayHints;
private setCompilerOptionsForInferredProjects;
@@ -9984,7 +9985,7 @@ declare namespace ts {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxLinkedEditAtPosition(fileName: string, currentCaretPosition: number): JsxLinkedEditInfo | unknown;
+ getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index 79047d331fd30..c9b3095a92215 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -6107,7 +6107,7 @@ declare namespace ts {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxLinkedEditAtPosition(fileName: string, currentCaretPosition: number): JsxLinkedEditInfo | unknown;
+ getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
From be34a1e2185bd81f5b35a7d11fcdfc1cf7106a81 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Thu, 30 Mar 2023 23:29:51 -0700
Subject: [PATCH 25/32] update protocol, refactor services
---
src/server/protocol.ts | 8 +++++--
src/server/session.ts | 21 +++++++++++++++++--
src/services/services.ts | 17 ++++-----------
.../reference/api/tsserverlibrary.d.ts | 6 +++++-
4 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index 5d250cf8a36b9..d7dda2d048926 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -4,7 +4,6 @@ import {
EndOfLineState,
FileExtensionInfo,
HighlightSpanKind,
- JsxLinkedEditInfo,
MapLike,
OutliningSpanKind,
OutputFile,
@@ -1107,8 +1106,13 @@ export interface JsxLinkedEditRequest extends FileLocationRequest {
readonly command: CommandTypes.JsxLinkedEdit;
}
+export interface LinkedEditingRanges {
+ ranges: TextSpan[];
+ wordPattern?: string;
+}
+
export interface JsxLinkedEditResponse extends Response {
- readonly info: JsxLinkedEditInfo;
+ readonly body: LinkedEditingRanges;
}
/**
diff --git a/src/server/session.ts b/src/server/session.ts
index bcfe7e7af2256..810b6deeb7c50 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -1803,10 +1803,13 @@ export class Session implements EventSender {
return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 };
}
- private getJsxLinkedEdit(args: protocol.FileLocationRequestArgs): JsxLinkedEditInfo | undefined {
+ private getJsxLinkedEdit(args: protocol.FileLocationRequestArgs): protocol.LinkedEditingRanges | undefined {
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
const position = this.getPositionInFile(args, file);
- return languageService.getJsxLinkedEditAtPosition(file, position);
+ const linkedEditInfo = languageService.getJsxLinkedEditAtPosition(file, position);
+ const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
+ if (scriptInfo === undefined || linkedEditInfo === undefined) return undefined;
+ return convertLinkedEditInfoToRanges(linkedEditInfo, scriptInfo);
}
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] {
@@ -3654,6 +3657,20 @@ function positionToLineOffset(info: ScriptInfoOrConfig, position: number): proto
return isConfigFile(info) ? locationFromLineAndCharacter(info.getLineAndCharacterOfPosition(position)) : info.positionToLineOffset(position);
}
+function convertLinkedEditInfoToRanges(linkedEdit: JsxLinkedEditInfo, scriptInfo: ScriptInfo): protocol.LinkedEditingRanges {
+ return {
+ ranges: linkedEdit.ranges.map(
+ s => {
+ return {
+ start: scriptInfo.positionToLineOffset(s.start),
+ end: scriptInfo.positionToLineOffset(s.start + s.length)
+ };
+ }
+ ),
+ wordPattern: linkedEdit.wordPattern,
+ };
+}
+
function locationFromLineAndCharacter(lc: LineAndCharacter): protocol.Location {
return { line: lc.line + 1, offset: lc.character + 1 };
}
diff --git a/src/services/services.ts b/src/services/services.ts
index 73311f85274b3..abb443a7ff0f4 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -73,7 +73,6 @@ import {
FindAllReferences,
findAncestor,
findChildOfKind,
- findNextToken,
findPrecedingToken,
first,
firstDefined,
@@ -155,13 +154,10 @@ import {
isJSDocCommentContainingNode,
isJsxAttributes,
isJsxClosingElement,
- isJsxClosingFragment,
isJsxElement,
isJsxFragment,
isJsxOpeningElement,
isJsxOpeningFragment,
- isJsxSelfClosingElement,
- isJSXTagName,
isJsxText,
isLabelName,
isLiteralComputedPropertyDeclarationName,
@@ -2491,9 +2487,7 @@ export function createLanguageService(
const token = findPrecedingToken(position, sourceFile);
if (!token) return undefined;
- if ((isJsxOpeningFragment(token.parent) && token.kind === SyntaxKind.LessThanToken)
- || (isJsxClosingFragment(token.parent) && token.kind === SyntaxKind.SlashToken)){
-
+ if (isJsxFragment(token.parent.parent)) {
const openPos = token.parent.parent.openingFragment.getStart(sourceFile) + 1; // "<".length
const closePos = token.parent.parent.closingFragment.getStart(sourceFile) + 2; // "".length
@@ -2504,17 +2498,13 @@ export function createLanguageService(
const wordPattern = undefined;
return { ranges, wordPattern };
}
- else if (isJsxFragment(token.parent.parent)) {
- return undefined;
- }
else {
+ // looks mirroring in element tag names
const tag = findAncestor(token,
n => {
if (!n.parent.parent) return "quit";
else if (isJsxElement(n.parent.parent)) {
- if ((isJSXTagName(n) && !isJsxSelfClosingElement(n.parent))
- || (n.kind === SyntaxKind.LessThanToken && isJSXTagName(findNextToken(n, n.parent, sourceFile) ?? n))
- || n.kind === SyntaxKind.SlashToken) {
+ if (isJsxOpeningElement(n.parent) || isJsxClosingElement(n.parent)) {
return true;
}
return "quit";
@@ -2527,6 +2517,7 @@ export function createLanguageService(
const openTag = { start: element.parent.openingElement.tagName.getStart(sourceFile), end: element.parent.openingElement.tagName.end };
const endTag = { start: element.parent.closingElement.tagName.getStart(sourceFile), end: element.parent.closingElement.tagName.end };
+ // only return a mirror if the cursor is within a tag name
if (!(openTag.start <= position && position <= openTag.end || endTag.start <= position && position <= endTag.end)) return undefined;
if (element.parent.openingElement.tagName.getText(sourceFile) !== element.parent.closingElement.tagName.getText(sourceFile)) return undefined;
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 6c985630f0fad..3439978eceb58 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -881,8 +881,12 @@ declare namespace ts {
interface JsxLinkedEditRequest extends FileLocationRequest {
readonly command: CommandTypes.JsxLinkedEdit;
}
+ interface LinkedEditingRanges {
+ ranges: TextSpan[];
+ wordPattern?: string;
+ }
interface JsxLinkedEditResponse extends Response {
- readonly info: JsxLinkedEditInfo;
+ readonly body: LinkedEditingRanges;
}
/**
* Get document highlights request; value of command field is
From 7f2f885abfa48cba84b690ac63788f7a36b68c97 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Fri, 31 Mar 2023 14:08:21 -0700
Subject: [PATCH 26/32] cleaned up tests
---
src/services/services.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit1.ts | 56 ++++++++++++++--------
tests/cases/fourslash/jsxTagLinkedEdit2.ts | 30 ++++++++----
tests/cases/fourslash/jsxTagLinkedEdit3.ts | 11 ++---
tests/cases/fourslash/jsxTagLinkedEdit4.ts | 17 ++++---
tests/cases/fourslash/jsxTagLinkedEdit5.ts | 21 ++++----
tests/cases/fourslash/jsxTagLinkedEdit6.ts | 13 +++--
tests/cases/fourslash/jsxTagLinkedEdit7.ts | 44 ++++++++---------
tests/cases/fourslash/jsxTagLinkedEdit8.ts | 4 --
9 files changed, 115 insertions(+), 83 deletions(-)
diff --git a/src/services/services.ts b/src/services/services.ts
index abb443a7ff0f4..ca18f43389739 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2499,7 +2499,7 @@ export function createLanguageService(
return { ranges, wordPattern };
}
else {
- // looks mirroring in element tag names
+ // looks for mirroring in element tag names
const tag = findAncestor(token,
n => {
if (!n.parent.parent) return "quit";
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
index efa6cf133ded3..f9ff4c0b2805f 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit1.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
@@ -8,8 +8,8 @@
// @Filename: /basic.tsx
////const jsx = (
-//// *0*/d/*1*/iv/*2*/>/*7*/
-//// *6*///*3*/di/*4*/v/*5*/>/*8*/
+//// *0*/d/*1*/iv/*2*/>/*3*/
+//// *4*///*5*/di/*6*/v/*7*/>/*8*/
////);
// @Filename: /whitespaceInvalidClosing.tsx
@@ -18,36 +18,54 @@
//// < /*9*/ /div>
////);
-// @Filename: /whitespaceOpening.tsx
-////const jsx3 = (
+// @Filename: /whitespace.tsx
+////const whitespaceOpening = (
//// *10*/ /*11*/div/*12*/ /*13*/> /*14*/
-////
+//// /*15*/di/*16*/v>
////);
-
-// @Filename: /whitespaceClosing.tsx
-////const jsx = (
-////
-//// /*15*/ /*16*/div/*17*/ /*18*/> /*19*/
+////const whitespaceClosing = (
+//// *17*/di/*18*/v>
+//// /*19*/ /*20*/div/*21*/ /*22*/> /*23*/
////);
-const linkedCursors1 = {ranges: [{start: 19, length: 3},
- {start: 30, length: 3}],
- wordPattern : 'div'};
+const markers = test.markers();
+const linkedCursors1 = {
+ ranges: [{ start: markers[0].position, length: 3 }, { start: markers[5].position, length: 3 }],
+ wordPattern: 'div'
+};
+const linkedCursors2 = {
+ ranges: [{ start: markers[11].position, length: 3 }, { start: markers[15].position, length: 3 }],
+ wordPattern: 'div'
+};
+const linkedCursors3 = {
+ ranges: [{ start: markers[17].position, length: 3 }, { start: markers[20].position, length: 3 }],
+ wordPattern: 'div'
+};
verify.jsxLinkedEdit( {
"0": linkedCursors1,
"1": linkedCursors1,
"2": linkedCursors1,
- "3": linkedCursors1,
- "4": linkedCursors1,
+ "3": undefined,
+ "4": undefined,
"5": linkedCursors1,
- "6": undefined,
- "7": undefined,
+ "6": linkedCursors1,
+ "7": linkedCursors1,
"8": undefined,
"9": undefined, // I believe this should be an invalid tag
"10": undefined,
+ "11": linkedCursors2,
+ "12": linkedCursors2,
"13": undefined,
- "15": undefined,
- "18": undefined,
+ "14": undefined,
+ "15": linkedCursors2,
+ "16": linkedCursors2,
+ "17": linkedCursors3,
+ "18": linkedCursors3,
+ "19": undefined,
+ "20": linkedCursors3,
+ "21": linkedCursors3,
+ "22": undefined,
+ "23": undefined,
});
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit2.ts b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
index 95f4fcf84977a..4a951630c19e7 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit2.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
@@ -1,24 +1,36 @@
///
+// for readability
+////const jsx = (
+////
+////
+////
+////
+////
+////);
+
// @Filename: /attrs.tsx
////const jsx = (
-//// *0*/div/*1*/ /*5*/styl/*2*/e={{ color: 'red' }}/*6*/>/*4*/
+//// *0*/div/*1*/ /*2*/styl/*3*/e={{ color: 'red' }}/*4*/>/*5*/
////
////
////
-////
+////
////);
-const linkedCursors2 = {ranges: [{start: 18, length: 3},
- {start: 91, length: 3}],
- wordPattern : 'div'};
+const startPos = test.markerByName("0").position;
+const endPos = test.markerByName("6").position - 2;
+const linkedCursors = {
+ ranges: [{ start: startPos, length: 3 }, { start: endPos, length: 3 }],
+ wordPattern : 'div'
+};
verify.jsxLinkedEdit( {
- "0": linkedCursors2,
- "1": linkedCursors2,
+ "0": linkedCursors,
+ "1": linkedCursors,
"2": undefined,
- "3": linkedCursors2,
+ "3": undefined,
"4": undefined,
"5": undefined,
- "6": undefined,
+ "6": linkedCursors,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit3.ts b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
index b056a9534ab00..c732f45624861 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit3.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
@@ -2,18 +2,16 @@
// @Filename: /selfClosing.tsx
////const jsx = (
-//// /*1*/
+////
/*0*/
////
/*4*/
-//// /*5*/
+//// No lin/*9*/ked cursors here!
+//// /*5*/*1*/img/*2*/ /*3*//>
//// /*6*/
/*8*/
//// /*7*/
////);
-// const linkedCursors3 = {ranges: [{start: 18, length: 3},
-// {start: 91, length: 3}],
-// wordPattern : 'div'};
-
verify.jsxLinkedEdit( {
+ "0": undefined,
"1": undefined,
"2": undefined,
"3": undefined,
@@ -22,4 +20,5 @@ verify.jsxLinkedEdit( {
"6": undefined,
"7": undefined,
"8": undefined,
+ "9": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit4.ts b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
index 4f26b52275dd3..d71e0cec1165a 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit4.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
@@ -15,19 +15,22 @@
////
////
////
-////
+//// /*6*/div>
////);
-const linkedCursors4 = {ranges: [{start: 18, length: 3},
- {start: 69, length: 3}],
- wordPattern : 'div'};
+const startPos = test.markerByName("0").position;
+const endPos = test.markerByName("6").position;
+const linkedCursors = {
+ ranges: [{ start: startPos, length: 3 }, { start: endPos, length: 3 }],
+ wordPattern : 'div'
+};
verify.jsxLinkedEdit( {
- "0": linkedCursors4,
- "1": linkedCursors4,
+ "0": linkedCursors,
+ "1": linkedCursors,
"2": undefined,
"3": undefined,
"4": undefined,
"5": undefined,
- "6": linkedCursors4,
+ "6": linkedCursors,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit5.ts b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
index 8860b7b0f0767..e6925ff4377f7 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit5.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
@@ -2,17 +2,20 @@
// @FileName: /invalid1.tsx
////const jsx = (
-////
-////
-////
+////
+////
+////
////);
-const linkedCursors5 = {ranges: [{start: 33, length: 3},
- {start: 44, length: 3}],
- wordPattern : 'div'};
+const startPos = test.markerByName("1").position - 3;
+const endPos = test.markerByName("2").position - 3;
+const linkedCursors = {
+ ranges: [{ start: startPos, length: 3 }, { start: endPos, length: 3 }],
+ wordPattern : 'div'
+};
verify.jsxLinkedEdit( {
- "4": undefined,
- "5": linkedCursors5,
- "6": linkedCursors5,
+ "0": undefined,
+ "1": linkedCursors,
+ "2": linkedCursors,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit6.ts b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
index 169a3cccd27b3..e6231a7dbc9ce 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit6.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
@@ -2,13 +2,16 @@
// @Filename: /namespace.tsx
////const jsx = (
-////
-////
+//// *start*/someNamespa/*3*/ce./*2*/Thing>
+//// /*end*/someNamespace/*1*/.Thing>
////);
-const linkedCursors6 = {ranges: [{start: 19, length: 19},
- {start: 46, length: 19}],
- wordPattern : 'someNamespace.Thing'};
+const startPos = test.markerByName("start").position;
+const endPos = test.markerByName("end").position;
+const linkedCursors6 = {
+ ranges: [{ start: startPos, length: 19 }, { start: endPos, length: 19 }],
+ wordPattern : 'someNamespace.Thing'
+};
verify.jsxLinkedEdit( {
"1": linkedCursors6,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit7.ts b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
index 0f80a753c8995..059ec9e0e0135 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit7.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
@@ -7,13 +7,13 @@
// >
// );
// const jsx2 = (
-// <>
-// >
-// );
-// const jsx3 = (
// /* this is comment */* more comment */>Hello
// /* even more comment */>
// );
+// const jsx3 = (
+// <>
+// >
+// );
// @FileName: /fragment.tsx
////const jsx = (
@@ -22,48 +22,46 @@
//// /*6*/*2*///*3*/>/*4*/
////);
////const jsx2 = (
-//// <>/*7*/
-//// >
-////);
-////const jsx3 = (
//// /* this is comment *//*13*/*10*//* /*11*/more comment *//*12*/>/*8*/Hello/*9*/
//// /*14*/ /*18*///*17*/* even/*15*/ more comment *//*16*/>
////);
-
-// @FileName: /mismatchedFragment.tsx
////const jsx3 = (
-//// *A*/>
-////
+//// <>/*7*/
//// >
////);
-const linkedCursors7 = {ranges: [{start: 19, length: 0},
- {start: 43, length: 0}],
- wordPattern : undefined};
+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
+};
-const linkedCursors7jsx3 = {ranges: [{start: 122, length: 0},
- {start: 153, length: 0}],
- wordPattern : undefined};
+const startPos2 = test.markerByName("10").position;
+const endPos2 = test.markerByName("14").position;
+const linkedCursors2 = {
+ ranges: [{ start: startPos2, length: 0 }, { start: endPos2, length: 0 }],
+ wordPattern : undefined
+};
verify.jsxLinkedEdit({
- "0": linkedCursors7,
+ "0": linkedCursors1,
"1": undefined,
"2": undefined,
- "3": linkedCursors7,
+ "3": linkedCursors1,
"4": undefined,
"5": undefined,
"6": undefined,
"7": undefined,
"8": undefined,
"9": undefined,
- "10": linkedCursors7jsx3,
+ "10": linkedCursors2,
"11": undefined,
"12": undefined,
"13": undefined,
- "14": linkedCursors7jsx3,
+ "14": linkedCursors2,
"15": undefined,
"16": undefined,
"17": undefined,
"18": undefined,
- // "A": undefined // I don't know what's supposed to happen in this case
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit8.ts b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
index f9617c1fcd4cd..4d5584a5a9933 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit8.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
@@ -8,10 +8,6 @@
////
////);
-// const linkedCursors8 = {ranges: [{start: 14, end: 14},
-// {start: 43, end: 43}],
-// wordPattern : };
-
verify.jsxLinkedEdit( {
"8": undefined,
});
\ No newline at end of file
From 516449577ef5d853dbcfe55e6ef2c3423149fda9 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Fri, 31 Mar 2023 14:54:12 -0700
Subject: [PATCH 27/32] rename to match lsp
---
src/harness/client.ts | 2 +-
src/harness/fourslashImpl.ts | 4 ++--
src/harness/fourslashInterfaceImpl.ts | 4 ++--
src/harness/harnessLanguageService.ts | 2 +-
src/server/protocol.ts | 8 ++++----
src/server/session.ts | 12 ++++++------
src/services/services.ts | 6 +++---
src/services/types.ts | 4 ++--
tests/baselines/reference/api/tsserverlibrary.d.ts | 14 +++++++-------
tests/baselines/reference/api/typescript.d.ts | 4 ++--
tests/cases/fourslash/fourslash.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit1.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit2.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit3.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit4.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit5.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit6.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit7.ts | 2 +-
tests/cases/fourslash/jsxTagLinkedEdit8.ts | 2 +-
19 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/src/harness/client.ts b/src/harness/client.ts
index 07b24a123cdca..7c7bdfcb36e54 100644
--- a/src/harness/client.ts
+++ b/src/harness/client.ts
@@ -726,7 +726,7 @@ export class SessionClient implements LanguageService {
return notImplemented();
}
- getJsxLinkedEditAtPosition(_fileName: string, _position: number): never {
+ getLinkedEditingAtPosition(_fileName: string, _position: number): never {
return notImplemented();
}
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index e79354c462d5b..59437024a0c05 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -3444,10 +3444,10 @@ export class TestState {
}
}
- public verifyJsxLinkedEdit(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined }): void {
+ public verifyLinkedEditing(map: { [markerName: string]: ts.LinkedEditingInfo | undefined }): void {
for (const markerName in map) {
this.goToMarker(markerName);
- const actual = this.languageService.getJsxLinkedEditAtPosition(this.activeFile.fileName, this.currentCaretPosition);
+ const actual = this.languageService.getLinkedEditingAtPosition(this.activeFile.fileName, this.currentCaretPosition);
assert.deepEqual(actual, map[markerName], markerName);
}
}
diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts
index 70b459733d40a..d3306b8b57aa1 100644
--- a/src/harness/fourslashInterfaceImpl.ts
+++ b/src/harness/fourslashInterfaceImpl.ts
@@ -189,8 +189,8 @@ export class VerifyNegatable {
this.state.verifyJsxClosingTag(map);
}
- public jsxLinkedEdit(map: { [markerName: string]: ts.JsxLinkedEditInfo | undefined }): void {
- this.state.verifyJsxLinkedEdit(map);
+ public linkedEditing(map: { [markerName: string]: ts.LinkedEditingInfo | undefined }): void {
+ this.state.verifyLinkedEditing(map);
}
public isInCommentAtPosition(onlyMultiLineDiverges?: boolean) {
diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts
index 2ad1a313cb15c..c6f95d66ad4d6 100644
--- a/src/harness/harnessLanguageService.ts
+++ b/src/harness/harnessLanguageService.ts
@@ -593,7 +593,7 @@ class LanguageServiceShimProxy implements ts.LanguageService {
getJsxClosingTagAtPosition(): never {
throw new Error("Not supported on the shim.");
}
- getJsxLinkedEditAtPosition(): never {
+ getLinkedEditingAtPosition(): never {
throw new Error("Not supported on the shim.");
}
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan {
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index d7dda2d048926..3dd2790198078 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -23,7 +23,7 @@ import {
export const enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
- JsxLinkedEdit = "jsxLinkedEdit",
+ LinkedEditing = "LinkedEditing",
Brace = "brace",
/** @internal */
BraceFull = "brace-full",
@@ -1102,8 +1102,8 @@ export interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
-export interface JsxLinkedEditRequest extends FileLocationRequest {
- readonly command: CommandTypes.JsxLinkedEdit;
+export interface LinkedEditingRequest extends FileLocationRequest {
+ readonly command: CommandTypes.LinkedEditing;
}
export interface LinkedEditingRanges {
@@ -1111,7 +1111,7 @@ export interface LinkedEditingRanges {
wordPattern?: string;
}
-export interface JsxLinkedEditResponse extends Response {
+export interface LinkedEditingResponse extends Response {
readonly body: LinkedEditingRanges;
}
diff --git a/src/server/session.ts b/src/server/session.ts
index 810b6deeb7c50..a8269fcee6717 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -81,9 +81,9 @@ import {
isStringLiteralLike,
JSDocLinkDisplayPart,
JSDocTagInfo,
- JsxLinkedEditInfo,
LanguageServiceMode,
LineAndCharacter,
+ LinkedEditingInfo,
map,
mapDefined,
mapDefinedIterator,
@@ -1803,10 +1803,10 @@ export class Session implements EventSender {
return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 };
}
- private getJsxLinkedEdit(args: protocol.FileLocationRequestArgs): protocol.LinkedEditingRanges | undefined {
+ private getLinkedEditing(args: protocol.FileLocationRequestArgs): protocol.LinkedEditingRanges | undefined {
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
const position = this.getPositionInFile(args, file);
- const linkedEditInfo = languageService.getJsxLinkedEditAtPosition(file, position);
+ const linkedEditInfo = languageService.getLinkedEditingAtPosition(file, position);
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
if (scriptInfo === undefined || linkedEditInfo === undefined) return undefined;
return convertLinkedEditInfoToRanges(linkedEditInfo, scriptInfo);
@@ -3399,8 +3399,8 @@ export class Session implements EventSender {
[protocol.CommandTypes.JsxClosingTag]: (request: protocol.JsxClosingTagRequest) => {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
},
- [protocol.CommandTypes.JsxLinkedEdit]: (request: protocol.JsxLinkedEditRequest) => {
- return this.requiredResponse(this.getJsxLinkedEdit(request.arguments));
+ [protocol.CommandTypes.LinkedEditing]: (request: protocol.LinkedEditingRequest) => {
+ return this.requiredResponse(this.getLinkedEditing(request.arguments));
},
[protocol.CommandTypes.GetCodeFixes]: (request: protocol.CodeFixRequest) => {
return this.requiredResponse(this.getCodeFixes(request.arguments, /*simplifiedResult*/ true));
@@ -3657,7 +3657,7 @@ function positionToLineOffset(info: ScriptInfoOrConfig, position: number): proto
return isConfigFile(info) ? locationFromLineAndCharacter(info.getLineAndCharacterOfPosition(position)) : info.positionToLineOffset(position);
}
-function convertLinkedEditInfoToRanges(linkedEdit: JsxLinkedEditInfo, scriptInfo: ScriptInfo): protocol.LinkedEditingRanges {
+function convertLinkedEditInfoToRanges(linkedEdit: LinkedEditingInfo, scriptInfo: ScriptInfo): protocol.LinkedEditingRanges {
return {
ranges: linkedEdit.ranges.map(
s => {
diff --git a/src/services/services.ts b/src/services/services.ts
index ca18f43389739..d3ef99f9bc1cf 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -191,7 +191,6 @@ import {
JsxElement,
JsxEmit,
JsxFragment,
- JsxLinkedEditInfo,
JsxOpeningElement,
LanguageService,
LanguageServiceHost,
@@ -201,6 +200,7 @@ import {
length,
LineAndCharacter,
lineBreakPart,
+ LinkedEditingInfo,
LiteralType,
map,
mapDefined,
@@ -2482,7 +2482,7 @@ export function createLanguageService(
}
}
- function getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined {
+ function getLinkedEditingAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const token = findPrecedingToken(position, sourceFile);
if (!token) return undefined;
@@ -3058,7 +3058,7 @@ export function createLanguageService(
getDocCommentTemplateAtPosition,
isValidBraceCompletionAtPosition,
getJsxClosingTagAtPosition,
- getJsxLinkedEditAtPosition,
+ getLinkedEditingAtPosition,
getSpanOfEnclosingComment,
getCodeFixesAtPosition,
getCombinedCodeFix,
diff --git a/src/services/types.ts b/src/services/types.ts
index 090045b7c141a..222e2d69e848a 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -607,7 +607,7 @@ export interface LanguageService {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined;
+ getLinkedEditingAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
@@ -662,7 +662,7 @@ export interface JsxClosingTagInfo {
readonly newText: string;
}
-export interface JsxLinkedEditInfo {
+export interface LinkedEditingInfo {
readonly ranges: TextSpan[];
wordPattern?: string;
}
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 3439978eceb58..28eb0c067aa12 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -89,7 +89,7 @@ declare namespace ts {
namespace protocol {
enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
- JsxLinkedEdit = "jsxLinkedEdit",
+ LinkedEditing = "LinkedEditing",
Brace = "brace",
BraceCompletion = "braceCompletion",
GetSpanOfEnclosingComment = "getSpanOfEnclosingComment",
@@ -878,14 +878,14 @@ declare namespace ts {
interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
- interface JsxLinkedEditRequest extends FileLocationRequest {
- readonly command: CommandTypes.JsxLinkedEdit;
+ interface LinkedEditingRequest extends FileLocationRequest {
+ readonly command: CommandTypes.LinkedEditing;
}
interface LinkedEditingRanges {
ranges: TextSpan[];
wordPattern?: string;
}
- interface JsxLinkedEditResponse extends Response {
+ interface LinkedEditingResponse extends Response {
readonly body: LinkedEditingRanges;
}
/**
@@ -3858,7 +3858,7 @@ declare namespace ts {
private getSemanticDiagnosticsSync;
private getSuggestionDiagnosticsSync;
private getJsxClosingTag;
- private getJsxLinkedEdit;
+ private getLinkedEditing;
private getDocumentHighlights;
private provideInlayHints;
private setCompilerOptionsForInferredProjects;
@@ -9989,7 +9989,7 @@ declare namespace ts {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined;
+ getLinkedEditingAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
@@ -10019,7 +10019,7 @@ declare namespace ts {
interface JsxClosingTagInfo {
readonly newText: string;
}
- interface JsxLinkedEditInfo {
+ interface LinkedEditingInfo {
readonly ranges: TextSpan[];
wordPattern?: string;
}
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index c9b3095a92215..21ed21435a4c3 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -6107,7 +6107,7 @@ declare namespace ts {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getJsxLinkedEditAtPosition(fileName: string, position: number): JsxLinkedEditInfo | undefined;
+ getLinkedEditingAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
@@ -6137,7 +6137,7 @@ declare namespace ts {
interface JsxClosingTagInfo {
readonly newText: string;
}
- interface JsxLinkedEditInfo {
+ interface LinkedEditingInfo {
readonly ranges: TextSpan[];
wordPattern?: string;
}
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 55dc2573701ab..1244e8031b9ee 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -260,7 +260,7 @@ declare namespace FourSlashInterface {
implementationListIsEmpty(): void;
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
- jsxLinkedEdit(map: { [markerName: string]: {
+ linkedEditing(map: { [markerName: string]: {
readonly ranges : { start: number, length: number }[],
wordPattern? : string ;} | undefined }): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
index f9ff4c0b2805f..8a8656ccb2f88 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit1.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit1.ts
@@ -42,7 +42,7 @@ const linkedCursors3 = {
wordPattern: 'div'
};
-verify.jsxLinkedEdit( {
+verify.linkedEditing( {
"0": linkedCursors1,
"1": linkedCursors1,
"2": linkedCursors1,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit2.ts b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
index 4a951630c19e7..1722119a737eb 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit2.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit2.ts
@@ -25,7 +25,7 @@ const linkedCursors = {
wordPattern : 'div'
};
-verify.jsxLinkedEdit( {
+verify.linkedEditing( {
"0": linkedCursors,
"1": linkedCursors,
"2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit3.ts b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
index c732f45624861..44d08a0e388c5 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit3.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit3.ts
@@ -10,7 +10,7 @@
//// /*7*/
////);
-verify.jsxLinkedEdit( {
+verify.linkedEditing( {
"0": undefined,
"1": undefined,
"2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit4.ts b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
index d71e0cec1165a..4126fae1129b7 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit4.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit4.ts
@@ -25,7 +25,7 @@ const linkedCursors = {
wordPattern : 'div'
};
-verify.jsxLinkedEdit( {
+verify.linkedEditing( {
"0": linkedCursors,
"1": linkedCursors,
"2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit5.ts b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
index e6925ff4377f7..9a3254742aaf2 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit5.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit5.ts
@@ -14,7 +14,7 @@ const linkedCursors = {
wordPattern : 'div'
};
-verify.jsxLinkedEdit( {
+verify.linkedEditing( {
"0": undefined,
"1": linkedCursors,
"2": linkedCursors,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit6.ts b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
index e6231a7dbc9ce..441ae1566d4b2 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit6.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit6.ts
@@ -13,7 +13,7 @@ const linkedCursors6 = {
wordPattern : 'someNamespace.Thing'
};
-verify.jsxLinkedEdit( {
+verify.linkedEditing( {
"1": linkedCursors6,
"2": linkedCursors6,
"3": linkedCursors6,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit7.ts b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
index 059ec9e0e0135..7c0262e28a684 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit7.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit7.ts
@@ -44,7 +44,7 @@ const linkedCursors2 = {
wordPattern : undefined
};
-verify.jsxLinkedEdit({
+verify.linkedEditing({
"0": linkedCursors1,
"1": undefined,
"2": undefined,
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit8.ts b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
index 4d5584a5a9933..c65d547deedf6 100644
--- a/tests/cases/fourslash/jsxTagLinkedEdit8.ts
+++ b/tests/cases/fourslash/jsxTagLinkedEdit8.ts
@@ -8,6 +8,6 @@
////
////);
-verify.jsxLinkedEdit( {
+verify.linkedEditing( {
"8": undefined,
});
\ No newline at end of file
From a3bdf2e84a30e8c62f0db7fddddae4ed4797d20f Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Fri, 31 Mar 2023 14:59:59 -0700
Subject: [PATCH 28/32] rename tests
---
.../fourslash/{jsxTagLinkedEdit1.ts => linkedEditingJsxTag1.ts} | 0
.../fourslash/{jsxTagLinkedEdit2.ts => linkedEditingJsxTag2.ts} | 0
.../fourslash/{jsxTagLinkedEdit3.ts => linkedEditingJsxTag3.ts} | 0
.../fourslash/{jsxTagLinkedEdit4.ts => linkedEditingJsxTag4.ts} | 0
.../fourslash/{jsxTagLinkedEdit5.ts => linkedEditingJsxTag5.ts} | 0
.../fourslash/{jsxTagLinkedEdit6.ts => linkedEditingJsxTag6.ts} | 0
.../fourslash/{jsxTagLinkedEdit7.ts => linkedEditingJsxTag7.ts} | 0
.../fourslash/{jsxTagLinkedEdit8.ts => linkedEditingJsxTag8.ts} | 0
8 files changed, 0 insertions(+), 0 deletions(-)
rename tests/cases/fourslash/{jsxTagLinkedEdit1.ts => linkedEditingJsxTag1.ts} (100%)
rename tests/cases/fourslash/{jsxTagLinkedEdit2.ts => linkedEditingJsxTag2.ts} (100%)
rename tests/cases/fourslash/{jsxTagLinkedEdit3.ts => linkedEditingJsxTag3.ts} (100%)
rename tests/cases/fourslash/{jsxTagLinkedEdit4.ts => linkedEditingJsxTag4.ts} (100%)
rename tests/cases/fourslash/{jsxTagLinkedEdit5.ts => linkedEditingJsxTag5.ts} (100%)
rename tests/cases/fourslash/{jsxTagLinkedEdit6.ts => linkedEditingJsxTag6.ts} (100%)
rename tests/cases/fourslash/{jsxTagLinkedEdit7.ts => linkedEditingJsxTag7.ts} (100%)
rename tests/cases/fourslash/{jsxTagLinkedEdit8.ts => linkedEditingJsxTag8.ts} (100%)
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit1.ts b/tests/cases/fourslash/linkedEditingJsxTag1.ts
similarity index 100%
rename from tests/cases/fourslash/jsxTagLinkedEdit1.ts
rename to tests/cases/fourslash/linkedEditingJsxTag1.ts
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit2.ts b/tests/cases/fourslash/linkedEditingJsxTag2.ts
similarity index 100%
rename from tests/cases/fourslash/jsxTagLinkedEdit2.ts
rename to tests/cases/fourslash/linkedEditingJsxTag2.ts
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit3.ts b/tests/cases/fourslash/linkedEditingJsxTag3.ts
similarity index 100%
rename from tests/cases/fourslash/jsxTagLinkedEdit3.ts
rename to tests/cases/fourslash/linkedEditingJsxTag3.ts
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit4.ts b/tests/cases/fourslash/linkedEditingJsxTag4.ts
similarity index 100%
rename from tests/cases/fourslash/jsxTagLinkedEdit4.ts
rename to tests/cases/fourslash/linkedEditingJsxTag4.ts
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit5.ts b/tests/cases/fourslash/linkedEditingJsxTag5.ts
similarity index 100%
rename from tests/cases/fourslash/jsxTagLinkedEdit5.ts
rename to tests/cases/fourslash/linkedEditingJsxTag5.ts
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit6.ts b/tests/cases/fourslash/linkedEditingJsxTag6.ts
similarity index 100%
rename from tests/cases/fourslash/jsxTagLinkedEdit6.ts
rename to tests/cases/fourslash/linkedEditingJsxTag6.ts
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit7.ts b/tests/cases/fourslash/linkedEditingJsxTag7.ts
similarity index 100%
rename from tests/cases/fourslash/jsxTagLinkedEdit7.ts
rename to tests/cases/fourslash/linkedEditingJsxTag7.ts
diff --git a/tests/cases/fourslash/jsxTagLinkedEdit8.ts b/tests/cases/fourslash/linkedEditingJsxTag8.ts
similarity index 100%
rename from tests/cases/fourslash/jsxTagLinkedEdit8.ts
rename to tests/cases/fourslash/linkedEditingJsxTag8.ts
From 228e0ae48d66e9c907fde4a83d9e415e32875f1a Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Mon, 3 Apr 2023 01:39:58 -0700
Subject: [PATCH 29/32] more-readable code/comments in
getLinkedEditingAtPosition
---
src/services/services.ts | 41 ++++++++++++++++++++++------------------
1 file changed, 23 insertions(+), 18 deletions(-)
diff --git a/src/services/services.ts b/src/services/services.ts
index d3ef99f9bc1cf..65feb87981b38 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2491,20 +2491,19 @@ export function createLanguageService(
const openPos = token.parent.parent.openingFragment.getStart(sourceFile) + 1; // "<".length
const closePos = token.parent.parent.closingFragment.getStart(sourceFile) + 2; // "".length
- // only allows mirroring right after opening bracket: <| >| >
+ // only allows linked editing right after opening bracket: <| >| >
if ((position !== openPos) && (position !== closePos)) return undefined;
- const ranges = [{ start: openPos, length: 0 }, { start: closePos, length: 0 }];
- const wordPattern = undefined;
- return { ranges, wordPattern };
+ // wordPattern is undefined since fragments have no tag name
+ return { ranges: [{ start: openPos, length: 0 }, { start: closePos, length: 0 }] };
}
else {
- // looks for mirroring in element tag names
- const tag = findAncestor(token,
+ // determines if the cursor is in an element tag
+ const tag = findAncestor(token.parent,
n => {
- if (!n.parent.parent) return "quit";
- else if (isJsxElement(n.parent.parent)) {
- if (isJsxOpeningElement(n.parent) || isJsxClosingElement(n.parent)) {
+ if (!n.parent) return "quit";
+ else if (isJsxElement(n.parent)) {
+ if (isJsxOpeningElement(n) || isJsxClosingElement(n)) {
return true;
}
return "quit";
@@ -2513,17 +2512,23 @@ export function createLanguageService(
});
if (!tag) return undefined;
- const element = tag.parent as JsxOpeningElement | JsxClosingElement;
- const openTag = { start: element.parent.openingElement.tagName.getStart(sourceFile), end: element.parent.openingElement.tagName.end };
- const endTag = { start: element.parent.closingElement.tagName.getStart(sourceFile), end: element.parent.closingElement.tagName.end };
+ const element = tag as JsxOpeningElement | JsxClosingElement;
+ const openTagStart = element.parent.openingElement.tagName.getStart(sourceFile);
+ const openTagEnd = element.parent.openingElement.tagName.end;
+ const closeTagStart = element.parent.closingElement.tagName.getStart(sourceFile);
+ const closeTagEnd = element.parent.closingElement.tagName.end;
- // only return a mirror if the cursor is within a tag name
- if (!(openTag.start <= position && position <= openTag.end || endTag.start <= position && position <= endTag.end)) return undefined;
- if (element.parent.openingElement.tagName.getText(sourceFile) !== element.parent.closingElement.tagName.getText(sourceFile)) return undefined;
+ // only return linked cursors if the cursor is within a tag name
+ if (!(openTagStart <= position && position <= openTagEnd || closeTagStart <= position && position <= closeTagEnd)) return undefined;
- const ranges = [{ start: openTag.start, length: openTag.end - openTag.start }, { start: endTag.start, length: endTag.end - endTag.start }];
- const wordPattern = element.tagName.getText(sourceFile);
- return { ranges, wordPattern };
+ // only return linked cursors if text in both tags is identical
+ const openingTagText = element.parent.openingElement.tagName.getText(sourceFile);
+ if (openingTagText !== element.parent.closingElement.tagName.getText(sourceFile)) return undefined;
+
+ return {
+ ranges: [{ start: openTagStart, length: openTagEnd - openTagStart }, { start: closeTagStart, length: closeTagEnd - closeTagStart }],
+ wordPattern: openingTagText
+ };
}
}
From 32e43c812bcb6278dc81c41380532217f1bea302 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Tue, 4 Apr 2023 15:29:03 -0700
Subject: [PATCH 30/32] add more tests + add `range` to function names
---
src/harness/client.ts | 2 +-
src/harness/fourslashImpl.ts | 4 +-
src/harness/fourslashInterfaceImpl.ts | 2 +-
src/harness/harnessLanguageService.ts | 2 +-
src/server/protocol.ts | 8 +-
src/server/session.ts | 23 +++---
src/services/services.ts | 15 ++--
src/services/types.ts | 2 +-
.../reference/api/tsserverlibrary.d.ts | 12 +--
tests/baselines/reference/api/typescript.d.ts | 2 +-
tests/cases/fourslash/fourslash.ts | 9 ++-
tests/cases/fourslash/linkedEditingJsxTag1.ts | 68 +++++++----------
.../cases/fourslash/linkedEditingJsxTag10.ts | 20 +++++
tests/cases/fourslash/linkedEditingJsxTag2.ts | 1 -
tests/cases/fourslash/linkedEditingJsxTag3.ts | 22 ++++--
tests/cases/fourslash/linkedEditingJsxTag4.ts | 1 -
tests/cases/fourslash/linkedEditingJsxTag5.ts | 47 +++++++++---
tests/cases/fourslash/linkedEditingJsxTag6.ts | 61 +++++++++++++--
tests/cases/fourslash/linkedEditingJsxTag7.ts | 14 ++--
tests/cases/fourslash/linkedEditingJsxTag9.ts | 74 +++++++++++++++++++
20 files changed, 274 insertions(+), 115 deletions(-)
create mode 100644 tests/cases/fourslash/linkedEditingJsxTag10.ts
create mode 100644 tests/cases/fourslash/linkedEditingJsxTag9.ts
diff --git a/src/harness/client.ts b/src/harness/client.ts
index 7c7bdfcb36e54..a74e616072302 100644
--- a/src/harness/client.ts
+++ b/src/harness/client.ts
@@ -726,7 +726,7 @@ export class SessionClient implements LanguageService {
return notImplemented();
}
- getLinkedEditingAtPosition(_fileName: string, _position: number): never {
+ getLinkedEditingRangeAtPosition(_fileName: string, _position: number): never {
return notImplemented();
}
diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index 59437024a0c05..2ee881e653d56 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -3444,10 +3444,10 @@ export class TestState {
}
}
- public verifyLinkedEditing(map: { [markerName: string]: ts.LinkedEditingInfo | undefined }): void {
+ public verifyLinkedEditingRange(map: { [markerName: string]: ts.LinkedEditingInfo | undefined }): void {
for (const markerName in map) {
this.goToMarker(markerName);
- const actual = this.languageService.getLinkedEditingAtPosition(this.activeFile.fileName, this.currentCaretPosition);
+ const actual = this.languageService.getLinkedEditingRangeAtPosition(this.activeFile.fileName, this.currentCaretPosition);
assert.deepEqual(actual, map[markerName], markerName);
}
}
diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts
index d3306b8b57aa1..ca086dc1b2799 100644
--- a/src/harness/fourslashInterfaceImpl.ts
+++ b/src/harness/fourslashInterfaceImpl.ts
@@ -190,7 +190,7 @@ export class VerifyNegatable {
}
public linkedEditing(map: { [markerName: string]: ts.LinkedEditingInfo | undefined }): void {
- this.state.verifyLinkedEditing(map);
+ this.state.verifyLinkedEditingRange(map);
}
public isInCommentAtPosition(onlyMultiLineDiverges?: boolean) {
diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts
index c6f95d66ad4d6..1f1cf4d0abac2 100644
--- a/src/harness/harnessLanguageService.ts
+++ b/src/harness/harnessLanguageService.ts
@@ -593,7 +593,7 @@ class LanguageServiceShimProxy implements ts.LanguageService {
getJsxClosingTagAtPosition(): never {
throw new Error("Not supported on the shim.");
}
- getLinkedEditingAtPosition(): never {
+ getLinkedEditingRangeAtPosition(): never {
throw new Error("Not supported on the shim.");
}
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan {
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index 3dd2790198078..fa350b88429d0 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -23,7 +23,7 @@ import {
export const enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
- LinkedEditing = "LinkedEditing",
+ LinkedEditingRange = "linkedEditingRange",
Brace = "brace",
/** @internal */
BraceFull = "brace-full",
@@ -1102,8 +1102,8 @@ export interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
-export interface LinkedEditingRequest extends FileLocationRequest {
- readonly command: CommandTypes.LinkedEditing;
+export interface LinkedEditingRangeRequest extends FileLocationRequest {
+ readonly command: CommandTypes.LinkedEditingRange;
}
export interface LinkedEditingRanges {
@@ -1111,7 +1111,7 @@ export interface LinkedEditingRanges {
wordPattern?: string;
}
-export interface LinkedEditingResponse extends Response {
+export interface LinkedEditingRangeResponse extends Response {
readonly body: LinkedEditingRanges;
}
diff --git a/src/server/session.ts b/src/server/session.ts
index a8269fcee6717..b956f4932e5c4 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -1803,10 +1803,10 @@ export class Session implements EventSender {
return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 };
}
- private getLinkedEditing(args: protocol.FileLocationRequestArgs): protocol.LinkedEditingRanges | undefined {
+ private getLinkedEditingRange(args: protocol.FileLocationRequestArgs): protocol.LinkedEditingRanges | undefined {
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
const position = this.getPositionInFile(args, file);
- const linkedEditInfo = languageService.getLinkedEditingAtPosition(file, position);
+ const linkedEditInfo = languageService.getLinkedEditingRangeAtPosition(file, position);
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
if (scriptInfo === undefined || linkedEditInfo === undefined) return undefined;
return convertLinkedEditInfoToRanges(linkedEditInfo, scriptInfo);
@@ -3399,8 +3399,8 @@ export class Session implements EventSender {
[protocol.CommandTypes.JsxClosingTag]: (request: protocol.JsxClosingTagRequest) => {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
},
- [protocol.CommandTypes.LinkedEditing]: (request: protocol.LinkedEditingRequest) => {
- return this.requiredResponse(this.getLinkedEditing(request.arguments));
+ [protocol.CommandTypes.LinkedEditingRange]: (request: protocol.LinkedEditingRangeRequest) => {
+ return this.requiredResponse(this.getLinkedEditingRange(request.arguments));
},
[protocol.CommandTypes.GetCodeFixes]: (request: protocol.CodeFixRequest) => {
return this.requiredResponse(this.getCodeFixes(request.arguments, /*simplifiedResult*/ true));
@@ -3658,17 +3658,16 @@ function positionToLineOffset(info: ScriptInfoOrConfig, position: number): proto
}
function convertLinkedEditInfoToRanges(linkedEdit: LinkedEditingInfo, scriptInfo: ScriptInfo): protocol.LinkedEditingRanges {
- return {
- ranges: linkedEdit.ranges.map(
- s => {
+ const ranges = linkedEdit.ranges.map(
+ r => {
return {
- start: scriptInfo.positionToLineOffset(s.start),
- end: scriptInfo.positionToLineOffset(s.start + s.length)
+ start: scriptInfo.positionToLineOffset(r.start),
+ end: scriptInfo.positionToLineOffset(r.start + r.length),
};
}
- ),
- wordPattern: linkedEdit.wordPattern,
- };
+ );
+ if (!linkedEdit.wordPattern) return { ranges };
+ return { ranges, wordPattern: linkedEdit.wordPattern };
}
function locationFromLineAndCharacter(lc: LineAndCharacter): protocol.Location {
diff --git a/src/services/services.ts b/src/services/services.ts
index 65feb87981b38..d13233dd7d9df 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -186,12 +186,10 @@ import {
JSDocTagInfo,
JsonSourceFile,
JsxAttributes,
- JsxClosingElement,
JsxClosingTagInfo,
JsxElement,
JsxEmit,
JsxFragment,
- JsxOpeningElement,
LanguageService,
LanguageServiceHost,
LanguageServiceMode,
@@ -2482,10 +2480,10 @@ export function createLanguageService(
}
}
- function getLinkedEditingAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined {
+ function getLinkedEditingRangeAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const token = findPrecedingToken(position, sourceFile);
- if (!token) return undefined;
+ if (!token || token.parent.kind === SyntaxKind.SourceFile) return undefined;
if (isJsxFragment(token.parent.parent)) {
const openPos = token.parent.parent.openingFragment.getStart(sourceFile) + 1; // "<".length
@@ -2494,12 +2492,11 @@ export function createLanguageService(
// only allows linked editing right after opening bracket: <| >| >
if ((position !== openPos) && (position !== closePos)) return undefined;
- // wordPattern is undefined since fragments have no tag name
return { ranges: [{ start: openPos, length: 0 }, { start: closePos, length: 0 }] };
}
else {
// determines if the cursor is in an element tag
- const tag = findAncestor(token.parent,
+ const element = findAncestor(token.parent,
n => {
if (!n.parent) return "quit";
else if (isJsxElement(n.parent)) {
@@ -2510,9 +2507,8 @@ export function createLanguageService(
}
return false;
});
- if (!tag) return undefined;
+ if (!element || !(isJsxOpeningElement(element) || isJsxClosingElement(element))) return undefined;
- const element = tag as JsxOpeningElement | JsxClosingElement;
const openTagStart = element.parent.openingElement.tagName.getStart(sourceFile);
const openTagEnd = element.parent.openingElement.tagName.end;
const closeTagStart = element.parent.closingElement.tagName.getStart(sourceFile);
@@ -2527,7 +2523,6 @@ export function createLanguageService(
return {
ranges: [{ start: openTagStart, length: openTagEnd - openTagStart }, { start: closeTagStart, length: closeTagEnd - closeTagStart }],
- wordPattern: openingTagText
};
}
}
@@ -3063,7 +3058,7 @@ export function createLanguageService(
getDocCommentTemplateAtPosition,
isValidBraceCompletionAtPosition,
getJsxClosingTagAtPosition,
- getLinkedEditingAtPosition,
+ getLinkedEditingRangeAtPosition,
getSpanOfEnclosingComment,
getCodeFixesAtPosition,
getCombinedCodeFix,
diff --git a/src/services/types.ts b/src/services/types.ts
index 222e2d69e848a..cf3205a88afb0 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -607,7 +607,7 @@ export interface LanguageService {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getLinkedEditingAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined;
+ getLinkedEditingRangeAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 28eb0c067aa12..15c876b40688e 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -89,7 +89,7 @@ declare namespace ts {
namespace protocol {
enum CommandTypes {
JsxClosingTag = "jsxClosingTag",
- LinkedEditing = "LinkedEditing",
+ LinkedEditingRange = "linkedEditingRange",
Brace = "brace",
BraceCompletion = "braceCompletion",
GetSpanOfEnclosingComment = "getSpanOfEnclosingComment",
@@ -878,14 +878,14 @@ declare namespace ts {
interface JsxClosingTagResponse extends Response {
readonly body: TextInsertion;
}
- interface LinkedEditingRequest extends FileLocationRequest {
- readonly command: CommandTypes.LinkedEditing;
+ interface LinkedEditingRangeRequest extends FileLocationRequest {
+ readonly command: CommandTypes.LinkedEditingRange;
}
interface LinkedEditingRanges {
ranges: TextSpan[];
wordPattern?: string;
}
- interface LinkedEditingResponse extends Response {
+ interface LinkedEditingRangeResponse extends Response {
readonly body: LinkedEditingRanges;
}
/**
@@ -3858,7 +3858,7 @@ declare namespace ts {
private getSemanticDiagnosticsSync;
private getSuggestionDiagnosticsSync;
private getJsxClosingTag;
- private getLinkedEditing;
+ private getLinkedEditingRange;
private getDocumentHighlights;
private provideInlayHints;
private setCompilerOptionsForInferredProjects;
@@ -9989,7 +9989,7 @@ declare namespace ts {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getLinkedEditingAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined;
+ getLinkedEditingRangeAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index 21ed21435a4c3..bff422b6466da 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -6107,7 +6107,7 @@ declare namespace ts {
* Editors should call this after `>` is typed.
*/
getJsxClosingTagAtPosition(fileName: string, position: number): JsxClosingTagInfo | undefined;
- getLinkedEditingAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined;
+ getLinkedEditingRangeAtPosition(fileName: string, position: number): LinkedEditingInfo | undefined;
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined;
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[];
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 1244e8031b9ee..4ad2445b60cd9 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -260,9 +260,7 @@ declare namespace FourSlashInterface {
implementationListIsEmpty(): void;
isValidBraceCompletionAtPosition(openingBrace?: string): void;
jsxClosingTag(map: { [markerName: string]: { readonly newText: string } | undefined }): void;
- linkedEditing(map: { [markerName: string]: {
- readonly ranges : { start: number, length: number }[],
- wordPattern? : string ;} | undefined }): void;
+ linkedEditing(map: { [markerName: string]: LinkedEditingInfo | undefined }): void;
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
codeFix(options: {
description: string | [string, ...(string | number)[]] | DiagnosticIgnoredInterpolations,
@@ -762,6 +760,11 @@ declare namespace FourSlashInterface {
generateReturnInDocTemplate?: boolean;
}
+ type LinkedEditingInfo = {
+ readonly ranges : { start: number, length: number }[];
+ wordPattern? : string;
+ }
+
export type SignatureHelpTriggerReason =
| SignatureHelpInvokedReason
| SignatureHelpCharacterTypedReason
diff --git a/tests/cases/fourslash/linkedEditingJsxTag1.ts b/tests/cases/fourslash/linkedEditingJsxTag1.ts
index 8a8656ccb2f88..ab0183c9c1e15 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag1.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag1.ts
@@ -7,39 +7,30 @@
//);
// @Filename: /basic.tsx
-////const jsx = (
-//// *0*/d/*1*/iv/*2*/>/*3*/
+/////*a*/const j/*b*/sx = (
+//// /*c*/*0*/d/*1*/iv/*2*/>/*3*/
//// *4*///*5*/di/*6*/v/*7*/>/*8*/
////);
+////const jsx2 = (
+////
+////
+////
+//// /*12*/p>
+////
+////
+////);/*d*/
-// @Filename: /whitespaceInvalidClosing.tsx
-////const jsx = (
-////
-//// < /*9*/ /div>
-////);
-
-// @Filename: /whitespace.tsx
-////const whitespaceOpening = (
-//// *10*/ /*11*/div/*12*/ /*13*/> /*14*/
-//// /*15*/di/*16*/v>
-////);
-////const whitespaceClosing = (
-//// *17*/di/*18*/v>
-//// /*19*/ /*20*/div/*21*/ /*22*/> /*23*/
-////);
-
-const markers = test.markers();
const linkedCursors1 = {
- ranges: [{ start: markers[0].position, length: 3 }, { start: markers[5].position, length: 3 }],
- wordPattern: 'div'
+ ranges: [{ start: test.markerByName("0").position, length: 3 }, { start: test.markerByName("5").position, length: 3 }],
};
const linkedCursors2 = {
- ranges: [{ start: markers[11].position, length: 3 }, { start: markers[15].position, length: 3 }],
- wordPattern: 'div'
+ ranges: [{ start: test.markerByName("9").position - 1, length: 3 }, { start: test.markerByName("14").position - 1, length: 3 }],
};
const linkedCursors3 = {
- ranges: [{ start: markers[17].position, length: 3 }, { start: markers[20].position, length: 3 }],
- wordPattern: 'div'
+ ranges: [{ start: test.markerByName("10").position - 1, length: 3 }, { start: test.markerByName("13").position - 1, length: 3 }],
+};
+const linkedCursors4 = {
+ ranges: [{ start: test.markerByName("11").position - 1, length: 1 }, { start: test.markerByName("12").position, length: 1 }],
};
verify.linkedEditing( {
@@ -52,20 +43,15 @@ verify.linkedEditing( {
"6": linkedCursors1,
"7": linkedCursors1,
"8": undefined,
- "9": undefined, // I believe this should be an invalid tag
- "10": undefined,
- "11": linkedCursors2,
- "12": linkedCursors2,
- "13": undefined,
- "14": undefined,
- "15": linkedCursors2,
- "16": linkedCursors2,
- "17": linkedCursors3,
- "18": linkedCursors3,
- "19": undefined,
- "20": linkedCursors3,
- "21": linkedCursors3,
- "22": undefined,
- "23": undefined,
- });
+ "9": linkedCursors2,
+ "10": linkedCursors3,
+ "11": linkedCursors4,
+ "12": linkedCursors4,
+ "13": linkedCursors3,
+ "14": linkedCursors2,
+ "a": undefined,
+ "b": undefined,
+ "c": undefined,
+ "d": undefined,
+});
diff --git a/tests/cases/fourslash/linkedEditingJsxTag10.ts b/tests/cases/fourslash/linkedEditingJsxTag10.ts
new file mode 100644
index 0000000000000..12a4255801d49
--- /dev/null
+++ b/tests/cases/fourslash/linkedEditingJsxTag10.ts
@@ -0,0 +1,20 @@
+///
+
+// @Filename: /jsx1.tsx
+////const jsx = *0*/div> /*1*/>;
+
+// @Filename: /jsx2.tsx
+////const jsx = *2*/> /*3*/div>;
+
+// const startPos = test.markerByName("start").position;
+// const endPos = test.markerByName("end").position;
+// const linkedCursors6 = {
+// ranges: [{ start: startPos, length: 19 }, { start: endPos, length: 19 }],
+// };
+
+verify.linkedEditing( {
+ "0": undefined,
+ "1": undefined,
+ // "2": undefined, these cases don't work yet
+ // "3": undefined,
+});
\ No newline at end of file
diff --git a/tests/cases/fourslash/linkedEditingJsxTag2.ts b/tests/cases/fourslash/linkedEditingJsxTag2.ts
index 1722119a737eb..e4d9abfb5bbec 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag2.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag2.ts
@@ -22,7 +22,6 @@ const startPos = test.markerByName("0").position;
const endPos = test.markerByName("6").position - 2;
const linkedCursors = {
ranges: [{ start: startPos, length: 3 }, { start: endPos, length: 3 }],
- wordPattern : 'div'
};
verify.linkedEditing( {
diff --git a/tests/cases/fourslash/linkedEditingJsxTag3.ts b/tests/cases/fourslash/linkedEditingJsxTag3.ts
index 44d08a0e388c5..2dfaa175e4cf9 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag3.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag3.ts
@@ -1,14 +1,14 @@
///
// @Filename: /selfClosing.tsx
-////const jsx = (
-////
/*0*/
-////
/*4*/
-//// No lin/*9*/ked cursors here!
-//// /*5*/*1*/img/*2*/ /*3*//>
-//// /*6*/
/*8*/
-//// /*7*/
-////);
+/////*0*/const jsx = /*1*/(
+////
/*2*/
+////
/*3*/
+//// No lin/*4*/ked cursors here!
+//// /*5*/*6*/img/*7*/ /*8*///*9*/>
+//// /*10*/
/*11*/
+//// /*12*/
+/////*13*/)/*14*/;/*15*/
verify.linkedEditing( {
"0": undefined,
@@ -21,4 +21,10 @@ verify.linkedEditing( {
"7": undefined,
"8": undefined,
"9": undefined,
+ "10": undefined,
+ "11": undefined,
+ "12": undefined,
+ "13": undefined,
+ "14": undefined,
+ "15": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/linkedEditingJsxTag4.ts b/tests/cases/fourslash/linkedEditingJsxTag4.ts
index 4126fae1129b7..2b95b156eb049 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag4.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag4.ts
@@ -22,7 +22,6 @@ const startPos = test.markerByName("0").position;
const endPos = test.markerByName("6").position;
const linkedCursors = {
ranges: [{ start: startPos, length: 3 }, { start: endPos, length: 3 }],
- wordPattern : 'div'
};
verify.linkedEditing( {
diff --git a/tests/cases/fourslash/linkedEditingJsxTag5.ts b/tests/cases/fourslash/linkedEditingJsxTag5.ts
index 9a3254742aaf2..2e7dbe56acea2 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag5.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag5.ts
@@ -1,21 +1,50 @@
///
-// @FileName: /invalid1.tsx
+// @FileName: /unclosedElement.tsx
////const jsx = (
////
////
-////
+//// /*3*/
+////);/*4*/
+
+// @FileName: /mismatchedElement.tsx
+////const jsx = (
+//// /*5*/
+////
+//// *8*//div/*9*/>/*10*/
////);
-const startPos = test.markerByName("1").position - 3;
-const endPos = test.markerByName("2").position - 3;
-const linkedCursors = {
- ranges: [{ start: startPos, length: 3 }, { start: endPos, length: 3 }],
- wordPattern : 'div'
+// @Filename: /invalidClosing.tsx
+////const jsx = (
+////
+//// *12*/ //*13*/div>
+////);
+
+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 }],
+};
+
+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 }],
};
verify.linkedEditing( {
"0": undefined,
- "1": linkedCursors,
- "2": linkedCursors,
+ "1": linkedCursors1,
+ "2": linkedCursors1,
+ "3": undefined,
+ "4": undefined,
+ "5": undefined,
+ "6": linkedCursors2,
+ "7": linkedCursors2,
+ "8": undefined,
+ "9": undefined,
+ "10": undefined,
+ "11": undefined, // this tag does not parse as a closing tag
+ "12": undefined,
+ "13": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/linkedEditingJsxTag6.ts b/tests/cases/fourslash/linkedEditingJsxTag6.ts
index 441ae1566d4b2..8cac987be18cb 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag6.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag6.ts
@@ -5,16 +5,61 @@
//// *start*/someNamespa/*3*/ce./*2*/Thing>
//// /*end*/someNamespace/*1*/.Thing>
////);
+//// const jsx1 = *4*/foo/*5*/ /*6*/./*7*/ /*8*/ba/*9*/r>/*10*/foo.bar>;
+//// const jsx2 = /*12*/ /*13*/f/*14*/oo /*15*/./*16*/b/*17*/ar/*18*/>;
+//// const jsx3 = *19*/foo/*20*/ //*21*// /*22*/some comment
+//// /*23*/./*24*/bar>
+//// ;
+//// let jsx4 =
+//// *26*/foo /*27*/ .// hi/*28*/
+//// /*29*/bar>
+//// /*30*/foo /*31*/ .// hi/*32*/
+//// /*33*/bar>
-const startPos = test.markerByName("start").position;
-const endPos = test.markerByName("end").position;
-const linkedCursors6 = {
- ranges: [{ start: startPos, length: 19 }, { start: endPos, length: 19 }],
- wordPattern : 'someNamespace.Thing'
+const startPos1 = test.markerByName("start").position;
+const endPos1 = test.markerByName("end").position;
+const linkedCursors1 = {
+ ranges: [{ start: startPos1, length: 19 }, { start: endPos1, length: 19 }],
+};
+
+const startPos2 = test.markerByName("26").position;
+const endPos2 = test.markerByName("30").position;
+const linkedCursors2 = {
+ ranges: [{ start: startPos2, length: 21 }, { start: endPos2, length: 21 }],
};
verify.linkedEditing( {
- "1": linkedCursors6,
- "2": linkedCursors6,
- "3": linkedCursors6,
+ "1": linkedCursors1,
+ "2": linkedCursors1,
+ "3": linkedCursors1,
+ "4": undefined,
+ "5": undefined,
+ "6": undefined,
+ "7": undefined,
+ "8": undefined,
+ "9": undefined,
+ "10": undefined,
+ "11": undefined,
+ "12": undefined,
+ "13": undefined,
+ "14": undefined,
+ "15": undefined,
+ "16": undefined,
+ "17": undefined,
+ "18": undefined,
+ "19": undefined,
+ "20": undefined,
+ "21": undefined,
+ "22": undefined,
+ "23": undefined,
+ "24": undefined,
+ "25": undefined,
+ "26": linkedCursors2,
+ "27": linkedCursors2,
+ "28": linkedCursors2,
+ "29": linkedCursors2,
+ "30": linkedCursors2,
+ "31": linkedCursors2,
+ "32": linkedCursors2,
+ "33": linkedCursors2,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/linkedEditingJsxTag7.ts b/tests/cases/fourslash/linkedEditingJsxTag7.ts
index 7c0262e28a684..c401de04cb5d0 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag7.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag7.ts
@@ -16,11 +16,11 @@
// );
// @FileName: /fragment.tsx
-////const jsx = (
+/////*a*/const j/*b*/sx =/*c*/ (
//// /*5*/*0*/>/*1*/
////
//// /*6*/*2*///*3*/>/*4*/
-////);
+////)/*d*/;
////const jsx2 = (
//// /* this is comment *//*13*/*10*//* /*11*/more comment *//*12*/>/*8*/Hello/*9*/
//// /*14*/ /*18*///*17*/* even/*15*/ more comment *//*16*/>
@@ -28,20 +28,19 @@
////const jsx3 = (
//// <>/*7*/
//// >
-////);
+////);/*e*/
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 : undefined
};
const startPos2 = test.markerByName("10").position;
const endPos2 = test.markerByName("14").position;
const linkedCursors2 = {
ranges: [{ start: startPos2, length: 0 }, { start: endPos2, length: 0 }],
- wordPattern : undefined
};
verify.linkedEditing({
@@ -64,4 +63,9 @@ verify.linkedEditing({
"16": undefined,
"17": undefined,
"18": undefined,
+ "a": undefined,
+ "b": undefined,
+ "c": undefined,
+ "d": undefined,
+ "e": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/linkedEditingJsxTag9.ts b/tests/cases/fourslash/linkedEditingJsxTag9.ts
new file mode 100644
index 0000000000000..67bd28d1fc5e7
--- /dev/null
+++ b/tests/cases/fourslash/linkedEditingJsxTag9.ts
@@ -0,0 +1,74 @@
+///
+
+// the content of whitespace.tsx
+//const whitespaceOpening = (
+// < div >
+//
+//);
+//const whitespaceClosing = (
+//
+// div >
+//);
+//const triviaOpening = (
+// /* this is comment */* more comment */ div /* comments */>Hello
+// /* even more comment */ div /* bye */>
+//);
+
+// @Filename: /whitespace.tsx
+////const whitespaceOpening = (
+//// *0*/ /*1*/div/*2*/ /*3*/> /*4*/
+//// /*5*/di/*6*/v>
+////);
+////const whitespaceClosing = (
+//// *7*/di/*8*/v>
+//// /*9*/ /*10*/div/*11*/ /*12*/> /*13*/
+////);
+////const triviaOpening = (
+//// /* this is/*14*/ comment *//*15*/*16*//* /*17*/more/*18*/ comment *//*19*/ di/*20*/v /* comments */>/*21*/Hello/*22*/
+//// /*23*/ /*24*///*25*/* even/*26*/ more comment *//*27*/ d/*28*/iv /* b/*29*/ye */>
+////);
+
+const markers = test.markers();
+const linkedCursors1 = {
+ ranges: [{ start: markers[1].position, length: 3 }, { start: markers[5].position, length: 3 }],
+};
+const linkedCursors2 = {
+ ranges: [{ start: markers[7].position, length: 3 }, { start: markers[10].position, length: 3 }],
+};
+const linkedCursors3 = {
+ ranges: [{ start: markers[20].position - 2, length: 3 }, { start: markers[28].position - 1, length: 3 }],
+};
+
+verify.linkedEditing( {
+ "0": undefined,
+ "1": linkedCursors1,
+ "2": linkedCursors1,
+ "3": undefined,
+ "4": undefined,
+ "5": linkedCursors1,
+ "6": linkedCursors1,
+ "7": linkedCursors2,
+ "8": linkedCursors2,
+ "9": undefined,
+ "10": linkedCursors2,
+ "11": linkedCursors2,
+ "12": undefined,
+ "13": undefined,
+ "14": undefined,
+ "15": undefined,
+ "16": undefined,
+ "17": undefined,
+ "18": undefined,
+ "19": undefined,
+ "20": linkedCursors3,
+ "21": undefined,
+ "22": undefined,
+ "23": undefined,
+ "24": undefined,
+ "25": undefined,
+ "26": undefined,
+ "27": undefined,
+ "28": linkedCursors3,
+ "29": undefined
+});
+
From da4f1cd2ec1bd64bb287282fac36422bebc98304 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Thu, 6 Apr 2023 14:15:09 -0700
Subject: [PATCH 31/32] more tests
---
src/services/services.ts | 9 +-
.../cases/fourslash/linkedEditingJsxTag10.ts | 86 +++++++++++++++++--
tests/cases/fourslash/linkedEditingJsxTag2.ts | 15 ++++
tests/cases/fourslash/linkedEditingJsxTag4.ts | 14 +++
4 files changed, 113 insertions(+), 11 deletions(-)
diff --git a/src/services/services.ts b/src/services/services.ts
index d13233dd7d9df..50bf8c419db2c 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -34,6 +34,7 @@ import {
Completions,
computePositionOfLineAndCharacter,
computeSuggestionDiagnostics,
+ containsParseError,
createDocumentRegistry,
createGetCanonicalFileName,
createMultiMap,
@@ -2486,8 +2487,12 @@ export function createLanguageService(
if (!token || token.parent.kind === SyntaxKind.SourceFile) return undefined;
if (isJsxFragment(token.parent.parent)) {
- const openPos = token.parent.parent.openingFragment.getStart(sourceFile) + 1; // "<".length
- const closePos = token.parent.parent.closingFragment.getStart(sourceFile) + 2; // "".length
+ const openFragment = token.parent.parent.openingFragment;
+ const closeFragment = token.parent.parent.closingFragment;
+ if (containsParseError(openFragment) || containsParseError(closeFragment)) return undefined;
+
+ const openPos = openFragment.getStart(sourceFile) + 1; // "<".length
+ const closePos = closeFragment.getStart(sourceFile) + 2; // "".length
// only allows linked editing right after opening bracket: <| >| >
if ((position !== openPos) && (position !== closePos)) return undefined;
diff --git a/tests/cases/fourslash/linkedEditingJsxTag10.ts b/tests/cases/fourslash/linkedEditingJsxTag10.ts
index 12a4255801d49..0cc40d35da978 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag10.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag10.ts
@@ -1,20 +1,88 @@
///
+// @Filename: /jsx0.tsx
+////const jsx = *0*/>
+
// @Filename: /jsx1.tsx
-////const jsx = *0*/div> /*1*/>;
+////const jsx = /*1*/>
// @Filename: /jsx2.tsx
-////const jsx = *2*/> /*3*/div>;
+////const jsx = *2*/div>
+
+// @Filename: /jsx3.tsx
+////const jsx = /*3*/div>
+
+// @Filename: /jsx4.tsx
+////const jsx = *4*/div> /*4a*/>;
+
+// @Filename: /jsx5.tsx
+////const jsx = *5*/> /*5a*/div>;
+
+// @Filename: /jsx6.tsx
+////const jsx = /*6*/div> /*6a*/div>;
+
+// @Filename: /jsx7.tsx
+////const jsx = *7*/div> //*7a*/div>;
+
+// @Filename: /jsx8.tsx
+////const jsx = *8*/div /*8a*/div>;
+
+// @Filename: /jsx9.tsx
+////const jsx = *9*/div> /*9a*/div;
+
+// @Filename: /jsx10.tsx
+////const jsx = *10*/> /*10a*/;
+
+// @Filename: /jsx11.tsx
+////const jsx = *11*/ /*11a*/>;
+
+// @Filename: /jsx12.tsx
+////const jsx = /*12*/> /*12a*/>;
+
+// @Filename: /jsx13.tsx
+////const jsx = *13*/> //*13a*/>;
+
+// @Filename: /jsx14.tsx
+////const jsx = *14*/> *14a*/div> /*14b*/> /*14c*/div>;
+
+// @Filename: /jsx15.tsx
+////const jsx = *15*/div> *15a*/> /*15b*/div> /*15c*/>;
-// const startPos = test.markerByName("start").position;
-// const endPos = test.markerByName("end").position;
-// const linkedCursors6 = {
-// ranges: [{ start: startPos, length: 19 }, { start: endPos, length: 19 }],
-// };
+const linkedCursors9 = {
+ ranges: [{ start: test.markerByName("9").position, length: 3 }, { start: test.markerByName("9a").position, length: 3 }],
+};
verify.linkedEditing( {
"0": undefined,
"1": undefined,
- // "2": undefined, these cases don't work yet
- // "3": undefined,
+ "2": undefined,
+ "3": undefined,
+ "4": undefined,
+ "4a": undefined,
+ "5": undefined,
+ "5a": undefined,
+ "6": undefined,
+ "6a": undefined,
+ "7": undefined,
+ "7a": undefined,
+ "8": undefined,
+ "8a": undefined,
+ "9": linkedCursors9,
+ "9a": linkedCursors9,
+ "10": undefined,
+ "10a": undefined,
+ "11": undefined,
+ "11a": undefined,
+ "12": undefined,
+ "12a": undefined,
+ "13": undefined,
+ "13a": undefined,
+ "14": undefined,
+ "14a": undefined,
+ "14b": undefined,
+ "14c": undefined,
+ "15": undefined,
+ "15a": undefined,
+ "15b": undefined,
+ "15c": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/linkedEditingJsxTag2.ts b/tests/cases/fourslash/linkedEditingJsxTag2.ts
index e4d9abfb5bbec..35c5a119653c9 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag2.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag2.ts
@@ -18,6 +18,14 @@
////
////);
+// this case is missing a closing brace in the attributes
+// @Filename: /attrsError.tsx
+////const jsx = (
+//// *10*/div/*11*/ /*12*/styl/*13*/e={{ color: 'red' }/*14*/>/*15*/
+//// *16*/p />
+//// /*17*/div>
+////);
+
const startPos = test.markerByName("0").position;
const endPos = test.markerByName("6").position - 2;
const linkedCursors = {
@@ -32,4 +40,11 @@ verify.linkedEditing( {
"4": undefined,
"5": undefined,
"6": linkedCursors,
+ "10": undefined,
+ "11": undefined,
+ "12": undefined,
+ "13": undefined,
+ "14": undefined,
+ "15": undefined,
+ "16": undefined,
});
\ No newline at end of file
diff --git a/tests/cases/fourslash/linkedEditingJsxTag4.ts b/tests/cases/fourslash/linkedEditingJsxTag4.ts
index 2b95b156eb049..b130c55e024f9 100644
--- a/tests/cases/fourslash/linkedEditingJsxTag4.ts
+++ b/tests/cases/fourslash/linkedEditingJsxTag4.ts
@@ -18,6 +18,13 @@
//// /*6*/div>
////);
+// @Filename: /typeTagError.tsx
+////const jsx = (
+//// *10*/div/*11*/*12*/T/*13*/>/*14*/
+//// *15*/p />
+//// /*16*/div>
+////);
+
const startPos = test.markerByName("0").position;
const endPos = test.markerByName("6").position;
const linkedCursors = {
@@ -32,4 +39,11 @@ verify.linkedEditing( {
"4": undefined,
"5": undefined,
"6": linkedCursors,
+ "10": undefined,
+ "11": undefined,
+ "12": undefined,
+ "13": undefined,
+ "14": undefined,
+ "15": undefined,
+ "16": undefined,
});
\ No newline at end of file
From db67aeedd5b3f9be3e19d37386ba5d34507d91c2 Mon Sep 17 00:00:00 2001
From: Isabel Duan
Date: Fri, 7 Apr 2023 12:21:58 -0700
Subject: [PATCH 32/32] update `Body`, simplify call to `findAncestor`
---
src/server/protocol.ts | 4 +--
src/server/session.ts | 4 +--
src/services/services.ts | 28 +++++++++----------
.../reference/api/tsserverlibrary.d.ts | 4 +--
tests/cases/fourslash/fourslash.ts | 4 +--
5 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index fa350b88429d0..fbd7f04088ae4 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -1106,13 +1106,13 @@ export interface LinkedEditingRangeRequest extends FileLocationRequest {
readonly command: CommandTypes.LinkedEditingRange;
}
-export interface LinkedEditingRanges {
+export interface LinkedEditingRangesBody {
ranges: TextSpan[];
wordPattern?: string;
}
export interface LinkedEditingRangeResponse extends Response {
- readonly body: LinkedEditingRanges;
+ readonly body: LinkedEditingRangesBody;
}
/**
diff --git a/src/server/session.ts b/src/server/session.ts
index b956f4932e5c4..853bfadc38882 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -1803,7 +1803,7 @@ export class Session implements EventSender {
return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 };
}
- private getLinkedEditingRange(args: protocol.FileLocationRequestArgs): protocol.LinkedEditingRanges | undefined {
+ private getLinkedEditingRange(args: protocol.FileLocationRequestArgs): protocol.LinkedEditingRangesBody | undefined {
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
const position = this.getPositionInFile(args, file);
const linkedEditInfo = languageService.getLinkedEditingRangeAtPosition(file, position);
@@ -3657,7 +3657,7 @@ function positionToLineOffset(info: ScriptInfoOrConfig, position: number): proto
return isConfigFile(info) ? locationFromLineAndCharacter(info.getLineAndCharacterOfPosition(position)) : info.positionToLineOffset(position);
}
-function convertLinkedEditInfoToRanges(linkedEdit: LinkedEditingInfo, scriptInfo: ScriptInfo): protocol.LinkedEditingRanges {
+function convertLinkedEditInfoToRanges(linkedEdit: LinkedEditingInfo, scriptInfo: ScriptInfo): protocol.LinkedEditingRangesBody {
const ranges = linkedEdit.ranges.map(
r => {
return {
diff --git a/src/services/services.ts b/src/services/services.ts
index 50bf8c419db2c..938f946a0d614 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2501,30 +2501,30 @@ export function createLanguageService(
}
else {
// determines if the cursor is in an element tag
- const element = findAncestor(token.parent,
+ const tag = findAncestor(token.parent,
n => {
- if (!n.parent) return "quit";
- else if (isJsxElement(n.parent)) {
- if (isJsxOpeningElement(n) || isJsxClosingElement(n)) {
- return true;
- }
- return "quit";
+ if (isJsxOpeningElement(n) || isJsxClosingElement(n)) {
+ return true;
}
return false;
});
- if (!element || !(isJsxOpeningElement(element) || isJsxClosingElement(element))) return undefined;
+ if (!tag) return undefined;
+ Debug.assert(isJsxOpeningElement(tag) || isJsxClosingElement(tag), "tag should be opening or closing element");
+
+ const openTag = tag.parent.openingElement;
+ const closeTag = tag.parent.closingElement;
- const openTagStart = element.parent.openingElement.tagName.getStart(sourceFile);
- const openTagEnd = element.parent.openingElement.tagName.end;
- const closeTagStart = element.parent.closingElement.tagName.getStart(sourceFile);
- const closeTagEnd = element.parent.closingElement.tagName.end;
+ const openTagStart = openTag.tagName.getStart(sourceFile);
+ const openTagEnd = openTag.tagName.end;
+ const closeTagStart = closeTag.tagName.getStart(sourceFile);
+ const closeTagEnd = closeTag.tagName.end;
// only return linked cursors if the cursor is within a tag name
if (!(openTagStart <= position && position <= openTagEnd || closeTagStart <= position && position <= closeTagEnd)) return undefined;
// only return linked cursors if text in both tags is identical
- const openingTagText = element.parent.openingElement.tagName.getText(sourceFile);
- if (openingTagText !== element.parent.closingElement.tagName.getText(sourceFile)) return undefined;
+ const openingTagText = openTag.tagName.getText(sourceFile);
+ if (openingTagText !== closeTag.tagName.getText(sourceFile)) return undefined;
return {
ranges: [{ start: openTagStart, length: openTagEnd - openTagStart }, { start: closeTagStart, length: closeTagEnd - closeTagStart }],
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 15c876b40688e..c60b924ffb3e0 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -881,12 +881,12 @@ declare namespace ts {
interface LinkedEditingRangeRequest extends FileLocationRequest {
readonly command: CommandTypes.LinkedEditingRange;
}
- interface LinkedEditingRanges {
+ interface LinkedEditingRangesBody {
ranges: TextSpan[];
wordPattern?: string;
}
interface LinkedEditingRangeResponse extends Response {
- readonly body: LinkedEditingRanges;
+ readonly body: LinkedEditingRangesBody;
}
/**
* Get document highlights request; value of command field is
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 4ad2445b60cd9..51a0eca5b1a18 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -761,8 +761,8 @@ declare namespace FourSlashInterface {
}
type LinkedEditingInfo = {
- readonly ranges : { start: number, length: number }[];
- wordPattern? : string;
+ readonly ranges: { start: number, length: number }[];
+ wordPattern?: string;
}
export type SignatureHelpTriggerReason =