@@ -1607,17 +1607,25 @@ impl Editor {
}
this.tasks_update_task = Some(this.refresh_runnables(window, cx));
this._subscriptions.extend(project_subscriptions);
- this._subscriptions
- .push(cx.subscribe_self(|editor, e: &EditorEvent, cx| {
+
+ this._subscriptions.push(cx.subscribe_in(
+ &cx.entity(),
+ window,
+ |editor, _, e: &EditorEvent, window, cx| {
if let EditorEvent::SelectionsChanged { local } = e {
if *local {
let new_anchor = editor.scroll_manager.anchor();
+ let snapshot = editor.snapshot(window, cx);
editor.update_restoration_data(cx, move |data| {
- data.scroll_anchor = new_anchor;
+ data.scroll_position = (
+ new_anchor.top_row(&snapshot.buffer_snapshot),
+ new_anchor.offset,
+ );
});
}
}
- }));
+ },
+ ));
this.end_selection(window, cx);
this.scroll_manager.show_scrollbars(window, cx);
@@ -2367,22 +2375,30 @@ impl Editor {
if selections.len() == 1 {
cx.emit(SearchEvent::ActiveMatchChanged)
}
- if local && self.is_singleton(cx) {
- let inmemory_selections = selections.iter().map(|s| s.range()).collect();
- self.update_restoration_data(cx, |data| {
- data.selections = inmemory_selections;
- });
+ if local {
+ if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
+ let inmemory_selections = selections
+ .iter()
+ .map(|s| {
+ text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
+ ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
+ })
+ .collect();
+ self.update_restoration_data(cx, |data| {
+ data.selections = inmemory_selections;
+ });
- if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
- {
- if let Some(workspace_id) =
- self.workspace.as_ref().and_then(|workspace| workspace.1)
+ if WorkspaceSettings::get(None, cx).restore_on_startup
+ != RestoreOnStartupBehavior::None
{
- let snapshot = self.buffer().read(cx).snapshot(cx);
- let selections = selections.clone();
- let background_executor = cx.background_executor().clone();
- let editor_id = cx.entity().entity_id().as_u64() as ItemId;
- self.serialize_selections = cx.background_spawn(async move {
+ if let Some(workspace_id) =
+ self.workspace.as_ref().and_then(|workspace| workspace.1)
+ {
+ let snapshot = self.buffer().read(cx).snapshot(cx);
+ let selections = selections.clone();
+ let background_executor = cx.background_executor().clone();
+ let editor_id = cx.entity().entity_id().as_u64() as ItemId;
+ self.serialize_selections = cx.background_spawn(async move {
background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
let db_selections = selections
.iter()
@@ -2399,6 +2415,7 @@ impl Editor {
.with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
.log_err();
});
+ }
}
}
}
@@ -2407,18 +2424,27 @@ impl Editor {
}
fn folds_did_change(&mut self, cx: &mut Context<Self>) {
- if !self.is_singleton(cx)
- || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
- {
+ use text::ToOffset as _;
+ use text::ToPoint as _;
+
+ if WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None {
return;
}
- let snapshot = self.buffer().read(cx).snapshot(cx);
+ let Some(singleton) = self.buffer().read(cx).as_singleton() else {
+ return;
+ };
+
+ let snapshot = singleton.read(cx).snapshot();
let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
- display_map
- .snapshot(cx)
- .folds_in_range(0..snapshot.len())
- .map(|fold| fold.range.deref().clone())
+ let display_snapshot = display_map.snapshot(cx);
+
+ display_snapshot
+ .folds_in_range(0..display_snapshot.buffer_snapshot.len())
+ .map(|fold| {
+ fold.range.start.text_anchor.to_point(&snapshot)
+ ..fold.range.end.text_anchor.to_point(&snapshot)
+ })
.collect()
});
self.update_restoration_data(cx, |data| {
@@ -2436,8 +2462,8 @@ impl Editor {
.folds_in_range(0..snapshot.len())
.map(|fold| {
(
- fold.range.start.to_offset(&snapshot),
- fold.range.end.to_offset(&snapshot),
+ fold.range.start.text_anchor.to_offset(&snapshot),
+ fold.range.end.text_anchor.to_offset(&snapshot),
)
})
.collect()
@@ -6,7 +6,6 @@ use crate::{
scroll::ScrollAnchor,
};
use anyhow::{Context as _, Result, anyhow};
-use clock::Global;
use collections::{HashMap, HashSet};
use file_icons::FileIcons;
use futures::future::try_join_all;
@@ -16,12 +15,12 @@ use gpui::{
ParentElement, Pixels, SharedString, Styled, Task, WeakEntity, Window, point,
};
use language::{
- Bias, Buffer, CharKind, DiskState, Point, SelectionGoal,
+ Bias, Buffer, BufferRow, CharKind, DiskState, LocalFile, Point, SelectionGoal,
proto::serialize_anchor as serialize_text_anchor,
};
use lsp::DiagnosticSeverity;
use project::{
- Project, ProjectEntryId, ProjectItem as _, ProjectPath, lsp_store::FormatTrigger,
+ Project, ProjectItem as _, ProjectPath, lsp_store::FormatTrigger,
project_settings::ProjectSettings, search::SearchQuery,
};
use rpc::proto::{self, PeerId, update_view};
@@ -30,13 +29,12 @@ use std::{
any::TypeId,
borrow::Cow,
cmp::{self, Ordering},
- collections::hash_map,
iter,
ops::Range,
- path::Path,
+ path::{Path, PathBuf},
sync::Arc,
};
-use text::{BufferId, Selection};
+use text::{BufferId, BufferSnapshot, Selection};
use theme::{Theme, ThemeSettings};
use ui::{IconDecorationKind, prelude::*};
use util::{ResultExt, TryFutureExt, paths::PathExt};
@@ -1243,26 +1241,14 @@ impl SerializableItem for Editor {
#[derive(Debug, Default)]
struct EditorRestorationData {
- entries: HashMap<ProjectEntryId, RestorationData>,
+ entries: HashMap<PathBuf, RestorationData>,
}
-#[derive(Debug)]
+#[derive(Default, Debug)]
pub struct RestorationData {
- pub scroll_anchor: ScrollAnchor,
- pub folds: Vec<Range<Anchor>>,
- pub selections: Vec<Range<Anchor>>,
- pub buffer_version: Global,
-}
-
-impl Default for RestorationData {
- fn default() -> Self {
- Self {
- scroll_anchor: ScrollAnchor::new(),
- folds: Vec::new(),
- selections: Vec::new(),
- buffer_version: Global::default(),
- }
- }
+ pub scroll_position: (BufferRow, gpui::Point<f32>),
+ pub folds: Vec<Range<Point>>,
+ pub selections: Vec<Range<Point>>,
}
impl ProjectItem for Editor {
@@ -1280,21 +1266,37 @@ impl ProjectItem for Editor {
cx: &mut Context<Self>,
) -> Self {
let mut editor = Self::for_buffer(buffer.clone(), Some(project), window, cx);
-
- if WorkspaceSettings::get(None, cx).restore_on_file_reopen {
- if let Some(restoration_data) = Self::project_item_kind()
- .and_then(|kind| pane.project_item_restoration_data.get(&kind))
- .and_then(|data| data.downcast_ref::<EditorRestorationData>())
- .and_then(|data| data.entries.get(&buffer.read(cx).entry_id(cx)?))
- .filter(|data| !buffer.read(cx).version.changed_since(&data.buffer_version))
- {
- editor.fold_ranges(restoration_data.folds.clone(), false, window, cx);
- if !restoration_data.selections.is_empty() {
- editor.change_selections(None, window, cx, |s| {
- s.select_ranges(restoration_data.selections.clone());
- });
+ if let Some((excerpt_id, buffer_id, snapshot)) =
+ editor.buffer().read(cx).snapshot(cx).as_singleton()
+ {
+ if WorkspaceSettings::get(None, cx).restore_on_file_reopen {
+ if let Some(restoration_data) = Self::project_item_kind()
+ .and_then(|kind| pane.project_item_restoration_data.get(&kind))
+ .and_then(|data| data.downcast_ref::<EditorRestorationData>())
+ .and_then(|data| {
+ let file = project::File::from_dyn(buffer.read(cx).file())?;
+ data.entries.get(&file.abs_path(cx))
+ })
+ {
+ editor.fold_ranges(
+ clip_ranges(&restoration_data.folds, &snapshot),
+ false,
+ window,
+ cx,
+ );
+ if !restoration_data.selections.is_empty() {
+ editor.change_selections(None, window, cx, |s| {
+ s.select_ranges(clip_ranges(&restoration_data.selections, &snapshot));
+ });
+ }
+ let (top_row, offset) = restoration_data.scroll_position;
+ let anchor = Anchor::in_buffer(
+ *excerpt_id,
+ buffer_id,
+ snapshot.anchor_before(Point::new(top_row, 0)),
+ );
+ editor.set_scroll_anchor(ScrollAnchor { anchor, offset }, window, cx);
}
- editor.set_scroll_anchor(restoration_data.scroll_anchor, window, cx);
}
}
@@ -1302,6 +1304,19 @@ impl ProjectItem for Editor {
}
}
+fn clip_ranges<'a>(
+ original: impl IntoIterator<Item = &'a Range<Point>> + 'a,
+ snapshot: &'a BufferSnapshot,
+) -> Vec<Range<Point>> {
+ original
+ .into_iter()
+ .map(|range| {
+ snapshot.clip_point(range.start, Bias::Left)
+ ..snapshot.clip_point(range.end, Bias::Right)
+ })
+ .collect()
+}
+
impl EventEmitter<SearchEvent> for Editor {}
impl Editor {
@@ -1320,8 +1335,7 @@ impl Editor {
let kind = Editor::project_item_kind()?;
let pane = editor.workspace()?.read(cx).pane_for(&cx.entity())?;
let buffer = editor.buffer().read(cx).as_singleton()?;
- let entry_id = buffer.read(cx).entry_id(cx)?;
- let buffer_version = buffer.read(cx).version();
+ let file_abs_path = project::File::from_dyn(buffer.read(cx).file())?.abs_path(cx);
pane.update(cx, |pane, _| {
let data = pane
.project_item_restoration_data
@@ -1336,17 +1350,8 @@ impl Editor {
}
};
- let data = match data.entries.entry(entry_id) {
- hash_map::Entry::Occupied(o) => {
- if buffer_version.changed_since(&o.get().buffer_version) {
- return None;
- }
- o.into_mut()
- }
- hash_map::Entry::Vacant(v) => v.insert(RestorationData::default()),
- };
+ let data = data.entries.entry(file_abs_path).or_default();
write(data);
- data.buffer_version = buffer_version;
Some(())
})
});