Merge branch 'main' into unfold-on-select-match

This commit is contained in:
Nathan Sobo 2022-03-24 14:13:27 -06:00
commit 2c232d585a
23 changed files with 869 additions and 675 deletions

View file

@ -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() {

View file

@ -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
}

View file

@ -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,
};

View file

@ -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))

File diff suppressed because it is too large Load diff

View file

@ -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,

View file

@ -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);

View file

@ -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> {

View file

@ -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)
}

View file

@ -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);

View file

@ -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());

View file

@ -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,
};

View file

@ -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();

View file

@ -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

View file

@ -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),
_ => {}
}
}

View file

@ -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()));

View file

@ -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),
_ => {}
}
}

View file

@ -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),
_ => {}
}

View file

@ -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;
}

View file

@ -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,
})
}

View file

@ -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
);
}

View file

@ -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>(

View file

@ -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);