code_label.rs

  1use crate::highlight_map::HighlightId;
  2use std::ops::Range;
  3
  4#[derive(Debug, Clone)]
  5pub struct Symbol {
  6    pub name: String,
  7    pub kind: lsp::SymbolKind,
  8    pub container_name: Option<String>,
  9}
 10
 11#[derive(Clone, Debug, Default, PartialEq, Eq)]
 12pub struct CodeLabel {
 13    /// The text to display.
 14    pub text: String,
 15    /// Syntax highlighting runs.
 16    pub runs: Vec<(Range<usize>, HighlightId)>,
 17    /// The portion of the text that should be used in fuzzy filtering.
 18    pub filter_range: Range<usize>,
 19}
 20
 21#[derive(Clone, Debug, Default, PartialEq, Eq)]
 22pub struct CodeLabelBuilder {
 23    /// The text to display.
 24    text: String,
 25    /// Syntax highlighting runs.
 26    runs: Vec<(Range<usize>, HighlightId)>,
 27    /// The portion of the text that should be used in fuzzy filtering.
 28    filter_range: Range<usize>,
 29}
 30
 31impl CodeLabel {
 32    pub fn plain(text: String, filter_text: Option<&str>) -> Self {
 33        Self::filtered(text.clone(), text.len(), filter_text, Vec::new())
 34    }
 35
 36    pub fn filtered(
 37        text: String,
 38        label_len: usize,
 39        filter_text: Option<&str>,
 40        runs: Vec<(Range<usize>, HighlightId)>,
 41    ) -> Self {
 42        assert!(label_len <= text.len());
 43        let filter_range = filter_text
 44            .and_then(|filter| text.find(filter).map(|index| index..index + filter.len()))
 45            .unwrap_or(0..label_len);
 46        Self::new(text, filter_range, runs)
 47    }
 48
 49    pub fn new(
 50        text: String,
 51        filter_range: Range<usize>,
 52        runs: Vec<(Range<usize>, HighlightId)>,
 53    ) -> Self {
 54        assert!(
 55            text.get(filter_range.clone()).is_some(),
 56            "invalid filter range"
 57        );
 58        runs.iter().for_each(|(range, _)| {
 59            assert!(
 60                text.get(range.clone()).is_some(),
 61                "invalid run range with inputs. Requested range {range:?} in text '{text}'",
 62            );
 63        });
 64        Self {
 65            runs,
 66            filter_range,
 67            text,
 68        }
 69    }
 70
 71    pub fn text(&self) -> &str {
 72        self.text.as_str()
 73    }
 74
 75    pub fn filter_text(&self) -> &str {
 76        &self.text[self.filter_range.clone()]
 77    }
 78}
 79
 80impl From<String> for CodeLabel {
 81    fn from(value: String) -> Self {
 82        Self::plain(value, None)
 83    }
 84}
 85
 86impl From<&str> for CodeLabel {
 87    fn from(value: &str) -> Self {
 88        Self::plain(value.to_string(), None)
 89    }
 90}
 91
 92impl CodeLabelBuilder {
 93    pub fn respan_filter_range(&mut self, filter_text: Option<&str>) {
 94        self.filter_range = filter_text
 95            .and_then(|filter| {
 96                self.text
 97                    .find(filter)
 98                    .map(|index| index..index + filter.len())
 99            })
100            .unwrap_or(0..self.text.len());
101    }
102
103    pub fn push_str(&mut self, text: &str, highlight: Option<HighlightId>) {
104        let start_index = self.text.len();
105        self.text.push_str(text);
106        if let Some(highlight) = highlight {
107            let end_index = self.text.len();
108            self.runs.push((start_index..end_index, highlight));
109        }
110    }
111
112    pub fn build(mut self) -> CodeLabel {
113        if self.filter_range.end == 0 {
114            self.respan_filter_range(None);
115        }
116        CodeLabel {
117            text: self.text,
118            runs: self.runs,
119            filter_range: self.filter_range,
120        }
121    }
122}