Detailed changes
@@ -278,7 +278,7 @@ impl ProjectDiagnosticsEditor {
prev_excerpt_id = excerpt_id.clone();
first_excerpt_id.get_or_insert_with(|| prev_excerpt_id.clone());
group_state.excerpts.push(excerpt_id.clone());
- let header_position = (excerpt_id.clone(), language::Anchor::min());
+ let header_position = (excerpt_id.clone(), language::Anchor::MIN);
if is_first_excerpt_for_group {
is_first_excerpt_for_group = false;
@@ -367,8 +367,7 @@ impl ProjectDiagnosticsEditor {
range_a
.start
.cmp(&range_b.start, &snapshot)
- .unwrap()
- .then_with(|| range_a.end.cmp(&range_b.end, &snapshot).unwrap())
+ .then_with(|| range_a.end.cmp(&range_b.end, &snapshot))
});
if path_state.diagnostic_groups.is_empty() {
@@ -490,7 +490,10 @@ impl ToDisplayPoint for Anchor {
#[cfg(test)]
mod tests {
use super::*;
- use crate::movement;
+ use crate::{
+ movement,
+ test::{marked_text_ranges},
+ };
use gpui::{color::Color, elements::*, test::observe, MutableAppContext};
use language::{Buffer, Language, LanguageConfig, RandomCharIter, SelectionGoal};
use rand::{prelude::*, Rng};
@@ -930,7 +933,7 @@ mod tests {
let map = cx
.add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, 1, 1, cx));
assert_eq!(
- cx.update(|cx| chunks(0..5, &map, &theme, cx)),
+ cx.update(|cx| syntax_chunks(0..5, &map, &theme, cx)),
vec![
("fn ".to_string(), None),
("outer".to_string(), Some(Color::blue())),
@@ -941,7 +944,7 @@ mod tests {
]
);
assert_eq!(
- cx.update(|cx| chunks(3..5, &map, &theme, cx)),
+ cx.update(|cx| syntax_chunks(3..5, &map, &theme, cx)),
vec![
(" fn ".to_string(), Some(Color::red())),
("inner".to_string(), Some(Color::blue())),
@@ -953,7 +956,7 @@ mod tests {
map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)
});
assert_eq!(
- cx.update(|cx| chunks(0..2, &map, &theme, cx)),
+ cx.update(|cx| syntax_chunks(0..2, &map, &theme, cx)),
vec![
("fn ".to_string(), None),
("out".to_string(), Some(Color::blue())),
@@ -1019,7 +1022,7 @@ mod tests {
DisplayMap::new(buffer, tab_size, font_id, font_size, Some(40.0), 1, 1, cx)
});
assert_eq!(
- cx.update(|cx| chunks(0..5, &map, &theme, cx)),
+ cx.update(|cx| syntax_chunks(0..5, &map, &theme, cx)),
[
("fn \n".to_string(), None),
("oute\nr".to_string(), Some(Color::blue())),
@@ -1027,7 +1030,7 @@ mod tests {
]
);
assert_eq!(
- cx.update(|cx| chunks(3..5, &map, &theme, cx)),
+ cx.update(|cx| syntax_chunks(3..5, &map, &theme, cx)),
[("{}\n\n".to_string(), None)]
);
@@ -1035,7 +1038,7 @@ mod tests {
map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)
});
assert_eq!(
- cx.update(|cx| chunks(1..4, &map, &theme, cx)),
+ cx.update(|cx| syntax_chunks(1..4, &map, &theme, cx)),
[
("out".to_string(), Some(Color::blue())),
("…\n".to_string(), None),
@@ -1045,6 +1048,89 @@ mod tests {
);
}
+ #[gpui::test]
+ async fn test_chunks_with_text_highlights(cx: &mut gpui::TestAppContext) {
+ cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX);
+
+ let theme = SyntaxTheme::new(vec![
+ ("operator".to_string(), Color::red().into()),
+ ("string".to_string(), Color::green().into()),
+ ]);
+ let language = Arc::new(
+ Language::new(
+ LanguageConfig {
+ name: "Test".into(),
+ path_suffixes: vec![".test".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ )
+ .with_highlights_query(
+ r#"
+ ":" @operator
+ (string_literal) @string
+ "#,
+ )
+ .unwrap(),
+ );
+ language.set_theme(&theme);
+
+ let (text, highlighted_ranges) = marked_text_ranges(
+ r#"const{} <a>: B = "c [d]""#,
+ vec![('{', '}'), ('<', '>'), ('[', ']')],
+ );
+
+ 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 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));
+
+ enum MyType {}
+
+ let style = HighlightStyle {
+ color: Some(Color::blue()),
+ ..Default::default()
+ };
+
+ map.update(cx, |map, _cx| {
+ map.highlight_text(
+ TypeId::of::<MyType>(),
+ highlighted_ranges
+ .into_iter()
+ .map(|range| {
+ buffer_snapshot.anchor_before(range.start)
+ ..buffer_snapshot.anchor_before(range.end)
+ })
+ .collect(),
+ style,
+ );
+ });
+
+ assert_eq!(
+ cx.update(|cx| chunks(0..10, &map, &theme, cx)),
+ [
+ ("const ".to_string(), None, None),
+ ("a".to_string(), None, Some(Color::blue())),
+ (":".to_string(), Some(Color::red()), None),
+ (" B = ".to_string(), None, None),
+ ("\"c ".to_string(), Some(Color::green()), None),
+ ("d".to_string(), Some(Color::green()), Some(Color::blue())),
+ ("\"".to_string(), Some(Color::green()), None),
+ ]
+ );
+ }
+
#[gpui::test]
fn test_clip_point(cx: &mut gpui::MutableAppContext) {
use Bias::{Left, Right};
@@ -1171,27 +1257,38 @@ mod tests {
)
}
- fn chunks<'a>(
+ fn syntax_chunks<'a>(
rows: Range<u32>,
map: &ModelHandle<DisplayMap>,
theme: &'a SyntaxTheme,
cx: &mut MutableAppContext,
) -> Vec<(String, Option<Color>)> {
+ chunks(rows, map, theme, cx)
+ .into_iter()
+ .map(|(text, color, _)| (text, color))
+ .collect()
+ }
+
+ fn chunks<'a>(
+ rows: Range<u32>,
+ map: &ModelHandle<DisplayMap>,
+ theme: &'a SyntaxTheme,
+ cx: &mut MutableAppContext,
+ ) -> Vec<(String, Option<Color>, Option<Color>)> {
let snapshot = map.update(cx, |map, cx| map.snapshot(cx));
- let mut chunks: Vec<(String, Option<Color>)> = Vec::new();
+ let mut chunks: Vec<(String, Option<Color>, Option<Color>)> = Vec::new();
for chunk in snapshot.chunks(rows, true) {
- let color = chunk
+ let syntax_color = chunk
.syntax_highlight_id
.and_then(|id| id.style(theme)?.color);
- if let Some((last_chunk, last_color)) = chunks.last_mut() {
- if color == *last_color {
+ let highlight_color = chunk.highlight_style.and_then(|style| style.color);
+ if let Some((last_chunk, last_syntax_color, last_highlight_color)) = chunks.last_mut() {
+ if syntax_color == *last_syntax_color && highlight_color == *last_highlight_color {
last_chunk.push_str(chunk.text);
- } else {
- chunks.push((chunk.text.to_string(), color));
+ continue;
}
- } else {
- chunks.push((chunk.text.to_string(), color));
}
+ chunks.push((chunk.text.to_string(), syntax_color, highlight_color));
}
chunks
}
@@ -499,7 +499,7 @@ impl<'a> BlockMapWriter<'a> {
let block_ix = match self
.0
.blocks
- .binary_search_by(|probe| probe.position.cmp(&position, &buffer).unwrap())
+ .binary_search_by(|probe| probe.position.cmp(&position, &buffer))
{
Ok(ix) | Err(ix) => ix,
};
@@ -257,7 +257,7 @@ impl FoldMap {
let mut folds = self.folds.iter().peekable();
while let Some(fold) = folds.next() {
if let Some(next_fold) = folds.peek() {
- let comparison = fold.0.cmp(&next_fold.0, &self.buffer.lock()).unwrap();
+ let comparison = fold.0.cmp(&next_fold.0, &self.buffer.lock());
assert!(comparison.is_le());
}
}
@@ -700,10 +700,7 @@ impl FoldSnapshot {
let ranges = &highlights.1;
let start_ix = match ranges.binary_search_by(|probe| {
- let cmp = probe
- .end
- .cmp(&transform_start, &self.buffer_snapshot())
- .unwrap();
+ let cmp = probe.end.cmp(&transform_start, &self.buffer_snapshot());
if cmp.is_gt() {
Ordering::Greater
} else {
@@ -716,7 +713,6 @@ impl FoldSnapshot {
if range
.start
.cmp(&transform_end, &self.buffer_snapshot)
- .unwrap()
.is_ge()
{
break;
@@ -821,8 +817,8 @@ where
let start = buffer.anchor_before(range.start.to_offset(buffer));
let end = buffer.anchor_after(range.end.to_offset(buffer));
let mut cursor = folds.filter::<_, usize>(move |summary| {
- let start_cmp = start.cmp(&summary.max_end, buffer).unwrap();
- let end_cmp = end.cmp(&summary.min_start, buffer).unwrap();
+ let start_cmp = start.cmp(&summary.max_end, buffer);
+ let end_cmp = end.cmp(&summary.min_start, buffer);
if inclusive {
start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal
@@ -963,19 +959,19 @@ impl sum_tree::Summary for FoldSummary {
type Context = MultiBufferSnapshot;
fn add_summary(&mut self, other: &Self, buffer: &MultiBufferSnapshot) {
- if other.min_start.cmp(&self.min_start, buffer).unwrap() == Ordering::Less {
+ if other.min_start.cmp(&self.min_start, buffer) == Ordering::Less {
self.min_start = other.min_start.clone();
}
- if other.max_end.cmp(&self.max_end, buffer).unwrap() == Ordering::Greater {
+ if other.max_end.cmp(&self.max_end, buffer) == Ordering::Greater {
self.max_end = other.max_end.clone();
}
#[cfg(debug_assertions)]
{
- let start_comparison = self.start.cmp(&other.start, buffer).unwrap();
+ let start_comparison = self.start.cmp(&other.start, buffer);
assert!(start_comparison <= Ordering::Equal);
if start_comparison == Ordering::Equal {
- assert!(self.end.cmp(&other.end, buffer).unwrap() >= Ordering::Equal);
+ assert!(self.end.cmp(&other.end, buffer) >= Ordering::Equal);
}
}
@@ -994,7 +990,7 @@ impl<'a> sum_tree::Dimension<'a, FoldSummary> for Fold {
impl<'a> sum_tree::SeekTarget<'a, FoldSummary, Fold> for Fold {
fn cmp(&self, other: &Self, buffer: &MultiBufferSnapshot) -> Ordering {
- self.0.cmp(&other.0, buffer).unwrap()
+ self.0.cmp(&other.0, buffer)
}
}
@@ -1157,7 +1153,7 @@ impl Ord for HighlightEndpoint {
fn cmp(&self, other: &Self) -> Ordering {
self.offset
.cmp(&other.offset)
- .then_with(|| self.is_start.cmp(&other.is_start))
+ .then_with(|| other.is_start.cmp(&self.is_start))
}
}
@@ -1606,9 +1602,8 @@ mod tests {
.filter(|fold| {
let start = buffer_snapshot.anchor_before(start);
let end = buffer_snapshot.anchor_after(end);
- start.cmp(&fold.0.end, &buffer_snapshot).unwrap() == Ordering::Less
- && end.cmp(&fold.0.start, &buffer_snapshot).unwrap()
- == Ordering::Greater
+ start.cmp(&fold.0.end, &buffer_snapshot) == Ordering::Less
+ && end.cmp(&fold.0.start, &buffer_snapshot) == Ordering::Greater
})
.map(|fold| fold.0)
.collect::<Vec<_>>();
@@ -1686,7 +1681,7 @@ mod tests {
let buffer = self.buffer.lock().clone();
let mut folds = self.folds.items(&buffer);
// Ensure sorting doesn't change how folds get merged and displayed.
- folds.sort_by(|a, b| a.0.cmp(&b.0, &buffer).unwrap());
+ folds.sort_by(|a, b| a.0.cmp(&b.0, &buffer));
let mut fold_ranges = folds
.iter()
.map(|fold| fold.0.start.to_offset(&buffer)..fold.0.end.to_offset(&buffer))
@@ -1744,134 +1744,135 @@ impl Editor {
pub fn handle_input(&mut self, action: &Input, cx: &mut ViewContext<Self>) {
let text = action.0.as_ref();
if !self.skip_autoclose_end(text, cx) {
- self.start_transaction(cx);
- if !self.surround_with_bracket_pair(text, cx) {
- self.insert(text, cx);
- self.autoclose_bracket_pairs(cx);
- }
- self.end_transaction(cx);
+ self.transact(cx, |this, cx| {
+ if !this.surround_with_bracket_pair(text, cx) {
+ this.insert(text, cx);
+ this.autoclose_bracket_pairs(cx);
+ }
+ });
self.trigger_completion_on_input(text, cx);
}
}
pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
- self.start_transaction(cx);
- let mut old_selections = SmallVec::<[_; 32]>::new();
- {
- let selections = self.local_selections::<usize>(cx);
- let buffer = self.buffer.read(cx).snapshot(cx);
- for selection in selections.iter() {
- let start_point = selection.start.to_point(&buffer);
- let indent = buffer
- .indent_column_for_line(start_point.row)
- .min(start_point.column);
- let start = selection.start;
- let end = selection.end;
-
- let mut insert_extra_newline = false;
- if let Some(language) = buffer.language() {
- let leading_whitespace_len = buffer
- .reversed_chars_at(start)
- .take_while(|c| c.is_whitespace() && *c != '\n')
- .map(|c| c.len_utf8())
- .sum::<usize>();
-
- let trailing_whitespace_len = buffer
- .chars_at(end)
- .take_while(|c| c.is_whitespace() && *c != '\n')
- .map(|c| c.len_utf8())
- .sum::<usize>();
-
- insert_extra_newline = language.brackets().iter().any(|pair| {
- let pair_start = pair.start.trim_end();
- let pair_end = pair.end.trim_start();
-
- pair.newline
- && buffer.contains_str_at(end + trailing_whitespace_len, pair_end)
- && buffer.contains_str_at(
- (start - leading_whitespace_len).saturating_sub(pair_start.len()),
- pair_start,
- )
- });
- }
+ self.transact(cx, |this, cx| {
+ let mut old_selections = SmallVec::<[_; 32]>::new();
+ {
+ let selections = this.local_selections::<usize>(cx);
+ let buffer = this.buffer.read(cx).snapshot(cx);
+ for selection in selections.iter() {
+ let start_point = selection.start.to_point(&buffer);
+ let indent = buffer
+ .indent_column_for_line(start_point.row)
+ .min(start_point.column);
+ let start = selection.start;
+ let end = selection.end;
+
+ let mut insert_extra_newline = false;
+ if let Some(language) = buffer.language() {
+ let leading_whitespace_len = buffer
+ .reversed_chars_at(start)
+ .take_while(|c| c.is_whitespace() && *c != '\n')
+ .map(|c| c.len_utf8())
+ .sum::<usize>();
+
+ let trailing_whitespace_len = buffer
+ .chars_at(end)
+ .take_while(|c| c.is_whitespace() && *c != '\n')
+ .map(|c| c.len_utf8())
+ .sum::<usize>();
+
+ insert_extra_newline = language.brackets().iter().any(|pair| {
+ let pair_start = pair.start.trim_end();
+ let pair_end = pair.end.trim_start();
+
+ pair.newline
+ && buffer.contains_str_at(end + trailing_whitespace_len, pair_end)
+ && buffer.contains_str_at(
+ (start - leading_whitespace_len)
+ .saturating_sub(pair_start.len()),
+ pair_start,
+ )
+ });
+ }
- old_selections.push((
- selection.id,
- buffer.anchor_after(end),
- start..end,
- indent,
- insert_extra_newline,
- ));
+ old_selections.push((
+ selection.id,
+ buffer.anchor_after(end),
+ start..end,
+ indent,
+ insert_extra_newline,
+ ));
+ }
}
- }
- self.buffer.update(cx, |buffer, cx| {
- let mut delta = 0_isize;
- let mut pending_edit: Option<PendingEdit> = None;
- for (_, _, range, indent, insert_extra_newline) in &old_selections {
- if pending_edit.as_ref().map_or(false, |pending| {
- pending.indent != *indent
- || pending.insert_extra_newline != *insert_extra_newline
- }) {
- let pending = pending_edit.take().unwrap();
- let mut new_text = String::with_capacity(1 + pending.indent as usize);
- new_text.push('\n');
- new_text.extend(iter::repeat(' ').take(pending.indent as usize));
- if pending.insert_extra_newline {
- new_text = new_text.repeat(2);
+ this.buffer.update(cx, |buffer, cx| {
+ let mut delta = 0_isize;
+ let mut pending_edit: Option<PendingEdit> = None;
+ for (_, _, range, indent, insert_extra_newline) in &old_selections {
+ if pending_edit.as_ref().map_or(false, |pending| {
+ pending.indent != *indent
+ || pending.insert_extra_newline != *insert_extra_newline
+ }) {
+ let pending = pending_edit.take().unwrap();
+ let mut new_text = String::with_capacity(1 + pending.indent as usize);
+ new_text.push('\n');
+ new_text.extend(iter::repeat(' ').take(pending.indent as usize));
+ if pending.insert_extra_newline {
+ new_text = new_text.repeat(2);
+ }
+ buffer.edit_with_autoindent(pending.ranges, new_text, cx);
+ delta += pending.delta;
}
- buffer.edit_with_autoindent(pending.ranges, new_text, cx);
- delta += pending.delta;
- }
- let start = (range.start as isize + delta) as usize;
- let end = (range.end as isize + delta) as usize;
- let mut text_len = *indent as usize + 1;
- if *insert_extra_newline {
- text_len *= 2;
+ let start = (range.start as isize + delta) as usize;
+ let end = (range.end as isize + delta) as usize;
+ let mut text_len = *indent as usize + 1;
+ if *insert_extra_newline {
+ text_len *= 2;
+ }
+
+ let pending = pending_edit.get_or_insert_with(Default::default);
+ pending.delta += text_len as isize - (end - start) as isize;
+ pending.indent = *indent;
+ pending.insert_extra_newline = *insert_extra_newline;
+ pending.ranges.push(start..end);
}
- let pending = pending_edit.get_or_insert_with(Default::default);
- pending.delta += text_len as isize - (end - start) as isize;
- pending.indent = *indent;
- pending.insert_extra_newline = *insert_extra_newline;
- pending.ranges.push(start..end);
- }
+ let pending = pending_edit.unwrap();
+ let mut new_text = String::with_capacity(1 + pending.indent as usize);
+ new_text.push('\n');
+ new_text.extend(iter::repeat(' ').take(pending.indent as usize));
+ if pending.insert_extra_newline {
+ new_text = new_text.repeat(2);
+ }
+ buffer.edit_with_autoindent(pending.ranges, new_text, cx);
- let pending = pending_edit.unwrap();
- let mut new_text = String::with_capacity(1 + pending.indent as usize);
- new_text.push('\n');
- new_text.extend(iter::repeat(' ').take(pending.indent as usize));
- if pending.insert_extra_newline {
- new_text = new_text.repeat(2);
- }
- buffer.edit_with_autoindent(pending.ranges, new_text, cx);
+ let buffer = buffer.read(cx);
+ this.selections = this
+ .selections
+ .iter()
+ .cloned()
+ .zip(old_selections)
+ .map(
+ |(mut new_selection, (_, end_anchor, _, _, insert_extra_newline))| {
+ let mut cursor = end_anchor.to_point(&buffer);
+ if insert_extra_newline {
+ cursor.row -= 1;
+ cursor.column = buffer.line_len(cursor.row);
+ }
+ let anchor = buffer.anchor_after(cursor);
+ new_selection.start = anchor.clone();
+ new_selection.end = anchor;
+ new_selection
+ },
+ )
+ .collect();
+ });
- let buffer = buffer.read(cx);
- self.selections = self
- .selections
- .iter()
- .cloned()
- .zip(old_selections)
- .map(
- |(mut new_selection, (_, end_anchor, _, _, insert_extra_newline))| {
- let mut cursor = end_anchor.to_point(&buffer);
- if insert_extra_newline {
- cursor.row -= 1;
- cursor.column = buffer.line_len(cursor.row);
- }
- let anchor = buffer.anchor_after(cursor);
- new_selection.start = anchor.clone();
- new_selection.end = anchor;
- new_selection
- },
- )
- .collect();
+ this.request_autoscroll(Autoscroll::Fit, cx);
});
- self.request_autoscroll(Autoscroll::Fit, cx);
- self.end_transaction(cx);
-
#[derive(Default)]
struct PendingEdit {
indent: u32,
@@ -1882,40 +1883,39 @@ impl Editor {
}
pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
- self.start_transaction(cx);
+ self.transact(cx, |this, cx| {
+ let old_selections = this.local_selections::<usize>(cx);
+ let selection_anchors = this.buffer.update(cx, |buffer, cx| {
+ let anchors = {
+ let snapshot = buffer.read(cx);
+ old_selections
+ .iter()
+ .map(|s| (s.id, s.goal, snapshot.anchor_after(s.end)))
+ .collect::<Vec<_>>()
+ };
+ let edit_ranges = old_selections.iter().map(|s| s.start..s.end);
+ buffer.edit_with_autoindent(edit_ranges, text, cx);
+ anchors
+ });
- let old_selections = self.local_selections::<usize>(cx);
- let selection_anchors = self.buffer.update(cx, |buffer, cx| {
- let anchors = {
- let snapshot = buffer.read(cx);
- old_selections
- .iter()
- .map(|s| (s.id, s.goal, snapshot.anchor_after(s.end)))
- .collect::<Vec<_>>()
+ let selections = {
+ let snapshot = this.buffer.read(cx).read(cx);
+ selection_anchors
+ .into_iter()
+ .map(|(id, goal, position)| {
+ let position = position.to_offset(&snapshot);
+ Selection {
+ id,
+ start: position,
+ end: position,
+ goal,
+ reversed: false,
+ }
+ })
+ .collect()
};
- let edit_ranges = old_selections.iter().map(|s| s.start..s.end);
- buffer.edit_with_autoindent(edit_ranges, text, cx);
- anchors
+ this.update_selections(selections, Some(Autoscroll::Fit), cx);
});
-
- let selections = {
- let snapshot = self.buffer.read(cx).read(cx);
- selection_anchors
- .into_iter()
- .map(|(id, goal, position)| {
- let position = position.to_offset(&snapshot);
- Selection {
- id,
- start: position,
- end: position,
- goal,
- reversed: false,
- }
- })
- .collect()
- };
- self.update_selections(selections, Some(Autoscroll::Fit), cx);
- self.end_transaction(cx);
}
fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
@@ -2284,21 +2284,21 @@ impl Editor {
}
let text = &text[common_prefix_len..];
- self.start_transaction(cx);
- if let Some(mut snippet) = snippet {
- snippet.text = text.to_string();
- for tabstop in snippet.tabstops.iter_mut().flatten() {
- tabstop.start -= common_prefix_len as isize;
- tabstop.end -= common_prefix_len as isize;
- }
+ self.transact(cx, |this, cx| {
+ if let Some(mut snippet) = snippet {
+ snippet.text = text.to_string();
+ for tabstop in snippet.tabstops.iter_mut().flatten() {
+ tabstop.start -= common_prefix_len as isize;
+ tabstop.end -= common_prefix_len as isize;
+ }
- self.insert_snippet(&ranges, snippet, cx).log_err();
- } else {
- self.buffer.update(cx, |buffer, cx| {
- buffer.edit_with_autoindent(ranges, text, cx);
- });
- }
- self.end_transaction(cx);
+ this.insert_snippet(&ranges, snippet, cx).log_err();
+ } else {
+ this.buffer.update(cx, |buffer, cx| {
+ buffer.edit_with_autoindent(ranges, text, cx);
+ });
+ }
+ });
let project = self.project.clone()?;
let apply_edits = project.update(cx, |project, cx| {
@@ -2397,7 +2397,7 @@ impl Editor {
) -> Result<()> {
let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
- // If the code action's edits are all contained within this editor, then
+ // If the project transaction's edits are all contained within this editor, then
// avoid opening a new editor to display them.
let mut entries = transaction.0.iter();
if let Some((buffer, transaction)) = entries.next() {
@@ -2519,7 +2519,6 @@ impl Editor {
}
let buffer_id = cursor_position.buffer_id;
- let excerpt_id = cursor_position.excerpt_id.clone();
let style = this.style(cx);
let read_background = style.document_highlight_read_background;
let write_background = style.document_highlight_write_background;
@@ -2531,22 +2530,39 @@ impl Editor {
return;
}
+ let cursor_buffer_snapshot = cursor_buffer.read(cx);
let mut write_ranges = Vec::new();
let mut read_ranges = Vec::new();
for highlight in highlights {
- let range = Anchor {
- buffer_id,
- excerpt_id: excerpt_id.clone(),
- text_anchor: highlight.range.start,
- }..Anchor {
- buffer_id,
- excerpt_id: excerpt_id.clone(),
- text_anchor: highlight.range.end,
- };
- if highlight.kind == lsp::DocumentHighlightKind::WRITE {
- write_ranges.push(range);
- } else {
- read_ranges.push(range);
+ for (excerpt_id, excerpt_range) in
+ buffer.excerpts_for_buffer(&cursor_buffer, cx)
+ {
+ let start = highlight
+ .range
+ .start
+ .max(&excerpt_range.start, cursor_buffer_snapshot);
+ let end = highlight
+ .range
+ .end
+ .min(&excerpt_range.end, cursor_buffer_snapshot);
+ if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
+ continue;
+ }
+
+ let range = Anchor {
+ buffer_id,
+ excerpt_id: excerpt_id.clone(),
+ text_anchor: start,
+ }..Anchor {
+ buffer_id,
+ excerpt_id,
+ text_anchor: end,
+ };
+ if highlight.kind == lsp::DocumentHighlightKind::WRITE {
+ write_ranges.push(range);
+ } else {
+ read_ranges.push(range);
+ }
}
}
@@ -2656,8 +2672,7 @@ impl Editor {
})
})
.collect::<Vec<_>>();
- tabstop_ranges
- .sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot).unwrap());
+ tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
tabstop_ranges
})
.collect::<Vec<_>>()
@@ -2732,14 +2747,13 @@ impl Editor {
}
pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
- self.start_transaction(cx);
- self.select_all(&SelectAll, cx);
- self.insert("", cx);
- self.end_transaction(cx);
+ self.transact(cx, |this, cx| {
+ this.select_all(&SelectAll, cx);
+ this.insert("", cx);
+ });
}
pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
- self.start_transaction(cx);
let mut selections = self.local_selections::<Point>(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
for selection in &mut selections {
@@ -2765,9 +2779,11 @@ impl Editor {
selection.set_head(new_head, SelectionGoal::None);
}
}
- self.update_selections(selections, Some(Autoscroll::Fit), cx);
- self.insert("", cx);
- self.end_transaction(cx);
+
+ self.transact(cx, |this, cx| {
+ this.update_selections(selections, Some(Autoscroll::Fit), cx);
+ this.insert("", cx);
+ });
}
pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
@@ -2787,75 +2803,76 @@ impl Editor {
return;
}
- self.start_transaction(cx);
let tab_size = cx.global::<Settings>().tab_size;
let mut selections = self.local_selections::<Point>(cx);
- let mut last_indent = None;
- self.buffer.update(cx, |buffer, cx| {
- for selection in &mut selections {
- if selection.is_empty() {
- let char_column = buffer
- .read(cx)
- .text_for_range(Point::new(selection.start.row, 0)..selection.start)
- .flat_map(str::chars)
- .count();
- let chars_to_next_tab_stop = tab_size - (char_column % tab_size);
- buffer.edit(
- [selection.start..selection.start],
- " ".repeat(chars_to_next_tab_stop),
- cx,
- );
- selection.start.column += chars_to_next_tab_stop as u32;
- selection.end = selection.start;
- } else {
- let mut start_row = selection.start.row;
- let mut end_row = selection.end.row + 1;
-
- // If a selection ends at the beginning of a line, don't indent
- // that last line.
- if selection.end.column == 0 {
- end_row -= 1;
- }
-
- // Avoid re-indenting a row that has already been indented by a
- // previous selection, but still update this selection's column
- // to reflect that indentation.
- if let Some((last_indent_row, last_indent_len)) = last_indent {
- if last_indent_row == selection.start.row {
- selection.start.column += last_indent_len;
- start_row += 1;
- }
- if last_indent_row == selection.end.row {
- selection.end.column += last_indent_len;
- }
- }
-
- for row in start_row..end_row {
- let indent_column = buffer.read(cx).indent_column_for_line(row) as usize;
- let columns_to_next_tab_stop = tab_size - (indent_column % tab_size);
- let row_start = Point::new(row, 0);
+ self.transact(cx, |this, cx| {
+ let mut last_indent = None;
+ this.buffer.update(cx, |buffer, cx| {
+ for selection in &mut selections {
+ if selection.is_empty() {
+ let char_column = buffer
+ .read(cx)
+ .text_for_range(Point::new(selection.start.row, 0)..selection.start)
+ .flat_map(str::chars)
+ .count();
+ let chars_to_next_tab_stop = tab_size - (char_column % tab_size);
buffer.edit(
- [row_start..row_start],
- " ".repeat(columns_to_next_tab_stop),
+ [selection.start..selection.start],
+ " ".repeat(chars_to_next_tab_stop),
cx,
);
+ selection.start.column += chars_to_next_tab_stop as u32;
+ selection.end = selection.start;
+ } else {
+ let mut start_row = selection.start.row;
+ let mut end_row = selection.end.row + 1;
- // Update this selection's endpoints to reflect the indentation.
- if row == selection.start.row {
- selection.start.column += columns_to_next_tab_stop as u32;
+ // If a selection ends at the beginning of a line, don't indent
+ // that last line.
+ if selection.end.column == 0 {
+ end_row -= 1;
}
- if row == selection.end.row {
- selection.end.column += columns_to_next_tab_stop as u32;
+
+ // Avoid re-indenting a row that has already been indented by a
+ // previous selection, but still update this selection's column
+ // to reflect that indentation.
+ if let Some((last_indent_row, last_indent_len)) = last_indent {
+ if last_indent_row == selection.start.row {
+ selection.start.column += last_indent_len;
+ start_row += 1;
+ }
+ if last_indent_row == selection.end.row {
+ selection.end.column += last_indent_len;
+ }
}
- last_indent = Some((row, columns_to_next_tab_stop as u32));
+ for row in start_row..end_row {
+ let indent_column =
+ buffer.read(cx).indent_column_for_line(row) as usize;
+ 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),
+ cx,
+ );
+
+ // Update this selection's endpoints to reflect the indentation.
+ if row == selection.start.row {
+ selection.start.column += columns_to_next_tab_stop as u32;
+ }
+ if row == selection.end.row {
+ selection.end.column += columns_to_next_tab_stop as u32;
+ }
+
+ last_indent = Some((row, columns_to_next_tab_stop as u32));
+ }
}
}
- }
- });
+ });
- self.update_selections(selections, Some(Autoscroll::Fit), cx);
- self.end_transaction(cx);
+ this.update_selections(selections, Some(Autoscroll::Fit), cx);
+ });
}
pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
@@ -2864,7 +2881,6 @@ impl Editor {
return;
}
- self.start_transaction(cx);
let tab_size = cx.global::<Settings>().tab_size;
let selections = self.local_selections::<Point>(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
@@ -2896,21 +2912,20 @@ impl Editor {
}
}
}
- self.buffer.update(cx, |buffer, cx| {
- buffer.edit(deletion_ranges, "", cx);
- });
- self.update_selections(
- self.local_selections::<usize>(cx),
- Some(Autoscroll::Fit),
- cx,
- );
- self.end_transaction(cx);
+ self.transact(cx, |this, cx| {
+ this.buffer.update(cx, |buffer, cx| {
+ buffer.edit(deletion_ranges, "", cx);
+ });
+ this.update_selections(
+ this.local_selections::<usize>(cx),
+ Some(Autoscroll::Fit),
+ cx,
+ );
+ });
}
pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
- self.start_transaction(cx);
-
let selections = self.local_selections::<Point>(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = self.buffer.read(cx).snapshot(cx);
@@ -2960,30 +2975,29 @@ impl Editor {
edit_ranges.push(edit_start..edit_end);
}
- let buffer = self.buffer.update(cx, |buffer, cx| {
- buffer.edit(edit_ranges, "", cx);
- buffer.snapshot(cx)
+ self.transact(cx, |this, cx| {
+ let buffer = this.buffer.update(cx, |buffer, cx| {
+ buffer.edit(edit_ranges, "", cx);
+ buffer.snapshot(cx)
+ });
+ let new_selections = new_cursors
+ .into_iter()
+ .map(|(id, cursor)| {
+ let cursor = cursor.to_point(&buffer);
+ Selection {
+ id,
+ start: cursor,
+ end: cursor,
+ reversed: false,
+ goal: SelectionGoal::None,
+ }
+ })
+ .collect();
+ this.update_selections(new_selections, Some(Autoscroll::Fit), cx);
});
- let new_selections = new_cursors
- .into_iter()
- .map(|(id, cursor)| {
- let cursor = cursor.to_point(&buffer);
- Selection {
- id,
- start: cursor,
- end: cursor,
- reversed: false,
- goal: SelectionGoal::None,
- }
- })
- .collect();
- self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
- self.end_transaction(cx);
}
pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
- self.start_transaction(cx);
-
let selections = self.local_selections::<Point>(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = &display_map.buffer_snapshot;
@@ -3014,14 +3028,15 @@ impl Editor {
edits.push((start, text, rows.len() as u32));
}
- self.buffer.update(cx, |buffer, cx| {
- for (point, text, _) in edits.into_iter().rev() {
- buffer.edit(Some(point..point), text, cx);
- }
- });
+ self.transact(cx, |this, cx| {
+ this.buffer.update(cx, |buffer, cx| {
+ for (point, text, _) in edits.into_iter().rev() {
+ buffer.edit(Some(point..point), text, cx);
+ }
+ });
- self.request_autoscroll(Autoscroll::Fit, cx);
- self.end_transaction(cx);
+ this.request_autoscroll(Autoscroll::Fit, cx);
+ });
}
pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
@@ -3122,16 +3137,16 @@ impl Editor {
new_selections.extend(contiguous_row_selections.drain(..));
}
- self.start_transaction(cx);
- self.unfold_ranges(unfold_ranges, true, cx);
- self.buffer.update(cx, |buffer, cx| {
- for (range, text) in edits {
- buffer.edit([range], text, cx);
- }
+ self.transact(cx, |this, cx| {
+ this.unfold_ranges(unfold_ranges, true, cx);
+ this.buffer.update(cx, |buffer, cx| {
+ for (range, text) in edits {
+ buffer.edit([range], text, cx);
+ }
+ });
+ this.fold_ranges(refold_ranges, cx);
+ this.update_selections(new_selections, Some(Autoscroll::Fit), cx);
});
- self.fold_ranges(refold_ranges, cx);
- self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
- self.end_transaction(cx);
}
pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
@@ -3225,20 +3240,19 @@ impl Editor {
new_selections.extend(contiguous_row_selections.drain(..));
}
- self.start_transaction(cx);
- self.unfold_ranges(unfold_ranges, true, cx);
- self.buffer.update(cx, |buffer, cx| {
- for (range, text) in edits {
- buffer.edit([range], text, cx);
- }
+ self.transact(cx, |this, cx| {
+ this.unfold_ranges(unfold_ranges, true, cx);
+ this.buffer.update(cx, |buffer, cx| {
+ for (range, text) in edits {
+ buffer.edit([range], text, cx);
+ }
+ });
+ this.fold_ranges(refold_ranges, cx);
+ this.update_selections(new_selections, Some(Autoscroll::Fit), cx);
});
- self.fold_ranges(refold_ranges, cx);
- self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
- self.end_transaction(cx);
}
pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
- self.start_transaction(cx);
let mut text = String::new();
let mut selections = self.local_selections::<Point>(cx);
let mut clipboard_selections = Vec::with_capacity(selections.len());
@@ -3263,12 +3277,12 @@ impl Editor {
});
}
}
- self.update_selections(selections, Some(Autoscroll::Fit), cx);
- self.insert("", cx);
- self.end_transaction(cx);
- cx.as_mut()
- .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
+ self.transact(cx, |this, cx| {
+ this.update_selections(selections, Some(Autoscroll::Fit), cx);
+ this.insert("", cx);
+ cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
+ });
}
pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
@@ -3298,63 +3312,65 @@ impl Editor {
}
}
- cx.as_mut()
- .write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
+ cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
}
pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
- if let Some(item) = cx.as_mut().read_from_clipboard() {
- let clipboard_text = item.text();
- if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
- let mut selections = self.local_selections::<usize>(cx);
- let all_selections_were_entire_line =
- clipboard_selections.iter().all(|s| s.is_entire_line);
- if clipboard_selections.len() != selections.len() {
- clipboard_selections.clear();
- }
-
- let mut delta = 0_isize;
- let mut start_offset = 0;
- for (i, selection) in selections.iter_mut().enumerate() {
- let to_insert;
- let entire_line;
- if let Some(clipboard_selection) = clipboard_selections.get(i) {
- let end_offset = start_offset + clipboard_selection.len;
- to_insert = &clipboard_text[start_offset..end_offset];
- entire_line = clipboard_selection.is_entire_line;
- start_offset = end_offset
- } else {
- to_insert = clipboard_text.as_str();
- entire_line = all_selections_were_entire_line;
+ self.transact(cx, |this, cx| {
+ if let Some(item) = cx.as_mut().read_from_clipboard() {
+ let clipboard_text = item.text();
+ if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
+ let mut selections = this.local_selections::<usize>(cx);
+ let all_selections_were_entire_line =
+ clipboard_selections.iter().all(|s| s.is_entire_line);
+ if clipboard_selections.len() != selections.len() {
+ clipboard_selections.clear();
}
- selection.start = (selection.start as isize + delta) as usize;
- selection.end = (selection.end as isize + delta) as usize;
-
- self.buffer.update(cx, |buffer, cx| {
- // If the corresponding selection was empty when this slice of the
- // clipboard text was written, then the entire line containing the
- // selection was copied. If this selection is also currently empty,
- // then paste the line before the current line of the buffer.
- let range = if selection.is_empty() && entire_line {
- let column = selection.start.to_point(&buffer.read(cx)).column as usize;
- let line_start = selection.start - column;
- line_start..line_start
+ let mut delta = 0_isize;
+ let mut start_offset = 0;
+ for (i, selection) in selections.iter_mut().enumerate() {
+ let to_insert;
+ let entire_line;
+ if let Some(clipboard_selection) = clipboard_selections.get(i) {
+ let end_offset = start_offset + clipboard_selection.len;
+ to_insert = &clipboard_text[start_offset..end_offset];
+ entire_line = clipboard_selection.is_entire_line;
+ start_offset = end_offset
} else {
- selection.start..selection.end
- };
+ to_insert = clipboard_text.as_str();
+ entire_line = all_selections_were_entire_line;
+ }
- delta += to_insert.len() as isize - range.len() as isize;
- buffer.edit([range], to_insert, cx);
- selection.start += to_insert.len();
- selection.end = selection.start;
- });
+ selection.start = (selection.start as isize + delta) as usize;
+ selection.end = (selection.end as isize + delta) as usize;
+
+ this.buffer.update(cx, |buffer, cx| {
+ // If the corresponding selection was empty when this slice of the
+ // clipboard text was written, then the entire line containing the
+ // selection was copied. If this selection is also currently empty,
+ // then paste the line before the current line of the buffer.
+ let range = if selection.is_empty() && entire_line {
+ let column =
+ selection.start.to_point(&buffer.read(cx)).column as usize;
+ let line_start = selection.start - column;
+ line_start..line_start
+ } else {
+ selection.start..selection.end
+ };
+
+ delta += to_insert.len() as isize - range.len() as isize;
+ buffer.edit([range], to_insert, cx);
+ selection.start += to_insert.len();
+ selection.end = selection.start;
+ });
+ }
+ this.update_selections(selections, Some(Autoscroll::Fit), cx);
+ } else {
+ this.insert(clipboard_text, cx);
}
- self.update_selections(selections, Some(Autoscroll::Fit), cx);
- } else {
- self.insert(clipboard_text, cx);
}
- }
+ });
}
pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
@@ -3363,6 +3379,7 @@ impl Editor {
self.set_selections(selections, None, true, cx);
}
self.request_autoscroll(Autoscroll::Fit, cx);
+ cx.emit(Event::Edited);
}
}
@@ -3372,6 +3389,7 @@ impl Editor {
self.set_selections(selections, None, true, cx);
}
self.request_autoscroll(Autoscroll::Fit, cx);
+ cx.emit(Event::Edited);
}
}
@@ -3964,90 +3982,94 @@ impl Editor {
let comment_prefix = full_comment_prefix.trim_end_matches(' ');
let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
- self.start_transaction(cx);
- let mut selections = self.local_selections::<Point>(cx);
- let mut all_selection_lines_are_comments = true;
- let mut edit_ranges = Vec::new();
- let mut last_toggled_row = None;
- self.buffer.update(cx, |buffer, cx| {
- for selection in &mut selections {
- edit_ranges.clear();
- let snapshot = buffer.snapshot(cx);
+ self.transact(cx, |this, cx| {
+ let mut selections = this.local_selections::<Point>(cx);
+ let mut all_selection_lines_are_comments = true;
+ let mut edit_ranges = Vec::new();
+ let mut last_toggled_row = None;
+ this.buffer.update(cx, |buffer, cx| {
+ for selection in &mut selections {
+ edit_ranges.clear();
+ let snapshot = buffer.snapshot(cx);
- let end_row =
- if selection.end.row > selection.start.row && selection.end.column == 0 {
- selection.end.row
- } else {
- selection.end.row + 1
- };
+ let end_row =
+ if selection.end.row > selection.start.row && selection.end.column == 0 {
+ selection.end.row
+ } else {
+ selection.end.row + 1
+ };
- for row in selection.start.row..end_row {
- // If multiple selections contain a given row, avoid processing that
- // row more than once.
- if last_toggled_row == Some(row) {
- continue;
- } else {
- last_toggled_row = Some(row);
- }
+ for row in selection.start.row..end_row {
+ // If multiple selections contain a given row, avoid processing that
+ // row more than once.
+ if last_toggled_row == Some(row) {
+ continue;
+ } else {
+ last_toggled_row = Some(row);
+ }
- if snapshot.is_line_blank(row) {
- continue;
- }
+ if snapshot.is_line_blank(row) {
+ continue;
+ }
- let start = Point::new(row, snapshot.indent_column_for_line(row));
- let mut line_bytes = snapshot
- .bytes_in_range(start..snapshot.max_point())
- .flatten()
- .copied();
-
- // If this line currently begins with the line comment prefix, then record
- // the range containing the prefix.
- if all_selection_lines_are_comments
- && line_bytes
- .by_ref()
- .take(comment_prefix.len())
- .eq(comment_prefix.bytes())
- {
- // Include any whitespace that matches the comment prefix.
- let matching_whitespace_len = line_bytes
- .zip(comment_prefix_whitespace.bytes())
- .take_while(|(a, b)| a == b)
- .count() as u32;
- let end = Point::new(
- row,
- start.column + comment_prefix.len() as u32 + matching_whitespace_len,
- );
- edit_ranges.push(start..end);
- }
- // If this line does not begin with the line comment prefix, then record
- // the position where the prefix should be inserted.
- else {
- all_selection_lines_are_comments = false;
- edit_ranges.push(start..start);
+ let start = Point::new(row, snapshot.indent_column_for_line(row));
+ let mut line_bytes = snapshot
+ .bytes_in_range(start..snapshot.max_point())
+ .flatten()
+ .copied();
+
+ // If this line currently begins with the line comment prefix, then record
+ // the range containing the prefix.
+ if all_selection_lines_are_comments
+ && line_bytes
+ .by_ref()
+ .take(comment_prefix.len())
+ .eq(comment_prefix.bytes())
+ {
+ // Include any whitespace that matches the comment prefix.
+ let matching_whitespace_len = line_bytes
+ .zip(comment_prefix_whitespace.bytes())
+ .take_while(|(a, b)| a == b)
+ .count()
+ as u32;
+ let end = Point::new(
+ row,
+ start.column
+ + comment_prefix.len() as u32
+ + matching_whitespace_len,
+ );
+ edit_ranges.push(start..end);
+ }
+ // If this line does not begin with the line comment prefix, then record
+ // the position where the prefix should be inserted.
+ else {
+ all_selection_lines_are_comments = false;
+ edit_ranges.push(start..start);
+ }
}
- }
- if !edit_ranges.is_empty() {
- if all_selection_lines_are_comments {
- buffer.edit(edit_ranges.iter().cloned(), "", cx);
- } else {
- let min_column = edit_ranges.iter().map(|r| r.start.column).min().unwrap();
- let edit_ranges = edit_ranges.iter().map(|range| {
- let position = Point::new(range.start.row, min_column);
- position..position
- });
- buffer.edit(edit_ranges, &full_comment_prefix, cx);
+ if !edit_ranges.is_empty() {
+ if all_selection_lines_are_comments {
+ buffer.edit(edit_ranges.iter().cloned(), "", cx);
+ } else {
+ let min_column =
+ edit_ranges.iter().map(|r| r.start.column).min().unwrap();
+ let edit_ranges = edit_ranges.iter().map(|range| {
+ let position = Point::new(range.start.row, min_column);
+ position..position
+ });
+ buffer.edit(edit_ranges, &full_comment_prefix, cx);
+ }
}
}
- }
- });
+ });
- self.update_selections(
- self.local_selections::<usize>(cx),
- Some(Autoscroll::Fit),
- cx,
- );
- self.end_transaction(cx);
+ this.update_selections(
+ this.local_selections::<usize>(cx),
+ Some(Autoscroll::Fit),
+ cx,
+ );
+ });
}
pub fn select_larger_syntax_node(
@@ -198,7 +198,7 @@ impl FollowableItem for Editor {
fn should_unfollow_on_event(event: &Self::Event, _: &AppContext) -> bool {
match event {
- Event::Edited { local } => *local,
+ Event::Edited => true,
Event::SelectionsChanged { local } => *local,
Event::ScrollPositionChanged { local } => *local,
_ => false,
@@ -211,7 +211,7 @@ impl MultiBuffer {
pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
let mut this = Self::new(buffer.read(cx).replica_id());
this.singleton = true;
- this.push_excerpts(buffer, [text::Anchor::min()..text::Anchor::max()], cx);
+ this.push_excerpts(buffer, [text::Anchor::MIN..text::Anchor::MAX], cx);
this.snapshot.borrow_mut().singleton = true;
this
}
@@ -522,24 +522,14 @@ impl MultiBuffer {
self.buffers.borrow()[&buffer_id]
.buffer
.update(cx, |buffer, cx| {
- selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
+ selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer));
let mut selections = selections.into_iter().peekable();
let merged_selections = Arc::from_iter(iter::from_fn(|| {
let mut selection = selections.next()?;
while let Some(next_selection) = selections.peek() {
- if selection
- .end
- .cmp(&next_selection.start, buffer)
- .unwrap()
- .is_ge()
- {
+ if selection.end.cmp(&next_selection.start, buffer).is_ge() {
let next_selection = selections.next().unwrap();
- if next_selection
- .end
- .cmp(&selection.end, buffer)
- .unwrap()
- .is_ge()
- {
+ if next_selection.end.cmp(&selection.end, buffer).is_ge() {
selection.end = next_selection.end;
}
} else {
@@ -814,11 +804,30 @@ impl MultiBuffer {
cx.notify();
}
- pub fn excerpt_ids_for_buffer(&self, buffer: &ModelHandle<Buffer>) -> Vec<ExcerptId> {
- self.buffers
- .borrow()
+ pub fn excerpts_for_buffer(
+ &self,
+ buffer: &ModelHandle<Buffer>,
+ cx: &AppContext,
+ ) -> Vec<(ExcerptId, Range<text::Anchor>)> {
+ let mut excerpts = Vec::new();
+ let snapshot = self.read(cx);
+ let buffers = self.buffers.borrow();
+ let mut cursor = snapshot.excerpts.cursor::<Option<&ExcerptId>>();
+ for excerpt_id in buffers
.get(&buffer.id())
- .map_or(Vec::new(), |state| state.excerpts.clone())
+ .map(|state| &state.excerpts)
+ .into_iter()
+ .flatten()
+ {
+ cursor.seek_forward(&Some(excerpt_id), Bias::Left, &());
+ if let Some(excerpt) = cursor.item() {
+ if excerpt.id == *excerpt_id {
+ excerpts.push((excerpt.id.clone(), excerpt.range.clone()));
+ }
+ }
+ }
+
+ excerpts
}
pub fn excerpt_ids(&self) -> Vec<ExcerptId> {
@@ -1917,11 +1926,7 @@ impl MultiBufferSnapshot {
.range
.start
.bias(anchor.text_anchor.bias, &excerpt.buffer);
- if text_anchor
- .cmp(&excerpt.range.end, &excerpt.buffer)
- .unwrap()
- .is_gt()
- {
+ if text_anchor.cmp(&excerpt.range.end, &excerpt.buffer).is_gt() {
text_anchor = excerpt.range.end.clone();
}
Anchor {
@@ -1936,7 +1941,6 @@ impl MultiBufferSnapshot {
.bias(anchor.text_anchor.bias, &excerpt.buffer);
if text_anchor
.cmp(&excerpt.range.start, &excerpt.buffer)
- .unwrap()
.is_lt()
{
text_anchor = excerpt.range.start.clone();
@@ -1956,7 +1960,7 @@ impl MultiBufferSnapshot {
result.push((anchor_ix, anchor, kept_position));
}
}
- result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self).unwrap());
+ result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self));
result
}
@@ -2303,10 +2307,10 @@ impl MultiBufferSnapshot {
excerpt_id: excerpt.id.clone(),
text_anchor: selection.end.clone(),
};
- if range.start.cmp(&start, self).unwrap().is_gt() {
+ if range.start.cmp(&start, self).is_gt() {
start = range.start.clone();
}
- if range.end.cmp(&end, self).unwrap().is_lt() {
+ if range.end.cmp(&end, self).is_lt() {
end = range.end.clone();
}
@@ -2530,17 +2534,9 @@ impl Excerpt {
}
fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
- if text_anchor
- .cmp(&self.range.start, &self.buffer)
- .unwrap()
- .is_lt()
- {
+ if text_anchor.cmp(&self.range.start, &self.buffer).is_lt() {
self.range.start.clone()
- } else if text_anchor
- .cmp(&self.range.end, &self.buffer)
- .unwrap()
- .is_gt()
- {
+ } else if text_anchor.cmp(&self.range.end, &self.buffer).is_gt() {
self.range.end.clone()
} else {
text_anchor
@@ -2553,13 +2549,11 @@ impl Excerpt {
.range
.start
.cmp(&anchor.text_anchor, &self.buffer)
- .unwrap()
.is_le()
&& self
.range
.end
.cmp(&anchor.text_anchor, &self.buffer)
- .unwrap()
.is_ge()
}
}
@@ -3070,7 +3064,8 @@ mod tests {
);
let snapshot = multibuffer.update(cx, |multibuffer, cx| {
- let buffer_2_excerpt_id = multibuffer.excerpt_ids_for_buffer(&buffer_2)[0].clone();
+ let (buffer_2_excerpt_id, _) =
+ multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone();
multibuffer.remove_excerpts(&[buffer_2_excerpt_id], cx);
multibuffer.snapshot(cx)
});
@@ -3365,7 +3360,7 @@ mod tests {
let bias = if rng.gen() { Bias::Left } else { Bias::Right };
log::info!("Creating anchor at {} with bias {:?}", offset, bias);
anchors.push(multibuffer.anchor_at(offset, bias));
- anchors.sort_by(|a, b| a.cmp(&b, &multibuffer).unwrap());
+ anchors.sort_by(|a, b| a.cmp(&b, &multibuffer));
}
40..=44 if !anchors.is_empty() => {
let multibuffer = multibuffer.read(cx).read(cx);
@@ -1,5 +1,4 @@
use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
-use anyhow::Result;
use std::{
cmp::Ordering,
ops::{Range, Sub},
@@ -19,7 +18,7 @@ impl Anchor {
Self {
buffer_id: None,
excerpt_id: ExcerptId::min(),
- text_anchor: text::Anchor::min(),
+ text_anchor: text::Anchor::MIN,
}
}
@@ -27,7 +26,7 @@ impl Anchor {
Self {
buffer_id: None,
excerpt_id: ExcerptId::max(),
- text_anchor: text::Anchor::max(),
+ text_anchor: text::Anchor::MAX,
}
}
@@ -35,18 +34,18 @@ impl Anchor {
&self.excerpt_id
}
- pub fn cmp<'a>(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Result<Ordering> {
+ pub fn cmp<'a>(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id);
if excerpt_id_cmp.is_eq() {
if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
- Ok(Ordering::Equal)
+ Ordering::Equal
} else if let Some(excerpt) = snapshot.excerpt(&self.excerpt_id) {
self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer)
} else {
- Ok(Ordering::Equal)
+ Ordering::Equal
}
} else {
- Ok(excerpt_id_cmp)
+ excerpt_id_cmp
}
}
@@ -97,17 +96,17 @@ impl ToPoint for Anchor {
}
pub trait AnchorRangeExt {
- fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering>;
+ fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering;
fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
}
impl AnchorRangeExt for Range<Anchor> {
- fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering> {
- Ok(match self.start.cmp(&other.start, buffer)? {
- Ordering::Equal => other.end.cmp(&self.end, buffer)?,
+ fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering {
+ match self.start.cmp(&other.start, buffer) {
+ Ordering::Equal => other.end.cmp(&self.end, buffer),
ord @ _ => ord,
- })
+ }
}
fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
@@ -1,3 +1,5 @@
+use std::ops::Range;
+
use collections::HashMap;
#[cfg(test)]
@@ -31,3 +33,24 @@ pub fn marked_text(marked_text: &str) -> (String, Vec<usize>) {
let (unmarked_text, mut markers) = marked_text_by(marked_text, vec!['|']);
(unmarked_text, markers.remove(&'|').unwrap_or_else(Vec::new))
}
+
+pub fn marked_text_ranges(
+ marked_text: &str,
+ range_markers: Vec<(char, char)>,
+) -> (String, Vec<Range<usize>>) {
+ let mut marker_chars = Vec::new();
+ for (start, end) in range_markers.iter() {
+ marker_chars.push(*start);
+ marker_chars.push(*end);
+ }
+ let (unmarked_text, markers) = marked_text_by(marked_text, marker_chars);
+ let ranges = range_markers
+ .iter()
+ .map(|(start_marker, end_marker)| {
+ let start = markers.get(start_marker).unwrap()[0];
+ let end = markers.get(end_marker).unwrap()[0];
+ start..end
+ })
+ .collect();
+ (unmarked_text, ranges)
+}
@@ -291,7 +291,7 @@ impl FileFinder {
cx: &mut ViewContext<Self>,
) {
match event {
- editor::Event::Edited { .. } => {
+ editor::Event::BufferEdited { .. } => {
let query = self.query_editor.update(cx, |buffer, cx| buffer.text(cx));
if query.is_empty() {
self.latest_search_id = post_inc(&mut self.search_count);
@@ -102,7 +102,7 @@ impl GoToLine {
) {
match event {
editor::Event::Blurred => cx.emit(Event::Dismissed),
- editor::Event::Edited { .. } => {
+ editor::Event::BufferEdited { .. } => {
let line_editor = self.line_editor.read(cx).buffer().read(cx).read(cx).text();
let mut components = line_editor.trim().split(&[',', ':'][..]);
let row = components.next().and_then(|row| row.parse::<u32>().ok());
@@ -142,7 +142,7 @@ pub enum Operation {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event {
Operation(Operation),
- Edited { local: bool },
+ Edited,
Dirtied,
Saved,
FileHandleChanged,
@@ -967,7 +967,7 @@ impl Buffer {
) -> Option<TransactionId> {
if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
let was_dirty = start_version != self.saved_version;
- self.did_edit(&start_version, was_dirty, true, cx);
+ self.did_edit(&start_version, was_dirty, cx);
Some(transaction_id)
} else {
None
@@ -1160,7 +1160,6 @@ impl Buffer {
&mut self,
old_version: &clock::Global,
was_dirty: bool,
- local: bool,
cx: &mut ModelContext<Self>,
) {
if self.edits_since::<usize>(old_version).next().is_none() {
@@ -1169,7 +1168,7 @@ impl Buffer {
self.reparse(cx);
- cx.emit(Event::Edited { local });
+ cx.emit(Event::Edited);
if !was_dirty {
cx.emit(Event::Dirtied);
}
@@ -1206,7 +1205,7 @@ impl Buffer {
self.text.apply_ops(buffer_ops)?;
self.deferred_ops.insert(deferred_ops);
self.flush_deferred_ops(cx);
- self.did_edit(&old_version, was_dirty, false, cx);
+ self.did_edit(&old_version, was_dirty, cx);
// Notify independently of whether the buffer was edited as the operations could include a
// selection update.
cx.notify();
@@ -1321,7 +1320,7 @@ impl Buffer {
if let Some((transaction_id, operation)) = self.text.undo() {
self.send_operation(Operation::Buffer(operation), cx);
- self.did_edit(&old_version, was_dirty, true, cx);
+ self.did_edit(&old_version, was_dirty, cx);
Some(transaction_id)
} else {
None
@@ -1342,7 +1341,7 @@ impl Buffer {
self.send_operation(Operation::Buffer(operation), cx);
}
if undone {
- self.did_edit(&old_version, was_dirty, true, cx)
+ self.did_edit(&old_version, was_dirty, cx)
}
undone
}
@@ -1353,7 +1352,7 @@ impl Buffer {
if let Some((transaction_id, operation)) = self.text.redo() {
self.send_operation(Operation::Buffer(operation), cx);
- self.did_edit(&old_version, was_dirty, true, cx);
+ self.did_edit(&old_version, was_dirty, cx);
Some(transaction_id)
} else {
None
@@ -1374,7 +1373,7 @@ impl Buffer {
self.send_operation(Operation::Buffer(operation), cx);
}
if redone {
- self.did_edit(&old_version, was_dirty, true, cx)
+ self.did_edit(&old_version, was_dirty, cx)
}
redone
}
@@ -1440,7 +1439,7 @@ impl Buffer {
if !ops.is_empty() {
for op in ops {
self.send_operation(Operation::Buffer(op), cx);
- self.did_edit(&old_version, was_dirty, true, cx);
+ self.did_edit(&old_version, was_dirty, cx);
}
}
}
@@ -1821,20 +1820,12 @@ impl BufferSnapshot {
})
.map(move |(replica_id, set)| {
let start_ix = match set.selections.binary_search_by(|probe| {
- probe
- .end
- .cmp(&range.start, self)
- .unwrap()
- .then(Ordering::Greater)
+ probe.end.cmp(&range.start, self).then(Ordering::Greater)
}) {
Ok(ix) | Err(ix) => ix,
};
let end_ix = match set.selections.binary_search_by(|probe| {
- probe
- .start
- .cmp(&range.end, self)
- .unwrap()
- .then(Ordering::Less)
+ probe.start.cmp(&range.end, self).then(Ordering::Less)
}) {
Ok(ix) | Err(ix) => ix,
};
@@ -81,8 +81,8 @@ impl DiagnosticSet {
let range = buffer.anchor_before(range.start)..buffer.anchor_at(range.end, end_bias);
let mut cursor = self.diagnostics.filter::<_, ()>({
move |summary: &Summary| {
- let start_cmp = range.start.cmp(&summary.max_end, buffer).unwrap();
- let end_cmp = range.end.cmp(&summary.min_start, buffer).unwrap();
+ let start_cmp = range.start.cmp(&summary.max_end, buffer);
+ let end_cmp = range.end.cmp(&summary.min_start, buffer);
if inclusive {
start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal
} else {
@@ -123,7 +123,7 @@ impl DiagnosticSet {
let start_ix = output.len();
output.extend(groups.into_values().filter_map(|mut entries| {
- entries.sort_unstable_by(|a, b| a.range.start.cmp(&b.range.start, buffer).unwrap());
+ entries.sort_unstable_by(|a, b| a.range.start.cmp(&b.range.start, buffer));
entries
.iter()
.position(|entry| entry.diagnostic.is_primary)
@@ -137,7 +137,6 @@ impl DiagnosticSet {
.range
.start
.cmp(&b.entries[b.primary_ix].range.start, buffer)
- .unwrap()
});
}
@@ -187,10 +186,10 @@ impl DiagnosticEntry<Anchor> {
impl Default for Summary {
fn default() -> Self {
Self {
- start: Anchor::min(),
- end: Anchor::max(),
- min_start: Anchor::max(),
- max_end: Anchor::min(),
+ start: Anchor::MIN,
+ end: Anchor::MAX,
+ min_start: Anchor::MAX,
+ max_end: Anchor::MIN,
count: 0,
}
}
@@ -200,15 +199,10 @@ impl sum_tree::Summary for Summary {
type Context = text::BufferSnapshot;
fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {
- if other
- .min_start
- .cmp(&self.min_start, buffer)
- .unwrap()
- .is_lt()
- {
+ if other.min_start.cmp(&self.min_start, buffer).is_lt() {
self.min_start = other.min_start.clone();
}
- if other.max_end.cmp(&self.max_end, buffer).unwrap().is_gt() {
+ if other.max_end.cmp(&self.max_end, buffer).is_gt() {
self.max_end = other.max_end.clone();
}
self.start = other.start.clone();
@@ -122,19 +122,11 @@ fn test_edit_events(cx: &mut gpui::MutableAppContext) {
let buffer_1_events = buffer_1_events.borrow();
assert_eq!(
*buffer_1_events,
- vec![
- Event::Edited { local: true },
- Event::Dirtied,
- Event::Edited { local: true },
- Event::Edited { local: true }
- ]
+ vec![Event::Edited, Event::Dirtied, Event::Edited, Event::Edited]
);
let buffer_2_events = buffer_2_events.borrow();
- assert_eq!(
- *buffer_2_events,
- vec![Event::Edited { local: false }, Event::Dirtied]
- );
+ assert_eq!(*buffer_2_events, vec![Event::Edited, Event::Dirtied]);
}
#[gpui::test]
@@ -827,7 +819,7 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
for buffer in &buffers {
let buffer = buffer.read(cx).snapshot();
let actual_remote_selections = buffer
- .remote_selections_in_range(Anchor::min()..Anchor::max())
+ .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
.map(|(replica_id, selections)| (replica_id, selections.collect::<Vec<_>>()))
.collect::<Vec<_>>();
let expected_remote_selections = active_selections
@@ -224,7 +224,7 @@ impl OutlineView {
) {
match event {
editor::Event::Blurred => cx.emit(Event::Dismissed),
- editor::Event::Edited { .. } => self.update_matches(cx),
+ editor::Event::BufferEdited { .. } => self.update_matches(cx),
_ => {}
}
}
@@ -6229,10 +6229,7 @@ mod tests {
assert!(buffer.is_dirty());
assert_eq!(
*events.borrow(),
- &[
- language::Event::Edited { local: true },
- language::Event::Dirtied
- ]
+ &[language::Event::Edited, language::Event::Dirtied]
);
events.borrow_mut().clear();
buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), None, cx);
@@ -6255,9 +6252,9 @@ mod tests {
assert_eq!(
*events.borrow(),
&[
- language::Event::Edited { local: true },
+ language::Event::Edited,
language::Event::Dirtied,
- language::Event::Edited { local: true },
+ language::Event::Edited,
],
);
events.borrow_mut().clear();
@@ -6269,7 +6266,7 @@ mod tests {
assert!(buffer.is_dirty());
});
- assert_eq!(*events.borrow(), &[language::Event::Edited { local: true }]);
+ assert_eq!(*events.borrow(), &[language::Event::Edited]);
// When a file is deleted, the buffer is considered dirty.
let events = Rc::new(RefCell::new(Vec::new()));
@@ -328,7 +328,7 @@ impl ProjectSymbolsView {
) {
match event {
editor::Event::Blurred => cx.emit(Event::Dismissed),
- editor::Event::Edited { .. } => self.update_matches(cx),
+ editor::Event::BufferEdited { .. } => self.update_matches(cx),
_ => {}
}
}
@@ -358,7 +358,7 @@ impl SearchBar {
cx: &mut ViewContext<Self>,
) {
match event {
- editor::Event::Edited { .. } => {
+ editor::Event::BufferEdited { .. } => {
self.query_contains_error = false;
self.clear_matches(cx);
self.update_matches(true, cx);
@@ -375,7 +375,7 @@ impl SearchBar {
cx: &mut ViewContext<Self>,
) {
match event {
- editor::Event::Edited { .. } => self.update_matches(false, cx),
+ editor::Event::BufferEdited { .. } => self.update_matches(false, cx),
editor::Event::SelectionsChanged { .. } => self.update_match_index(cx),
_ => {}
}
@@ -39,9 +39,9 @@ pub(crate) fn active_match_index(
None
} else {
match ranges.binary_search_by(|probe| {
- if probe.end.cmp(&cursor, &*buffer).unwrap().is_lt() {
+ if probe.end.cmp(&cursor, &*buffer).is_lt() {
Ordering::Less
- } else if probe.start.cmp(&cursor, &*buffer).unwrap().is_gt() {
+ } else if probe.start.cmp(&cursor, &*buffer).is_gt() {
Ordering::Greater
} else {
Ordering::Equal
@@ -59,7 +59,7 @@ pub(crate) fn match_index_for_direction(
direction: Direction,
buffer: &MultiBufferSnapshot,
) -> usize {
- if ranges[index].start.cmp(&cursor, &buffer).unwrap().is_gt() {
+ if ranges[index].start.cmp(&cursor, &buffer).is_gt() {
if direction == Direction::Prev {
if index == 0 {
index = ranges.len() - 1;
@@ -67,7 +67,7 @@ pub(crate) fn match_index_for_direction(
index -= 1;
}
}
- } else if ranges[index].end.cmp(&cursor, &buffer).unwrap().is_lt() {
+ } else if ranges[index].end.cmp(&cursor, &buffer).is_lt() {
if direction == Direction::Next {
index = 0;
}
@@ -12,23 +12,19 @@ pub struct Anchor {
}
impl Anchor {
- pub fn min() -> Self {
- Self {
- timestamp: clock::Local::MIN,
- offset: usize::MIN,
- bias: Bias::Left,
- }
- }
+ pub const MIN: Self = Self {
+ timestamp: clock::Local::MIN,
+ offset: usize::MIN,
+ bias: Bias::Left,
+ };
- pub fn max() -> Self {
- Self {
- timestamp: clock::Local::MAX,
- offset: usize::MAX,
- bias: Bias::Right,
- }
- }
+ pub const MAX: Self = Self {
+ timestamp: clock::Local::MAX,
+ offset: usize::MAX,
+ bias: Bias::Right,
+ };
- pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Result<Ordering> {
+ pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
let fragment_id_comparison = if self.timestamp == other.timestamp {
Ordering::Equal
} else {
@@ -37,9 +33,25 @@ impl Anchor {
.cmp(&buffer.fragment_id_for_anchor(other))
};
- Ok(fragment_id_comparison
+ fragment_id_comparison
.then_with(|| self.offset.cmp(&other.offset))
- .then_with(|| self.bias.cmp(&other.bias)))
+ .then_with(|| self.bias.cmp(&other.bias))
+ }
+
+ pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
+ if self.cmp(other, buffer).is_le() {
+ self.clone()
+ } else {
+ other.clone()
+ }
+ }
+
+ pub fn max(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
+ if self.cmp(other, buffer).is_ge() {
+ self.clone()
+ } else {
+ other.clone()
+ }
}
pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor {
@@ -105,8 +117,8 @@ pub trait AnchorRangeExt {
impl AnchorRangeExt for Range<Anchor> {
fn cmp(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering> {
- Ok(match self.start.cmp(&other.start, buffer)? {
- Ordering::Equal => other.end.cmp(&self.end, buffer)?,
+ Ok(match self.start.cmp(&other.start, buffer) {
+ Ordering::Equal => other.end.cmp(&self.end, buffer),
ord @ _ => ord,
})
}
@@ -340,59 +340,41 @@ fn test_anchors() {
let anchor_at_offset_2 = buffer.anchor_before(2);
assert_eq!(
- anchor_at_offset_0
- .cmp(&anchor_at_offset_0, &buffer)
- .unwrap(),
+ anchor_at_offset_0.cmp(&anchor_at_offset_0, &buffer),
Ordering::Equal
);
assert_eq!(
- anchor_at_offset_1
- .cmp(&anchor_at_offset_1, &buffer)
- .unwrap(),
+ anchor_at_offset_1.cmp(&anchor_at_offset_1, &buffer),
Ordering::Equal
);
assert_eq!(
- anchor_at_offset_2
- .cmp(&anchor_at_offset_2, &buffer)
- .unwrap(),
+ anchor_at_offset_2.cmp(&anchor_at_offset_2, &buffer),
Ordering::Equal
);
assert_eq!(
- anchor_at_offset_0
- .cmp(&anchor_at_offset_1, &buffer)
- .unwrap(),
+ anchor_at_offset_0.cmp(&anchor_at_offset_1, &buffer),
Ordering::Less
);
assert_eq!(
- anchor_at_offset_1
- .cmp(&anchor_at_offset_2, &buffer)
- .unwrap(),
+ anchor_at_offset_1.cmp(&anchor_at_offset_2, &buffer),
Ordering::Less
);
assert_eq!(
- anchor_at_offset_0
- .cmp(&anchor_at_offset_2, &buffer)
- .unwrap(),
+ anchor_at_offset_0.cmp(&anchor_at_offset_2, &buffer),
Ordering::Less
);
assert_eq!(
- anchor_at_offset_1
- .cmp(&anchor_at_offset_0, &buffer)
- .unwrap(),
+ anchor_at_offset_1.cmp(&anchor_at_offset_0, &buffer),
Ordering::Greater
);
assert_eq!(
- anchor_at_offset_2
- .cmp(&anchor_at_offset_1, &buffer)
- .unwrap(),
+ anchor_at_offset_2.cmp(&anchor_at_offset_1, &buffer),
Ordering::Greater
);
assert_eq!(
- anchor_at_offset_2
- .cmp(&anchor_at_offset_0, &buffer)
- .unwrap(),
+ anchor_at_offset_2.cmp(&anchor_at_offset_0, &buffer),
Ordering::Greater
);
}
@@ -1318,8 +1318,8 @@ impl Buffer {
let mut futures = Vec::new();
for anchor in anchors {
if !self.version.observed(anchor.timestamp)
- && *anchor != Anchor::max()
- && *anchor != Anchor::min()
+ && *anchor != Anchor::MAX
+ && *anchor != Anchor::MIN
{
let (tx, rx) = oneshot::channel();
self.edit_id_resolvers
@@ -1638,9 +1638,9 @@ impl BufferSnapshot {
let mut position = D::default();
anchors.map(move |anchor| {
- if *anchor == Anchor::min() {
+ if *anchor == Anchor::MIN {
return D::default();
- } else if *anchor == Anchor::max() {
+ } else if *anchor == Anchor::MAX {
return D::from_text_summary(&self.visible_text.summary());
}
@@ -1680,9 +1680,9 @@ impl BufferSnapshot {
where
D: TextDimension,
{
- if *anchor == Anchor::min() {
+ if *anchor == Anchor::MIN {
D::default()
- } else if *anchor == Anchor::max() {
+ } else if *anchor == Anchor::MAX {
D::from_text_summary(&self.visible_text.summary())
} else {
let anchor_key = InsertionFragmentKey {
@@ -1718,9 +1718,9 @@ impl BufferSnapshot {
}
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
- if *anchor == Anchor::min() {
+ if *anchor == Anchor::MIN {
&locator::MIN
- } else if *anchor == Anchor::max() {
+ } else if *anchor == Anchor::MAX {
&locator::MAX
} else {
let anchor_key = InsertionFragmentKey {
@@ -1758,9 +1758,9 @@ impl BufferSnapshot {
pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
let offset = position.to_offset(self);
if bias == Bias::Left && offset == 0 {
- Anchor::min()
+ Anchor::MIN
} else if bias == Bias::Right && offset == self.len() {
- Anchor::max()
+ Anchor::MAX
} else {
let mut fragment_cursor = self.fragments.cursor::<usize>();
fragment_cursor.seek(&offset, bias, &None);
@@ -1775,9 +1775,7 @@ impl BufferSnapshot {
}
pub fn can_resolve(&self, anchor: &Anchor) -> bool {
- *anchor == Anchor::min()
- || *anchor == Anchor::max()
- || self.version.observed(anchor.timestamp)
+ *anchor == Anchor::MIN || *anchor == Anchor::MAX || self.version.observed(anchor.timestamp)
}
pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
@@ -1799,7 +1797,7 @@ impl BufferSnapshot {
where
D: TextDimension + Ord,
{
- self.edits_since_in_range(since, Anchor::min()..Anchor::max())
+ self.edits_since_in_range(since, Anchor::MIN..Anchor::MAX)
}
pub fn edited_ranges_for_transaction<'a, D>(
@@ -204,7 +204,7 @@ impl ThemeSelector {
cx: &mut ViewContext<Self>,
) {
match event {
- editor::Event::Edited { .. } => {
+ editor::Event::BufferEdited { .. } => {
self.update_matches(cx);
self.select_if_matching(&cx.global::<Settings>().theme.name);
self.show_selected_theme(cx);