Unnamed repository; edit this file 'description' to name the repository.
LSP commands: Move offset encoding onto the Location type
<https://github.com/helix-editor/helix/pull/11486> introduced a Location type in the LSP commands module which unified helpers like `jump_to_location`. This change moves `OffsetEncoding` onto that type. `SymbolInformationItem` and `PickerDiagnostic` already had fields for carrying the offset encoding. We would want a similar setup for goto definition/references as well (for supporting multiple language servers with that feature) but those use the `Location` type. By moving `OffsetEncoding` onto `Location` we make future changes to allow mulitple language servers possible for goto definition/references features and also simplify some calls for symbols and diagnostics.
Michael Davis 2025-01-30
parent c9dc940 · commit ba116b4
-rw-r--r--helix-term/src/commands/lsp.rs77
1 files changed, 41 insertions, 36 deletions
diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs
index a7151b40..24da6f55 100644
--- a/helix-term/src/commands/lsp.rs
+++ b/helix-term/src/commands/lsp.rs
@@ -61,14 +61,19 @@ macro_rules! language_server_with_feature {
}};
}
-/// A wrapper around `lsp::Location` that swaps out the LSP URI for `helix_core::Uri`.
+/// A wrapper around `lsp::Location` that swaps out the LSP URI for `helix_core::Uri` and adds
+/// the server's offset encoding.
#[derive(Debug, Clone, PartialEq, Eq)]
struct Location {
uri: Uri,
range: lsp::Range,
+ offset_encoding: OffsetEncoding,
}
-fn lsp_location_to_location(location: lsp::Location) -> Option<Location> {
+fn lsp_location_to_location(
+ location: lsp::Location,
+ offset_encoding: OffsetEncoding,
+) -> Option<Location> {
let uri = match location.uri.try_into() {
Ok(uri) => uri,
Err(err) => {
@@ -79,13 +84,13 @@ fn lsp_location_to_location(location: lsp::Location) -> Option<Location> {
Some(Location {
uri,
range: location.range,
+ offset_encoding,
})
}
struct SymbolInformationItem {
location: Location,
symbol: lsp::SymbolInformation,
- offset_encoding: OffsetEncoding,
}
struct DiagnosticStyles {
@@ -98,7 +103,6 @@ struct DiagnosticStyles {
struct PickerDiagnostic {
location: Location,
diag: lsp::Diagnostic,
- offset_encoding: OffsetEncoding,
}
fn location_to_file_location(location: &Location) -> Option<FileLocation> {
@@ -110,12 +114,7 @@ fn location_to_file_location(location: &Location) -> Option<FileLocation> {
Some((path.into(), line))
}
-fn jump_to_location(
- editor: &mut Editor,
- location: &Location,
- offset_encoding: OffsetEncoding,
- action: Action,
-) {
+fn jump_to_location(editor: &mut Editor, location: &Location, action: Action) {
let (view, doc) = current!(editor);
push_jump(view, doc);
@@ -124,7 +123,13 @@ fn jump_to_location(
editor.set_error(err);
return;
};
- jump_to_position(editor, path, location.range, offset_encoding, action);
+ jump_to_position(
+ editor,
+ path,
+ location.range,
+ location.offset_encoding,
+ action,
+ );
}
fn jump_to_position(
@@ -220,9 +225,9 @@ fn diag_picker(
location: Location {
uri: uri.clone(),
range: diag.range,
+ offset_encoding: ls.offset_encoding(),
},
diag,
- offset_encoding: ls.offset_encoding(),
});
}
}
@@ -286,7 +291,7 @@ fn diag_picker(
flat_diag,
styles,
move |cx, diag, action| {
- jump_to_location(cx.editor, &diag.location, diag.offset_encoding, action);
+ jump_to_location(cx.editor, &diag.location, action);
let (view, doc) = current!(cx.editor);
view.diagnostics_handler
.immediately_show_diagnostic(doc, view.id);
@@ -314,10 +319,10 @@ pub fn symbol_picker(cx: &mut Context) {
location: lsp::Location::new(file.uri.clone(), symbol.selection_range),
container_name: None,
},
- offset_encoding,
location: Location {
uri: uri.clone(),
range: symbol.selection_range,
+ offset_encoding,
},
});
for child in symbol.children.into_iter().flatten() {
@@ -355,9 +360,9 @@ pub fn symbol_picker(cx: &mut Context) {
location: Location {
uri: doc_uri.clone(),
range: symbol.location.range,
+ offset_encoding,
},
symbol,
- offset_encoding,
})
.collect(),
lsp::DocumentSymbolResponse::Nested(symbols) => {
@@ -410,7 +415,7 @@ pub fn symbol_picker(cx: &mut Context) {
symbols,
(),
move |cx, item, action| {
- jump_to_location(cx.editor, &item.location, item.offset_encoding, action);
+ jump_to_location(cx.editor, &item.location, action);
},
)
.with_preview(move |_editor, item| location_to_file_location(&item.location))
@@ -467,9 +472,9 @@ pub fn workspace_symbol_picker(cx: &mut Context) {
location: Location {
uri,
range: symbol.location.range,
+ offset_encoding,
},
symbol,
- offset_encoding,
})
})
.collect();
@@ -521,7 +526,7 @@ pub fn workspace_symbol_picker(cx: &mut Context) {
[],
(),
move |cx, item, action| {
- jump_to_location(cx.editor, &item.location, item.offset_encoding, action);
+ jump_to_location(cx.editor, &item.location, action);
},
)
.with_preview(|_editor, item| location_to_file_location(&item.location))
@@ -853,17 +858,12 @@ impl Display for ApplyEditErrorKind {
}
/// Precondition: `locations` should be non-empty.
-fn goto_impl(
- editor: &mut Editor,
- compositor: &mut Compositor,
- locations: Vec<Location>,
- offset_encoding: OffsetEncoding,
-) {
+fn goto_impl(editor: &mut Editor, compositor: &mut Compositor, locations: Vec<Location>) {
let cwdir = helix_stdx::env::current_working_dir();
match locations.as_slice() {
[location] => {
- jump_to_location(editor, location, offset_encoding, Action::Replace);
+ jump_to_location(editor, location, Action::Replace);
}
[] => unreachable!("`locations` should be non-empty for `goto_impl`"),
_locations => {
@@ -880,30 +880,35 @@ fn goto_impl(
},
)];
- let picker = Picker::new(columns, 0, locations, cwdir, move |cx, location, action| {
- jump_to_location(cx.editor, location, offset_encoding, action)
+ let picker = Picker::new(columns, 0, locations, cwdir, |cx, location, action| {
+ jump_to_location(cx.editor, location, action)
})
- .with_preview(move |_editor, location| location_to_file_location(location));
+ .with_preview(|_editor, location| location_to_file_location(location));
compositor.push(Box::new(overlaid(picker)));
}
}
}
-fn to_locations(definitions: Option<lsp::GotoDefinitionResponse>) -> Vec<Location> {
+fn to_locations(
+ definitions: Option<lsp::GotoDefinitionResponse>,
+ offset_encoding: OffsetEncoding,
+) -> Vec<Location> {
match definitions {
Some(lsp::GotoDefinitionResponse::Scalar(location)) => {
- lsp_location_to_location(location).into_iter().collect()
+ lsp_location_to_location(location, offset_encoding)
+ .into_iter()
+ .collect()
}
Some(lsp::GotoDefinitionResponse::Array(locations)) => locations
.into_iter()
- .flat_map(lsp_location_to_location)
+ .flat_map(|location| lsp_location_to_location(location, offset_encoding))
.collect(),
Some(lsp::GotoDefinitionResponse::Link(locations)) => locations
.into_iter()
.map(|location_link| {
lsp::Location::new(location_link.target_uri, location_link.target_range)
})
- .flat_map(lsp_location_to_location)
+ .flat_map(|location| lsp_location_to_location(location, offset_encoding))
.collect(),
None => Vec::new(),
}
@@ -924,11 +929,11 @@ where
cx.callback(
future,
move |editor, compositor, response: Option<lsp::GotoDefinitionResponse>| {
- let items = to_locations(response);
+ let items = to_locations(response, offset_encoding);
if items.is_empty() {
editor.set_error("No definition found.");
} else {
- goto_impl(editor, compositor, items, offset_encoding);
+ goto_impl(editor, compositor, items);
}
},
);
@@ -991,12 +996,12 @@ pub fn goto_reference(cx: &mut Context) {
let items: Vec<Location> = response
.into_iter()
.flatten()
- .flat_map(lsp_location_to_location)
+ .flat_map(|location| lsp_location_to_location(location, offset_encoding))
.collect();
if items.is_empty() {
editor.set_error("No references found.");
} else {
- goto_impl(editor, compositor, items, offset_encoding);
+ goto_impl(editor, compositor, items);
}
},
);