diff --git a/Cargo.lock b/Cargo.lock index d380fa4306..605ddf6c26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3632,6 +3632,7 @@ dependencies = [ "rpc", "serde", "serde_json", + "settings", "sha2 0.10.2", "similar", "smol", diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index 27db9a8de5..6bf495c91f 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -12,6 +12,7 @@ use gpui::{ Entity, ModelContext, ModelHandle, }; use language::{Point, Subscription as BufferSubscription}; +use settings::Settings; use std::{any::TypeId, fmt::Debug, ops::Range, sync::Arc}; use sum_tree::{Bias, TreeMap}; use tab_map::TabMap; @@ -46,8 +47,6 @@ impl Entity for DisplayMap { impl DisplayMap { pub fn new( buffer: ModelHandle, - // TODO - remove. read tab_size from settings inside - tab_size: usize, font_id: FontId, font_size: f32, wrap_width: Option, @@ -56,6 +55,8 @@ impl DisplayMap { cx: &mut ModelContext, ) -> Self { let buffer_subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); + + let tab_size = Self::tab_size(&buffer, cx); let (fold_map, snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx)); let (tab_map, snapshot) = TabMap::new(snapshot, tab_size); let (wrap_map, snapshot) = WrapMap::new(snapshot, font_id, font_size, wrap_width, cx); @@ -78,8 +79,8 @@ impl DisplayMap { let edits = self.buffer_subscription.consume().into_inner(); let (folds_snapshot, edits) = self.fold_map.read(buffer_snapshot, edits); - // TODO: Pull tabsize out of cx and pass it to sync - let (tabs_snapshot, edits) = self.tab_map.sync(folds_snapshot.clone(), edits); + let tab_size = Self::tab_size(&self.buffer, cx); + let (tabs_snapshot, edits) = self.tab_map.sync(folds_snapshot.clone(), edits, tab_size); let (wraps_snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(tabs_snapshot.clone(), edits, cx)); @@ -103,14 +104,15 @@ impl DisplayMap { ) { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); + let tab_size = Self::tab_size(&self.buffer, cx); let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits); - let (snapshot, edits) = self.tab_map.sync(snapshot, edits); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); self.block_map.read(snapshot, edits); let (snapshot, edits) = fold_map.fold(ranges); - let (snapshot, edits) = self.tab_map.sync(snapshot, edits); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -125,14 +127,15 @@ impl DisplayMap { ) { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); + let tab_size = Self::tab_size(&self.buffer, cx); let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits); - let (snapshot, edits) = self.tab_map.sync(snapshot, edits); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); self.block_map.read(snapshot, edits); let (snapshot, edits) = fold_map.unfold(ranges, inclusive); - let (snapshot, edits) = self.tab_map.sync(snapshot, edits); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -146,8 +149,9 @@ impl DisplayMap { ) -> Vec { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); + let tab_size = Self::tab_size(&self.buffer, cx); let (snapshot, edits) = self.fold_map.read(snapshot, edits); - let (snapshot, edits) = self.tab_map.sync(snapshot, edits); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -162,8 +166,9 @@ impl DisplayMap { pub fn remove_blocks(&mut self, ids: HashSet, cx: &mut ModelContext) { let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); + let tab_size = Self::tab_size(&self.buffer, cx); let (snapshot, edits) = self.fold_map.read(snapshot, edits); - let (snapshot, edits) = self.tab_map.sync(snapshot, edits); + let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self .wrap_map .update(cx, |map, cx| map.sync(snapshot, edits, cx)); @@ -198,6 +203,11 @@ impl DisplayMap { .update(cx, |map, cx| map.set_wrap_width(width, cx)) } + fn tab_size(buffer: &ModelHandle, cx: &mut ModelContext) -> u32 { + let language_name = buffer.read(cx).language(cx).map(|language| language.name()); + cx.global::().tab_size(language_name.as_deref()) + } + #[cfg(test)] pub fn is_rewrapping(&self, cx: &gpui::AppContext) -> bool { self.wrap_map.read(cx).is_rewrapping() @@ -539,6 +549,8 @@ pub mod tests { log::info!("tab size: {}", tab_size); log::info!("wrap width: {:?}", wrap_width); + cx.update(|cx| cx.set_global(Settings::test(cx))); + let buffer = cx.update(|cx| { if rng.gen() { let len = rng.gen_range(0..10); @@ -552,7 +564,6 @@ pub mod tests { let map = cx.add_model(|cx| { DisplayMap::new( buffer.clone(), - tab_size, font_id, font_size, wrap_width, @@ -762,27 +773,18 @@ pub mod tests { let font_cache = cx.font_cache(); - let tab_size = 4; let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); let font_size = 12.0; let wrap_width = Some(64.); + cx.set_global(Settings::test(cx)); let text = "one two three four five\nsix seven eight"; let buffer = MultiBuffer::build_simple(text, cx); let map = cx.add_model(|cx| { - DisplayMap::new( - buffer.clone(), - tab_size, - font_id, - font_size, - wrap_width, - 1, - 1, - cx, - ) + DisplayMap::new(buffer.clone(), font_id, font_size, wrap_width, 1, 1, cx) }); let snapshot = map.update(cx, |map, cx| map.snapshot(cx)); @@ -850,18 +852,17 @@ pub mod tests { #[gpui::test] fn test_text_chunks(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); let text = sample_text(6, 6, 'a'); let buffer = MultiBuffer::build_simple(&text, cx); - let tab_size = 4; let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); let font_id = cx .font_cache() .select_font(family_id, &Default::default()) .unwrap(); let font_size = 14.0; - let map = cx.add_model(|cx| { - DisplayMap::new(buffer.clone(), tab_size, font_id, font_size, None, 1, 1, cx) - }); + let map = + cx.add_model(|cx| DisplayMap::new(buffer.clone(), font_id, font_size, None, 1, 1, cx)); buffer.update(cx, |buffer, cx| { buffer.edit( vec![ @@ -926,12 +927,17 @@ pub mod tests { .unwrap(), ); language.set_theme(&theme); + cx.update(|cx| { + cx.set_global(Settings { + tab_size: 2, + ..Settings::test(cx) + }) + }); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); buffer.condition(&cx, |buf, _| !buf.is_parsing()).await; let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); - let tab_size = 2; let font_cache = cx.font_cache(); let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); let font_id = font_cache @@ -939,8 +945,7 @@ pub mod tests { .unwrap(); let font_size = 14.0; - let map = cx - .add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, 1, 1, cx)); + let map = cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx)); assert_eq!( cx.update(|cx| syntax_chunks(0..5, &map, &theme, cx)), vec![ @@ -1014,22 +1019,22 @@ pub mod tests { ); language.set_theme(&theme); + cx.update(|cx| cx.set_global(Settings::test(cx))); + let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx)); buffer.condition(&cx, |buf, _| !buf.is_parsing()).await; let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let font_cache = cx.font_cache(); - let tab_size = 4; let family_id = font_cache.load_family(&["Courier"]).unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); let font_size = 16.0; - let map = cx.add_model(|cx| { - DisplayMap::new(buffer, tab_size, font_id, font_size, Some(40.0), 1, 1, cx) - }); + let map = + cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, Some(40.0), 1, 1, cx)); assert_eq!( cx.update(|cx| syntax_chunks(0..5, &map, &theme, cx)), [ @@ -1061,6 +1066,7 @@ pub mod tests { async fn test_chunks_with_text_highlights(cx: &mut gpui::TestAppContext) { cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX); + cx.update(|cx| cx.set_global(Settings::test(cx))); let theme = SyntaxTheme::new(vec![ ("operator".to_string(), Color::red().into()), ("string".to_string(), Color::green().into()), @@ -1093,14 +1099,12 @@ pub mod tests { let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx)); let font_cache = cx.font_cache(); - let tab_size = 4; let family_id = font_cache.load_family(&["Courier"]).unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); let font_size = 16.0; - let map = cx - .add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, 1, 1, cx)); + let map = cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx)); enum MyType {} @@ -1139,6 +1143,7 @@ pub mod tests { #[gpui::test] fn test_clip_point(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); fn assert(text: &str, shift_right: bool, bias: Bias, cx: &mut gpui::MutableAppContext) { let (unmarked_snapshot, mut markers) = marked_display_snapshot(text, cx); @@ -1190,6 +1195,8 @@ pub mod tests { #[gpui::test] fn test_clip_at_line_ends(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); + fn assert(text: &str, cx: &mut gpui::MutableAppContext) { let (mut unmarked_snapshot, markers) = marked_display_snapshot(text, cx); unmarked_snapshot.clip_at_line_ends = true; @@ -1207,9 +1214,9 @@ pub mod tests { #[gpui::test] fn test_tabs_with_multibyte_chars(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); let text = "✅\t\tα\nβ\t\n🏀β\t\tγ"; let buffer = MultiBuffer::build_simple(text, cx); - let tab_size = 4; let font_cache = cx.font_cache(); let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); let font_id = font_cache @@ -1217,9 +1224,8 @@ pub mod tests { .unwrap(); let font_size = 14.0; - let map = cx.add_model(|cx| { - DisplayMap::new(buffer.clone(), tab_size, font_id, font_size, None, 1, 1, cx) - }); + let map = + cx.add_model(|cx| DisplayMap::new(buffer.clone(), font_id, font_size, None, 1, 1, cx)); let map = map.update(cx, |map, cx| map.snapshot(cx)); assert_eq!(map.text(), "✅ α\nβ \n🏀β γ"); assert_eq!( @@ -1267,17 +1273,16 @@ pub mod tests { #[gpui::test] fn test_max_point(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); let buffer = MultiBuffer::build_simple("aaa\n\t\tbbb", cx); - let tab_size = 4; let font_cache = cx.font_cache(); let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); let font_id = font_cache .select_font(family_id, &Default::default()) .unwrap(); let font_size = 14.0; - let map = cx.add_model(|cx| { - DisplayMap::new(buffer.clone(), tab_size, font_id, font_size, None, 1, 1, cx) - }); + let map = + cx.add_model(|cx| DisplayMap::new(buffer.clone(), font_id, font_size, None, 1, 1, cx)); assert_eq!( map.update(cx, |map, cx| map.snapshot(cx)).max_point(), DisplayPoint::new(1, 11) diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 9d1b7a7588..d749b607eb 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -1157,7 +1157,7 @@ mod tests { let (folds_snapshot, fold_edits) = fold_map.read(buffer_snapshot, subscription.consume().into_inner()); - let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits); + let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits, 4); let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| { wrap_map.sync(tabs_snapshot, tab_edits, cx) }); @@ -1296,7 +1296,8 @@ mod tests { let (folds_snapshot, fold_edits) = fold_map.read(buffer_snapshot.clone(), vec![]); - let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits); + let (tabs_snapshot, tab_edits) = + tab_map.sync(folds_snapshot, fold_edits, tab_size); let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| { wrap_map.sync(tabs_snapshot, tab_edits, cx) }); @@ -1318,7 +1319,8 @@ mod tests { let (folds_snapshot, fold_edits) = fold_map.read(buffer_snapshot.clone(), vec![]); - let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits); + let (tabs_snapshot, tab_edits) = + tab_map.sync(folds_snapshot, fold_edits, tab_size); let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| { wrap_map.sync(tabs_snapshot, tab_edits, cx) }); @@ -1338,7 +1340,7 @@ mod tests { } let (folds_snapshot, fold_edits) = fold_map.read(buffer_snapshot.clone(), buffer_edits); - let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits); + let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits, tab_size); let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| { wrap_map.sync(tabs_snapshot, tab_edits, cx) }); diff --git a/crates/editor/src/display_map/tab_map.rs b/crates/editor/src/display_map/tab_map.rs index de76a6f261..77ec73d8bf 100644 --- a/crates/editor/src/display_map/tab_map.rs +++ b/crates/editor/src/display_map/tab_map.rs @@ -12,7 +12,7 @@ use text::Point; pub struct TabMap(Mutex); impl TabMap { - pub fn new(input: FoldSnapshot, tab_size: usize) -> (Self, TabSnapshot) { + pub fn new(input: FoldSnapshot, tab_size: u32) -> (Self, TabSnapshot) { let snapshot = TabSnapshot { fold_snapshot: input, tab_size, @@ -24,12 +24,13 @@ impl TabMap { &self, fold_snapshot: FoldSnapshot, mut fold_edits: Vec, + tab_size: u32, ) -> (TabSnapshot, Vec) { let mut old_snapshot = self.0.lock(); let max_offset = old_snapshot.fold_snapshot.len(); let new_snapshot = TabSnapshot { fold_snapshot, - tab_size: old_snapshot.tab_size, + tab_size, }; let mut tab_edits = Vec::with_capacity(fold_edits.len()); @@ -87,7 +88,7 @@ impl TabMap { #[derive(Clone)] pub struct TabSnapshot { pub fold_snapshot: FoldSnapshot, - pub tab_size: usize, + pub tab_size: u32, } impl TabSnapshot { @@ -234,7 +235,7 @@ impl TabSnapshot { .to_buffer_point(&self.fold_snapshot) } - fn expand_tabs(chars: impl Iterator, column: usize, tab_size: usize) -> usize { + fn expand_tabs(chars: impl Iterator, column: usize, tab_size: u32) -> usize { let mut expanded_chars = 0; let mut expanded_bytes = 0; let mut collapsed_bytes = 0; @@ -243,7 +244,7 @@ impl TabSnapshot { break; } if c == '\t' { - let tab_len = tab_size - expanded_chars % tab_size; + let tab_len = tab_size as usize - expanded_chars % tab_size as usize; expanded_bytes += tab_len; expanded_chars += tab_len; } else { @@ -259,7 +260,7 @@ impl TabSnapshot { mut chars: impl Iterator, column: usize, bias: Bias, - tab_size: usize, + tab_size: u32, ) -> (usize, usize, usize) { let mut expanded_bytes = 0; let mut expanded_chars = 0; @@ -270,7 +271,7 @@ impl TabSnapshot { } if c == '\t' { - let tab_len = tab_size - (expanded_chars % tab_size); + let tab_len = tab_size as usize - (expanded_chars % tab_size as usize); expanded_chars += tab_len; expanded_bytes += tab_len; if expanded_bytes > column { @@ -383,7 +384,7 @@ pub struct TabChunks<'a> { column: usize, output_position: Point, max_output_position: Point, - tab_size: usize, + tab_size: u32, skip_leading_tab: bool, } @@ -415,16 +416,16 @@ impl<'a> Iterator for TabChunks<'a> { }); } else { self.chunk.text = &self.chunk.text[1..]; - let mut len = self.tab_size - self.column % self.tab_size; + let mut len = self.tab_size - self.column as u32 % self.tab_size; let next_output_position = cmp::min( - self.output_position + Point::new(0, len as u32), + self.output_position + Point::new(0, len), self.max_output_position, ); - len = (next_output_position.column - self.output_position.column) as usize; - self.column += len; + len = next_output_position.column - self.output_position.column; + self.column += len as usize; self.output_position = next_output_position; return Some(Chunk { - text: &SPACES[0..len], + text: &SPACES[0..len as usize], ..self.chunk }); } diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index 2fab37fb30..790cc8017b 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -1104,7 +1104,8 @@ mod tests { } 20..=39 => { for (folds_snapshot, fold_edits) in fold_map.randomly_mutate(&mut rng) { - let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits); + let (tabs_snapshot, tab_edits) = + tab_map.sync(folds_snapshot, fold_edits, tab_size); let (mut snapshot, wrap_edits) = wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx)); snapshot.check_invariants(); @@ -1129,7 +1130,7 @@ mod tests { "Unwrapped text (unexpanded tabs): {:?}", folds_snapshot.text() ); - let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits); + let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits, tab_size); log::info!("Unwrapped text (expanded tabs): {:?}", tabs_snapshot.text()); let unwrapped_text = tabs_snapshot.text(); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 46d71ebeae..d52e456b95 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1010,7 +1010,6 @@ impl Editor { let style = build_style(&*settings, get_field_editor_theme, None, cx); DisplayMap::new( buffer.clone(), - settings.tab_size, style.text.font_id, style.text.font_size, None, @@ -3006,13 +3005,14 @@ impl Editor { ) .flat_map(str::chars) .count(); - let chars_to_next_tab_stop = tab_size - (char_column % tab_size); + let chars_to_next_tab_stop = + tab_size - (char_column as u32 % tab_size); buffer.edit( [selection.start..selection.start], - " ".repeat(chars_to_next_tab_stop), + " ".repeat(chars_to_next_tab_stop as usize), cx, ); - selection.start.column += chars_to_next_tab_stop as u32; + selection.start.column += chars_to_next_tab_stop; selection.end = selection.start; } }); @@ -3055,12 +3055,12 @@ impl Editor { } for row in start_row..end_row { - let indent_column = buffer.read(cx).indent_column_for_line(row) as usize; + let indent_column = buffer.read(cx).indent_column_for_line(row); let columns_to_next_tab_stop = tab_size - (indent_column % tab_size); let row_start = Point::new(row, 0); buffer.edit( [row_start..row_start], - " ".repeat(columns_to_next_tab_stop), + " ".repeat(columns_to_next_tab_stop as usize), cx, ); @@ -3101,11 +3101,11 @@ impl Editor { } for row in rows { - let column = buffer.indent_column_for_line(row) as usize; + let column = buffer.indent_column_for_line(row); if column > 0 { - let mut deletion_len = (column % tab_size) as u32; + let mut deletion_len = column % tab_size; if deletion_len == 0 { - deletion_len = tab_size as u32; + deletion_len = tab_size; } deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len)); last_outdent = Some(row); diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index cf2d772b16..d5f0f480fb 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -268,9 +268,11 @@ mod tests { use super::*; use crate::{test::marked_display_snapshot, Buffer, DisplayMap, MultiBuffer}; use language::Point; + use settings::Settings; #[gpui::test] fn test_previous_word_start(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) { let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); assert_eq!( @@ -297,6 +299,7 @@ mod tests { #[gpui::test] fn test_previous_subword_start(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) { let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); assert_eq!( @@ -330,6 +333,7 @@ mod tests { #[gpui::test] fn test_find_preceding_boundary(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); fn assert( marked_text: &str, cx: &mut gpui::MutableAppContext, @@ -361,6 +365,7 @@ mod tests { #[gpui::test] fn test_next_word_end(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) { let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); assert_eq!( @@ -384,6 +389,7 @@ mod tests { #[gpui::test] fn test_next_subword_end(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) { let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); assert_eq!( @@ -416,6 +422,7 @@ mod tests { #[gpui::test] fn test_find_boundary(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); fn assert( marked_text: &str, cx: &mut gpui::MutableAppContext, @@ -447,6 +454,7 @@ mod tests { #[gpui::test] fn test_surrounding_word(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) { let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); assert_eq!( @@ -467,6 +475,7 @@ mod tests { #[gpui::test] fn test_move_up_and_down_with_excerpts(cx: &mut gpui::MutableAppContext) { + cx.set_global(Settings::test(cx)); let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); let font_id = cx .font_cache() @@ -487,7 +496,7 @@ mod tests { multibuffer }); let display_map = - cx.add_model(|cx| DisplayMap::new(multibuffer, 2, font_id, 14.0, None, 2, 2, cx)); + cx.add_model(|cx| DisplayMap::new(multibuffer, font_id, 14.0, None, 2, 2, cx)); let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx)); assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn"); diff --git a/crates/editor/src/test.rs b/crates/editor/src/test.rs index e80547c9dd..7de488a7c7 100644 --- a/crates/editor/src/test.rs +++ b/crates/editor/src/test.rs @@ -20,7 +20,6 @@ pub fn marked_display_snapshot( ) -> (DisplaySnapshot, Vec) { let (unmarked_text, markers) = marked_text(text); - let tab_size = 4; let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); let font_id = cx .font_cache() @@ -30,7 +29,7 @@ pub fn marked_display_snapshot( let buffer = MultiBuffer::build_simple(&unmarked_text, cx); let display_map = - cx.add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, 1, 1, cx)); + cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx)); let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx)); let markers = markers .into_iter() diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 7dfe9a54de..7c4bfbd93d 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -8,6 +8,7 @@ use gpui::{ ViewContext, ViewHandle, WeakViewHandle, }; use project::{Project, ProjectPath, WorktreeId}; +use settings::Settings; use std::{ cmp, path::Path, @@ -21,7 +22,6 @@ use workspace::{ menu::{Confirm, SelectNext, SelectPrev}, Workspace, }; -use settings::Settings; pub struct FileFinder { handle: WeakViewHandle, diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 0888e3347e..6eb5a8f616 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1019,7 +1019,10 @@ impl MutableAppContext { .insert(TypeId::of::(), handler) .is_some() { - panic!("registered multiple global handlers for the same action type"); + panic!( + "registered multiple global handlers for {}", + type_name::() + ); } } @@ -2355,11 +2358,11 @@ impl AppContext { } pub fn global(&self) -> &T { - self.globals - .get(&TypeId::of::()) - .expect("no app state has been added for this type") - .downcast_ref() - .unwrap() + if let Some(global) = self.globals.get(&TypeId::of::()) { + global.downcast_ref().unwrap() + } else { + panic!("no global has been added for {}", type_name::()); + } } } diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 89f6999efa..8fda3aa0f3 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -25,6 +25,7 @@ gpui = { path = "../gpui" } language = { path = "../language" } lsp = { path = "../lsp" } rpc = { path = "../rpc" } +settings = { path = "../settings" } sum_tree = { path = "../sum_tree" } util = { path = "../util" } aho-corasick = "0.7" diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index b3fe42bbd3..d9a9052235 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -28,6 +28,7 @@ use parking_lot::Mutex; use postage::watch; use rand::prelude::*; use search::SearchQuery; +use settings::Settings; use sha2::{Digest, Sha256}; use similar::{ChangeTag, TextDiff}; use std::{ @@ -2173,6 +2174,10 @@ impl Project { lsp::Url::from_file_path(&buffer_abs_path).unwrap(), ); let capabilities = &language_server.capabilities(); + let tab_size = cx.update(|cx| { + let language_name = buffer.read(cx).language().map(|language| language.name()); + cx.global::().tab_size(language_name.as_deref()) + }); let lsp_edits = if capabilities .document_formatting_provider .as_ref() @@ -2182,7 +2187,7 @@ impl Project { .request::(lsp::DocumentFormattingParams { text_document, options: lsp::FormattingOptions { - tab_size: 4, + tab_size, insert_spaces: true, insert_final_newline: Some(true), ..Default::default() diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 5dc93245b9..c87a3a2391 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -8,9 +8,9 @@ use gpui::{ }; use language::OffsetRangeExt; use project::search::SearchQuery; +use settings::Settings; use std::ops::Range; use workspace::{ItemHandle, Pane, ToolbarItemLocation, ToolbarItemView}; -use settings::Settings; action!(Deploy, bool); action!(Dismiss); diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 467456b2fc..c897586017 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -11,7 +11,7 @@ pub struct Settings { pub buffer_font_family: FamilyId, pub buffer_font_size: f32, pub vim_mode: bool, - pub tab_size: usize, + pub tab_size: u32, pub soft_wrap: SoftWrap, pub preferred_line_length: u32, pub language_overrides: HashMap, LanguageOverride>, @@ -20,7 +20,7 @@ pub struct Settings { #[derive(Clone, Debug, Default, Deserialize, JsonSchema)] pub struct LanguageOverride { - pub tab_size: Option, + pub tab_size: Option, pub soft_wrap: Option, pub preferred_line_length: Option, } @@ -81,7 +81,7 @@ impl Settings { self } - pub fn tab_size(&self, language: Option<&str>) -> usize { + pub fn tab_size(&self, language: Option<&str>) -> u32 { language .and_then(|language| self.language_overrides.get(language)) .and_then(|settings| settings.tab_size) diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index a13cbe86f9..653788187b 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -48,6 +48,20 @@ fn main() { soft_wrap: Some(settings::SoftWrap::PreferredLineLength), ..Default::default() }, + ) + .with_overrides( + "Rust", + settings::LanguageOverride { + tab_size: Some(4), + ..Default::default() + }, + ) + .with_overrides( + "TypeScript", + settings::LanguageOverride { + tab_size: Some(2), + ..Default::default() + }, ); let settings_file = load_settings_file(&app, fs.clone());