Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mirror Cursor for JSX #51832

Closed
octref opened this issue Nov 27, 2019 · 27 comments · Fixed by #53284
Closed

Mirror Cursor for JSX #51832

octref opened this issue Nov 27, 2019 · 27 comments · Fixed by #53284
Assignees
Labels
API Relates to the public API for TypeScript Committed The team has roadmapped this issue Domain: TSServer Issues related to the TSServer Fix Available A PR has been opened for this issue Suggestion An idea for TypeScript

Comments

@octref
Copy link

octref commented Nov 27, 2019

microsoft/vscode#47069 implements this for HTML.

We should look for a way to support this for JSX/TSX.

@octref octref added the feature-request A request for a new feature label Nov 27, 2019
@octref octref added this to the Backlog milestone Nov 27, 2019
@svipas
Copy link

svipas commented Nov 27, 2019

@octref Finally, amazing news!

@mjbvz
Copy link
Contributor

mjbvz commented Dec 10, 2019

@octref Can you please share a link to the code that implements this feature for html?

@octref
Copy link
Author

octref commented Dec 11, 2019

The client side implementation is more complicated: https://github.com/microsoft/vscode/blob/master/extensions/html-language-features/client/src/mirrorCursor.ts

The server side is pretty easy, just need to compute mirror position: https://github.com/microsoft/vscode-html-languageservice/blob/master/src/services/htmlMatchingTagPosition.ts

@sntran
Copy link

sntran commented Jan 2, 2020

I would like to suggest an option for the languages that this feature can apply to. I work with XSL file and there is no mirror cursor. I could change the language to HTML, but I would loose formatting, highlighting, etc.. for XSL.

@Matelasse

This comment has been minimized.

@tifa2UP

This comment has been minimized.

@cgarrovillo

This comment has been minimized.

@aeschli aeschli changed the title Mirror Cursor for JSX [rename on type] Mirror Cursor for JSX May 4, 2020
@aeschli aeschli changed the title [rename on type] Mirror Cursor for JSX Mirror Cursor for JSX May 4, 2020
@OliverJAsh
Copy link
Contributor

Isn't this technically already solved via the "Emmet: Update Tag" command? Although it doesn't work perfectly: microsoft/vscode#99896

@pgfearo
Copy link

pgfearo commented Oct 2, 2020

I would like to suggest an option for the languages that this feature can apply to. I work with XSL file and there is no mirror cursor. I could change the language to HTML, but I would loose formatting, highlighting, etc.. for XSL.

The XSLT/XPath VSCode extension has built in tag-renaming (without a mirror cursor), code formatting, syntax- highlighting, outline etc.

@docrinehart
Copy link

docrinehart commented Dec 22, 2020

So it seems like the support is already available for highlighting the appropriate tag in JSX, and has been fixed at least once: microsoft/vscode#65921

I would assume that some of the same logic can be leveraged to handle renaming the tag as well, unless I'm missing something? It's late, and I'll try to look at this tomorrow but wanted to comment and bring it up before it slipped my mind.

UPDATE:
Maybe this is already happening soon...
microsoft/vscode#109923

@finnmerlett
Copy link

Would very much like this feature!

@yume-chan
Copy link
Contributor

yume-chan commented Feb 21, 2021

Note: this feature had been renamed a thousand times and it's now called "linked editing"

It would be nice if you could include this for the <template> section of .vue files. Is this a consideration?

@robole You need to file a feature request to Vue extension.

Maybe this is already happening soon... microsoft/vscode#109923

The API is stable but extensions still need to implement it for each language.


Some tips for anyone who want to give it a try:

Linked editing is now a part of Language Server Protocol (https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_linkedEditingRange), HTML extension now implements it in this way:

https://github.com/microsoft/vscode/blob/11cd76005bc7516dcc726d7389d0bce1744e5c85/extensions/html-language-features/server/src/htmlServer.ts#L512-L529

However we all know that TypeScript extension doesn't use Language Server Protocol, so it still needs to be implemented "manually", by calling Code Extension API (in microsoft/vscode#109923) directly.

I don't know whether TypeScript server protocol supports finding open/close JSX tags, but at least it's not same as document highlight. Document highlight doesn't care about type of current selected node.


I may try to implement it if changes to TypeScript server is not required. Otherwise it will be a massive change, requiring coordination between Code and TypeScript teams, and pretty hard for outside contributors.

@robole
Copy link

robole commented Feb 21, 2021

@yume-chan There is an open feature request in Vetur (Vue extension) from Nov 2017. Pine (octref) who opened this issue is also the author of Vetur. He has it open for PR / bug bounty / sponsorship.

@robertmassaioli
Copy link

robertmassaioli commented Mar 16, 2021

I find that most of the times that I want to accomplish this: just putting the cursor in the first tag and hitting Command+D hotkey twice does what I want.

As the docs say "⌘D selects the word at the cursor, or the next occurrence of the current selection." (Source)

This is not perfect, however, so I absolutely would love this feature to be implemented for JSX / TSX files.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Dec 9, 2022
@mjbvz
Copy link
Contributor

mjbvz commented Dec 14, 2022

Here's a proposal for the TS Server protocol to implement this in VS Code.

TS Server protocol

Add a new request jsxLinkedTag that takes a file location (path + position) and returns an LinkedEditingRanges with an array of spans for all occurrences of that tag

interface LinkedEditingRanges {
    ranges: TextSpan[];
    wordPattern?: string; // Regexp. See https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vscode-dts/vscode.d.ts#L5568
}

interface JsLinkedTagRequest extends FileLocationRequest {
	command: 'jsxLinkedTag';
	arguments: FileLocationRequestArgs;
}

interface JsLinkedTagResponse extends Response {
	readonly body: LinkedEditingRanges;
}

A few details on the expected behavior:

  • The returned ranges should include both the tag at the current cursor position and it's matching tag.
  • The ranges should include the full range of the tag name (but not attributes and not < or /).
  • If there is no matching pair, we return an empty list.
  • Self-closing tags always return an empty list.

This same request should also let us support making normal rename (F2) rename matched tags instead of

Examples

In these examples, | is the cursor position:


const jsx = (
    <div|>
    </div>
);

Same for cursor being anywhere on div

  • startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8
  • startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 9

const jsx = (
    <div| style={{ color: 'red' }}>
        <p>
            <img />
        </p>
    </div>
);
  • startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 8
  • startLine: 5, startCharacter: 6, endLine: 5, endCharacter: 9

const jsx = (
    <div>
        <p>
            <img| />
        </p>
    </div>
);
  • Empty, we're on a self closing tag

Namespace

const jsx = (
    <someNamespa|ce.Thing>
    </someNamespace.Thing>
);

This applies for the cursor being anywhere in the tag name

  • startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 25
  • startLine: 2, startCharacter: 6, endLine: 2, endCharacter: 26

Invalid tags 1

const jsx = (
    <div|>
        <div>
    </div>
);

Match what HTML does:

  • Empty

Invalid tags 2

const jsx = (
    <div>
        <div|>
    </div>
);

Match what HTML does:

  • startLine: 2, startCharacter: 9, endLine: 2, endCharacter: 12
  • startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 9

Fragment shorthand

const jsx = (
    <|>
        <img />
    </>
);

Return empty ranges (need to confirm VS Code supports this):

  • startLine: 1, startCharacter: 5, endLine: 1, endCharacter: 5
  • startLine: 3, startCharacter: 6, endLine: 3, endCharacter: 6

Only exact matches of the entire name are supported

const A = thing;
const B = thing;

const jsx = (
    <A>
    </B>
);
  • empty, tags don't match

@ThaJay

This comment was marked as spam.

@DanielRosenwasser DanielRosenwasser added this to the TypeScript 5.1.0 milestone Feb 25, 2023
@DanielRosenwasser DanielRosenwasser added API Relates to the public API for TypeScript Domain: TSServer Issues related to the TSServer and removed In Discussion Not yet reached consensus labels Feb 25, 2023
mjbvz added a commit to mjbvz/vscode that referenced this issue Mar 6, 2023
For microsoft/TypeScript#51832

Not actually implemented on TS yet
@mjbvz
Copy link
Contributor

mjbvz commented Mar 6, 2023

@iisaduan I've updated the proposed protocol to more closely match VS Code / LSP. Here's the LSP linked editing spec for reference: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_linkedEditingRange

This PR against VS Code also stubs out this feature using the proposed API: microsoft/vscode#176279 Let me know once you have something on the TS side and I will update the VS Code PR to match the actual protocol

mjbvz added a commit to mjbvz/vscode that referenced this issue Mar 28, 2023
For microsoft/TypeScript#51832

Not actually implemented on TS yet
mjbvz added a commit to mjbvz/vscode that referenced this issue Apr 3, 2023
@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Apr 7, 2023
@RyanCavanaugh RyanCavanaugh added the Committed The team has roadmapped this issue label Apr 7, 2023
mjbvz added a commit to mjbvz/vscode that referenced this issue Apr 10, 2023
mjbvz added a commit to microsoft/vscode that referenced this issue Apr 10, 2023
* Add stubs jsx linked editing

For microsoft/TypeScript#51832

* Update for new TS changes

* Update to finalized protocol
@Cristy94
Copy link

I see this issue is closed, but it still doesn't work for me. Is JSX linked editing supported?

@andresribeiro
Copy link

andresribeiro commented Sep 20, 2023

@Cristy94 be sure that "editor.linkedEditing": true is set on settings.json. it's disabled by default

@Cristy94
Copy link

@Cristy94 be sure that "editor.linkedEditing": true is set on settings.json. it's disabled by default

Am I missing anything? Is there a shortcut for it? I didn't find any documentation for this feature.
If I just edit the opening tag of a <div></div> element, the end tag is not updated.
If I use CTRL+F2, all occurrences of "div" in that document are replaced.

@Cristy94
Copy link

Cristy94 commented Sep 24, 2023

It seems to work for HTML (as expected, automatically edit, no keyboard shortcut needed). But for .jsx and .tsx it doesn't work or highlight the tags.

image image image

@Cristy94
Copy link

Found the issue, it doesn't work in TypeScript 5.0, and my editor was using the wrong version:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API Relates to the public API for TypeScript Committed The team has roadmapped this issue Domain: TSServer Issues related to the TSServer Fix Available A PR has been opened for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.