Pass inlay highlight information
This commit is contained in:
parent
477fc865f5
commit
6c5761d05b
9 changed files with 279 additions and 145 deletions
|
@ -4,7 +4,10 @@ mod inlay_map;
|
|||
mod tab_map;
|
||||
mod wrap_map;
|
||||
|
||||
use crate::{Anchor, AnchorRangeExt, InlayId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint};
|
||||
use crate::{
|
||||
link_go_to_definition::InlayCoordinates, Anchor, AnchorRangeExt, InlayId, MultiBuffer,
|
||||
MultiBufferSnapshot, ToOffset, ToPoint,
|
||||
};
|
||||
pub use block_map::{BlockMap, BlockPoint};
|
||||
use collections::{HashMap, HashSet};
|
||||
use fold_map::FoldMap;
|
||||
|
@ -40,6 +43,7 @@ pub trait ToDisplayPoint {
|
|||
}
|
||||
|
||||
type TextHighlights = TreeMap<Option<TypeId>, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>;
|
||||
type InlayHighlights = TreeMap<Option<TypeId>, Arc<(HighlightStyle, Vec<InlayCoordinates>)>>;
|
||||
|
||||
pub struct DisplayMap {
|
||||
buffer: ModelHandle<MultiBuffer>,
|
||||
|
@ -50,6 +54,7 @@ pub struct DisplayMap {
|
|||
wrap_map: ModelHandle<WrapMap>,
|
||||
block_map: BlockMap,
|
||||
text_highlights: TextHighlights,
|
||||
inlay_highlights: InlayHighlights,
|
||||
pub clip_at_line_ends: bool,
|
||||
}
|
||||
|
||||
|
@ -85,6 +90,7 @@ impl DisplayMap {
|
|||
wrap_map,
|
||||
block_map,
|
||||
text_highlights: Default::default(),
|
||||
inlay_highlights: Default::default(),
|
||||
clip_at_line_ends: false,
|
||||
}
|
||||
}
|
||||
|
@ -109,6 +115,7 @@ impl DisplayMap {
|
|||
wrap_snapshot,
|
||||
block_snapshot,
|
||||
text_highlights: self.text_highlights.clone(),
|
||||
inlay_highlights: self.inlay_highlights.clone(),
|
||||
clip_at_line_ends: self.clip_at_line_ends,
|
||||
}
|
||||
}
|
||||
|
@ -215,6 +222,16 @@ impl DisplayMap {
|
|||
.insert(Some(type_id), Arc::new((style, ranges)));
|
||||
}
|
||||
|
||||
pub fn highlight_inlays(
|
||||
&mut self,
|
||||
type_id: TypeId,
|
||||
ranges: Vec<InlayCoordinates>,
|
||||
style: HighlightStyle,
|
||||
) {
|
||||
self.inlay_highlights
|
||||
.insert(Some(type_id), Arc::new((style, ranges)));
|
||||
}
|
||||
|
||||
pub fn text_highlights(&self, type_id: TypeId) -> Option<(HighlightStyle, &[Range<Anchor>])> {
|
||||
let highlights = self.text_highlights.get(&Some(type_id))?;
|
||||
Some((highlights.0, &highlights.1))
|
||||
|
@ -227,6 +244,13 @@ impl DisplayMap {
|
|||
self.text_highlights.remove(&Some(type_id))
|
||||
}
|
||||
|
||||
pub fn clear_inlay_highlights(
|
||||
&mut self,
|
||||
type_id: TypeId,
|
||||
) -> Option<Arc<(HighlightStyle, Vec<InlayCoordinates>)>> {
|
||||
self.inlay_highlights.remove(&Some(type_id))
|
||||
}
|
||||
|
||||
pub fn set_font(&self, font_id: FontId, font_size: f32, cx: &mut ModelContext<Self>) -> bool {
|
||||
self.wrap_map
|
||||
.update(cx, |map, cx| map.set_font(font_id, font_size, cx))
|
||||
|
@ -296,6 +320,7 @@ pub struct DisplaySnapshot {
|
|||
wrap_snapshot: wrap_map::WrapSnapshot,
|
||||
block_snapshot: block_map::BlockSnapshot,
|
||||
text_highlights: TextHighlights,
|
||||
inlay_highlights: InlayHighlights,
|
||||
clip_at_line_ends: bool,
|
||||
}
|
||||
|
||||
|
@ -421,6 +446,7 @@ impl DisplaySnapshot {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.map(|h| h.text)
|
||||
}
|
||||
|
@ -429,7 +455,7 @@ impl DisplaySnapshot {
|
|||
pub fn reverse_text_chunks(&self, display_row: u32) -> impl Iterator<Item = &str> {
|
||||
(0..=display_row).into_iter().rev().flat_map(|row| {
|
||||
self.block_snapshot
|
||||
.chunks(row..row + 1, false, None, None, None)
|
||||
.chunks(row..row + 1, false, None, None, None, None)
|
||||
.map(|h| h.text)
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
|
@ -441,15 +467,16 @@ impl DisplaySnapshot {
|
|||
&self,
|
||||
display_rows: Range<u32>,
|
||||
language_aware: bool,
|
||||
hint_highlights: Option<HighlightStyle>,
|
||||
suggestion_highlights: Option<HighlightStyle>,
|
||||
inlay_highlight_style: Option<HighlightStyle>,
|
||||
suggestion_highlight_style: Option<HighlightStyle>,
|
||||
) -> DisplayChunks<'_> {
|
||||
self.block_snapshot.chunks(
|
||||
display_rows,
|
||||
language_aware,
|
||||
Some(&self.text_highlights),
|
||||
hint_highlights,
|
||||
suggestion_highlights,
|
||||
Some(&self.inlay_highlights),
|
||||
inlay_highlight_style,
|
||||
suggestion_highlight_style,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{
|
||||
wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot},
|
||||
TextHighlights,
|
||||
InlayHighlights, TextHighlights,
|
||||
};
|
||||
use crate::{Anchor, Editor, ExcerptId, ExcerptRange, ToPoint as _};
|
||||
use collections::{Bound, HashMap, HashSet};
|
||||
|
@ -579,6 +579,7 @@ impl BlockSnapshot {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect()
|
||||
|
@ -589,8 +590,9 @@ impl BlockSnapshot {
|
|||
rows: Range<u32>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
hint_highlights: Option<HighlightStyle>,
|
||||
suggestion_highlights: Option<HighlightStyle>,
|
||||
inlay_highlights: Option<&'a InlayHighlights>,
|
||||
inlay_highlight_style: Option<HighlightStyle>,
|
||||
suggestion_highlight_style: Option<HighlightStyle>,
|
||||
) -> BlockChunks<'a> {
|
||||
let max_output_row = cmp::min(rows.end, self.transforms.summary().output_rows);
|
||||
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
|
||||
|
@ -623,8 +625,9 @@ impl BlockSnapshot {
|
|||
input_start..input_end,
|
||||
language_aware,
|
||||
text_highlights,
|
||||
hint_highlights,
|
||||
suggestion_highlights,
|
||||
inlay_highlights,
|
||||
inlay_highlight_style,
|
||||
suggestion_highlight_style,
|
||||
),
|
||||
input_chunk: Default::default(),
|
||||
transforms: cursor,
|
||||
|
@ -1504,6 +1507,7 @@ mod tests {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect::<String>();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{
|
||||
inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot},
|
||||
TextHighlights,
|
||||
InlayHighlights, TextHighlights,
|
||||
};
|
||||
use crate::{Anchor, AnchorRangeExt, MultiBufferSnapshot, ToOffset};
|
||||
use gpui::{color::Color, fonts::HighlightStyle};
|
||||
|
@ -475,7 +475,7 @@ pub struct FoldSnapshot {
|
|||
impl FoldSnapshot {
|
||||
#[cfg(test)]
|
||||
pub fn text(&self) -> String {
|
||||
self.chunks(FoldOffset(0)..self.len(), false, None, None, None)
|
||||
self.chunks(FoldOffset(0)..self.len(), false, None, None, None, None)
|
||||
.map(|c| c.text)
|
||||
.collect()
|
||||
}
|
||||
|
@ -652,8 +652,9 @@ impl FoldSnapshot {
|
|||
range: Range<FoldOffset>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
hint_highlights: Option<HighlightStyle>,
|
||||
suggestion_highlights: Option<HighlightStyle>,
|
||||
inlay_highlights: Option<&'a InlayHighlights>,
|
||||
inlay_highlight_style: Option<HighlightStyle>,
|
||||
suggestion_highlight_style: Option<HighlightStyle>,
|
||||
) -> FoldChunks<'a> {
|
||||
let mut transform_cursor = self.transforms.cursor::<(FoldOffset, InlayOffset)>();
|
||||
|
||||
|
@ -675,8 +676,9 @@ impl FoldSnapshot {
|
|||
inlay_start..inlay_end,
|
||||
language_aware,
|
||||
text_highlights,
|
||||
hint_highlights,
|
||||
suggestion_highlights,
|
||||
inlay_highlights,
|
||||
inlay_highlight_style,
|
||||
suggestion_highlight_style,
|
||||
),
|
||||
inlay_chunk: None,
|
||||
inlay_offset: inlay_start,
|
||||
|
@ -687,8 +689,15 @@ impl FoldSnapshot {
|
|||
}
|
||||
|
||||
pub fn chars_at(&self, start: FoldPoint) -> impl '_ + Iterator<Item = char> {
|
||||
self.chunks(start.to_offset(self)..self.len(), false, None, None, None)
|
||||
.flat_map(|chunk| chunk.text.chars())
|
||||
self.chunks(
|
||||
start.to_offset(self)..self.len(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.flat_map(|chunk| chunk.text.chars())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1496,7 +1505,7 @@ mod tests {
|
|||
let text = &expected_text[start.0..end.0];
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.chunks(start..end, false, None, None, None)
|
||||
.chunks(start..end, false, None, None, None, None)
|
||||
.map(|c| c.text)
|
||||
.collect::<String>(),
|
||||
text,
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::{
|
|||
use sum_tree::{Bias, Cursor, SumTree};
|
||||
use text::{Patch, Rope};
|
||||
|
||||
use super::TextHighlights;
|
||||
use super::{InlayHighlights, TextHighlights};
|
||||
|
||||
pub struct InlayMap {
|
||||
snapshot: InlaySnapshot,
|
||||
|
@ -973,8 +973,9 @@ impl InlaySnapshot {
|
|||
range: Range<InlayOffset>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
hint_highlights: Option<HighlightStyle>,
|
||||
suggestion_highlights: Option<HighlightStyle>,
|
||||
inlay_highlights: Option<&'a InlayHighlights>,
|
||||
inlay_highlight_style: Option<HighlightStyle>,
|
||||
suggestion_highlight_style: Option<HighlightStyle>,
|
||||
) -> InlayChunks<'a> {
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, usize)>();
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
|
@ -983,53 +984,50 @@ impl InlaySnapshot {
|
|||
if let Some(text_highlights) = text_highlights {
|
||||
if !text_highlights.is_empty() {
|
||||
while cursor.start().0 < range.end {
|
||||
if true {
|
||||
let transform_start = self.buffer.anchor_after(
|
||||
self.to_buffer_offset(cmp::max(range.start, cursor.start().0)),
|
||||
);
|
||||
let transform_start = self.buffer.anchor_after(
|
||||
self.to_buffer_offset(cmp::max(range.start, cursor.start().0)),
|
||||
);
|
||||
|
||||
let transform_end = {
|
||||
let overshoot = InlayOffset(range.end.0 - cursor.start().0 .0);
|
||||
self.buffer.anchor_before(self.to_buffer_offset(cmp::min(
|
||||
cursor.end(&()).0,
|
||||
cursor.start().0 + overshoot,
|
||||
)))
|
||||
};
|
||||
let transform_end = {
|
||||
let overshoot = InlayOffset(range.end.0 - cursor.start().0 .0);
|
||||
self.buffer.anchor_before(self.to_buffer_offset(cmp::min(
|
||||
cursor.end(&()).0,
|
||||
cursor.start().0 + overshoot,
|
||||
)))
|
||||
};
|
||||
|
||||
for (tag, highlights) in text_highlights.iter() {
|
||||
let style = highlights.0;
|
||||
let ranges = &highlights.1;
|
||||
for (tag, highlights) in text_highlights.iter() {
|
||||
let style = highlights.0;
|
||||
let ranges = &highlights.1;
|
||||
|
||||
let start_ix = match ranges.binary_search_by(|probe| {
|
||||
let cmp = probe.end.cmp(&transform_start, &self.buffer);
|
||||
if cmp.is_gt() {
|
||||
cmp::Ordering::Greater
|
||||
} else {
|
||||
cmp::Ordering::Less
|
||||
}
|
||||
}) {
|
||||
Ok(i) | Err(i) => i,
|
||||
};
|
||||
// TODO kb add a way to highlight inlay hints through here.
|
||||
for range in &ranges[start_ix..] {
|
||||
if range.start.cmp(&transform_end, &self.buffer).is_ge() {
|
||||
break;
|
||||
}
|
||||
|
||||
highlight_endpoints.push(HighlightEndpoint {
|
||||
offset: self
|
||||
.to_inlay_offset(range.start.to_offset(&self.buffer)),
|
||||
is_start: true,
|
||||
tag: *tag,
|
||||
style,
|
||||
});
|
||||
highlight_endpoints.push(HighlightEndpoint {
|
||||
offset: self.to_inlay_offset(range.end.to_offset(&self.buffer)),
|
||||
is_start: false,
|
||||
tag: *tag,
|
||||
style,
|
||||
});
|
||||
let start_ix = match ranges.binary_search_by(|probe| {
|
||||
let cmp = probe.end.cmp(&transform_start, &self.buffer);
|
||||
if cmp.is_gt() {
|
||||
cmp::Ordering::Greater
|
||||
} else {
|
||||
cmp::Ordering::Less
|
||||
}
|
||||
}) {
|
||||
Ok(i) | Err(i) => i,
|
||||
};
|
||||
// TODO kb add a way to highlight inlay hints through here.
|
||||
for range in &ranges[start_ix..] {
|
||||
if range.start.cmp(&transform_end, &self.buffer).is_ge() {
|
||||
break;
|
||||
}
|
||||
|
||||
highlight_endpoints.push(HighlightEndpoint {
|
||||
offset: self.to_inlay_offset(range.start.to_offset(&self.buffer)),
|
||||
is_start: true,
|
||||
tag: *tag,
|
||||
style,
|
||||
});
|
||||
highlight_endpoints.push(HighlightEndpoint {
|
||||
offset: self.to_inlay_offset(range.end.to_offset(&self.buffer)),
|
||||
is_start: false,
|
||||
tag: *tag,
|
||||
style,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1050,8 +1048,8 @@ impl InlaySnapshot {
|
|||
buffer_chunk: None,
|
||||
output_offset: range.start,
|
||||
max_output_offset: range.end,
|
||||
hint_highlight_style: hint_highlights,
|
||||
suggestion_highlight_style: suggestion_highlights,
|
||||
hint_highlight_style: inlay_highlight_style,
|
||||
suggestion_highlight_style,
|
||||
highlight_endpoints: highlight_endpoints.into_iter().peekable(),
|
||||
active_highlights: Default::default(),
|
||||
snapshot: self,
|
||||
|
@ -1060,9 +1058,16 @@ impl InlaySnapshot {
|
|||
|
||||
#[cfg(test)]
|
||||
pub fn text(&self) -> String {
|
||||
self.chunks(Default::default()..self.len(), false, None, None, None)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect()
|
||||
self.chunks(
|
||||
Default::default()..self.len(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn check_invariants(&self) {
|
||||
|
@ -1636,6 +1641,8 @@ mod tests {
|
|||
InlayOffset(start)..InlayOffset(end),
|
||||
false,
|
||||
Some(&highlights),
|
||||
// TODO kb add tests
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{
|
||||
fold_map::{self, FoldChunks, FoldEdit, FoldPoint, FoldSnapshot},
|
||||
TextHighlights,
|
||||
InlayHighlights, TextHighlights,
|
||||
};
|
||||
use crate::MultiBufferSnapshot;
|
||||
use gpui::fonts::HighlightStyle;
|
||||
|
@ -71,6 +71,7 @@ impl TabMap {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
for (ix, _) in chunk.text.match_indices('\t') {
|
||||
let offset_from_edit = offset_from_edit + (ix as u32);
|
||||
|
@ -183,7 +184,7 @@ impl TabSnapshot {
|
|||
self.max_point()
|
||||
};
|
||||
for c in self
|
||||
.chunks(range.start..line_end, false, None, None, None)
|
||||
.chunks(range.start..line_end, false, None, None, None, None)
|
||||
.flat_map(|chunk| chunk.text.chars())
|
||||
{
|
||||
if c == '\n' {
|
||||
|
@ -203,6 +204,7 @@ impl TabSnapshot {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.flat_map(|chunk| chunk.text.chars())
|
||||
{
|
||||
|
@ -223,9 +225,11 @@ impl TabSnapshot {
|
|||
&'a self,
|
||||
range: Range<TabPoint>,
|
||||
language_aware: bool,
|
||||
// TODO kb extract into one struct
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
hint_highlights: Option<HighlightStyle>,
|
||||
suggestion_highlights: Option<HighlightStyle>,
|
||||
inlay_highlights: Option<&'a InlayHighlights>,
|
||||
inlay_highlight_style: Option<HighlightStyle>,
|
||||
suggestion_highlight_style: Option<HighlightStyle>,
|
||||
) -> TabChunks<'a> {
|
||||
let (input_start, expanded_char_column, to_next_stop) =
|
||||
self.to_fold_point(range.start, Bias::Left);
|
||||
|
@ -246,8 +250,9 @@ impl TabSnapshot {
|
|||
input_start..input_end,
|
||||
language_aware,
|
||||
text_highlights,
|
||||
hint_highlights,
|
||||
suggestion_highlights,
|
||||
inlay_highlights,
|
||||
inlay_highlight_style,
|
||||
suggestion_highlight_style,
|
||||
),
|
||||
input_column,
|
||||
column: expanded_char_column,
|
||||
|
@ -270,9 +275,16 @@ impl TabSnapshot {
|
|||
|
||||
#[cfg(test)]
|
||||
pub fn text(&self) -> String {
|
||||
self.chunks(TabPoint::zero()..self.max_point(), false, None, None, None)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect()
|
||||
self.chunks(
|
||||
TabPoint::zero()..self.max_point(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn max_point(&self) -> TabPoint {
|
||||
|
@ -600,6 +612,7 @@ mod tests {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.map(|c| c.text)
|
||||
.collect::<String>(),
|
||||
|
@ -674,7 +687,8 @@ mod tests {
|
|||
let mut chunks = Vec::new();
|
||||
let mut was_tab = false;
|
||||
let mut text = String::new();
|
||||
for chunk in snapshot.chunks(start..snapshot.max_point(), false, None, None, None) {
|
||||
for chunk in snapshot.chunks(start..snapshot.max_point(), false, None, None, None, None)
|
||||
{
|
||||
if chunk.is_tab != was_tab {
|
||||
if !text.is_empty() {
|
||||
chunks.push((mem::take(&mut text), was_tab));
|
||||
|
@ -743,7 +757,7 @@ mod tests {
|
|||
let expected_summary = TextSummary::from(expected_text.as_str());
|
||||
assert_eq!(
|
||||
tabs_snapshot
|
||||
.chunks(start..end, false, None, None, None)
|
||||
.chunks(start..end, false, None, None, None, None)
|
||||
.map(|c| c.text)
|
||||
.collect::<String>(),
|
||||
expected_text,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{
|
||||
fold_map::FoldBufferRows,
|
||||
tab_map::{self, TabEdit, TabPoint, TabSnapshot},
|
||||
TextHighlights,
|
||||
InlayHighlights, TextHighlights,
|
||||
};
|
||||
use crate::MultiBufferSnapshot;
|
||||
use gpui::{
|
||||
|
@ -447,6 +447,7 @@ impl WrapSnapshot {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
let mut edit_transforms = Vec::<Transform>::new();
|
||||
for _ in edit.new_rows.start..edit.new_rows.end {
|
||||
|
@ -576,8 +577,9 @@ impl WrapSnapshot {
|
|||
rows: Range<u32>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
hint_highlights: Option<HighlightStyle>,
|
||||
suggestion_highlights: Option<HighlightStyle>,
|
||||
inlay_highlights: Option<&'a InlayHighlights>,
|
||||
inlay_highlight_style: Option<HighlightStyle>,
|
||||
suggestion_highlight_style: Option<HighlightStyle>,
|
||||
) -> WrapChunks<'a> {
|
||||
let output_start = WrapPoint::new(rows.start, 0);
|
||||
let output_end = WrapPoint::new(rows.end, 0);
|
||||
|
@ -595,8 +597,9 @@ impl WrapSnapshot {
|
|||
input_start..input_end,
|
||||
language_aware,
|
||||
text_highlights,
|
||||
hint_highlights,
|
||||
suggestion_highlights,
|
||||
inlay_highlights,
|
||||
inlay_highlight_style,
|
||||
suggestion_highlight_style,
|
||||
),
|
||||
input_chunk: Default::default(),
|
||||
output_position: output_start,
|
||||
|
@ -1326,6 +1329,7 @@ mod tests {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.map(|h| h.text)
|
||||
}
|
||||
|
@ -1350,7 +1354,7 @@ mod tests {
|
|||
}
|
||||
|
||||
let actual_text = self
|
||||
.chunks(start_row..end_row, true, None, None, None)
|
||||
.chunks(start_row..end_row, true, None, None, None, None)
|
||||
.map(|c| c.text)
|
||||
.collect::<String>();
|
||||
assert_eq!(
|
||||
|
|
|
@ -64,7 +64,9 @@ use language::{
|
|||
Diagnostic, DiagnosticSeverity, File, IndentKind, IndentSize, Language, OffsetRangeExt,
|
||||
OffsetUtf16, Point, Selection, SelectionGoal, TransactionId,
|
||||
};
|
||||
use link_go_to_definition::{hide_link_definition, show_link_definition, LinkGoToDefinitionState};
|
||||
use link_go_to_definition::{
|
||||
hide_link_definition, show_link_definition, InlayCoordinates, LinkGoToDefinitionState,
|
||||
};
|
||||
use log::error;
|
||||
use multi_buffer::ToOffsetUtf16;
|
||||
pub use multi_buffer::{
|
||||
|
@ -7716,6 +7718,18 @@ impl Editor {
|
|||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn highlight_inlays<T: 'static>(
|
||||
&mut self,
|
||||
ranges: Vec<InlayCoordinates>,
|
||||
style: HighlightStyle,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.display_map.update(cx, |map, _| {
|
||||
map.highlight_inlays(TypeId::of::<T>(), ranges, style)
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn text_highlights<'a, T: 'static>(
|
||||
&'a self,
|
||||
cx: &'a AppContext,
|
||||
|
@ -7736,6 +7750,19 @@ impl Editor {
|
|||
highlights
|
||||
}
|
||||
|
||||
pub fn clear_highlights<T: 'static>(
|
||||
&mut self,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
|
||||
let highlights = self
|
||||
.display_map
|
||||
.update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
|
||||
if highlights.is_some() {
|
||||
cx.notify();
|
||||
}
|
||||
highlights
|
||||
}
|
||||
|
||||
pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
|
||||
self.blink_manager.read(cx).visible() && self.focused
|
||||
}
|
||||
|
@ -8327,7 +8354,7 @@ impl View for Editor {
|
|||
|
||||
self.link_go_to_definition_state.task = None;
|
||||
|
||||
self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
|
||||
self.clear_highlights::<LinkGoToDefinitionState>(cx);
|
||||
}
|
||||
|
||||
false
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
},
|
||||
link_go_to_definition::{
|
||||
go_to_fetched_definition, go_to_fetched_type_definition, update_go_to_definition_link,
|
||||
GoToDefinitionTrigger,
|
||||
GoToDefinitionTrigger, InlayCoordinates,
|
||||
},
|
||||
mouse_context_menu, EditorSettings, EditorStyle, GutterHover, UnfoldAt,
|
||||
};
|
||||
|
@ -1927,7 +1927,12 @@ fn update_inlay_link_and_hover_points(
|
|||
update_go_to_definition_link(
|
||||
editor,
|
||||
GoToDefinitionTrigger::InlayHint(
|
||||
hovered_hint.position,
|
||||
InlayCoordinates {
|
||||
inlay_id: hovered_hint.id,
|
||||
inlay_position: hovered_hint.position,
|
||||
inlay_start: hint_start_offset,
|
||||
highlight_end: hovered_offset,
|
||||
},
|
||||
LocationLink {
|
||||
origin: Some(Location {
|
||||
buffer,
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::{element::PointForPosition, Anchor, DisplayPoint, Editor, EditorSnapshot, SelectPhase};
|
||||
use crate::{
|
||||
display_map::InlayOffset, element::PointForPosition, Anchor, DisplayPoint, Editor,
|
||||
EditorSnapshot, InlayId, SelectPhase,
|
||||
};
|
||||
use gpui::{Task, ViewContext};
|
||||
use language::{Bias, ToOffset};
|
||||
use project::LocationLink;
|
||||
|
@ -7,8 +10,8 @@ use util::TryFutureExt;
|
|||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct LinkGoToDefinitionState {
|
||||
pub last_trigger_point: Option<TriggerAnchor>,
|
||||
pub symbol_range: Option<Range<Anchor>>,
|
||||
pub last_trigger_point: Option<TriggerPoint>,
|
||||
pub symbol_range: Option<SymbolRange>,
|
||||
pub kind: Option<LinkDefinitionKind>,
|
||||
pub definitions: Vec<LocationLink>,
|
||||
pub task: Option<Task<Option<()>>>,
|
||||
|
@ -16,34 +19,65 @@ pub struct LinkGoToDefinitionState {
|
|||
|
||||
pub enum GoToDefinitionTrigger {
|
||||
Text(DisplayPoint),
|
||||
InlayHint(Anchor, LocationLink),
|
||||
InlayHint(InlayCoordinates, LocationLink),
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TriggerAnchor {
|
||||
Text(Anchor),
|
||||
InlayHint(Anchor, LocationLink),
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct InlayCoordinates {
|
||||
pub inlay_id: InlayId,
|
||||
pub inlay_position: Anchor,
|
||||
pub inlay_start: InlayOffset,
|
||||
pub highlight_end: InlayOffset,
|
||||
}
|
||||
|
||||
impl TriggerAnchor {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TriggerPoint {
|
||||
Text(Anchor),
|
||||
InlayHint(InlayCoordinates, LocationLink),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SymbolRange {
|
||||
Text(Range<Anchor>),
|
||||
Inlay(InlayCoordinates),
|
||||
}
|
||||
|
||||
impl SymbolRange {
|
||||
fn point_within_range(&self, trigger_point: &TriggerPoint, snapshot: &EditorSnapshot) -> bool {
|
||||
match (self, trigger_point) {
|
||||
(SymbolRange::Text(range), TriggerPoint::Text(point)) => {
|
||||
let point_after_start = range.start.cmp(point, &snapshot.buffer_snapshot).is_le();
|
||||
point_after_start && range.end.cmp(point, &snapshot.buffer_snapshot).is_ge()
|
||||
}
|
||||
(SymbolRange::Inlay(range), TriggerPoint::InlayHint(point, _)) => {
|
||||
range.inlay_start.cmp(&point.highlight_end).is_le()
|
||||
&& range.highlight_end.cmp(&point.highlight_end).is_ge()
|
||||
}
|
||||
(SymbolRange::Inlay(_), TriggerPoint::Text(_))
|
||||
| (SymbolRange::Text(_), TriggerPoint::InlayHint(_, _)) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TriggerPoint {
|
||||
fn anchor(&self) -> &Anchor {
|
||||
match self {
|
||||
TriggerAnchor::Text(anchor) => anchor,
|
||||
TriggerAnchor::InlayHint(anchor, _) => anchor,
|
||||
TriggerPoint::Text(anchor) => anchor,
|
||||
TriggerPoint::InlayHint(coordinates, _) => &coordinates.inlay_position,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn definition_kind(&self, shift: bool) -> LinkDefinitionKind {
|
||||
match self {
|
||||
TriggerAnchor::Text(_) => {
|
||||
TriggerPoint::Text(_) => {
|
||||
if shift {
|
||||
LinkDefinitionKind::Type
|
||||
} else {
|
||||
LinkDefinitionKind::Symbol
|
||||
}
|
||||
}
|
||||
TriggerAnchor::InlayHint(_, _) => LinkDefinitionKind::Type,
|
||||
TriggerPoint::InlayHint(_, _) => LinkDefinitionKind::Type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,11 +95,11 @@ pub fn update_go_to_definition_link(
|
|||
let snapshot = editor.snapshot(cx);
|
||||
let trigger_point = match origin {
|
||||
GoToDefinitionTrigger::Text(p) => {
|
||||
Some(TriggerAnchor::Text(snapshot.buffer_snapshot.anchor_before(
|
||||
Some(TriggerPoint::Text(snapshot.buffer_snapshot.anchor_before(
|
||||
p.to_offset(&snapshot.display_snapshot, Bias::Left),
|
||||
)))
|
||||
}
|
||||
GoToDefinitionTrigger::InlayHint(p, target) => Some(TriggerAnchor::InlayHint(p, target)),
|
||||
GoToDefinitionTrigger::InlayHint(p, target) => Some(TriggerPoint::InlayHint(p, target)),
|
||||
GoToDefinitionTrigger::None => None,
|
||||
};
|
||||
|
||||
|
@ -109,7 +143,7 @@ pub enum LinkDefinitionKind {
|
|||
pub fn show_link_definition(
|
||||
definition_kind: LinkDefinitionKind,
|
||||
editor: &mut Editor,
|
||||
trigger_point: TriggerAnchor,
|
||||
trigger_point: TriggerPoint,
|
||||
snapshot: EditorSnapshot,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
|
@ -122,7 +156,7 @@ pub fn show_link_definition(
|
|||
return;
|
||||
}
|
||||
|
||||
let trigger_anchor = trigger_point.anchor().clone();
|
||||
let trigger_anchor = trigger_point.anchor();
|
||||
let (buffer, buffer_position) = if let Some(output) = editor
|
||||
.buffer
|
||||
.read(cx)
|
||||
|
@ -151,26 +185,15 @@ pub fn show_link_definition(
|
|||
|
||||
// Don't request again if the location is within the symbol region of a previous request with the same kind
|
||||
if let Some(symbol_range) = &editor.link_go_to_definition_state.symbol_range {
|
||||
let point_after_start = symbol_range
|
||||
.start
|
||||
.cmp(&trigger_anchor, &snapshot.buffer_snapshot)
|
||||
.is_le();
|
||||
|
||||
let point_before_end = symbol_range
|
||||
.end
|
||||
.cmp(&trigger_anchor, &snapshot.buffer_snapshot)
|
||||
.is_ge();
|
||||
|
||||
let point_within_range = point_after_start && point_before_end;
|
||||
if point_within_range && same_kind {
|
||||
if same_kind && symbol_range.point_within_range(&trigger_point, &snapshot) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let task = cx.spawn(|this, mut cx| {
|
||||
async move {
|
||||
let result = match trigger_point {
|
||||
TriggerAnchor::Text(_) => {
|
||||
let result = match &trigger_point {
|
||||
TriggerPoint::Text(_) => {
|
||||
// query the LSP for definition info
|
||||
cx.update(|cx| {
|
||||
project.update(cx, |project, cx| match definition_kind {
|
||||
|
@ -196,23 +219,22 @@ pub fn show_link_definition(
|
|||
.buffer_snapshot
|
||||
.anchor_in_excerpt(excerpt_id.clone(), origin.range.end);
|
||||
|
||||
start..end
|
||||
SymbolRange::Text(start..end)
|
||||
})
|
||||
}),
|
||||
definition_result,
|
||||
)
|
||||
})
|
||||
}
|
||||
TriggerAnchor::InlayHint(trigger_source, trigger_target) => {
|
||||
// TODO kb range is wrong, should be in inlay coordinates have a proper inlay range.
|
||||
// Or highlight inlays differently, in their layer?
|
||||
Some((Some(trigger_source..trigger_source), vec![trigger_target]))
|
||||
}
|
||||
TriggerPoint::InlayHint(trigger_source, trigger_target) => Some((
|
||||
Some(SymbolRange::Inlay(trigger_source.clone())),
|
||||
vec![trigger_target.clone()],
|
||||
)),
|
||||
};
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
// Clear any existing highlights
|
||||
this.clear_text_highlights::<LinkGoToDefinitionState>(cx);
|
||||
this.clear_highlights::<LinkGoToDefinitionState>(cx);
|
||||
this.link_go_to_definition_state.kind = Some(definition_kind);
|
||||
this.link_go_to_definition_state.symbol_range = result
|
||||
.as_ref()
|
||||
|
@ -248,22 +270,37 @@ pub fn show_link_definition(
|
|||
});
|
||||
|
||||
if any_definition_does_not_contain_current_location {
|
||||
// If no symbol range returned from language server, use the surrounding word.
|
||||
let highlight_range = symbol_range.unwrap_or_else(|| {
|
||||
let snapshot = &snapshot.buffer_snapshot;
|
||||
let (offset_range, _) = snapshot.surrounding_word(trigger_anchor);
|
||||
|
||||
snapshot.anchor_before(offset_range.start)
|
||||
..snapshot.anchor_after(offset_range.end)
|
||||
});
|
||||
|
||||
// Highlight symbol using theme link definition highlight style
|
||||
let style = theme::current(cx).editor.link_definition;
|
||||
this.highlight_text::<LinkGoToDefinitionState>(
|
||||
vec![highlight_range],
|
||||
style,
|
||||
cx,
|
||||
);
|
||||
let highlight_range = symbol_range.unwrap_or_else(|| match trigger_point {
|
||||
TriggerPoint::Text(trigger_anchor) => {
|
||||
let snapshot = &snapshot.buffer_snapshot;
|
||||
// If no symbol range returned from language server, use the surrounding word.
|
||||
let (offset_range, _) = snapshot.surrounding_word(trigger_anchor);
|
||||
SymbolRange::Text(
|
||||
snapshot.anchor_before(offset_range.start)
|
||||
..snapshot.anchor_after(offset_range.end),
|
||||
)
|
||||
}
|
||||
TriggerPoint::InlayHint(inlay_trigger, _) => {
|
||||
SymbolRange::Inlay(inlay_trigger)
|
||||
}
|
||||
});
|
||||
|
||||
match highlight_range {
|
||||
SymbolRange::Text(text_range) => this
|
||||
.highlight_text::<LinkGoToDefinitionState>(
|
||||
vec![text_range],
|
||||
style,
|
||||
cx,
|
||||
),
|
||||
SymbolRange::Inlay(inlay_coordinates) => this
|
||||
.highlight_inlays::<LinkGoToDefinitionState>(
|
||||
vec![inlay_coordinates],
|
||||
style,
|
||||
cx,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
hide_link_definition(this, cx);
|
||||
}
|
||||
|
@ -289,7 +326,7 @@ pub fn hide_link_definition(editor: &mut Editor, cx: &mut ViewContext<Editor>) {
|
|||
|
||||
editor.link_go_to_definition_state.task = None;
|
||||
|
||||
editor.clear_text_highlights::<LinkGoToDefinitionState>(cx);
|
||||
editor.clear_highlights::<LinkGoToDefinitionState>(cx);
|
||||
}
|
||||
|
||||
pub fn go_to_fetched_definition(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue