Skip to content

Commit de09092

Browse files
committed
Move LSP inlay hints to the event system
1 parent 5194c52 commit de09092

File tree

9 files changed

+412
-219
lines changed

9 files changed

+412
-219
lines changed

helix-lsp/src/client.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ impl Client {
10941094
text_document: lsp::TextDocumentIdentifier,
10951095
range: lsp::Range,
10961096
work_done_token: Option<lsp::ProgressToken>,
1097-
) -> Option<impl Future<Output = Result<Value>>> {
1097+
) -> Option<impl Future<Output = Result<Option<Vec<lsp::InlayHint>>>>> {
10981098
let capabilities = self.capabilities.get().unwrap();
10991099

11001100
match capabilities.inlay_hint_provider {
@@ -1111,7 +1111,8 @@ impl Client {
11111111
work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
11121112
};
11131113

1114-
Some(self.call::<lsp::request::InlayHintRequest>(params))
1114+
let res = self.call::<lsp::request::InlayHintRequest>(params);
1115+
Some(async move { Ok(serde_json::from_value(res.await?)?) })
11151116
}
11161117

11171118
pub fn text_document_hover(

helix-term/src/commands/lsp.rs

Lines changed: 2 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,9 @@ use tui::{text::Span, widgets::Row};
1313

1414
use super::{align_view, push_jump, Align, Context, Editor};
1515

16-
use helix_core::{
17-
syntax::LanguageServerFeature, text_annotations::InlineAnnotation, Selection, Uri,
18-
};
16+
use helix_core::{syntax::LanguageServerFeature, Selection, Uri};
1917
use helix_stdx::path;
20-
use helix_view::{
21-
document::{DocumentInlayHints, DocumentInlayHintsId},
22-
editor::Action,
23-
handlers::lsp::SignatureHelpInvoked,
24-
theme::Style,
25-
Document, View,
26-
};
18+
use helix_view::{editor::Action, handlers::lsp::SignatureHelpInvoked, theme::Style};
2719

2820
use crate::{
2921
compositor::{self, Compositor},
@@ -1286,164 +1278,3 @@ pub fn select_references_to_symbol_under_cursor(cx: &mut Context) {
12861278
},
12871279
);
12881280
}
1289-
1290-
pub fn compute_inlay_hints_for_all_views(editor: &mut Editor, jobs: &mut crate::job::Jobs) {
1291-
if !editor.config().lsp.display_inlay_hints {
1292-
return;
1293-
}
1294-
1295-
for (view, _) in editor.tree.views() {
1296-
let doc = match editor.documents.get(&view.doc) {
1297-
Some(doc) => doc,
1298-
None => continue,
1299-
};
1300-
if let Some(callback) = compute_inlay_hints_for_view(view, doc) {
1301-
jobs.callback(callback);
1302-
}
1303-
}
1304-
}
1305-
1306-
fn compute_inlay_hints_for_view(
1307-
view: &View,
1308-
doc: &Document,
1309-
) -> Option<std::pin::Pin<Box<impl Future<Output = Result<crate::job::Callback, anyhow::Error>>>>> {
1310-
let view_id = view.id;
1311-
let doc_id = view.doc;
1312-
1313-
let language_server = doc
1314-
.language_servers_with_feature(LanguageServerFeature::InlayHints)
1315-
.next()?;
1316-
1317-
let doc_text = doc.text();
1318-
let len_lines = doc_text.len_lines();
1319-
1320-
// Compute ~3 times the current view height of inlay hints, that way some scrolling
1321-
// will not show half the view with hints and half without while still being faster
1322-
// than computing all the hints for the full file (which could be dozens of time
1323-
// longer than the view is).
1324-
let view_height = view.inner_height();
1325-
let first_visible_line =
1326-
doc_text.char_to_line(doc.view_offset(view_id).anchor.min(doc_text.len_chars()));
1327-
let first_line = first_visible_line.saturating_sub(view_height);
1328-
let last_line = first_visible_line
1329-
.saturating_add(view_height.saturating_mul(2))
1330-
.min(len_lines);
1331-
1332-
let new_doc_inlay_hints_id = DocumentInlayHintsId {
1333-
first_line,
1334-
last_line,
1335-
};
1336-
// Don't recompute the annotations in case nothing has changed about the view
1337-
if !doc.inlay_hints_oudated
1338-
&& doc
1339-
.inlay_hints(view_id)
1340-
.is_some_and(|dih| dih.id == new_doc_inlay_hints_id)
1341-
{
1342-
return None;
1343-
}
1344-
1345-
let doc_slice = doc_text.slice(..);
1346-
let first_char_in_range = doc_slice.line_to_char(first_line);
1347-
let last_char_in_range = doc_slice.line_to_char(last_line);
1348-
1349-
let range = helix_lsp::util::range_to_lsp_range(
1350-
doc_text,
1351-
helix_core::Range::new(first_char_in_range, last_char_in_range),
1352-
language_server.offset_encoding(),
1353-
);
1354-
1355-
let offset_encoding = language_server.offset_encoding();
1356-
1357-
let callback = super::make_job_callback(
1358-
language_server.text_document_range_inlay_hints(doc.identifier(), range, None)?,
1359-
move |editor, _compositor, response: Option<Vec<lsp::InlayHint>>| {
1360-
// The config was modified or the window was closed while the request was in flight
1361-
if !editor.config().lsp.display_inlay_hints || editor.tree.try_get(view_id).is_none() {
1362-
return;
1363-
}
1364-
1365-
// Add annotations to relevant document, not the current one (it may have changed in between)
1366-
let doc = match editor.documents.get_mut(&doc_id) {
1367-
Some(doc) => doc,
1368-
None => return,
1369-
};
1370-
1371-
// If we have neither hints nor an LSP, empty the inlay hints since they're now oudated
1372-
let mut hints = match response {
1373-
Some(hints) if !hints.is_empty() => hints,
1374-
_ => {
1375-
doc.set_inlay_hints(
1376-
view_id,
1377-
DocumentInlayHints::empty_with_id(new_doc_inlay_hints_id),
1378-
);
1379-
doc.inlay_hints_oudated = false;
1380-
return;
1381-
}
1382-
};
1383-
1384-
// Most language servers will already send them sorted but ensure this is the case to
1385-
// avoid errors on our end.
1386-
hints.sort_by_key(|inlay_hint| inlay_hint.position);
1387-
1388-
let mut padding_before_inlay_hints = Vec::new();
1389-
let mut type_inlay_hints = Vec::new();
1390-
let mut parameter_inlay_hints = Vec::new();
1391-
let mut other_inlay_hints = Vec::new();
1392-
let mut padding_after_inlay_hints = Vec::new();
1393-
1394-
let doc_text = doc.text();
1395-
1396-
for hint in hints {
1397-
let char_idx =
1398-
match helix_lsp::util::lsp_pos_to_pos(doc_text, hint.position, offset_encoding)
1399-
{
1400-
Some(pos) => pos,
1401-
// Skip inlay hints that have no "real" position
1402-
None => continue,
1403-
};
1404-
1405-
let label = match hint.label {
1406-
lsp::InlayHintLabel::String(s) => s,
1407-
lsp::InlayHintLabel::LabelParts(parts) => parts
1408-
.into_iter()
1409-
.map(|p| p.value)
1410-
.collect::<Vec<_>>()
1411-
.join(""),
1412-
};
1413-
1414-
let inlay_hints_vec = match hint.kind {
1415-
Some(lsp::InlayHintKind::TYPE) => &mut type_inlay_hints,
1416-
Some(lsp::InlayHintKind::PARAMETER) => &mut parameter_inlay_hints,
1417-
// We can't warn on unknown kind here since LSPs are free to set it or not, for
1418-
// example Rust Analyzer does not: every kind will be `None`.
1419-
_ => &mut other_inlay_hints,
1420-
};
1421-
1422-
if let Some(true) = hint.padding_left {
1423-
padding_before_inlay_hints.push(InlineAnnotation::new(char_idx, " "));
1424-
}
1425-
1426-
inlay_hints_vec.push(InlineAnnotation::new(char_idx, label));
1427-
1428-
if let Some(true) = hint.padding_right {
1429-
padding_after_inlay_hints.push(InlineAnnotation::new(char_idx, " "));
1430-
}
1431-
}
1432-
1433-
doc.set_inlay_hints(
1434-
view_id,
1435-
DocumentInlayHints {
1436-
id: new_doc_inlay_hints_id,
1437-
type_inlay_hints,
1438-
parameter_inlay_hints,
1439-
other_inlay_hints,
1440-
padding_before_inlay_hints,
1441-
padding_after_inlay_hints,
1442-
},
1443-
);
1444-
doc.inlay_hints_oudated = false;
1445-
},
1446-
);
1447-
1448-
Some(callback)
1449-
}

helix-term/src/commands/typed.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,8 +1562,6 @@ fn lsp_stop(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> any
15621562
for doc in cx.editor.documents_mut() {
15631563
if let Some(client) = doc.remove_language_server_by_name(ls_name) {
15641564
doc.clear_diagnostics(Some(client.id()));
1565-
doc.reset_all_inlay_hints();
1566-
doc.inlay_hints_oudated = true;
15671565
}
15681566
}
15691567
}

helix-term/src/handlers.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,30 @@ use helix_event::AsyncHook;
66
use crate::config::Config;
77
use crate::events;
88
use crate::handlers::auto_save::AutoSaveHandler;
9+
use crate::handlers::inlay_hints::InlayHintHandler;
910
use crate::handlers::signature_help::SignatureHelpHandler;
1011

1112
pub use helix_view::handlers::Handlers;
1213

1314
mod auto_save;
1415
pub mod completion;
1516
mod diagnostics;
17+
mod inlay_hints;
1618
mod signature_help;
1719
mod snippet;
1820

1921
pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers {
2022
events::register();
2123

22-
let event_tx = completion::CompletionHandler::new(config).spawn();
24+
let completion_sender = completion::CompletionHandler::new(config).spawn();
2325
let signature_hints = SignatureHelpHandler::new().spawn();
26+
let inlay_hint_sender = InlayHintHandler::new().spawn();
2427
let auto_save = AutoSaveHandler::new().spawn();
2528

2629
let handlers = Handlers {
27-
completions: helix_view::handlers::completion::CompletionHandler::new(event_tx),
30+
completions: helix_view::handlers::completion::CompletionHandler::new(completion_sender),
2831
signature_hints,
32+
inlay_hints: helix_view::handlers::lsp::InlayHintHandler::new(inlay_hint_sender),
2933
auto_save,
3034
};
3135

@@ -35,5 +39,6 @@ pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers {
3539
auto_save::register_hooks(&handlers);
3640
diagnostics::register_hooks(&handlers);
3741
snippet::register_hooks(&handlers);
42+
inlay_hints::register_hooks(&handlers);
3843
handlers
3944
}

0 commit comments

Comments
 (0)