Detailed changes
@@ -30,6 +30,8 @@ pub use block_map::{
BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock, TransformBlock,
};
+use self::editor_addition_map::InlayHintToRender;
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FoldStatus {
Folded,
@@ -286,6 +288,25 @@ impl DisplayMap {
.update(cx, |map, cx| map.set_wrap_width(width, cx))
}
+ pub fn set_inlay_hints(&self, new_hints: &[project::InlayHint], cx: &mut ModelContext<Self>) {
+ let multi_buffer = self.buffer.read(cx);
+ self.editor_addition_map.set_inlay_hints(
+ new_hints
+ .into_iter()
+ .filter_map(|hint| {
+ let buffer = multi_buffer.buffer(hint.buffer_id)?.read(cx);
+ let snapshot = buffer.snapshot();
+ Some(InlayHintToRender {
+ position: editor_addition_map::EditorAdditionPoint(
+ text::ToPoint::to_point(&hint.position, &snapshot),
+ ),
+ text: hint.text().trim_end().into(),
+ })
+ })
+ .collect(),
+ )
+ }
+
fn tab_size(buffer: &ModelHandle<MultiBuffer>, cx: &mut ModelContext<Self>) -> NonZeroU32 {
let language = buffer
.read(cx)
@@ -10,17 +10,20 @@ use super::{
TextHighlights,
};
use gpui::fonts::HighlightStyle;
-use language::{Chunk, Edit, Point, TextSummary};
+use language::{Chunk, Edit, Point, Rope, TextSummary};
+use parking_lot::Mutex;
+use project::InlayHint;
use rand::Rng;
use sum_tree::Bias;
-pub struct EditorAdditionMap;
+pub struct EditorAdditionMap(Mutex<EditorAdditionSnapshot>);
#[derive(Clone)]
pub struct EditorAdditionSnapshot {
// TODO kb merge these two together
pub suggestion_snapshot: SuggestionSnapshot,
pub version: usize,
+ hints: Vec<InlayHintToRender>,
}
pub type EditorAdditionEdit = Edit<EditorAdditionOffset>;
@@ -63,6 +66,12 @@ pub struct EditorAdditionChunks<'a> {
_z: &'a std::marker::PhantomData<()>,
}
+#[derive(Clone)]
+pub struct InlayHintToRender {
+ pub(super) position: EditorAdditionPoint,
+ pub(super) text: Rope,
+}
+
impl<'a> Iterator for EditorAdditionChunks<'a> {
type Item = Chunk<'a>;
@@ -95,7 +104,12 @@ impl EditorAdditionPoint {
impl EditorAdditionMap {
pub fn new(suggestion_snapshot: SuggestionSnapshot) -> (Self, EditorAdditionSnapshot) {
- todo!("TODO kb")
+ let snapshot = EditorAdditionSnapshot {
+ suggestion_snapshot: suggestion_snapshot.clone(),
+ version: 0,
+ hints: Vec::new(),
+ };
+ (Self(Mutex::new(snapshot.clone())), snapshot)
}
pub fn sync(
@@ -103,14 +117,24 @@ impl EditorAdditionMap {
suggestion_snapshot: SuggestionSnapshot,
suggestion_edits: Vec<SuggestionEdit>,
) -> (EditorAdditionSnapshot, Vec<EditorAdditionEdit>) {
- todo!("TODO kb")
+ let mut snapshot = self.0.lock();
+
+ if snapshot.suggestion_snapshot.version != suggestion_snapshot.version {
+ snapshot.version += 1;
+ }
+
+ let editor_addition_edits = Vec::new();
+ {
+ todo!("TODO kb")
+ }
+
+ snapshot.suggestion_snapshot = suggestion_snapshot;
+
+ (snapshot.clone(), editor_addition_edits)
}
- pub fn randomly_mutate(
- &self,
- rng: &mut impl Rng,
- ) -> (EditorAdditionSnapshot, Vec<EditorAdditionEdit>) {
- todo!("TODO kb")
+ pub fn set_inlay_hints(&self, new_hints: Vec<InlayHintToRender>) {
+ self.0.lock().hints = new_hints;
}
}
@@ -761,11 +761,13 @@ mod tests {
let (suggestion_map, _) = SuggestionMap::new(fold_snapshot);
let (suggestion_snapshot, _) = suggestion_map.randomly_mutate(&mut rng);
log::info!("SuggestionMap text: {:?}", suggestion_snapshot.text());
- let (editor_addition_map, _) = EditorAdditionMap::new(suggestion_snapshot.clone());
- let (suggestion_snapshot, _) = editor_addition_map.randomly_mutate(&mut rng);
- log::info!("EditorAdditionMap text: {:?}", suggestion_snapshot.text());
+ let (_, editor_addition_snapshot) = EditorAdditionMap::new(suggestion_snapshot.clone());
+ log::info!(
+ "EditorAdditionMap text: {:?}",
+ editor_addition_snapshot.text()
+ );
- let (tab_map, _) = TabMap::new(suggestion_snapshot.clone(), tab_size);
+ let (tab_map, _) = TabMap::new(editor_addition_snapshot.clone(), tab_size);
let tabs_snapshot = tab_map.set_max_expansion_column(32);
let text = text::Rope::from(tabs_snapshot.text().as_str());
@@ -803,7 +805,7 @@ mod tests {
);
let mut actual_summary = tabs_snapshot.text_summary_for_range(start..end);
- if tab_size.get() > 1 && suggestion_snapshot.text().contains('\t') {
+ if tab_size.get() > 1 && editor_addition_snapshot.text().contains('\t') {
actual_summary.longest_row = expected_summary.longest_row;
actual_summary.longest_row_chars = expected_summary.longest_row_chars;
}
@@ -1169,11 +1169,19 @@ impl InlayHintState {
Self::first_timestamp_newer(timestamp, ¤t_timestamp)
}
- fn update_if_newer(&self, new_hints: Vec<InlayHint>, new_timestamp: HashMap<usize, Global>) {
+ fn update_if_newer(
+ &self,
+ new_hints: Vec<InlayHint>,
+ new_timestamp: HashMap<usize, Global>,
+ ) -> bool {
let mut guard = self.0.write();
if Self::first_timestamp_newer(&new_timestamp, &guard.0) {
guard.0 = new_timestamp;
guard.1 = new_hints;
+
+ true
+ } else {
+ false
}
}
@@ -2688,7 +2696,7 @@ impl Editor {
let inlay_hints_storage = Arc::clone(&self.inlay_hints);
if inlay_hints_storage.is_newer(&new_timestamp) {
- cx.spawn(|_, _| async move {
+ cx.spawn(|editor, mut cx| async move {
let mut new_hints = Vec::new();
for task_result in futures::future::join_all(hint_fetch_tasks).await {
match task_result {
@@ -2696,7 +2704,18 @@ impl Editor {
Err(e) => error!("Failed to update hints for buffer: {e:#}"),
}
}
- inlay_hints_storage.update_if_newer(new_hints, new_timestamp);
+
+ // TODO kb another odd clone, can be avoid all this? hide hints behind a handle?
+ if inlay_hints_storage.update_if_newer(new_hints.clone(), new_timestamp) {
+ editor
+ .update(&mut cx, |editor, cx| {
+ editor.display_map.update(cx, |display_map, cx| {
+ display_map.set_inlay_hints(&new_hints, cx)
+ });
+ })
+ .log_err()
+ .unwrap_or(())
+ }
})
.detach();
}
@@ -1834,6 +1834,7 @@ impl LspCommand for InlayHints {
.unwrap_or_default()
.into_iter()
.map(|lsp_hint| InlayHint {
+ buffer_id: buffer.id() as u64,
position: origin_buffer.anchor_after(
origin_buffer
.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left),
@@ -2006,6 +2007,7 @@ impl LspCommand for InlayHints {
let mut hints = Vec::new();
for message_hint in message.hints {
let hint = InlayHint {
+ buffer_id: buffer.id() as u64,
position: message_hint
.position
.and_then(language::proto::deserialize_anchor)
@@ -29,6 +29,7 @@ use gpui::{
AnyModelHandle, AppContext, AsyncAppContext, BorrowAppContext, Entity, ModelContext,
ModelHandle, Task, WeakModelHandle,
};
+use itertools::Itertools;
use language::{
language_settings::{language_settings, FormatOnSave, Formatter},
point_to_lsp,
@@ -320,46 +321,56 @@ pub struct DiagnosticSummary {
pub warning_count: usize,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Location {
pub buffer: ModelHandle<Buffer>,
pub range: Range<language::Anchor>,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InlayHint {
+ pub buffer_id: u64,
pub position: Anchor,
pub label: InlayHintLabel,
pub kind: Option<String>,
pub tooltip: Option<InlayHintTooltip>,
}
-#[derive(Debug, Clone)]
+impl InlayHint {
+ pub fn text(&self) -> String {
+ match &self.label {
+ InlayHintLabel::String(s) => s.to_owned(),
+ InlayHintLabel::LabelParts(parts) => parts.iter().map(|part| &part.value).join(""),
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InlayHintLabel {
String(String),
LabelParts(Vec<InlayHintLabelPart>),
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InlayHintLabelPart {
pub value: String,
pub tooltip: Option<InlayHintLabelPartTooltip>,
pub location: Option<Location>,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InlayHintTooltip {
String(String),
MarkupContent(MarkupContent),
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InlayHintLabelPartTooltip {
String(String),
MarkupContent(MarkupContent),
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MarkupContent {
pub kind: String,
pub value: String,