1601 lines · 55.0 KB · Rust
RawDownload
use std::{    cmp, fmt, iter, mem,    ops::{AddAssign, Deref, DerefMut, Range, Sub},    sync::Arc,}; use gpui::Pixels;use itertools::{Either, Itertools as _};use language::{Bias, Point, Selection, SelectionGoal};use multi_buffer::{MultiBufferDimension, MultiBufferOffset, ToPoint};use util::post_inc; use crate::{    Anchor, DisplayPoint, DisplayRow, MultiBufferSnapshot, SelectMode, ToOffset,    display_map::{DisplaySnapshot, ToDisplayPoint},    movement::TextLayoutDetails,}; #[derive(Debug, Clone)]pub struct PendingSelection {    selection: Selection<Anchor>,    mode: SelectMode,} #[derive(Debug, Clone)]pub struct SelectionsCollection {    next_selection_id: usize,    line_mode: bool,    /// The non-pending, non-overlapping selections.    /// The [SelectionsCollection::pending] selection could possibly overlap these    disjoint: Arc<[Selection<Anchor>]>,    /// A pending selection, such as when the mouse is being dragged    pending: Option<PendingSelection>,    select_mode: SelectMode,    is_extending: bool,} impl SelectionsCollection {    pub fn new() -> Self {        Self {            next_selection_id: 1,            line_mode: false,            disjoint: Arc::default(),            pending: Some(PendingSelection {                selection: Selection {                    id: 0,                    start: Anchor::Min,                    end: Anchor::Min,                    reversed: false,                    goal: SelectionGoal::None,                },                mode: SelectMode::Character,            }),            select_mode: SelectMode::Character,            is_extending: false,        }    }     pub fn clone_state(&mut self, other: &SelectionsCollection) {        self.next_selection_id = other.next_selection_id;        self.line_mode = other.line_mode;        self.disjoint = other.disjoint.clone();        self.pending.clone_from(&other.pending);    }     pub fn count(&self) -> usize {        let mut count = self.disjoint.len();        if self.pending.is_some() {            count += 1;        }        count    }     /// The non-pending, non-overlapping selections. There could be a pending selection that    /// overlaps these if the mouse is being dragged, etc. This could also be empty if there is a    /// pending selection. Returned as selections over Anchors.    pub fn disjoint_anchors_arc(&self) -> Arc<[Selection<Anchor>]> {        self.disjoint.clone()    }     /// The non-pending, non-overlapping selections. There could be a pending selection that    /// overlaps these if the mouse is being dragged, etc. This could also be empty if there is a    /// pending selection. Returned as selections over Anchors.    pub fn disjoint_anchors(&self) -> &[Selection<Anchor>] {        &self.disjoint    }     pub fn disjoint_anchor_ranges(&self) -> impl Iterator<Item = Range<Anchor>> {        // Mapping the Arc slice would borrow it, whereas indexing captures it.        let disjoint = self.disjoint_anchors_arc();        (0..disjoint.len()).map(move |ix| disjoint[ix].range())    }     /// Non-overlapping selections using anchors, including the pending selection.    pub fn all_anchors(&self, snapshot: &DisplaySnapshot) -> Arc<[Selection<Anchor>]> {        if self.pending.is_none() {            self.disjoint_anchors_arc()        } else {            let all_offset_selections = self.all::<MultiBufferOffset>(snapshot);            all_offset_selections                .into_iter()                .map(|selection| selection_to_anchor_selection(selection, snapshot))                .collect()        }    }     pub fn pending_anchor(&self) -> Option<&Selection<Anchor>> {        self.pending.as_ref().map(|pending| &pending.selection)    }     pub fn pending<D>(&self, snapshot: &DisplaySnapshot) -> Option<Selection<D>>    where        D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,    {        resolve_selections_wrapping_blocks(self.pending_anchor(), &snapshot).next()    }     pub(crate) fn pending_mode(&self) -> Option<SelectMode> {        self.pending.as_ref().map(|pending| pending.mode.clone())    }     pub fn all<D>(&self, snapshot: &DisplaySnapshot) -> Vec<Selection<D>>    where        D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,    {        self.all_iter(snapshot).collect()    }     fn all_iter<'a, D>(        &'a self,        snapshot: &'a DisplaySnapshot,    ) -> impl 'a + Iterator<Item = Selection<D>>    where        D: 'a + MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,    {        let mut disjoint =            resolve_selections_wrapping_blocks::<D, _>(self.disjoint.iter(), snapshot).peekable();        let mut pending_opt = self.pending::<D>(snapshot);        iter::from_fn(move || {            if let Some(pending) = pending_opt.as_mut() {                while let Some(next_selection) = disjoint.peek() {                    if should_merge(                        pending.start,                        pending.end,                        next_selection.start,                        next_selection.end,                        false,                    ) {                        let next_selection = disjoint.next().unwrap();                        if next_selection.start < pending.start {                            pending.start = next_selection.start;                        }                        if next_selection.end > pending.end {                            pending.end = next_selection.end;                        }                    } else if next_selection.end < pending.start {                        return disjoint.next();                    } else {                        break;                    }                }                 pending_opt.take()            } else {                disjoint.next()            }        })    }     /// Returns all of the selections, adjusted to take into account the selection line_mode    pub fn all_adjusted(&self, snapshot: &DisplaySnapshot) -> Vec<Selection<Point>> {        let mut selections = self.all::<Point>(&snapshot);        if self.line_mode {            for selection in &mut selections {                let new_range = snapshot.expand_to_line(selection.range());                selection.start = new_range.start;                selection.end = new_range.end;            }        }        selections    }     /// Returns the newest selection, adjusted to take into account the selection line_mode    pub fn newest_adjusted(&self, snapshot: &DisplaySnapshot) -> Selection<Point> {        let mut selection = self.newest::<Point>(&snapshot);        if self.line_mode {            let new_range = snapshot.expand_to_line(selection.range());            selection.start = new_range.start;            selection.end = new_range.end;        }        selection    }     pub fn all_adjusted_display(        &self,        display_map: &DisplaySnapshot,    ) -> Vec<Selection<DisplayPoint>> {        if self.line_mode {            let selections = self.all::<Point>(&display_map);            let result = selections                .into_iter()                .map(|mut selection| {                    let new_range = display_map.expand_to_line(selection.range());                    selection.start = new_range.start;                    selection.end = new_range.end;                    selection.map(|point| point.to_display_point(&display_map))                })                .collect();            result        } else {            self.all_display(display_map)        }    }     pub fn disjoint_in_row_range<D>(        &self,        range: Range<Anchor>,        snapshot: &DisplaySnapshot,    ) -> Vec<Selection<D>>    where        D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord + std::fmt::Debug,    {        let buffer = snapshot.buffer_snapshot();        let start_row = range.start.to_point(buffer).row;        let end_row = range.end.to_point(buffer).row;        let start_ix = self            .disjoint            .partition_point(|probe| probe.end.to_point(buffer).row < start_row);        let end_ix = self            .disjoint            .partition_point(|probe| probe.start.to_point(buffer).row <= end_row);        resolve_selections_wrapping_blocks(&self.disjoint[start_ix..end_ix], snapshot).collect()    }     pub fn disjoint_in_range<D>(        &self,        range: Range<Anchor>,        snapshot: &DisplaySnapshot,    ) -> Vec<Selection<D>>    where        D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord + std::fmt::Debug,    {        let buffer = snapshot.buffer_snapshot();        let start_ix = self            .disjoint            .partition_point(|probe| probe.end.cmp(&range.start, buffer).is_lt());        let end_ix = self            .disjoint            .partition_point(|probe| probe.start.cmp(&range.end, buffer).is_le());        resolve_selections_wrapping_blocks(&self.disjoint[start_ix..end_ix], snapshot).collect()    }     pub fn all_display(&self, snapshot: &DisplaySnapshot) -> Vec<Selection<DisplayPoint>> {        let disjoint_anchors = &self.disjoint;        let mut disjoint =            resolve_selections_display(disjoint_anchors.iter(), &snapshot).peekable();        let mut pending_opt = resolve_selections_display(self.pending_anchor(), &snapshot).next();        iter::from_fn(move || {            if let Some(pending) = pending_opt.as_mut() {                while let Some(next_selection) = disjoint.peek() {                    if should_merge(                        pending.start,                        pending.end,                        next_selection.start,                        next_selection.end,                        false,                    ) {                        let next_selection = disjoint.next().unwrap();                        if next_selection.start < pending.start {                            pending.start = next_selection.start;                        }                        if next_selection.end > pending.end {                            pending.end = next_selection.end;                        }                    } else if next_selection.end < pending.start {                        return disjoint.next();                    } else {                        break;                    }                }                 pending_opt.take()            } else {                disjoint.next()            }        })        .collect()    }     pub fn newest_anchor(&self) -> &Selection<Anchor> {        self.pending            .as_ref()            .map(|s| &s.selection)            .or_else(|| self.disjoint.iter().max_by_key(|s| s.id))            .unwrap()    }     pub fn newest<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>    where        D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,    {        resolve_selections_wrapping_blocks([self.newest_anchor()], &snapshot)            .next()            .unwrap()    }     pub fn newest_display(&self, snapshot: &DisplaySnapshot) -> Selection<DisplayPoint> {        resolve_selections_display([self.newest_anchor()], &snapshot)            .next()            .unwrap()    }     pub fn oldest_anchor(&self) -> &Selection<Anchor> {        self.disjoint            .iter()            .min_by_key(|s| s.id)            .or_else(|| self.pending.as_ref().map(|p| &p.selection))            .unwrap()    }     pub fn oldest<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>    where        D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,    {        resolve_selections_wrapping_blocks([self.oldest_anchor()], &snapshot)            .next()            .unwrap()    }     pub fn first_anchor(&self) -> Selection<Anchor> {        self.pending            .as_ref()            .map(|pending| pending.selection.clone())            .unwrap_or_else(|| self.disjoint.first().cloned().unwrap())    }     pub fn first<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>    where        D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,    {        // Without a pending selection, the first disjoint selection is also the first resolved        // selection, so avoid resolving every selection.        if self.pending.is_none()            && let Some(first) = self.disjoint.first()        {            return resolve_selections_wrapping_blocks([first], snapshot)                .next()                .unwrap();        }        self.all_iter(snapshot).next().unwrap()    }     pub fn last<D>(&self, snapshot: &DisplaySnapshot) -> Selection<D>    where        D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,    {        if self.pending.is_none()            && let Some(last) = self.disjoint.last()        {            return resolve_selections_wrapping_blocks([last], snapshot)                .next()                .unwrap();        }        self.all_iter(snapshot).last().unwrap()    }     /// Returns a list of (potentially backwards!) ranges representing the selections.    /// Useful for test assertions, but prefer `.all()` instead.    #[cfg(any(test, feature = "test-support"))]    pub fn ranges<D>(&self, snapshot: &DisplaySnapshot) -> Vec<Range<D>>    where        D: MultiBufferDimension + Sub + AddAssign<<D as Sub>::Output> + Ord,    {        self.all::<D>(snapshot)            .iter()            .map(|s| {                if s.reversed {                    s.end..s.start                } else {                    s.start..s.end                }            })            .collect()    }     #[cfg(any(test, feature = "test-support"))]    pub fn display_ranges(&self, display_snapshot: &DisplaySnapshot) -> Vec<Range<DisplayPoint>> {        self.disjoint_anchors_arc()            .iter()            .chain(self.pending_anchor())            .map(|s| {                if s.reversed {                    s.end.to_display_point(display_snapshot)                        ..s.start.to_display_point(display_snapshot)                } else {                    s.start.to_display_point(display_snapshot)                        ..s.end.to_display_point(display_snapshot)                }            })            .collect()    }     /// Attempts to build a selection in the provided `DisplayRow` within the    /// same range as the provided range of `Pixels`.    /// Returns `None` if the range is not empty but it starts past the line's    /// length, meaning that the line isn't long enough to be contained within    /// part of the provided range.    pub fn build_columnar_selection(        &mut self,        display_map: &DisplaySnapshot,        row: DisplayRow,        positions: &Range<Pixels>,        reversed: bool,        text_layout_details: &TextLayoutDetails,    ) -> Option<Selection<Point>> {        let is_empty = positions.start == positions.end;        let line_len = display_map.line_len(row);        let line = display_map.layout_row(row, text_layout_details);        let start_col = line.closest_index_for_x(positions.start) as u32;         let (start, end) = if is_empty {            let point = DisplayPoint::new(row, std::cmp::min(start_col, line_len));            (point, point)        } else {            if start_col >= line_len {                return None;            }            let start = DisplayPoint::new(row, start_col);            let end_col = line.closest_index_for_x(positions.end) as u32;            let end = DisplayPoint::new(row, end_col);            (start, end)        };         Some(Selection {            id: post_inc(&mut self.next_selection_id),            start: start.to_point(display_map),            end: end.to_point(display_map),            reversed,            goal: SelectionGoal::HorizontalRange {                start: positions.start.into(),                end: positions.end.into(),            },        })    }     /// Attempts to build a selection in the provided buffer row using the    /// same UTF-16 column range as specified.    /// Returns `None` if the range is not empty but it starts past the line's    /// length, meaning that the line isn't long enough to be contained within    /// part of the provided range.    fn build_columnar_selection_from_tab_expanded_columns(        &mut self,        display_map: &DisplaySnapshot,        buffer_row: u32,        positions: &Range<u32>,        reversed: bool,        text_layout_details: &TextLayoutDetails,    ) -> Option<Selection<Point>> {        let is_empty = positions.start == positions.end;        let line_len = display_map.tab_expanded_line_len(buffer_row);         let (start, end) = if is_empty {            let point = display_map.point_for_tab_expanded_column(buffer_row, positions.start);            (point, point)        } else {            if positions.start >= line_len {                return None;            }             let start = display_map.point_for_tab_expanded_column(buffer_row, positions.start);            let end = display_map.point_for_tab_expanded_column(buffer_row, positions.end);            (start, end)        };         let start_display_point = start.to_display_point(display_map);        let end_display_point = end.to_display_point(display_map);        let start_x = display_map.x_for_display_point(start_display_point, text_layout_details);        let end_x = display_map.x_for_display_point(end_display_point, text_layout_details);         Some(Selection {            id: post_inc(&mut self.next_selection_id),            start,            end,            reversed,            goal: SelectionGoal::HorizontalRange {                start: start_x.min(end_x).into(),                end: start_x.max(end_x).into(),            },        })    }     /// Finds the next columnar selection by walking display rows one at a time    /// so that soft-wrapped lines are considered and not skipped.    pub fn find_next_columnar_selection_by_display_row(        &mut self,        display_map: &DisplaySnapshot,        start_row: DisplayRow,        end_row: DisplayRow,        above: bool,        positions: &Range<Pixels>,

Lines 1–500 of 1601.