Skip to content

feat(language-service): add linked editing ranges for HTML tag synchronization#66738

Merged
leonsenft merged 1 commit intoangular:mainfrom
kbrilla:feat/linked-editing-ranges
Feb 4, 2026
Merged

feat(language-service): add linked editing ranges for HTML tag synchronization#66738
leonsenft merged 1 commit intoangular:mainfrom
kbrilla:feat/linked-editing-ranges

Conversation

@kbrilla
Copy link
Copy Markdown
Contributor

@kbrilla kbrilla commented Jan 24, 2026

PR Description

This PR adds support for Linked Editing Ranges (LSP 3.16) in the Angular Language Service to enable synchronized editing of opening and closing HTML tag pairs in Angular templates.

What is Linked Editing?

Linked editing allows users to edit matching HTML tags simultaneously. When the cursor is on an element's tag name, both the opening and closing tags are linked, so changes to one automatically update the other.

Changes

Language Service (packages/language-service):

  • Add linked_editing_range.ts implementing getLinkedEditingRangeAtPosition()
  • Add getLinkedEditingRangeAtPosition method to NgLanguageService interface
  • Register the method in language_service.ts

VS Code Extension (vscode-ng-language-service):

  • Add linked_editing_range.ts handler
  • Register handler for textDocument/linkedEditingRange in session.ts
  • Add linkedEditingRangeProvider capability in initialization.ts

Features

  • Works in both external HTML template files and inline templates in TypeScript
  • Returns word pattern [-\w]+ for valid tag names
  • Only activates when cursor is directly on the tag name (not attributes)
  • Excludes self-closing and void elements (no closing tag to link)

Testing

  • All existing tests pass
  • Manual testing confirms synchronized tag editing in VS Code

Related

Fixes #66736

Checklist

  • Tests pass
  • Works with external HTML templates
  • Works with inline templates in TypeScript
  • Capability properly registered

@pullapprove pullapprove Bot requested a review from mmalerba January 24, 2026 10:55
@angular-robot angular-robot Bot added detected: feature PR contains a feature commit area: language-service Issues related to Angular's VS Code language service labels Jan 24, 2026
@ngbot ngbot Bot added this to the Backlog milestone Jan 24, 2026
@mmalerba mmalerba requested review from atscott and removed request for mmalerba January 25, 2026 17:28
@atscott
Copy link
Copy Markdown
Contributor

atscott commented Jan 26, 2026

@kbrilla Can you add a demo for how exactly this works?

@angular-robot angular-robot Bot requested a review from atscott January 26, 2026 18:27
kbrilla added a commit to kbrilla/angular that referenced this pull request Jan 26, 2026
…onization

This adds support for linked editing ranges in Angular templates, allowing
VS Code to synchronize the editing of matching HTML opening and closing tags.
When you rename an opening tag, the closing tag is automatically renamed too.

The implementation:
- Adds a new linked_editing_range.ts module
- Uses the Angular template AST to find matching tag pairs
- Works in both inline templates and external HTML template files
- Handles components, directives, and standard HTML elements

PR Close angular#66738
@kbrilla kbrilla force-pushed the feat/linked-editing-ranges branch from 1434ea6 to 5d819d4 Compare January 26, 2026 18:36
…onization

This feature enables synchronized editing of opening and closing HTML tag pairs
in Angular inline templates. When the cursor is on an element tag name, editing
it will automatically update the corresponding tag.

Implementation:
- Add getLinkedEditingRangeAtPosition method to NgLanguageService interface
- Implement linked editing range detection for opening and closing tags
- Handle edge cases: self-closing elements, void elements, cursor detection
- Export through ts_plugin wrapper to override TypeScript JSX-only implementation
- For external HTML templates, VS Code built-in HTML support handles linked editing
@kbrilla kbrilla force-pushed the feat/linked-editing-ranges branch from 5d819d4 to ee36f64 Compare January 26, 2026 22:08
@kbrilla
Copy link
Copy Markdown
Contributor Author

kbrilla commented Jan 26, 2026

@kbrilla Can you add a demo for how exactly this works?

What is Linked Editing?

Linked editing (also known as "mirror cursor" or "rename on type") allows you to edit matching HTML tag pairs simultaneously. When you rename an opening tag, the closing tag updates automatically, and vice versa.

How to Enable

Option 1: Always-On (Settings)

Linked editing is enabled by default in VS Code. If it's not working, check your settings:

  1. Open VS Code Settings (Cmd+, on macOS or Ctrl+, on Windows/Linux)
  2. Search for "linked editing"
  3. Ensure "Editor: Linked Editing" is checked (editor.linkedEditing: true)

Alternatively, add to your settings.json:

{
  "editor.linkedEditing": true
}

Option 2: On-Demand (Command)

If you don't want linked editing always active, you can trigger it on-demand:

  1. Place your cursor on an HTML tag name
  2. Open Command Palette (Cmd+Shift+P on macOS or Ctrl+Shift+P on Windows/Linux)
  3. Run "Start Linked Editing"
  4. Or use the keyboard shortcut: ⇧⌘F2 (macOS) / Ctrl+Shift+F2 (Windows/Linux)

This temporarily activates linked editing for the current tag pair until you move your cursor away.
image

How to Use

  1. Place your cursor on an HTML tag name in an inline Angular template (within a .ts file)
  2. Start typing to rename the tag
  3. The corresponding opening/closing tag will update automatically

Example

@Component({
  template: `
    <div class="container">     <!-- Place cursor on "div" here -->
      <span>Hello</span>
    </div>                      <!-- "div" here updates automatically -->
  `
})
image image image

Supported Scenarios

Scenario Supported
Inline templates in .ts files ✅ Yes
External .html template files ✅ Yes (via VS Code's built-in HTML support)
Opening tag → Closing tag ✅ Yes
Closing tag → Opening tag ✅ Yes
Custom Angular component selectors (e.g., <app-my-component>) ✅ Yes
Nested elements ✅ Yes

Excluded Scenarios

Scenario Reason
Self-closing tags (<input />, <br />) No closing tag to link
Void elements (<input>, <br>, <img>, etc.) HTML5 void elements have no closing tag
Cursor on attributes or content Must be on the tag name itself

Technical Details

  • Uses the LSP textDocument/linkedEditingRange request
  • For inline templates: Angular Language Service handles the request
  • For external HTML templates: VS Code's built-in HTML Language Support handles it
  • Word pattern: [-\w]+ (allows hyphens for custom element names)

Troubleshooting

Linked editing not working in inline templates?

  1. Make sure you have the Angular Language Service extension installed and active
  2. Check that the file is a TypeScript file with an Angular @Component decorator
  3. Ensure your cursor is directly on the tag name (not on < or attributes)
  4. Restart the Angular Language Server: Cmd+Shift+P → "Angular: Restart Angular Language server"

Works in HTML but not in TypeScript?

The Angular Language Service specifically handles inline templates. Make sure:

  • The extension version includes this feature (v21.0.0+)
  • The template is properly defined with template: (not templateUrl:)

@kbrilla
Copy link
Copy Markdown
Contributor Author

kbrilla commented Jan 26, 2026

@atscott if I could ask for You to review code again as there were issues with not overriding ts implementation of getLinkedEditingRangeAtPosition which i did not catch https://github.com/angular/angular/compare/5d819d40f66ab349fc71fdfdb7fae4c2d65a0430..ee36f64e78ee7cb0a0a4460b53d2a0ddc4682f1b#diff-d101cf9913b0899c7728f93db6b858a1fd05a0605cc0ea14dd97db2dc28a4c28

Comment thread packages/language-service/src/ts_plugin.ts
@atscott atscott added action: merge The PR is ready for merge by the caretaker target: minor This PR is targeted for the next minor release labels Feb 4, 2026
@leonsenft leonsenft merged commit 8c21866 into angular:main Feb 4, 2026
22 checks passed
@leonsenft
Copy link
Copy Markdown
Contributor

This PR was merged into the repository. The changes were merged into the following branches:

@angular-automatic-lock-bot
Copy link
Copy Markdown

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot Bot locked and limited conversation to collaborators Mar 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

action: merge The PR is ready for merge by the caretaker area: language-service Issues related to Angular's VS Code language service detected: feature PR contains a feature commit target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(language-service): Add Linked Editing Ranges for HTML tag synchronization

3 participants