Conrad IrwinTEMP51ab6191 year agoHistory
2529 lines · 89.5 KB · Rust
RawDownload
use crate::{    excerpt_map::{        ExcerptMap, ExcerptMapChunks, ExcerptMapRows, ExcerptMapSnapshot, ExcerptOffset,        ExcerptPoint, ExcerptRow,    },    position::{TypedOffset, TypedPoint, TypedPointUtf16, TypedRow},    RowInfo,}; use super::{    Anchor, AnchorRangeExt, MultiBuffer, MultiBufferDiffHunk, MultiBufferRow, MultiBufferRows,    MultiBufferSnapshot, ToOffset, ToPoint as _,};use collections::HashMap;use git::diff::DiffHunkStatus;use gpui::{AppContext, Context as _, HighlightStyle, Model, ModelContext, Subscription};use language::{BufferChunks, BufferId, Chunk};use project::buffer_store::BufferChangeSet;use std::{    any::TypeId,    mem::{self},    ops::Range,    sync::Arc,};use sum_tree::{Cursor, SumTree, TreeMap};use text::{Bias, Edit, Patch, Point, TextSummary, ToOffset as _, ToPoint as _}; pub(crate) struct DiffMap {    excerpt_map: ExcerptMap,    snapshot: DiffMapSnapshot,    diff_bases: HashMap<BufferId, ChangeSetState>,    all_hunks_expanded: bool,    edits_since_sync: Patch<DiffOffset>,} struct ChangeSetState {    change_set: Model<BufferChangeSet>,    _subscription: Subscription,} #[derive(Clone)]struct DiffSnapshot {    diff: git::diff::BufferDiff,    base_text: language::BufferSnapshot,    base_text_version: usize,} #[derive(Clone)]pub struct DiffMapSnapshot {    diffs: TreeMap<BufferId, DiffSnapshot>,    excerpt_map_snapshot: ExcerptMapSnapshot,    pub(crate) transforms: SumTree<DiffTransform>,    pub(crate) version: usize,} #[derive(Debug, Clone)]pub(crate) enum DiffTransform {    BufferContent {        summary: TextSummary,        is_inserted_hunk: bool,    },    DeletedHunk {        summary_including_newline: TextSummary,        buffer_id: BufferId,        base_text_byte_range: Range<usize>,        base_text_start: Point,        needs_newline: bool,    },} #[derive(Debug, Clone)]pub(crate) struct DiffTransformSummary {    excerpt_map: TextSummary,    diff_map: TextSummary,} impl DiffTransformSummary {    pub fn excerpt_point(&self) -> ExcerptPoint {        ExcerptPoint::wrap(self.excerpt_map.lines)    }    pub fn multibuffer_offset(&self) -> ExcerptOffset {        ExcerptOffset::new(self.excerpt_map.len)    }    pub fn diff_point(&self) -> DiffPoint {        DiffPoint::wrap(self.diff_map.lines)    }    pub fn diff_offset(&self) -> DiffOffset {        DiffOffset::new(self.diff_map.len)    }} pub struct DiffMapChunks<'a> {    snapshot: &'a DiffMapSnapshot,    language_aware: bool,    cursor: Cursor<'a, DiffTransform, (DiffOffset, ExcerptOffset)>,    excerpt_map_chunks: ExcerptMapChunks<'a>,    current_chunk: Option<Chunk<'a>>,    excerpt_map_offset: ExcerptOffset,    offset: DiffOffset,    end_offset: DiffOffset,    diff_base_chunks: Option<(BufferId, BufferChunks<'a>)>,} #[derive(Clone)]pub struct DiffMapRows<'a> {    cursor: Cursor<'a, DiffTransform, (DiffPoint, ExcerptPoint)>,    diff_point: DiffPoint,    input_buffer_rows: ExcerptMapRows<'a>,} pub type DiffEdit = text::Edit<DiffOffset>; #[derive(Debug)]enum ChangeKind {    DiffUpdated {        base_changed: bool,    },    InputEdited,    ExpandOrCollapseHunks {        range: Range<ExcerptOffset>,        expand: bool,    },} pub type DiffOffset = TypedOffset<DiffMap>;pub type DiffPoint = TypedPoint<DiffMap>;pub type DiffPointUtf16 = TypedPointUtf16<DiffMap>;pub type DiffRow = TypedRow<DiffMap>; impl DiffMap {    pub fn new(excerpt_map: ExcerptMap, cx: &mut AppContext) -> Self {        let excerpt_map_snapshot = excerpt_map.snapshot(cx);        let snapshot = DiffMapSnapshot {            diffs: TreeMap::default(),            version: 0,            transforms: SumTree::from_item(                DiffTransform::BufferContent {                    summary: excerpt_map_snapshot.text_summary(),                    is_inserted_hunk: false,                },                &(),            ),            excerpt_map_snapshot,        };        Self {            excerpt_map,            snapshot,            all_hunks_expanded: false,            diff_bases: HashMap::default(),            edits_since_sync: Patch::default(),        }    }     pub fn add_change_set(        &mut self,        change_set: Model<BufferChangeSet>,        cx: &mut ModelContext<MultiBuffer>,    ) {        let buffer_id = change_set.read(cx).buffer_id;        self.buffer_diff_changed(change_set.clone(), cx);        self.diff_bases.insert(            buffer_id,            ChangeSetState {                _subscription: cx.observe(&change_set, |multibuffer, change_set, cx| {                    multibuffer                        .diff_map                        .buffer_diff_changed(change_set.clone(), cx);                }),                change_set,            },        );    }     pub fn diff_base_for(&self, buffer_id: BufferId) -> Option<&Model<BufferChangeSet>> {        self.diff_bases            .get(&buffer_id)            .map(|state| &state.change_set)    }     pub fn sync(        &mut self,        input_edits: Vec<text::Edit<ExcerptOffset>>,        cx: &AppContext,    ) -> (DiffMapSnapshot, Vec<DiffEdit>) {        let changes = input_edits            .iter()            .map(|edit| (edit.clone(), ChangeKind::InputEdited))            .collect::<Vec<_>>();         self.recompute_transforms(changes, cx);         // we probably need to update our excerpt map snapshot at this point.        todo!();         (            self.snapshot.clone(),            mem::take(&mut self.edits_since_sync).into_inner(),        )    }     fn buffer_diff_changed(&mut self, change_set: Model<BufferChangeSet>, cx: &AppContext) {        let change_set = change_set.read(cx);        let buffer_id = change_set.buffer_id;        let diff = change_set.diff_to_buffer.clone();        let base_text = change_set            .base_text            .as_ref()            .map(|buffer| buffer.read(cx).snapshot());        let base_text_version_changed = self            .snapshot            .diffs            .get(&buffer_id)            .map_or(true, |snapshot| {                snapshot.base_text_version != change_set.base_text_version            });         if let Some(base_text) = base_text.clone() {            self.snapshot.diffs.insert(                buffer_id,                DiffSnapshot {                    diff: diff.clone(),                    base_text,                    base_text_version: change_set.base_text_version,                },            );        } else {            self.snapshot.diffs.remove(&buffer_id);        }         let multibuffer_snapshot = &self.snapshot.excerpt_map_snapshot;        let changes = (&self.excerpt_map)            .ranges_for_buffer(buffer_id, cx)            .into_iter()            .map(|(_, range, _)| {                let multibuffer_start = multibuffer_snapshot.point_to_offset(range.start);                let multibuffer_end = multibuffer_snapshot.point_to_offset(range.end);                (                    text::Edit {                        old: multibuffer_start..multibuffer_end,                        new: multibuffer_start..multibuffer_end,                    },                    ChangeKind::DiffUpdated {                        base_changed: base_text_version_changed,                    },                )            })            .collect();        self.recompute_transforms(changes, cx);    }     pub(super) fn has_multiple_hunks(&self) -> bool {        self.snapshot            .diff_hunks_in_range(DiffOffset::new(0)..self.snapshot.len())            .nth(1)            .is_some()    }     pub(super) fn has_expanded_diff_hunks_in_ranges(&self, ranges: &[Range<DiffOffset>]) -> bool {        let mut cursor = self.snapshot.transforms.cursor::<ExcerptOffset>(&());        let excerpt_map_snapshot = &self.snapshot.excerpt_map_snapshot;        for range in ranges {            let range = excerpt_map_snapshot                .offset_to_point(self.snapshot.to_excerpt_offset(range.start))                ..excerpt_map_snapshot.offset_to_point(self.snapshot.to_excerpt_offset(range.end));            let mut start =                excerpt_map_snapshot.point_to_offset(ExcerptPoint::new(range.start.row(), 0));            let mut end =                excerpt_map_snapshot.point_to_offset(ExcerptPoint::new(range.end.row() + 1, 0));            start.value = start.value.saturating_sub(1);            end = excerpt_map_snapshot.len().min(end + ExcerptOffset::new(1));            cursor.seek(&start, Bias::Right, &());            while *cursor.start() < end {                match cursor.item() {                    Some(DiffTransform::DeletedHunk { .. })                    | Some(DiffTransform::BufferContent {                        is_inserted_hunk: true,                        ..                    }) => return true,                    _ => {}                }                cursor.next(&());            }        }        false    }     pub(super) fn expand_diff_hunks(&mut self, ranges: Vec<Range<Anchor>>, cx: &mut AppContext) {        todo!();        // self.expand_or_collapse_diff_hunks(ranges, true, cx);    }     pub(super) fn collapse_diff_hunks(&mut self, ranges: Vec<Range<Anchor>>, cx: &mut AppContext) {        todo!();        // self.expand_or_collapse_diff_hunks(ranges, false, cx);    }     pub(super) fn set_all_hunks_expanded(&mut self, cx: &mut AppContext) {        todo!();        // self.all_hunks_expanded = true;        // self.expand_or_collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], true, cx);    }     fn expand_or_collapse_diff_hunks(        &mut self,        ranges: Vec<Range<DiffOffset>>,        expand: bool,        cx: &AppContext,    ) {        let excerpt_map_snapshot = &self.snapshot.excerpt_map_snapshot;        let mut changes = Vec::new();        for range in ranges.iter() {            let excerpt_start = self                .snapshot                .excerpt_map_snapshot                .offset_to_point(self.snapshot.to_excerpt_offset(range.start));            let excerpt_end = self                .snapshot                .excerpt_map_snapshot                .offset_to_point(self.snapshot.to_excerpt_offset(range.start));             let excerpt_start =                excerpt_map_snapshot.point_to_offset(ExcerptPoint::new(excerpt_start.row(), 0));            let excerpt_end =                excerpt_map_snapshot.point_to_offset(ExcerptPoint::new(excerpt_end.row() + 1, 0));            let expanded_start = excerpt_start.saturating_sub(ExcerptOffset::new(1));            let expanded_end = excerpt_map_snapshot.len().min(excerpt_end);            changes.push((                text::Edit {                    old: expanded_start..expanded_end,                    new: expanded_start..expanded_end,                },                ChangeKind::ExpandOrCollapseHunks {                    range: excerpt_start..excerpt_end,                    expand,                },            ));        }         self.recompute_transforms(changes, cx);    }     fn recompute_transforms(        &mut self,        changes: Vec<(text::Edit<ExcerptOffset>, ChangeKind)>,        cx: &AppContext,    ) {        let mut cursor = self            .snapshot            .transforms            .cursor::<(ExcerptOffset, DiffOffset)>(&());        let mut new_transforms = SumTree::default();        let mut edits = Patch::default();         let mut changes = changes.into_iter().peekable();        let mut delta = 0_isize;        while let Some((mut edit, mut operation)) = changes.next() {            let mut to_skip = cursor.slice(&edit.old.start, Bias::Left, &());            while cursor.end(&()).0 < edit.old.start                || (cursor.end(&()).0 == edit.old.start && cursor.start().0 < edit.old.start)            {                to_skip.extend(cursor.item().cloned(), &());                cursor.next(&());            }             self.append_transforms(&mut new_transforms, to_skip);             let mut end_of_current_insert = ExcerptOffset::new(0);            loop {                let excerpt_map_range = edit.new.clone();                let edit_old_start =                    cursor.start().1 + DiffOffset::new((edit.old.start - cursor.start().0).value);                let mut edit_old_end =                    cursor.start().1 + DiffOffset::new((edit.old.end - cursor.start().0).value);                 for (buffer, buffer_range, excerpt_id) in self                    .snapshot                    .excerpt_map_snapshot                    .range_to_buffer_ranges(excerpt_map_range.clone())                {                    let excerpt_range = self                        .snapshot                        .excerpt_map_snapshot                        .range_for_excerpt::<ExcerptOffset>(excerpt_id)                        .unwrap();                    let excerpt_buffer_range = self                        .snapshot                        .excerpt_map_snapshot                        .buffer_range_for_excerpt(excerpt_id)                        .unwrap();                    let buffer_id = buffer.remote_id();                    let diff_state = self.snapshot.diffs.get(&buffer_id);                     let buffer_anchor_range = buffer.anchor_before(buffer_range.start)                        ..buffer.anchor_after(buffer_range.end);                    let change_start_buffer_offset = buffer_range.start;                    if let Some(diff_state) = diff_state {                        let diff = &diff_state.diff;                        let base_text = &diff_state.base_text;                         for hunk in diff.hunks_intersecting_range(buffer_anchor_range, &buffer) {                            let hunk_start_buffer_offset =                                hunk.buffer_range.start.to_offset(&buffer);                            let hunk_end_buffer_offset = hunk.buffer_range.end.to_offset(&buffer);                             let excerpt_buffer_range_start_offset =                                excerpt_buffer_range.start.to_offset(&buffer);                            let hunk_start_multibuffer_offset = excerpt_range.start                                + ExcerptOffset::new(                                    hunk_start_buffer_offset                                        .saturating_sub(excerpt_buffer_range_start_offset),                                );                            let hunk_end_multibuffer_offset = excerpt_range.start                                + ExcerptOffset::new(                                    hunk_end_buffer_offset                                        .saturating_sub(excerpt_buffer_range_start_offset),                                );                             self.push_buffer_content_transform(                                &mut new_transforms,                                hunk_start_multibuffer_offset,                                end_of_current_insert,                            );                             while cursor.end(&()).0 < hunk_start_multibuffer_offset                                || (cursor.end(&()).0 == hunk_start_multibuffer_offset                                    && cursor.start().0 < hunk_start_multibuffer_offset)                            {                                let Some(item) = cursor.item() else {                                    break;                                };                                if let DiffTransform::DeletedHunk { .. } = item {                                    let old_range = cursor.start().1..cursor.end(&()).1;                                    let new_offset = DiffOffset::new(                                        (old_range.start.value as isize + delta) as usize,                                    );                                    delta -= (old_range.end - old_range.start).value as isize;                                    let edit = Edit {                                        old: old_range,                                        new: new_offset..new_offset,                                    };                                    edits.push(edit);                                }                                cursor.next(&());                            }                             let mut was_previously_expanded = false;                            let mut previous_expanded_summary = TextSummary::default();                            if cursor.start().0 == hunk_start_multibuffer_offset {                                match cursor.item() {                                    Some(DiffTransform::DeletedHunk {                                        summary_including_newline,                                        ..                                    }) => {                                        was_previously_expanded = true;                                        previous_expanded_summary =                                            summary_including_newline.clone();                                    }                                    Some(DiffTransform::BufferContent {                                        is_inserted_hunk, ..                                    }) => {                                        was_previously_expanded = *is_inserted_hunk;                                    }                                    None => {}                                };                            }                             let hunk_is_deletion =                                hunk_start_buffer_offset == hunk_end_buffer_offset;                             let should_expand_hunk = match &operation {                                ChangeKind::DiffUpdated { base_changed: true } => {                                    self.all_hunks_expanded                                }                                ChangeKind::ExpandOrCollapseHunks { range, expand } => {                                    let intersects = hunk_is_deletion                                        || (hunk_start_multibuffer_offset < range.end                                            && hunk_end_multibuffer_offset > range.start);                                    if *expand {                                        was_previously_expanded                                            || self.all_hunks_expanded                                            || intersects                                    } else {                                        !intersects                                            && (was_previously_expanded || self.all_hunks_expanded)                                    }                                }                                _ => was_previously_expanded || self.all_hunks_expanded,                            };                             if should_expand_hunk {                                if hunk.diff_base_byte_range.len() > 0                                    && hunk_start_buffer_offset >= change_start_buffer_offset                                {                                    let mut text_cursor = base_text.as_rope().cursor(0);                                    let base_text_start = text_cursor                                        .summary::<Point>(hunk.diff_base_byte_range.start);                                    let mut base_text_summary = text_cursor                                        .summary::<TextSummary>(hunk.diff_base_byte_range.end);                                    let mut needs_newline = false;                                    let mut diff_len =

Lines 1–500 of 2529.