diff --git a/.zed/settings.json b/.zed/settings.json index 8ede01358d6b245d1d3f82ff987e9a4dba4e965f..f7437543c3c0a038cef2434b647069bb18cedd7a 100644 --- a/.zed/settings.json +++ b/.zed/settings.json @@ -61,5 +61,5 @@ "**/.classpath", "**/.settings", ], - "read_only_files": ["**/.rustup/**", "**/.cargo/registry/**", "**/.cargo/git/**", "target/**"], + "read_only_files": ["**/.rustup/**", "**/.cargo/registry/**", "**/.cargo/git/**", "target/**", "**/*.lock"], } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 8560705802264dad55b87dbf21e1f9aa7625edf8..7413af66149784c2e990e9a0731eba04c1bd5886 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -3351,7 +3351,12 @@ impl Editor { { let start_offset = selection_start.to_offset(buffer); let position_matches = start_offset == completion_position.to_offset(buffer); - let continue_showing = if position_matches { + let continue_showing = if let Some((snap, ..)) = + buffer.point_to_buffer_offset(completion_position) + && snap.capability == Capability::ReadOnly + { + false + } else if position_matches { if self.snippet_stack.is_empty() { buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion)) == Some(CharKind::Word) @@ -4310,10 +4315,26 @@ impl Editor { let mut new_autoclose_regions = Vec::new(); let snapshot = self.buffer.read(cx).read(cx); let mut clear_linked_edit_ranges = false; + let mut all_selections_read_only = true; for (selection, autoclose_region) in self.selections_with_autoclose_regions(selections, &snapshot) { + if snapshot + .point_to_buffer_point(selection.head()) + .is_none_or(|(snapshot, ..)| snapshot.capability == Capability::ReadOnly) + { + continue; + } + if snapshot + .point_to_buffer_point(selection.tail()) + .is_none_or(|(snapshot, ..)| snapshot.capability == Capability::ReadOnly) + { + // note, ideally we'd clip the tail to the closest writeable region towards the head + continue; + } + all_selections_read_only = false; + if let Some(scope) = snapshot.language_scope_at(selection.head()) { // Determine if the inserted text matches the opening or closing // bracket of any of this language's bracket pairs. @@ -4593,6 +4614,10 @@ impl Editor { edits.push((selection.start..selection.end, text.clone())); } + if all_selections_read_only { + return; + } + drop(snapshot); self.transact(window, cx, |this, window, cx| { diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 4c3b44335bcad10be4303d545a8d2ad505938098..a658b4616c4c429ec27b63931790a54ccd71cfa6 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -51,7 +51,7 @@ use gpui::{ quad, relative, size, solid_background, transparent_black, }; use itertools::Itertools; -use language::{IndentGuideSettings, language_settings::ShowWhitespaceSetting}; +use language::{Capability, IndentGuideSettings, language_settings::ShowWhitespaceSetting}; use markdown::Markdown; use multi_buffer::{ Anchor, ExcerptId, ExcerptInfo, ExpandExcerptDirection, ExpandInfo, MultiBufferPoint, @@ -4146,6 +4146,14 @@ impl EditorElement { } })), ) + .when( + for_excerpt.buffer.capability == Capability::ReadOnly, + |el| { + el.child( + Icon::new(IconName::FileLock).color(Color::Muted), + ) + }, + ) .when_some(parent_path, |then, path| { then.child(Label::new(path).truncate().color( if file_status.is_some_and(FileStatus::is_deleted) { diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 99e0c8d4ebdad709eea0e9ab6dbdf9d889d54ec5..0e4dd56449e4810d7c6e8040667d9dcba1358ca8 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -188,6 +188,7 @@ pub struct BufferSnapshot { language: Option>, non_text_state_update_count: usize, tree_sitter_data: Arc, + pub capability: Capability, } /// The kind and amount of indentation in a particular line. For now, @@ -1135,6 +1136,7 @@ impl Buffer { tree_sitter_data: Arc::new(tree_sitter_data), language, non_text_state_update_count: 0, + capability: Capability::ReadOnly, } } } @@ -1160,6 +1162,7 @@ impl Buffer { remote_selections: Default::default(), language: None, non_text_state_update_count: 0, + capability: Capability::ReadOnly, } } @@ -1189,6 +1192,7 @@ impl Buffer { remote_selections: Default::default(), language, non_text_state_update_count: 0, + capability: Capability::ReadOnly, } } @@ -1215,6 +1219,7 @@ impl Buffer { diagnostics: self.diagnostics.clone(), language: self.language.clone(), non_text_state_update_count: self.non_text_state_update_count, + capability: self.capability, } } @@ -5138,6 +5143,7 @@ impl Clone for BufferSnapshot { language: self.language.clone(), tree_sitter_data: self.tree_sitter_data.clone(), non_text_state_update_count: self.non_text_state_update_count, + capability: self.capability, } } } diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 0c0e87b60a7b8950f7461228c929503d516791e0..8424c85f9670aea69952da055eb5a8932ca83f9e 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -1431,7 +1431,9 @@ impl MultiBuffer { (end_region.buffer_range.start + end_overshoot).min(end_region.buffer_range.end); if start_region.excerpt.id == end_region.excerpt.id { - if start_region.is_main_buffer { + if start_region.buffer.capability == Capability::ReadWrite + && start_region.is_main_buffer + { edited_excerpt_ids.push(start_region.excerpt.id); buffer_edits .entry(start_region.buffer.remote_id()) @@ -1447,7 +1449,9 @@ impl MultiBuffer { } else { let start_excerpt_range = buffer_start..start_region.buffer_range.end; let end_excerpt_range = end_region.buffer_range.start..buffer_end; - if start_region.is_main_buffer { + if start_region.buffer.capability == Capability::ReadWrite + && start_region.is_main_buffer + { edited_excerpt_ids.push(start_region.excerpt.id); buffer_edits .entry(start_region.buffer.remote_id()) @@ -1460,7 +1464,9 @@ impl MultiBuffer { excerpt_id: start_region.excerpt.id, }); } - if end_region.is_main_buffer { + if end_region.buffer.capability == Capability::ReadWrite + && end_region.is_main_buffer + { edited_excerpt_ids.push(end_region.excerpt.id); buffer_edits .entry(end_region.buffer.remote_id()) @@ -1480,7 +1486,7 @@ impl MultiBuffer { if region.excerpt.id == end_region.excerpt.id { break; } - if region.is_main_buffer { + if region.buffer.capability == Capability::ReadWrite && region.is_main_buffer { edited_excerpt_ids.push(region.excerpt.id); buffer_edits .entry(region.buffer.remote_id()) @@ -1560,26 +1566,6 @@ impl MultiBuffer { } } - /// Inserts newlines at the given position to create an empty line, returning the start of the new line. - /// You can also request the insertion of empty lines above and below the line starting at the returned point. - /// Panics if the given position is invalid. - pub fn insert_empty_line( - &mut self, - position: impl ToPoint, - space_above: bool, - space_below: bool, - cx: &mut Context, - ) -> Point { - let multibuffer_point = position.to_point(&self.read(cx)); - let (buffer, buffer_point, _) = self.point_to_buffer_point(multibuffer_point, cx).unwrap(); - self.start_transaction(cx); - let empty_line_start = buffer.update(cx, |buffer, cx| { - buffer.insert_empty_line(buffer_point, space_above, space_below, cx) - }); - self.end_transaction(cx); - multibuffer_point + (empty_line_start - buffer_point) - } - pub fn set_active_selections( &self, selections: &[Selection],