use slices instead of Rc for virtual text

pull/9973/head
Pascal Kuthe 7 months ago committed by Blaž Hrastnik
parent 68b21578ac
commit 69e07ab61e

@ -116,7 +116,7 @@ impl Default for TextFormat {
#[derive(Debug)] #[derive(Debug)]
pub struct DocumentFormatter<'t> { pub struct DocumentFormatter<'t> {
text_fmt: &'t TextFormat, text_fmt: &'t TextFormat,
annotations: &'t TextAnnotations, annotations: &'t TextAnnotations<'t>,
/// The visual position at the end of the last yielded word boundary /// The visual position at the end of the last yielded word boundary
visual_pos: Position, visual_pos: Position,

@ -1,5 +1,3 @@
use std::rc::Rc;
use crate::doc_formatter::{DocumentFormatter, TextFormat}; use crate::doc_formatter::{DocumentFormatter, TextFormat};
use crate::text_annotations::{InlineAnnotation, Overlay, TextAnnotations}; use crate::text_annotations::{InlineAnnotation, Overlay, TextAnnotations};
@ -105,7 +103,7 @@ fn overlay_text(text: &str, char_pos: usize, softwrap: bool, overlays: &[Overlay
DocumentFormatter::new_at_prev_checkpoint( DocumentFormatter::new_at_prev_checkpoint(
text.into(), text.into(),
&TextFormat::new_test(softwrap), &TextFormat::new_test(softwrap),
TextAnnotations::default().add_overlay(overlays.into(), None), TextAnnotations::default().add_overlay(overlays, None),
char_pos, char_pos,
) )
.0 .0
@ -142,7 +140,7 @@ fn annotate_text(text: &str, softwrap: bool, annotations: &[InlineAnnotation]) -
DocumentFormatter::new_at_prev_checkpoint( DocumentFormatter::new_at_prev_checkpoint(
text.into(), text.into(),
&TextFormat::new_test(softwrap), &TextFormat::new_test(softwrap),
TextAnnotations::default().add_inline_annotations(annotations.into(), None), TextAnnotations::default().add_inline_annotations(annotations, None),
0, 0,
) )
.0 .0
@ -164,15 +162,24 @@ fn annotation() {
"foo foo foo foo \n.foo foo foo foo \n.foo foo foo " "foo foo foo foo \n.foo foo foo foo \n.foo foo foo "
); );
} }
#[test] #[test]
fn annotation_and_overlay() { fn annotation_and_overlay() {
let annotations = [InlineAnnotation {
char_idx: 0,
text: "fooo".into(),
}];
let overlay = [Overlay {
char_idx: 0,
grapheme: "\t".into(),
}];
assert_eq!( assert_eq!(
DocumentFormatter::new_at_prev_checkpoint( DocumentFormatter::new_at_prev_checkpoint(
"bbar".into(), "bbar".into(),
&TextFormat::new_test(false), &TextFormat::new_test(false),
TextAnnotations::default() TextAnnotations::default()
.add_inline_annotations(Rc::new([InlineAnnotation::new(0, "fooo")]), None) .add_inline_annotations(annotations.as_slice(), None)
.add_overlay(Rc::new([Overlay::new(0, "\t")]), None), .add_overlay(overlay.as_slice(), None),
0, 0,
) )
.0 .0

@ -1,6 +1,5 @@
use std::cell::Cell; use std::cell::Cell;
use std::ops::Range; use std::ops::Range;
use std::rc::Rc;
use crate::syntax::Highlight; use crate::syntax::Highlight;
use crate::Tendril; use crate::Tendril;
@ -92,23 +91,23 @@ pub struct LineAnnotation {
} }
#[derive(Debug)] #[derive(Debug)]
struct Layer<A, M> { struct Layer<'a, A, M> {
annotations: Rc<[A]>, annotations: &'a [A],
current_index: Cell<usize>, current_index: Cell<usize>,
metadata: M, metadata: M,
} }
impl<A, M: Clone> Clone for Layer<A, M> { impl<A, M: Clone> Clone for Layer<'_, A, M> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Layer { Layer {
annotations: self.annotations.clone(), annotations: self.annotations,
current_index: self.current_index.clone(), current_index: self.current_index.clone(),
metadata: self.metadata.clone(), metadata: self.metadata.clone(),
} }
} }
} }
impl<A, M> Layer<A, M> { impl<A, M> Layer<'_, A, M> {
pub fn reset_pos(&self, char_idx: usize, get_char_idx: impl Fn(&A) -> usize) { pub fn reset_pos(&self, char_idx: usize, get_char_idx: impl Fn(&A) -> usize) {
let new_index = self let new_index = self
.annotations .annotations
@ -128,8 +127,8 @@ impl<A, M> Layer<A, M> {
} }
} }
impl<A, M> From<(Rc<[A]>, M)> for Layer<A, M> { impl<'a, A, M> From<(&'a [A], M)> for Layer<'a, A, M> {
fn from((annotations, metadata): (Rc<[A]>, M)) -> Layer<A, M> { fn from((annotations, metadata): (&'a [A], M)) -> Layer<A, M> {
Layer { Layer {
annotations, annotations,
current_index: Cell::new(0), current_index: Cell::new(0),
@ -147,13 +146,13 @@ fn reset_pos<A, M>(layers: &[Layer<A, M>], pos: usize, get_pos: impl Fn(&A) -> u
/// Annotations that change that is displayed when the document is render. /// Annotations that change that is displayed when the document is render.
/// Also commonly called virtual text. /// Also commonly called virtual text.
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct TextAnnotations { pub struct TextAnnotations<'a> {
inline_annotations: Vec<Layer<InlineAnnotation, Option<Highlight>>>, inline_annotations: Vec<Layer<'a, InlineAnnotation, Option<Highlight>>>,
overlays: Vec<Layer<Overlay, Option<Highlight>>>, overlays: Vec<Layer<'a, Overlay, Option<Highlight>>>,
line_annotations: Vec<Layer<LineAnnotation, ()>>, line_annotations: Vec<Layer<'a, LineAnnotation, ()>>,
} }
impl TextAnnotations { impl<'a> TextAnnotations<'a> {
/// Prepare the TextAnnotations for iteration starting at char_idx /// Prepare the TextAnnotations for iteration starting at char_idx
pub fn reset_pos(&self, char_idx: usize) { pub fn reset_pos(&self, char_idx: usize) {
reset_pos(&self.inline_annotations, char_idx, |annot| annot.char_idx); reset_pos(&self.inline_annotations, char_idx, |annot| annot.char_idx);
@ -194,7 +193,7 @@ impl TextAnnotations {
/// the annotations that belong to the layers added first will be shown first. /// the annotations that belong to the layers added first will be shown first.
pub fn add_inline_annotations( pub fn add_inline_annotations(
&mut self, &mut self,
layer: Rc<[InlineAnnotation]>, layer: &'a [InlineAnnotation],
highlight: Option<Highlight>, highlight: Option<Highlight>,
) -> &mut Self { ) -> &mut Self {
self.inline_annotations.push((layer, highlight).into()); self.inline_annotations.push((layer, highlight).into());
@ -211,7 +210,7 @@ impl TextAnnotations {
/// ///
/// If multiple layers contain overlay at the same position /// If multiple layers contain overlay at the same position
/// the overlay from the layer added last will be show. /// the overlay from the layer added last will be show.
pub fn add_overlay(&mut self, layer: Rc<[Overlay]>, highlight: Option<Highlight>) -> &mut Self { pub fn add_overlay(&mut self, layer: &'a [Overlay], highlight: Option<Highlight>) -> &mut Self {
self.overlays.push((layer, highlight).into()); self.overlays.push((layer, highlight).into());
self self
} }
@ -220,7 +219,7 @@ impl TextAnnotations {
/// ///
/// The line annotations **must be sorted** by their `char_idx`. /// The line annotations **must be sorted** by their `char_idx`.
/// Multiple line annotations with the same `char_idx` **are not allowed**. /// Multiple line annotations with the same `char_idx` **are not allowed**.
pub fn add_line_annotation(&mut self, layer: Rc<[LineAnnotation]>) -> &mut Self { pub fn add_line_annotation(&mut self, layer: &'a [LineAnnotation]) -> &mut Self {
self.line_annotations.push((layer, ()).into()); self.line_annotations.push((layer, ()).into());
self self
} }

@ -617,6 +617,7 @@ fn move_impl(cx: &mut Context, move_fn: MoveFn, dir: Direction, behaviour: Movem
&mut annotations, &mut annotations,
) )
}); });
drop(annotations);
doc.set_selection(view.id, selection); doc.set_selection(view.id, selection);
} }
@ -1637,7 +1638,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor
let doc_text = doc.text().slice(..); let doc_text = doc.text().slice(..);
let viewport = view.inner_area(doc); let viewport = view.inner_area(doc);
let text_fmt = doc.text_format(viewport.width, None); let text_fmt = doc.text_format(viewport.width, None);
let mut annotations = view.text_annotations(doc, None); let mut annotations = view.text_annotations(&*doc, None);
(view.offset.anchor, view.offset.vertical_offset) = char_idx_at_visual_offset( (view.offset.anchor, view.offset.vertical_offset) = char_idx_at_visual_offset(
doc_text, doc_text,
view.offset.anchor, view.offset.anchor,
@ -1715,6 +1716,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor
let mut sel = doc.selection(view.id).clone(); let mut sel = doc.selection(view.id).clone();
let idx = sel.primary_index(); let idx = sel.primary_index();
sel = sel.replace(idx, prim_sel); sel = sel.replace(idx, prim_sel);
drop(annotations);
doc.set_selection(view.id, sel); doc.set_selection(view.id, sel);
} }

@ -1315,11 +1315,11 @@ fn compute_inlay_hints_for_view(
view_id, view_id,
DocumentInlayHints { DocumentInlayHints {
id: new_doc_inlay_hints_id, id: new_doc_inlay_hints_id,
type_inlay_hints: type_inlay_hints.into(), type_inlay_hints,
parameter_inlay_hints: parameter_inlay_hints.into(), parameter_inlay_hints,
other_inlay_hints: other_inlay_hints.into(), other_inlay_hints,
padding_before_inlay_hints: padding_before_inlay_hints.into(), padding_before_inlay_hints,
padding_after_inlay_hints: padding_after_inlay_hints.into(), padding_after_inlay_hints,
}, },
); );
doc.inlay_hints_oudated = false; doc.inlay_hints_oudated = false;

@ -8,7 +8,7 @@ use helix_core::chars::char_is_word;
use helix_core::doc_formatter::TextFormat; use helix_core::doc_formatter::TextFormat;
use helix_core::encoding::Encoding; use helix_core::encoding::Encoding;
use helix_core::syntax::{Highlight, LanguageServerFeature}; use helix_core::syntax::{Highlight, LanguageServerFeature};
use helix_core::text_annotations::{InlineAnnotation, TextAnnotations}; use helix_core::text_annotations::InlineAnnotation;
use helix_lsp::util::lsp_pos_to_pos; use helix_lsp::util::lsp_pos_to_pos;
use helix_vcs::{DiffHandle, DiffProviderRegistry}; use helix_vcs::{DiffHandle, DiffProviderRegistry};
@ -21,7 +21,6 @@ use std::collections::HashMap;
use std::fmt::Display; use std::fmt::Display;
use std::future::Future; use std::future::Future;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::time::SystemTime; use std::time::SystemTime;
@ -200,22 +199,22 @@ pub struct DocumentInlayHints {
pub id: DocumentInlayHintsId, pub id: DocumentInlayHintsId,
/// Inlay hints of `TYPE` kind, if any. /// Inlay hints of `TYPE` kind, if any.
pub type_inlay_hints: Rc<[InlineAnnotation]>, pub type_inlay_hints: Vec<InlineAnnotation>,
/// Inlay hints of `PARAMETER` kind, if any. /// Inlay hints of `PARAMETER` kind, if any.
pub parameter_inlay_hints: Rc<[InlineAnnotation]>, pub parameter_inlay_hints: Vec<InlineAnnotation>,
/// Inlay hints that are neither `TYPE` nor `PARAMETER`. /// Inlay hints that are neither `TYPE` nor `PARAMETER`.
/// ///
/// LSPs are not required to associate a kind to their inlay hints, for example Rust-Analyzer /// LSPs are not required to associate a kind to their inlay hints, for example Rust-Analyzer
/// currently never does (February 2023) and the LSP spec may add new kinds in the future that /// currently never does (February 2023) and the LSP spec may add new kinds in the future that
/// we want to display even if we don't have some special highlighting for them. /// we want to display even if we don't have some special highlighting for them.
pub other_inlay_hints: Rc<[InlineAnnotation]>, pub other_inlay_hints: Vec<InlineAnnotation>,
/// Inlay hint padding. When creating the final `TextAnnotations`, the `before` padding must be /// Inlay hint padding. When creating the final `TextAnnotations`, the `before` padding must be
/// added first, then the regular inlay hints, then the `after` padding. /// added first, then the regular inlay hints, then the `after` padding.
pub padding_before_inlay_hints: Rc<[InlineAnnotation]>, pub padding_before_inlay_hints: Vec<InlineAnnotation>,
pub padding_after_inlay_hints: Rc<[InlineAnnotation]>, pub padding_after_inlay_hints: Vec<InlineAnnotation>,
} }
impl DocumentInlayHints { impl DocumentInlayHints {
@ -223,11 +222,11 @@ impl DocumentInlayHints {
pub fn empty_with_id(id: DocumentInlayHintsId) -> Self { pub fn empty_with_id(id: DocumentInlayHintsId) -> Self {
Self { Self {
id, id,
type_inlay_hints: Rc::new([]), type_inlay_hints: Vec::new(),
parameter_inlay_hints: Rc::new([]), parameter_inlay_hints: Vec::new(),
other_inlay_hints: Rc::new([]), other_inlay_hints: Vec::new(),
padding_before_inlay_hints: Rc::new([]), padding_before_inlay_hints: Vec::new(),
padding_after_inlay_hints: Rc::new([]), padding_after_inlay_hints: Vec::new(),
} }
} }
} }
@ -1266,13 +1265,12 @@ impl Document {
}); });
// Update the inlay hint annotations' positions, helping ensure they are displayed in the proper place // Update the inlay hint annotations' positions, helping ensure they are displayed in the proper place
let apply_inlay_hint_changes = |annotations: &mut Rc<[InlineAnnotation]>| { let apply_inlay_hint_changes = |annotations: &mut Vec<InlineAnnotation>| {
if let Some(data) = Rc::get_mut(annotations) { changes.update_positions(
changes.update_positions( annotations
data.iter_mut() .iter_mut()
.map(|annotation| (&mut annotation.char_idx, Assoc::After)), .map(|annotation| (&mut annotation.char_idx, Assoc::After)),
); );
}
}; };
self.inlay_hints_oudated = true; self.inlay_hints_oudated = true;
@ -1940,12 +1938,6 @@ impl Document {
} }
} }
/// Get the text annotations that apply to the whole document, those that do not apply to any
/// specific view.
pub fn text_annotations(&self, _theme: Option<&Theme>) -> TextAnnotations {
TextAnnotations::default()
}
/// Set the inlay hints for this document and `view_id`. /// Set the inlay hints for this document and `view_id`.
pub fn set_inlay_hints(&mut self, view_id: ViewId, inlay_hints: DocumentInlayHints) { pub fn set_inlay_hints(&mut self, view_id: ViewId, inlay_hints: DocumentInlayHints) {
self.inlay_hints.insert(view_id, inlay_hints); self.inlay_hints.insert(view_id, inlay_hints);

@ -19,7 +19,6 @@ use helix_core::{
use std::{ use std::{
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},
fmt, fmt,
rc::Rc,
}; };
const JUMP_LIST_CAPACITY: usize = 30; const JUMP_LIST_CAPACITY: usize = 30;
@ -409,10 +408,12 @@ impl View {
} }
/// Get the text annotations to display in the current view for the given document and theme. /// Get the text annotations to display in the current view for the given document and theme.
pub fn text_annotations(&self, doc: &Document, theme: Option<&Theme>) -> TextAnnotations { pub fn text_annotations<'a>(
// TODO custom annotations for custom views like side by side diffs &self,
doc: &'a Document,
let mut text_annotations = doc.text_annotations(theme); theme: Option<&Theme>,
) -> TextAnnotations<'a> {
let mut text_annotations = TextAnnotations::default();
let DocumentInlayHints { let DocumentInlayHints {
id: _, id: _,
@ -436,20 +437,15 @@ impl View {
.and_then(|t| t.find_scope_index("ui.virtual.inlay-hint")) .and_then(|t| t.find_scope_index("ui.virtual.inlay-hint"))
.map(Highlight); .map(Highlight);
let mut add_annotations = |annotations: &Rc<[_]>, style| {
if !annotations.is_empty() {
text_annotations.add_inline_annotations(Rc::clone(annotations), style);
}
};
// Overlapping annotations are ignored apart from the first so the order here is not random: // Overlapping annotations are ignored apart from the first so the order here is not random:
// types -> parameters -> others should hopefully be the "correct" order for most use cases, // types -> parameters -> others should hopefully be the "correct" order for most use cases,
// with the padding coming before and after as expected. // with the padding coming before and after as expected.
add_annotations(padding_before_inlay_hints, None); text_annotations
add_annotations(type_inlay_hints, type_style); .add_inline_annotations(padding_before_inlay_hints, None)
add_annotations(parameter_inlay_hints, parameter_style); .add_inline_annotations(type_inlay_hints, type_style)
add_annotations(other_inlay_hints, other_style); .add_inline_annotations(parameter_inlay_hints, parameter_style)
add_annotations(padding_after_inlay_hints, None); .add_inline_annotations(other_inlay_hints, other_style)
.add_inline_annotations(padding_after_inlay_hints, None);
text_annotations text_annotations
} }

Loading…
Cancel
Save