Detailed changes
@@ -410,7 +410,8 @@ impl Editor {
) -> Self {
cx.observe_model(&buffer, Self::on_buffer_changed);
cx.subscribe_to_model(&buffer, Self::on_buffer_event);
- let display_map = DisplayMap::new(buffer.clone(), settings.borrow().tab_size, cx.as_ref());
+ let display_map =
+ DisplayMap::new(buffer.clone(), settings.borrow().clone(), None, cx.as_ref());
let mut next_selection_id = 0;
let selection_set_id = buffer.update(cx, |buffer, cx| {
@@ -2,35 +2,36 @@ mod fold_map;
mod tab_map;
mod wrap_map;
-use super::{buffer, Anchor, Bias, Buffer, Point, ToOffset, ToPoint};
+use super::{buffer, Anchor, Bias, Buffer, Point, Settings, ToOffset, ToPoint};
use fold_map::FoldMap;
pub use fold_map::InputRows;
use gpui::{AppContext, ModelHandle};
use std::ops::Range;
use tab_map::TabMap;
-// use wrap_map::WrapMap;
+use wrap_map::WrapMap;
pub struct DisplayMap {
buffer: ModelHandle<Buffer>,
fold_map: FoldMap,
tab_map: TabMap,
- // wrap_map: WrapMap,
+ wrap_map: WrapMap,
}
impl DisplayMap {
- pub fn new(buffer: ModelHandle<Buffer>, tab_size: usize, cx: &AppContext) -> Self {
- let fold_map = FoldMap::new(buffer.clone(), cx);
- let (snapshot, edits) = fold_map.read(cx);
- assert_eq!(edits.len(), 0);
- let tab_map = TabMap::new(snapshot, tab_size);
- // TODO: take `wrap_width` as a parameter.
- // let config = { todo!() };
- // let wrap_map = WrapMap::new(snapshot, config, cx);
+ pub fn new(
+ buffer: ModelHandle<Buffer>,
+ settings: Settings,
+ wrap_width: Option<f32>,
+ cx: &AppContext,
+ ) -> Self {
+ let (fold_map, snapshot) = FoldMap::new(buffer.clone(), cx);
+ let (tab_map, snapshot) = TabMap::new(snapshot, settings.tab_size);
+ let wrap_map = WrapMap::new(snapshot, settings, wrap_width, cx);
DisplayMap {
buffer,
fold_map,
tab_map,
- // wrap_map,
+ wrap_map,
}
}
@@ -61,6 +62,10 @@ impl DisplayMap {
let (mut fold_map, snapshot, edits) = self.fold_map.write(cx);
let edits = fold_map.unfold(ranges, cx);
}
+
+ pub fn set_wrap_width(&self, width: Option<f32>) {
+ self.wrap_map.set_wrap_width(width);
+ }
}
pub struct DisplayMapSnapshot {
@@ -257,7 +262,12 @@ mod tests {
fn test_chunks_at(cx: &mut gpui::MutableAppContext) {
let text = sample_text(6, 6);
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
- let map = DisplayMap::new(buffer.clone(), 4, cx.as_ref());
+ let map = DisplayMap::new(
+ buffer.clone(),
+ Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
+ None,
+ cx.as_ref(),
+ );
buffer.update(cx, |buffer, cx| {
buffer.edit(
vec![
@@ -334,7 +344,14 @@ mod tests {
});
buffer.condition(&cx, |buf, _| !buf.is_parsing()).await;
- let mut map = cx.read(|cx| DisplayMap::new(buffer, 2, cx));
+ let mut map = cx.read(|cx| {
+ DisplayMap::new(
+ buffer,
+ Settings::new(cx.font_cache()).unwrap().with_tab_size(2),
+ None,
+ cx,
+ )
+ });
assert_eq!(
cx.read(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
vec![
@@ -399,7 +416,12 @@ mod tests {
let display_text = "\n'a', 'α', 'ā', 'ā', 'š'\n";
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
let cx = cx.as_ref();
- let map = DisplayMap::new(buffer.clone(), 4, cx);
+ let map = DisplayMap::new(
+ buffer.clone(),
+ Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
+ None,
+ cx,
+ );
let map = map.snapshot(cx);
assert_eq!(map.text(), display_text);
@@ -434,7 +456,12 @@ mod tests {
let text = "ā
\t\tα\nβ\t\nšĪ²\t\tγ";
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
let cx = cx.as_ref();
- let map = DisplayMap::new(buffer.clone(), 4, cx);
+ let map = DisplayMap::new(
+ buffer.clone(),
+ Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
+ None,
+ cx,
+ );
let map = map.snapshot(cx);
assert_eq!(map.text(), "ā
α\nβ \nšĪ² γ");
@@ -495,7 +522,12 @@ mod tests {
#[gpui::test]
fn test_max_point(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, "aaa\n\t\tbbb", cx));
- let map = DisplayMap::new(buffer.clone(), 4, cx.as_ref());
+ let map = DisplayMap::new(
+ buffer.clone(),
+ Settings::new(cx.font_cache()).unwrap().with_tab_size(4),
+ None,
+ cx.as_ref(),
+ );
assert_eq!(
map.snapshot(cx.as_ref()).max_point(),
DisplayPoint::new(1, 11)
@@ -161,9 +161,9 @@ pub struct FoldMap {
}
impl FoldMap {
- pub fn new(buffer_handle: ModelHandle<Buffer>, cx: &AppContext) -> Self {
+ pub fn new(buffer_handle: ModelHandle<Buffer>, cx: &AppContext) -> (Self, Snapshot) {
let buffer = buffer_handle.read(cx);
- Self {
+ let this = Self {
buffer: buffer_handle,
folds: Default::default(),
transforms: Mutex::new(SumTree::from_item(
@@ -178,7 +178,9 @@ impl FoldMap {
)),
last_sync: Mutex::new(buffer.version()),
version: AtomicUsize::new(0),
- }
+ };
+ let (snapshot, _) = this.read(cx);
+ (this, snapshot)
}
pub fn read(&self, cx: &AppContext) -> (Snapshot, Vec<Edit>) {
@@ -1105,7 +1107,7 @@ mod tests {
#[gpui::test]
fn test_basic_folds(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
- let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
+ let mut map = FoldMap::new(buffer.clone(), cx.as_ref()).0;
let (mut writer, _, _) = map.write(cx.as_ref());
let (snapshot2, edits) = writer.fold(
@@ -1180,7 +1182,7 @@ mod tests {
let buffer = cx.add_model(|cx| Buffer::new(0, "abcdefghijkl", cx));
{
- let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
+ let mut map = FoldMap::new(buffer.clone(), cx.as_ref()).0;
let (mut writer, _, _) = map.write(cx.as_ref());
writer.fold(vec![5..8], cx.as_ref());
@@ -1201,7 +1203,7 @@ mod tests {
}
{
- let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
+ let mut map = FoldMap::new(buffer.clone(), cx.as_ref()).0;
// Create two adjacent folds.
let (mut writer, _, _) = map.write(cx.as_ref());
@@ -1219,7 +1221,7 @@ mod tests {
#[gpui::test]
fn test_overlapping_folds(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
- let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
+ let mut map = FoldMap::new(buffer.clone(), cx.as_ref()).0;
let (mut writer, _, _) = map.write(cx.as_ref());
writer.fold(
vec![
@@ -1237,7 +1239,7 @@ mod tests {
#[gpui::test]
fn test_merging_folds_via_edit(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
- let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
+ let mut map = FoldMap::new(buffer.clone(), cx.as_ref()).0;
let (mut writer, _, _) = map.write(cx.as_ref());
writer.fold(
@@ -1260,7 +1262,7 @@ mod tests {
#[gpui::test]
fn test_folds_in_range(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
- let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
+ let mut map = FoldMap::new(buffer.clone(), cx.as_ref()).0;
let buffer = buffer.read(cx);
let (mut writer, _, _) = map.write(cx.as_ref());
@@ -1317,7 +1319,7 @@ mod tests {
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
Buffer::new(0, text, cx)
});
- let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
+ let mut map = FoldMap::new(buffer.clone(), cx.as_ref()).0;
let (mut initial_snapshot, _) = map.read(cx.as_ref());
let mut snapshot_edits = Vec::new();
@@ -1537,7 +1539,7 @@ mod tests {
let text = sample_text(6, 6) + "\n";
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
- let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
+ let mut map = FoldMap::new(buffer.clone(), cx.as_ref()).0;
let (mut writer, _, _) = map.write(cx.as_ref());
writer.fold(
@@ -13,8 +13,9 @@ use std::{
pub struct TabMap(Mutex<Snapshot>);
impl TabMap {
- pub fn new(input: InputSnapshot, tab_size: usize) -> Self {
- Self(Mutex::new(Snapshot { input, tab_size }))
+ pub fn new(input: InputSnapshot, tab_size: usize) -> (Self, Snapshot) {
+ let snapshot = Snapshot { input, tab_size };
+ (Self(Mutex::new(snapshot.clone())), snapshot)
}
pub fn sync(
@@ -5,8 +5,9 @@ use crate::{
editor::Point,
sum_tree::{self, Cursor, SumTree},
util::Bias,
+ Settings,
};
-use gpui::{font_cache::FamilyId, AppContext, FontCache, FontSystem, Task};
+use gpui::{AppContext, FontCache, FontSystem, Task};
use parking_lot::Mutex;
use postage::{
prelude::{Sink, Stream},
@@ -208,13 +209,6 @@ struct State {
pending_edits: VecDeque<(InputSnapshot, Vec<InputEdit>)>,
}
-#[derive(Clone)]
-pub struct Config {
- pub wrap_width: f32,
- pub font_family: FamilyId,
- pub font_size: f32,
-}
-
pub struct WrapMap {
state: Mutex<State>,
edits_tx: channel::Sender<(InputSnapshot, Vec<InputEdit>)>,
@@ -223,7 +217,12 @@ pub struct WrapMap {
}
impl WrapMap {
- pub fn new(input: InputSnapshot, config: Config, cx: &AppContext) -> Self {
+ pub fn new(
+ input: InputSnapshot,
+ settings: Settings,
+ wrap_width: Option<f32>,
+ cx: &AppContext,
+ ) -> Self {
let font_cache = cx.font_cache().clone();
let font_system = cx.platform().fonts();
let snapshot = Snapshot::new(input.clone());
@@ -233,7 +232,8 @@ impl WrapMap {
let background_task = {
let snapshot = snapshot.clone();
cx.background().spawn(async move {
- let mut wrapper = BackgroundWrapper::new(snapshot, config, font_cache, font_system);
+ let mut wrapper =
+ BackgroundWrapper::new(snapshot, settings, wrap_width, font_cache, font_system);
wrapper.run(input, edits_rx, background_snapshot_tx).await;
})
};
@@ -254,11 +254,20 @@ impl WrapMap {
.try_send((input.clone(), edits.clone()))
.unwrap();
+ let mut snapshot = self.state.lock().snapshot.clone();
+ let mut background_snapshot = self.background_snapshot.clone();
+ cx.background().block_on(Duration::from_millis(5), async {
+ loop {
+ snapshot = background_snapshot.recv().await.unwrap();
+ if snapshot.input.version() == input.version() {
+ break;
+ }
+ }
+ });
+
let mut state = &mut *self.state.lock();
- state.snapshot = self.background_snapshot.borrow().clone();
- state
- .pending_edits
- .push_back((input.clone(), edits.clone()));
+ state.snapshot = snapshot;
+ state.pending_edits.push_back((input, edits));
while state.pending_edits.front().map_or(false, |(input, _)| {
input.version() <= state.snapshot.input.version()
}) {
@@ -267,20 +276,17 @@ impl WrapMap {
for (input, edits) in &state.pending_edits {
state.snapshot.interpolate(input.clone(), &edits);
}
+ state.snapshot.clone()
+ }
- let mut background_snapshot = self.background_snapshot.clone();
- let next_snapshot = cx
- .background()
- .block_on(Duration::from_millis(5), async move {
- background_snapshot.recv().await;
- });
-
- self.state.lock().snapshot.clone()
+ pub fn set_wrap_width(&self, width: Option<f32>) {
+ todo!()
}
}
struct BackgroundWrapper {
- config: Config,
+ settings: Settings,
+ wrap_width: Option<f32>,
font_cache: Arc<FontCache>,
font_system: Arc<dyn FontSystem>,
snapshot: Snapshot,
@@ -289,12 +295,14 @@ struct BackgroundWrapper {
impl BackgroundWrapper {
fn new(
snapshot: Snapshot,
- config: Config,
+ settings: Settings,
+ wrap_width: Option<f32>,
font_cache: Arc<FontCache>,
font_system: Arc<dyn FontSystem>,
) -> Self {
Self {
- config,
+ settings,
+ wrap_width,
font_cache,
font_system,
snapshot,
@@ -331,10 +339,9 @@ impl BackgroundWrapper {
let font_id = self
.font_cache
- .select_font(self.config.font_family, &Default::default())
+ .select_font(self.settings.buffer_font_family, &Default::default())
.unwrap();
- let font_size = self.config.font_size;
- let wrap_width = self.config.wrap_width;
+ let font_size = self.settings.buffer_font_size;
#[derive(Debug)]
struct RowEdit {
@@ -403,15 +410,17 @@ impl BackgroundWrapper {
}
let mut prev_boundary_ix = 0;
- for boundary_ix in self
- .font_system
- .wrap_line(&line, font_id, font_size, wrap_width)
- {
- let wrapped = &line[prev_boundary_ix..boundary_ix];
- new_transforms
- .push_or_extend(Transform::isomorphic(TextSummary::from(wrapped)));
- new_transforms.push_or_extend(Transform::newline());
- prev_boundary_ix = boundary_ix;
+ if let Some(wrap_width) = self.wrap_width {
+ for boundary_ix in self
+ .font_system
+ .wrap_line(&line, font_id, font_size, wrap_width)
+ {
+ let wrapped = &line[prev_boundary_ix..boundary_ix];
+ new_transforms
+ .push_or_extend(Transform::isomorphic(TextSummary::from(wrapped)));
+ new_transforms.push_or_extend(Transform::newline());
+ prev_boundary_ix = boundary_ix;
+ }
}
if prev_boundary_ix < line.len() {
@@ -574,36 +583,6 @@ mod tests {
use rand::prelude::*;
use std::env;
- #[gpui::test]
- async fn test_simple_wraps(mut cx: gpui::TestAppContext) {
- let text = "one two three four five\nsix seven eight";
- let font_cache = cx.font_cache().clone();
- let config = Config {
- wrap_width: 64.,
- font_family: font_cache.load_family(&["Helvetica"]).unwrap(),
- font_size: 14.0,
- };
-
- let buffer = cx.add_model(|cx| Buffer::new(0, text.to_string(), cx));
- let mut wrap_map = cx.read(|cx| {
- let fold_map = FoldMap::new(buffer.clone(), cx);
- let (folds_snapshot, edits) = fold_map.read(cx);
- let tab_map = TabMap::new(folds_snapshot.clone(), 4);
- let (tabs_snapshot, _) = tab_map.sync(folds_snapshot, edits);
- WrapMap::new(tabs_snapshot, config, cx)
- });
-
- wrap_map.background_snapshot.next().await;
- let snapshot = wrap_map.background_snapshot.next().await.unwrap();
-
- assert_eq!(
- snapshot
- .chunks_at(OutputPoint(Point::new(0, 3)))
- .collect::<String>(),
- " two \nthree four \nfive\nsix seven \neight"
- );
- }
-
#[gpui::test]
fn test_random_wraps(cx: &mut gpui::MutableAppContext) {
let iterations = env::var("ITERATIONS")
@@ -629,23 +608,25 @@ mod tests {
log::info!("Initial buffer text: {:?}", text);
Buffer::new(0, text, cx)
});
- let fold_map = FoldMap::new(buffer.clone(), cx.as_ref());
- let (folds_snapshot, edits) = fold_map.read(cx.as_ref());
- let tab_map = TabMap::new(folds_snapshot.clone(), rng.gen_range(1..=4));
- let (tabs_snapshot, _) = tab_map.sync(folds_snapshot, edits);
+ let (fold_map, folds_snapshot) = FoldMap::new(buffer.clone(), cx.as_ref());
+ let (tab_map, tabs_snapshot) =
+ TabMap::new(folds_snapshot.clone(), rng.gen_range(1..=4));
let font_cache = cx.font_cache().clone();
let font_system = cx.platform().fonts();
- let config = Config {
- wrap_width: rng.gen_range(100.0..=1000.0),
- font_family: font_cache.load_family(&["Helvetica"]).unwrap(),
- font_size: 14.0,
+ let wrap_width = rng.gen_range(100.0..=1000.0);
+ let settings = Settings {
+ tab_size: 4,
+ buffer_font_family: font_cache.load_family(&["Helvetica"]).unwrap(),
+ buffer_font_size: 14.0,
+ ..Settings::new(&font_cache).unwrap()
};
let font_id = font_cache
- .select_font(config.font_family, &Default::default())
+ .select_font(settings.buffer_font_family, &Default::default())
.unwrap();
let mut wrapper = BackgroundWrapper::new(
Snapshot::new(tabs_snapshot.clone()),
- config.clone(),
+ settings.clone(),
+ Some(wrap_width),
font_cache.clone(),
font_system.clone(),
);
@@ -656,12 +637,8 @@ mod tests {
wrapper.sync(tabs_snapshot.clone(), vec![edit]);
let unwrapped_text = tabs_snapshot.text();
- let expected_text = wrap_text(
- &unwrapped_text,
- config.wrap_width,
- font_id,
- font_system.as_ref(),
- );
+ let expected_text =
+ wrap_text(&unwrapped_text, wrap_width, font_id, font_system.as_ref());
let actual_text = wrapper
.snapshot
@@ -683,12 +660,8 @@ mod tests {
interpolated_snapshot.check_invariants();
let unwrapped_text = snapshot.text();
- let expected_text = wrap_text(
- &unwrapped_text,
- config.wrap_width,
- font_id,
- font_system.as_ref(),
- );
+ let expected_text =
+ wrap_text(&unwrapped_text, wrap_width, font_id, font_system.as_ref());
wrapper.sync(snapshot, edits);
wrapper.snapshot.check_invariants();
let actual_text = wrapper
@@ -17,8 +17,9 @@ mod util;
pub mod workspace;
pub mod worktree;
+pub use settings::Settings;
pub struct AppState {
- pub settings: postage::watch::Receiver<settings::Settings>,
+ pub settings: postage::watch::Receiver<Settings>,
pub languages: std::sync::Arc<language::LanguageRegistry>,
pub rpc_router: std::sync::Arc<ForegroundRouter>,
pub rpc: rpc::Client,
@@ -49,6 +49,11 @@ impl Settings {
),
})
}
+
+ pub fn with_tab_size(mut self, tab_size: usize) -> Self {
+ self.tab_size = tab_size;
+ self
+ }
}
impl Theme {