Skip to main content

editor/editor/
anchors.rs

1//! Anchors: ids on ranges that follow the words through edits.
2
3use super::*;
4
5impl Editor {
6    /// The comment ranges, mapped up to date with the document.
7    ///
8    /// A range that reads [`Anchor::detached`] lost the words it pointed at.
9    /// It is kept rather than dropped, because whether that means "outdated" or
10    /// "resolved" is the app's question.
11    pub fn anchors(&self) -> &[Anchor] {
12        &self.anchors
13    }
14
15    /// Hand over the whole list — the app keeps the threads, this keeps their
16    /// ranges. One entry point rather than add/remove/update, since the app is
17    /// already holding the list that decides all three.
18    pub fn set_anchors(&mut self, anchors: Vec<Anchor>, cx: &mut Context<Self>) {
19        self.anchors = anchors;
20        cx.notify();
21    }
22
23    /// The comment under a point in window coordinates — the space
24    /// [`Self::anchor_bounds`] answers in and the press handler resolves in.
25    ///
26    /// The last match wins, so the newer of two overlapping ranges is the one a
27    /// click opens.
28    pub fn anchor_at(&self, at: gpui::Point<gpui::Pixels>) -> Option<AnchorId> {
29        let at = self.layouts.hit(at)?;
30        self.anchors
31            .iter()
32            .rfind(|anchor| {
33                let (start, end) = anchor.range.ordered();
34                !anchor.detached() && start <= at && at <= end
35            })
36            .map(|anchor| anchor.id)
37    }
38
39    /// Where to float a thread, mirroring [`Self::selection_bounds`].
40    pub fn anchor_bounds(&self, id: AnchorId) -> Option<gpui::Bounds<gpui::Pixels>> {
41        let anchor = self.anchors.iter().find(|anchor| anchor.id == id)?;
42        let (point, line_height) = self.layouts.position(anchor.range.ordered().0)?;
43        Some(gpui::Bounds::new(
44            point,
45            gpui::size(gpui::px(0.0), line_height),
46        ))
47    }
48
49    /// The ranges the renderer washes, clamped because a block can change kind
50    /// under an anchor and take its part with it.
51    pub(super) fn annotations(&self) -> Vec<(Selection, Annotation)> {
52        self.anchors
53            .iter()
54            .filter(|anchor| !anchor.detached())
55            .map(|anchor| (anchor.range.clamp(&self.doc), anchor.state))
56            .collect()
57    }
58}