1305 lines · 44.1 KB · Rust
RawDownload
use crate::{    display_map::ToDisplayPoint, link_go_to_definition::hide_link_definition,    movement::surrounding_word, persistence::DB, scroll::ScrollAnchor, Anchor, Autoscroll, Editor,    Event, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, NavigationData, ToPoint as _,};use anyhow::{Context, Result};use collections::HashSet;use futures::future::try_join_all;use gpui::{    elements::*,    geometry::vector::{vec2f, Vector2F},    AppContext, AsyncAppContext, Entity, ModelHandle, Subscription, Task, View, ViewContext,    ViewHandle, WeakViewHandle,};use language::{    proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point,    SelectionGoal,};use project::{FormatTrigger, Item as _, Project, ProjectPath};use rpc::proto::{self, update_view};use smallvec::SmallVec;use std::{    borrow::Cow,    cmp::{self, Ordering},    fmt::Write,    iter,    ops::Range,    path::{Path, PathBuf},};use text::Selection;use util::{    paths::{PathExt, FILE_ROW_COLUMN_DELIMITER},    ResultExt, TryFutureExt,};use workspace::item::{BreadcrumbText, FollowableItemHandle};use workspace::{    item::{FollowableItem, Item, ItemEvent, ItemHandle, ProjectItem},    searchable::{Direction, SearchEvent, SearchableItem, SearchableItemHandle},    ItemId, ItemNavHistory, Pane, StatusItemView, ToolbarItemLocation, ViewId, Workspace,    WorkspaceId,}; pub const MAX_TAB_TITLE_LEN: usize = 24; impl FollowableItem for Editor {    fn remote_id(&self) -> Option<ViewId> {        self.remote_id    }     fn from_state_proto(        pane: ViewHandle<workspace::Pane>,        workspace: ViewHandle<Workspace>,        remote_id: ViewId,        state: &mut Option<proto::view::Variant>,        cx: &mut AppContext,    ) -> Option<Task<Result<ViewHandle<Self>>>> {        let project = workspace.read(cx).project().to_owned();        let Some(proto::view::Variant::Editor(_)) = state else {            return None;        };        let Some(proto::view::Variant::Editor(state)) = state.take() else {            unreachable!()        };         let client = project.read(cx).client();        let replica_id = project.read(cx).replica_id();        let buffer_ids = state            .excerpts            .iter()            .map(|excerpt| excerpt.buffer_id)            .collect::<HashSet<_>>();        let buffers = project.update(cx, |project, cx| {            buffer_ids                .iter()                .map(|id| project.open_buffer_by_id(*id, cx))                .collect::<Vec<_>>()        });         let pane = pane.downgrade();        Some(cx.spawn(|mut cx| async move {            let mut buffers = futures::future::try_join_all(buffers).await?;            let editor = pane.read_with(&cx, |pane, cx| {                let mut editors = pane.items_of_type::<Self>();                editors.find(|editor| {                    let ids_match = editor.remote_id(&client, cx) == Some(remote_id);                    let singleton_buffer_matches = state.singleton                        && buffers.first()                            == editor.read(cx).buffer.read(cx).as_singleton().as_ref();                    ids_match || singleton_buffer_matches                })            })?;             let editor = if let Some(editor) = editor {                editor            } else {                pane.update(&mut cx, |_, cx| {                    let multibuffer = cx.add_model(|cx| {                        let mut multibuffer;                        if state.singleton && buffers.len() == 1 {                            multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx)                        } else {                            multibuffer = MultiBuffer::new(replica_id);                            let mut excerpts = state.excerpts.into_iter().peekable();                            while let Some(excerpt) = excerpts.peek() {                                let buffer_id = excerpt.buffer_id;                                let buffer_excerpts = iter::from_fn(|| {                                    let excerpt = excerpts.peek()?;                                    (excerpt.buffer_id == buffer_id)                                        .then(|| excerpts.next().unwrap())                                });                                let buffer =                                    buffers.iter().find(|b| b.read(cx).remote_id() == buffer_id);                                if let Some(buffer) = buffer {                                    multibuffer.push_excerpts(                                        buffer.clone(),                                        buffer_excerpts.filter_map(deserialize_excerpt_range),                                        cx,                                    );                                }                            }                        };                         if let Some(title) = &state.title {                            multibuffer = multibuffer.with_title(title.clone())                        }                         multibuffer                    });                     cx.add_view(|cx| {                        let mut editor =                            Editor::for_multibuffer(multibuffer, Some(project.clone()), cx);                        editor.remote_id = Some(remote_id);                        editor                    })                })?            };             update_editor_from_message(                editor.downgrade(),                project,                proto::update_view::Editor {                    selections: state.selections,                    pending_selection: state.pending_selection,                    scroll_top_anchor: state.scroll_top_anchor,                    scroll_x: state.scroll_x,                    scroll_y: state.scroll_y,                    ..Default::default()                },                &mut cx,            )            .await?;             Ok(editor)        }))    }     fn set_leader_replica_id(        &mut self,        leader_replica_id: Option<u16>,        cx: &mut ViewContext<Self>,    ) {        self.leader_replica_id = leader_replica_id;        if self.leader_replica_id.is_some() {            self.buffer.update(cx, |buffer, cx| {                buffer.remove_active_selections(cx);            });        } else {            self.buffer.update(cx, |buffer, cx| {                if self.focused {                    buffer.set_active_selections(                        &self.selections.disjoint_anchors(),                        self.selections.line_mode,                        self.cursor_shape,                        cx,                    );                }            });        }        cx.notify();    }     fn to_state_proto(&self, cx: &AppContext) -> Option<proto::view::Variant> {        let buffer = self.buffer.read(cx);        let scroll_anchor = self.scroll_manager.anchor();        let excerpts = buffer            .read(cx)            .excerpts()            .map(|(id, buffer, range)| proto::Excerpt {                id: id.to_proto(),                buffer_id: buffer.remote_id(),                context_start: Some(serialize_text_anchor(&range.context.start)),                context_end: Some(serialize_text_anchor(&range.context.end)),                primary_start: range                    .primary                    .as_ref()                    .map(|range| serialize_text_anchor(&range.start)),                primary_end: range                    .primary                    .as_ref()                    .map(|range| serialize_text_anchor(&range.end)),            })            .collect();         Some(proto::view::Variant::Editor(proto::view::Editor {            singleton: buffer.is_singleton(),            title: (!buffer.is_singleton()).then(|| buffer.title(cx).into()),            excerpts,            scroll_top_anchor: Some(serialize_anchor(&scroll_anchor.anchor)),            scroll_x: scroll_anchor.offset.x(),            scroll_y: scroll_anchor.offset.y(),            selections: self                .selections                .disjoint_anchors()                .iter()                .map(serialize_selection)                .collect(),            pending_selection: self                .selections                .pending_anchor()                .as_ref()                .map(serialize_selection),        }))    }     fn add_event_to_update_proto(        &self,        event: &Self::Event,        update: &mut Option<proto::update_view::Variant>,        cx: &AppContext,    ) -> bool {        let update =            update.get_or_insert_with(|| proto::update_view::Variant::Editor(Default::default()));         match update {            proto::update_view::Variant::Editor(update) => match event {                Event::ExcerptsAdded {                    buffer,                    predecessor,                    excerpts,                } => {                    let buffer_id = buffer.read(cx).remote_id();                    let mut excerpts = excerpts.iter();                    if let Some((id, range)) = excerpts.next() {                        update.inserted_excerpts.push(proto::ExcerptInsertion {                            previous_excerpt_id: Some(predecessor.to_proto()),                            excerpt: serialize_excerpt(buffer_id, id, range),                        });                        update.inserted_excerpts.extend(excerpts.map(|(id, range)| {                            proto::ExcerptInsertion {                                previous_excerpt_id: None,                                excerpt: serialize_excerpt(buffer_id, id, range),                            }                        }))                    }                    true                }                Event::ExcerptsRemoved { ids } => {                    update                        .deleted_excerpts                        .extend(ids.iter().map(ExcerptId::to_proto));                    true                }                Event::ScrollPositionChanged { .. } => {                    let scroll_anchor = self.scroll_manager.anchor();                    update.scroll_top_anchor = Some(serialize_anchor(&scroll_anchor.anchor));                    update.scroll_x = scroll_anchor.offset.x();                    update.scroll_y = scroll_anchor.offset.y();                    true                }                Event::SelectionsChanged { .. } => {                    update.selections = self                        .selections                        .disjoint_anchors()                        .iter()                        .map(serialize_selection)                        .collect();                    update.pending_selection = self                        .selections                        .pending_anchor()                        .as_ref()                        .map(serialize_selection);                    true                }                _ => false,            },        }    }     fn apply_update_proto(        &mut self,        project: &ModelHandle<Project>,        message: update_view::Variant,        cx: &mut ViewContext<Self>,    ) -> Task<Result<()>> {        let update_view::Variant::Editor(message) = message;        let project = project.clone();        cx.spawn(|this, mut cx| async move {            update_editor_from_message(this, project, message, &mut cx).await        })    }     fn should_unfollow_on_event(event: &Self::Event, _: &AppContext) -> bool {        match event {            Event::Edited => true,            Event::SelectionsChanged { local } => *local,            Event::ScrollPositionChanged { local, .. } => *local,            _ => false,        }    }} async fn update_editor_from_message(    this: WeakViewHandle<Editor>,    project: ModelHandle<Project>,    message: proto::update_view::Editor,    cx: &mut AsyncAppContext,) -> Result<()> {    // Open all of the buffers of which excerpts were added to the editor.    let inserted_excerpt_buffer_ids = message        .inserted_excerpts        .iter()        .filter_map(|insertion| Some(insertion.excerpt.as_ref()?.buffer_id))        .collect::<HashSet<_>>();    let inserted_excerpt_buffers = project.update(cx, |project, cx| {        inserted_excerpt_buffer_ids            .into_iter()            .map(|id| project.open_buffer_by_id(id, cx))            .collect::<Vec<_>>()    });    let _inserted_excerpt_buffers = try_join_all(inserted_excerpt_buffers).await?;     // Update the editor's excerpts.    this.update(cx, |editor, cx| {        editor.buffer.update(cx, |multibuffer, cx| {            let mut removed_excerpt_ids = message                .deleted_excerpts                .into_iter()                .map(ExcerptId::from_proto)                .collect::<Vec<_>>();            removed_excerpt_ids.sort_by({                let multibuffer = multibuffer.read(cx);                move |a, b| a.cmp(&b, &multibuffer)            });             let mut insertions = message.inserted_excerpts.into_iter().peekable();            while let Some(insertion) = insertions.next() {                let Some(excerpt) = insertion.excerpt else {                    continue;                };                let Some(previous_excerpt_id) = insertion.previous_excerpt_id else {                    continue;                };                let buffer_id = excerpt.buffer_id;                let Some(buffer) = project.read(cx).buffer_for_id(buffer_id, cx) else {                    continue;                };                 let adjacent_excerpts = iter::from_fn(|| {                    let insertion = insertions.peek()?;                    if insertion.previous_excerpt_id.is_none()                        && insertion.excerpt.as_ref()?.buffer_id == buffer_id                    {                        insertions.next()?.excerpt                    } else {                        None                    }                });                 multibuffer.insert_excerpts_with_ids_after(                    ExcerptId::from_proto(previous_excerpt_id),                    buffer,                    [excerpt]                        .into_iter()                        .chain(adjacent_excerpts)                        .filter_map(|excerpt| {                            Some((                                ExcerptId::from_proto(excerpt.id),                                deserialize_excerpt_range(excerpt)?,                            ))                        }),                    cx,                );            }             multibuffer.remove_excerpts(removed_excerpt_ids, cx);        });    })?;     // Deserialize the editor state.    let (selections, pending_selection, scroll_top_anchor) = this.update(cx, |editor, cx| {        let buffer = editor.buffer.read(cx).read(cx);        let selections = message            .selections            .into_iter()            .filter_map(|selection| deserialize_selection(&buffer, selection))            .collect::<Vec<_>>();        let pending_selection = message            .pending_selection            .and_then(|selection| deserialize_selection(&buffer, selection));        let scroll_top_anchor = message            .scroll_top_anchor            .and_then(|anchor| deserialize_anchor(&buffer, anchor));        anyhow::Ok((selections, pending_selection, scroll_top_anchor))    })??;     // Wait until the buffer has received all of the operations referenced by    // the editor's new state.    this.update(cx, |editor, cx| {        editor.buffer.update(cx, |buffer, cx| {            buffer.wait_for_anchors(                selections                    .iter()                    .chain(pending_selection.as_ref())                    .flat_map(|selection| [selection.start, selection.end])                    .chain(scroll_top_anchor),                cx,            )        })    })?    .await?;     // Update the editor's state.    this.update(cx, |editor, cx| {        if !selections.is_empty() || pending_selection.is_some() {            editor.set_selections_from_remote(selections, pending_selection, cx);            editor.request_autoscroll_remotely(Autoscroll::newest(), cx);        } else if let Some(scroll_top_anchor) = scroll_top_anchor {            editor.set_scroll_anchor_remote(                ScrollAnchor {                    anchor: scroll_top_anchor,                    offset: vec2f(message.scroll_x, message.scroll_y),                },                cx,            );        }    })?;    Ok(())} fn serialize_excerpt(    buffer_id: u64,    id: &ExcerptId,    range: &ExcerptRange<language::Anchor>,) -> Option<proto::Excerpt> {    Some(proto::Excerpt {        id: id.to_proto(),        buffer_id,        context_start: Some(serialize_text_anchor(&range.context.start)),        context_end: Some(serialize_text_anchor(&range.context.end)),        primary_start: range            .primary            .as_ref()            .map(|r| serialize_text_anchor(&r.start)),        primary_end: range            .primary            .as_ref()            .map(|r| serialize_text_anchor(&r.end)),    })} fn serialize_selection(selection: &Selection<Anchor>) -> proto::Selection {    proto::Selection {        id: selection.id as u64,        start: Some(serialize_anchor(&selection.start)),        end: Some(serialize_anchor(&selection.end)),        reversed: selection.reversed,    }} fn serialize_anchor(anchor: &Anchor) -> proto::EditorAnchor {    proto::EditorAnchor {        excerpt_id: anchor.excerpt_id.to_proto(),        anchor: Some(serialize_text_anchor(&anchor.text_anchor)),    }} fn deserialize_excerpt_range(excerpt: proto::Excerpt) -> Option<ExcerptRange<language::Anchor>> {    let context = {        let start = language::proto::deserialize_anchor(excerpt.context_start?)?;        let end = language::proto::deserialize_anchor(excerpt.context_end?)?;        start..end    };    let primary = excerpt        .primary_start        .zip(excerpt.primary_end)        .and_then(|(start, end)| {            let start = language::proto::deserialize_anchor(start)?;            let end = language::proto::deserialize_anchor(end)?;            Some(start..end)        });    Some(ExcerptRange { context, primary })} fn deserialize_selection(    buffer: &MultiBufferSnapshot,    selection: proto::Selection,) -> Option<Selection<Anchor>> {    Some(Selection {        id: selection.id as usize,

Lines 1–500 of 1305.