lsp: Add support for linked editing range edits (HTML tag autorenaming) (#12769)
This PR adds support for [linked editing of ranges](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_linkedEditingRange), which in short means that editing one part of a file can now change related parts in that same file. Think of automatically renaming HTML/TSX closing tags when the opening one is changed. TODO: - [x] proto changes - [x] Allow disabling linked editing ranges on a per language basis. Fixes #4535 Release Notes: - Added support for linked editing ranges LSP request. Editing opening tags in HTML/TSX files (with vtsls) performs the same edit on the closing tag as well (and vice versa). It can be turned off on a language-by-language basis with the following setting: ``` "languages": { "HTML": { "linked_edits": true }, } ``` --------- Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
parent
98659eabf1
commit
b6ea393d14
9 changed files with 574 additions and 8 deletions
|
@ -42,7 +42,9 @@ use gpui::{
|
|||
use http::{HttpClient, Url};
|
||||
use itertools::Itertools;
|
||||
use language::{
|
||||
language_settings::{language_settings, FormatOnSave, Formatter, InlayHintKind},
|
||||
language_settings::{
|
||||
language_settings, AllLanguageSettings, FormatOnSave, Formatter, InlayHintKind,
|
||||
},
|
||||
markdown, point_to_lsp, prepare_completion_documentation,
|
||||
proto::{
|
||||
deserialize_anchor, deserialize_line_ending, deserialize_version, serialize_anchor,
|
||||
|
@ -712,6 +714,7 @@ impl Project {
|
|||
client.add_model_request_handler(Self::handle_restart_language_servers);
|
||||
client.add_model_request_handler(Self::handle_task_context_for_location);
|
||||
client.add_model_request_handler(Self::handle_task_templates);
|
||||
client.add_model_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
|
||||
}
|
||||
|
||||
pub fn local(
|
||||
|
@ -5804,6 +5807,62 @@ impl Project {
|
|||
self.hover_impl(buffer, position, cx)
|
||||
}
|
||||
|
||||
fn linked_edit_impl(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
position: Anchor,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Vec<Range<Anchor>>>> {
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let scope = snapshot.language_scope_at(position);
|
||||
let Some(server_id) = self
|
||||
.language_servers_for_buffer(buffer.read(cx), cx)
|
||||
.filter(|(_, server)| {
|
||||
server
|
||||
.capabilities()
|
||||
.linked_editing_range_provider
|
||||
.is_some()
|
||||
})
|
||||
.filter(|(adapter, _)| {
|
||||
scope
|
||||
.as_ref()
|
||||
.map(|scope| scope.language_allowed(&adapter.name))
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
|
||||
.next()
|
||||
.or_else(|| self.is_remote().then_some(LanguageServerToQuery::Primary))
|
||||
.filter(|_| {
|
||||
maybe!({
|
||||
let language_name = buffer.read(cx).language_at(position)?.name();
|
||||
Some(
|
||||
AllLanguageSettings::get_global(cx)
|
||||
.language(Some(&language_name))
|
||||
.linked_edits,
|
||||
)
|
||||
}) == Some(true)
|
||||
})
|
||||
else {
|
||||
return Task::ready(Ok(vec![]));
|
||||
};
|
||||
|
||||
self.request_lsp(
|
||||
buffer.clone(),
|
||||
server_id,
|
||||
LinkedEditingRange { position },
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn linked_edit(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
position: Anchor,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Vec<Range<Anchor>>>> {
|
||||
self.linked_edit_impl(buffer, position, cx)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn completions_impl(
|
||||
&self,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue