Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--helix-term/src/commands/lsp.rs174
-rw-r--r--helix-term/src/commands/typed.rs2
-rw-r--r--helix-term/src/handlers.rs5
-rw-r--r--helix-term/src/handlers/inlay_hints.rs338
-rw-r--r--helix-term/src/ui/editor.rs8
-rw-r--r--helix-view/src/document.rs41
-rw-r--r--helix-view/src/handlers.rs1
-rw-r--r--helix-view/src/handlers/lsp.rs15
8 files changed, 368 insertions, 216 deletions
diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs
index 8377f7c7..f4abf6e8 100644
--- a/helix-term/src/commands/lsp.rs
+++ b/helix-term/src/commands/lsp.rs
@@ -13,18 +13,9 @@ use tui::{text::Span, widgets::Row};
use super::{align_view, push_jump, Align, Context, Editor};
-use helix_core::{
- diagnostic::DiagnosticProvider, syntax::LanguageServerFeature,
- text_annotations::InlineAnnotation, Selection, Uri,
-};
+use helix_core::{diagnostic::DiagnosticProvider, syntax::LanguageServerFeature, Selection, Uri};
use helix_stdx::path;
-use helix_view::{
- document::{DocumentInlayHints, DocumentInlayHintsId},
- editor::Action,
- handlers::lsp::SignatureHelpInvoked,
- theme::Style,
- Document, View,
-};
+use helix_view::{editor::Action, handlers::lsp::SignatureHelpInvoked, theme::Style};
use crate::{
compositor::{self, Compositor},
@@ -1251,164 +1242,3 @@ pub fn select_references_to_symbol_under_cursor(cx: &mut Context) {
},
);
}
-
-pub fn compute_inlay_hints_for_all_views(editor: &mut Editor, jobs: &mut crate::job::Jobs) {
- if !editor.config().lsp.display_inlay_hints {
- return;
- }
-
- for (view, _) in editor.tree.views() {
- let doc = match editor.documents.get(&view.doc) {
- Some(doc) => doc,
- None => continue,
- };
- if let Some(callback) = compute_inlay_hints_for_view(view, doc) {
- jobs.callback(callback);
- }
- }
-}
-
-fn compute_inlay_hints_for_view(
- view: &View,
- doc: &Document,
-) -> Option<std::pin::Pin<Box<impl Future<Output = Result<crate::job::Callback, anyhow::Error>>>>> {
- let view_id = view.id;
- let doc_id = view.doc;
-
- let language_server = doc
- .language_servers_with_feature(LanguageServerFeature::InlayHints)
- .next()?;
-
- let doc_text = doc.text();
- let len_lines = doc_text.len_lines();
-
- // Compute ~3 times the current view height of inlay hints, that way some scrolling
- // will not show half the view with hints and half without while still being faster
- // than computing all the hints for the full file (which could be dozens of time
- // longer than the view is).
- let view_height = view.inner_height();
- let first_visible_line =
- doc_text.char_to_line(doc.view_offset(view_id).anchor.min(doc_text.len_chars()));
- let first_line = first_visible_line.saturating_sub(view_height);
- let last_line = first_visible_line
- .saturating_add(view_height.saturating_mul(2))
- .min(len_lines);
-
- let new_doc_inlay_hints_id = DocumentInlayHintsId {
- first_line,
- last_line,
- };
- // Don't recompute the annotations in case nothing has changed about the view
- if !doc.inlay_hints_oudated
- && doc
- .inlay_hints(view_id)
- .is_some_and(|dih| dih.id == new_doc_inlay_hints_id)
- {
- return None;
- }
-
- let doc_slice = doc_text.slice(..);
- let first_char_in_range = doc_slice.line_to_char(first_line);
- let last_char_in_range = doc_slice.line_to_char(last_line);
-
- let range = helix_lsp::util::range_to_lsp_range(
- doc_text,
- helix_core::Range::new(first_char_in_range, last_char_in_range),
- language_server.offset_encoding(),
- );
-
- let offset_encoding = language_server.offset_encoding();
-
- let callback = super::make_job_callback(
- language_server.text_document_range_inlay_hints(doc.identifier(), range, None)?,
- move |editor, _compositor, response: Option<Vec<lsp::InlayHint>>| {
- // The config was modified or the window was closed while the request was in flight
- if !editor.config().lsp.display_inlay_hints || editor.tree.try_get(view_id).is_none() {
- return;
- }
-
- // Add annotations to relevant document, not the current one (it may have changed in between)
- let doc = match editor.documents.get_mut(&doc_id) {
- Some(doc) => doc,
- None => return,
- };
-
- // If we have neither hints nor an LSP, empty the inlay hints since they're now oudated
- let mut hints = match response {
- Some(hints) if !hints.is_empty() => hints,
- _ => {
- doc.set_inlay_hints(
- view_id,
- DocumentInlayHints::empty_with_id(new_doc_inlay_hints_id),
- );
- doc.inlay_hints_oudated = false;
- return;
- }
- };
-
- // Most language servers will already send them sorted but ensure this is the case to
- // avoid errors on our end.
- hints.sort_by_key(|inlay_hint| inlay_hint.position);
-
- let mut padding_before_inlay_hints = Vec::new();
- let mut type_inlay_hints = Vec::new();
- let mut parameter_inlay_hints = Vec::new();
- let mut other_inlay_hints = Vec::new();
- let mut padding_after_inlay_hints = Vec::new();
-
- let doc_text = doc.text();
-
- for hint in hints {
- let char_idx =
- match helix_lsp::util::lsp_pos_to_pos(doc_text, hint.position, offset_encoding)
- {
- Some(pos) => pos,
- // Skip inlay hints that have no "real" position
- None => continue,
- };
-
- let label = match hint.label {
- lsp::InlayHintLabel::String(s) => s,
- lsp::InlayHintLabel::LabelParts(parts) => parts
- .into_iter()
- .map(|p| p.value)
- .collect::<Vec<_>>()
- .join(""),
- };
-
- let inlay_hints_vec = match hint.kind {
- Some(lsp::InlayHintKind::TYPE) => &mut type_inlay_hints,
- Some(lsp::InlayHintKind::PARAMETER) => &mut parameter_inlay_hints,
- // We can't warn on unknown kind here since LSPs are free to set it or not, for
- // example Rust Analyzer does not: every kind will be `None`.
- _ => &mut other_inlay_hints,
- };
-
- if let Some(true) = hint.padding_left {
- padding_before_inlay_hints.push(InlineAnnotation::new(char_idx, " "));
- }
-
- inlay_hints_vec.push(InlineAnnotation::new(char_idx, label));
-
- if let Some(true) = hint.padding_right {
- padding_after_inlay_hints.push(InlineAnnotation::new(char_idx, " "));
- }
- }
-
- doc.set_inlay_hints(
- view_id,
- DocumentInlayHints {
- id: new_doc_inlay_hints_id,
- type_inlay_hints,
- parameter_inlay_hints,
- other_inlay_hints,
- padding_before_inlay_hints,
- padding_after_inlay_hints,
- },
- );
- doc.inlay_hints_oudated = false;
- },
- );
-
- Some(callback)
-}
diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs
index 4e912127..b3d57b50 100644
--- a/helix-term/src/commands/typed.rs
+++ b/helix-term/src/commands/typed.rs
@@ -1623,8 +1623,6 @@ fn lsp_stop(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> any
for doc in cx.editor.documents_mut() {
if let Some(client) = doc.remove_language_server_by_name(ls_name) {
doc.clear_diagnostics_for_language_server(client.id());
- doc.reset_all_inlay_hints();
- doc.inlay_hints_oudated = true;
}
}
}
diff --git a/helix-term/src/handlers.rs b/helix-term/src/handlers.rs
index c7d71526..a0982a49 100644
--- a/helix-term/src/handlers.rs
+++ b/helix-term/src/handlers.rs
@@ -6,6 +6,7 @@ use helix_event::AsyncHook;
use crate::config::Config;
use crate::events;
use crate::handlers::auto_save::AutoSaveHandler;
+use crate::handlers::inlay_hints::InlayHintHandler;
use crate::handlers::signature_help::SignatureHelpHandler;
pub use helix_view::handlers::Handlers;
@@ -16,6 +17,7 @@ mod auto_save;
pub mod completion;
mod diagnostics;
mod document_colors;
+mod inlay_hints;
mod signature_help;
mod snippet;
@@ -24,12 +26,14 @@ pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers {
let event_tx = completion::CompletionHandler::new(config).spawn();
let signature_hints = SignatureHelpHandler::new().spawn();
+ let inlay_hints = InlayHintHandler::default().spawn();
let auto_save = AutoSaveHandler::new().spawn();
let document_colors = DocumentColorsHandler::default().spawn();
let handlers = Handlers {
completions: helix_view::handlers::completion::CompletionHandler::new(event_tx),
signature_hints,
+ inlay_hints,
auto_save,
document_colors,
};
@@ -41,5 +45,6 @@ pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers {
diagnostics::register_hooks(&handlers);
snippet::register_hooks(&handlers);
document_colors::register_hooks(&handlers);
+ inlay_hints::register_hooks(&handlers);
handlers
}
diff --git a/helix-term/src/handlers/inlay_hints.rs b/helix-term/src/handlers/inlay_hints.rs
new file mode 100644
index 00000000..e2d50a2b
--- /dev/null
+++ b/helix-term/src/handlers/inlay_hints.rs
@@ -0,0 +1,338 @@
+use std::{collections::HashSet, mem, time::Duration};
+
+use crate::job;
+
+use super::Handlers;
+
+use helix_core::{syntax::LanguageServerFeature, text_annotations::InlineAnnotation};
+use helix_event::{cancelable_future, register_hook, send_blocking};
+use helix_lsp::lsp;
+use helix_view::{
+ document::{DocumentInlayHints, DocumentInlayHintsId},
+ events::{
+ DocumentDidChange, DocumentDidOpen, LanguageServerExited, LanguageServerInitialized,
+ SelectionDidChange,
+ },
+ handlers::lsp::InlayHintEvent,
+ DocumentId, Editor, ViewId,
+};
+use tokio::time::Instant;
+
+#[derive(Debug, Default)]
+pub(super) struct InlayHintHandler {
+ views: HashSet<ViewId>,
+ docs: HashSet<DocumentId>,
+}
+
+const DOCUMENT_CHANGE_DEBOUNCE: Duration = Duration::from_millis(500);
+const VIEWPORT_SCROLL_DEBOUNCE: Duration = Duration::from_millis(100);
+
+impl helix_event::AsyncHook for InlayHintHandler {
+ type Event = InlayHintEvent;
+
+ fn handle_event(&mut self, event: Self::Event, timeout: Option<Instant>) -> Option<Instant> {
+ match event {
+ InlayHintEvent::DocumentChanged(doc) => {
+ self.docs.insert(doc);
+ Some(Instant::now() + DOCUMENT_CHANGE_DEBOUNCE)
+ }
+ InlayHintEvent::ViewportScrolled(view) => {
+ self.views.insert(view);
+ let mut new_timeout = Instant::now() + VIEWPORT_SCROLL_DEBOUNCE;
+ if let Some(timeout) = timeout {
+ new_timeout = new_timeout.max(timeout);
+ }
+ Some(new_timeout)
+ }
+ }
+ }
+
+ fn finish_debounce(&mut self) {
+ let mut views = mem::take(&mut self.views);
+ let docs = mem::take(&mut self.docs);
+
+ job::dispatch_blocking(move |editor, _compositor| {
+ // Drop any views which have been closed.
+ views.retain(|&view| editor.tree.contains(view));
+ // Add any views that show documents which changed.
+ views.extend(
+ editor
+ .tree
+ .views()
+ .filter_map(|(view, _)| docs.contains(&view.doc).then_some(view.id)),
+ );
+
+ for view in views {
+ let doc = editor.tree.get(view).doc;
+ let is_scroll = !docs.contains(&doc);
+ request_inlay_hints_for_view(editor, view, doc, is_scroll);
+ }
+ });
+ }
+}
+
+fn request_inlay_hints_for_view(
+ editor: &mut Editor,
+ view_id: ViewId,
+ doc_id: DocumentId,
+ is_scroll: bool,
+) {
+ if !editor.config().lsp.display_inlay_hints {
+ return;
+ }
+ let Some(doc) = editor.documents.get_mut(&doc_id) else {
+ return;
+ };
+ let Some(view) = editor.tree.try_get(view_id) else {
+ return;
+ };
+ let Some(language_server) = doc
+ .language_servers_with_feature(LanguageServerFeature::InlayHints)
+ .next()
+ else {
+ return;
+ };
+
+ let rope = doc.text();
+ let text = rope.slice(..);
+ let len_lines = text.len_lines();
+ let view_height = view.inner_height();
+ let first_visible_line =
+ text.char_to_line(doc.view_offset(view_id).anchor.min(text.len_chars()));
+ let first_line = first_visible_line.saturating_sub(view_height);
+ let last_line = first_visible_line
+ .saturating_add(view_height.saturating_mul(2))
+ .min(len_lines);
+ let new_doc_inlay_hints_id = DocumentInlayHintsId {
+ first_line,
+ last_line,
+ };
+ // If the view was updated by scrolling (rather than changing) and the viewport still has the
+ // the same position, we can reuse the hints.
+ if is_scroll
+ && doc
+ .inlay_hints(view_id)
+ .is_some_and(|hint| hint.id == new_doc_inlay_hints_id)
+ {
+ return;
+ }
+ let offset_encoding = language_server.offset_encoding();
+ let range = helix_lsp::util::range_to_lsp_range(
+ rope,
+ helix_core::Range::new(text.line_to_char(first_line), text.line_to_char(last_line)),
+ offset_encoding,
+ );
+ let future = language_server
+ .text_document_range_inlay_hints(doc.identifier(), range, None)
+ .expect("language server must return Some if it supports inlay hints");
+ let controller = doc.inlay_hint_controllers.entry(view_id).or_default();
+ let cancel = controller.restart();
+
+ tokio::spawn(async move {
+ match cancelable_future(future, cancel).await {
+ Some(Ok(res)) => {
+ job::dispatch(move |editor, _compositor| {
+ attach_inlay_hints(
+ editor,
+ view_id,
+ doc_id,
+ new_doc_inlay_hints_id,
+ offset_encoding,
+ res,
+ );
+ })
+ .await
+ }
+ Some(Err(err)) => log::error!("inlay hint request failed: {err}"),
+ None => (),
+ }
+ });
+}
+
+fn attach_inlay_hints(
+ editor: &mut Editor,
+ view_id: ViewId,
+ doc_id: DocumentId,
+ id: DocumentInlayHintsId,
+ offset_encoding: helix_lsp::OffsetEncoding,
+ response: Option<Vec<lsp::InlayHint>>,
+) {
+ if !editor.config().lsp.display_inlay_hints || editor.tree.try_get(view_id).is_none() {
+ return;
+ }
+
+ let Some(doc) = editor.documents.get_mut(&doc_id) else {
+ return;
+ };
+
+ let mut hints = match response {
+ Some(hints) if !hints.is_empty() => hints,
+ _ => {
+ doc.set_inlay_hints(view_id, DocumentInlayHints::empty_with_id(id));
+ return;
+ }
+ };
+
+ // Most language servers will already send them sorted but ensure this is the case to
+ // avoid errors on our end.
+ hints.sort_by_key(|inlay_hint| inlay_hint.position);
+
+ let mut padding_before_inlay_hints = Vec::new();
+ let mut type_inlay_hints = Vec::new();
+ let mut parameter_inlay_hints = Vec::new();
+ let mut other_inlay_hints = Vec::new();
+ let mut padding_after_inlay_hints = Vec::new();
+
+ let doc_text = doc.text();
+
+ for hint in hints {
+ let char_idx =
+ match helix_lsp::util::lsp_pos_to_pos(doc_text, hint.position, offset_encoding) {
+ Some(pos) => pos,
+ // Skip inlay hints that have no "real" position
+ None => continue,
+ };
+
+ let label = match hint.label {
+ lsp::InlayHintLabel::String(s) => s,
+ lsp::InlayHintLabel::LabelParts(parts) => parts
+ .into_iter()
+ .map(|p| p.value)
+ .collect::<Vec<_>>()
+ .join(""),
+ };
+
+ let inlay_hints_vec = match hint.kind {
+ Some(lsp::InlayHintKind::TYPE) => &mut type_inlay_hints,
+ Some(lsp::InlayHintKind::PARAMETER) => &mut parameter_inlay_hints,
+ // We can't warn on unknown kind here since LSPs are free to set it or not, for
+ // example Rust Analyzer does not: every kind will be `None`.
+ _ => &mut other_inlay_hints,
+ };
+
+ if let Some(true) = hint.padding_left {
+ padding_before_inlay_hints.push(InlineAnnotation::new(char_idx, " "));
+ }
+
+ inlay_hints_vec.push(InlineAnnotation::new(char_idx, label));
+
+ if let Some(true) = hint.padding_right {
+ padding_after_inlay_hints.push(InlineAnnotation::new(char_idx, " "));
+ }
+ }
+
+ doc.set_inlay_hints(
+ view_id,
+ DocumentInlayHints {
+ id,
+ type_inlay_hints,
+ parameter_inlay_hints,
+ other_inlay_hints,
+ padding_before_inlay_hints,
+ padding_after_inlay_hints,
+ },
+ );
+}
+
+pub(super) fn register_hooks(handlers: &Handlers) {
+ register_hook!(move |event: &mut DocumentDidOpen<'_>| {
+ // When a document is initially opened, request inlay hints for it.
+ let views: Vec<_> = event
+ .editor
+ .tree
+ .views()
+ .filter_map(|(view, _)| (view.doc == event.doc).then_some(view.id))
+ .collect();
+ for view in views {
+ request_inlay_hints_for_view(event.editor, view, event.doc, false);
+ }
+
+ Ok(())
+ });
+
+ let tx = handlers.inlay_hints.clone();
+ register_hook!(move |event: &mut DocumentDidChange<'_>| {
+ // Update the inlay hint annotations' positions, helping ensure they are displayed in the
+ // proper place.
+ let apply_inlay_hint_changes = |annotations: &mut Vec<InlineAnnotation>| {
+ event.changes.update_positions(
+ annotations
+ .iter_mut()
+ .map(|annotation| (&mut annotation.char_idx, helix_core::Assoc::After)),
+ );
+ };
+
+ for (_view_id, text_annotation) in event.doc.inlay_hints_mut() {
+ let DocumentInlayHints {
+ id: _,
+ type_inlay_hints,
+ parameter_inlay_hints,
+ other_inlay_hints,
+ padding_before_inlay_hints,
+ padding_after_inlay_hints,
+ } = text_annotation;
+
+ apply_inlay_hint_changes(padding_before_inlay_hints);
+ apply_inlay_hint_changes(type_inlay_hints);
+ apply_inlay_hint_changes(parameter_inlay_hints);
+ apply_inlay_hint_changes(other_inlay_hints);
+ apply_inlay_hint_changes(padding_after_inlay_hints);
+ }
+
+ if !event.ghost_transaction {
+ if let Some(controller) = event.doc.inlay_hint_controllers.get_mut(&event.view) {
+ controller.cancel();
+ }
+ // TODO: ideally we should only send this if the document is visible.
+ send_blocking(&tx, InlayHintEvent::DocumentChanged(event.doc.id()));
+ }
+
+ Ok(())
+ });
+
+ let tx = handlers.inlay_hints.clone();
+ register_hook!(move |event: &mut SelectionDidChange<'_>| {
+ if let Some(controller) = event.doc.inlay_hint_controllers.get_mut(&event.view) {
+ controller.cancel();
+ }
+ // Ideally this would only trigger an update if the viewport changed...
+ send_blocking(&tx, InlayHintEvent::ViewportScrolled(event.view));
+
+ Ok(())
+ });
+
+ register_hook!(move |event: &mut LanguageServerInitialized<'_>| {
+ let views: Vec<_> = event
+ .editor
+ .tree
+ .views()
+ .map(|(view, _)| (view.id, view.doc))
+ .collect();
+ for (view, doc) in views {
+ request_inlay_hints_for_view(event.editor, view, doc, false);
+ }
+
+ Ok(())
+ });
+
+ register_hook!(move |event: &mut LanguageServerExited<'_>| {
+ // Clear and re-request all annotations when a server exits.
+ for doc in event.editor.documents_mut() {
+ if doc.supports_language_server(event.server_id) {
+ doc.reset_all_inlay_hints();
+ }
+ }
+
+ let views: Vec<_> = event
+ .editor
+ .tree
+ .views()
+ .map(|(view, _)| (view.id, view.doc))
+ .collect();
+ for (view, doc) in views {
+ request_inlay_hints_for_view(event.editor, view, doc, false);
+ }
+
+ Ok(())
+ });
+}
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 6be56574..1fe8df99 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -1105,12 +1105,6 @@ impl EditorView {
}
on_next_key
}
-
- pub fn handle_idle_timeout(&mut self, cx: &mut commands::Context) -> EventResult {
- commands::compute_inlay_hints_for_all_views(cx.editor, cx.jobs);
-
- EventResult::Ignored(None)
- }
}
impl EditorView {
@@ -1516,7 +1510,7 @@ impl Component for EditorView {
}
Event::Mouse(event) => self.handle_mouse_event(event, &mut cx),
- Event::IdleTimeout => self.handle_idle_timeout(&mut cx),
+ Event::IdleTimeout => EventResult::Ignored(None),
Event::FocusGained => {
self.terminal_focused = true;
EventResult::Consumed(None)
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index 41c9ee1e..7dde7985 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -148,9 +148,6 @@ pub struct Document {
/// To know if they're up-to-date, check the `id` field in `DocumentInlayHints`.
pub(crate) inlay_hints: HashMap<ViewId, DocumentInlayHints>,
pub(crate) jump_labels: HashMap<ViewId, Vec<Overlay>>,
- /// Set to `true` when the document is updated, reset to `false` on the next inlay hints
- /// update from the LSP
- pub inlay_hints_oudated: bool,
path: Option<PathBuf>,
relative_path: OnceCell<Option<PathBuf>>,
@@ -207,6 +204,8 @@ pub struct Document {
// NOTE: ideally this would live on the handler for color swatches. This is blocked on a
// large refactor that would make `&mut Editor` available on the `DocumentDidChange` event.
pub color_swatch_controller: TaskController,
+ // NOTE: ideally this would live on the handler for inlay hints, see the comment above.
+ pub inlay_hint_controllers: HashMap<ViewId, TaskController>,
}
#[derive(Debug, Clone, Default)]
@@ -290,7 +289,6 @@ impl fmt::Debug for Document {
.field("id", &self.id)
.field("text", &self.text)
.field("selections", &self.selections)
- .field("inlay_hints_oudated", &self.inlay_hints_oudated)
.field("text_annotations", &self.inlay_hints)
.field("view_data", &self.view_data)
.field("path", &self.path)
@@ -693,7 +691,7 @@ impl Document {
text,
selections: HashMap::default(),
inlay_hints: HashMap::default(),
- inlay_hints_oudated: false,
+ inlay_hint_controllers: HashMap::default(),
view_data: Default::default(),
indent_style: DEFAULT_INDENT,
editor_config: EditorConfig::default(),
@@ -1461,33 +1459,6 @@ impl Document {
)
});
- // Update the inlay hint annotations' positions, helping ensure they are displayed in the proper place
- let apply_inlay_hint_changes = |annotations: &mut Vec<InlineAnnotation>| {
- changes.update_positions(
- annotations
- .iter_mut()
- .map(|annotation| (&mut annotation.char_idx, Assoc::After)),
- );
- };
-
- self.inlay_hints_oudated = true;
- for text_annotation in self.inlay_hints.values_mut() {
- let DocumentInlayHints {
- id: _,
- type_inlay_hints,
- parameter_inlay_hints,
- other_inlay_hints,
- padding_before_inlay_hints,
- padding_after_inlay_hints,
- } = text_annotation;
-
- apply_inlay_hint_changes(padding_before_inlay_hints);
- apply_inlay_hint_changes(type_inlay_hints);
- apply_inlay_hint_changes(parameter_inlay_hints);
- apply_inlay_hint_changes(other_inlay_hints);
- apply_inlay_hint_changes(padding_after_inlay_hints);
- }
-
helix_event::dispatch(DocumentDidChange {
doc: self,
view: view_id,
@@ -2242,6 +2213,12 @@ impl Document {
self.inlay_hints.get(&view_id)
}
+ pub fn inlay_hints_mut(&mut self) -> impl Iterator<Item = (ViewId, &mut DocumentInlayHints)> {
+ self.inlay_hints
+ .iter_mut()
+ .map(|(view_id, hints)| (*view_id, hints))
+ }
+
/// Completely removes all the inlay hints saved for the document, dropping them to free memory
/// (since it often means inlay hints have been fully deactivated).
pub fn reset_all_inlay_hints(&mut self) {
diff --git a/helix-view/src/handlers.rs b/helix-view/src/handlers.rs
index 258ed89e..6c4c30fe 100644
--- a/helix-view/src/handlers.rs
+++ b/helix-view/src/handlers.rs
@@ -20,6 +20,7 @@ pub struct Handlers {
// only public because most of the actual implementation is in helix-term right now :/
pub completions: CompletionHandler,
pub signature_hints: Sender<lsp::SignatureHelpEvent>,
+ pub inlay_hints: Sender<lsp::InlayHintEvent>,
pub auto_save: Sender<AutoSaveEvent>,
pub document_colors: Sender<lsp::DocumentColorsEvent>,
}
diff --git a/helix-view/src/handlers/lsp.rs b/helix-view/src/handlers/lsp.rs
index c1041b2a..b60be0c0 100644
--- a/helix-view/src/handlers/lsp.rs
+++ b/helix-view/src/handlers/lsp.rs
@@ -5,9 +5,8 @@ use crate::editor::Action;
use crate::events::{
DiagnosticsDidChange, DocumentDidChange, DocumentDidClose, LanguageServerInitialized,
};
-use crate::{DocumentId, Editor};
-use helix_core::diagnostic::DiagnosticProvider;
-use helix_core::Uri;
+use crate::{DocumentId, Editor, ViewId};
+use helix_core::{diagnostic::DiagnosticProvider, Uri};
use helix_event::register_hook;
use helix_lsp::util::generate_transaction_from_edits;
use helix_lsp::{lsp, LanguageServerId, OffsetEncoding};
@@ -31,6 +30,16 @@ pub enum SignatureHelpEvent {
}
#[derive(Debug)]
+pub enum InlayHintEvent {
+ /// The contents of a document changed.
+ /// This event should request annotations after a long debounce.
+ DocumentChanged(DocumentId),
+ /// The viewport was scrolled and/or the selection changed.
+ /// This event should request annotations after a short debounce.
+ ViewportScrolled(ViewId),
+}
+
+#[derive(Debug)]
pub struct ApplyEditError {
pub kind: ApplyEditErrorKind,
pub failed_change_idx: usize,