Merge branch 'main' into unfold-on-select-match
This commit is contained in:
commit
2c232d585a
23 changed files with 869 additions and 675 deletions
|
@ -278,7 +278,7 @@ impl ProjectDiagnosticsEditor {
|
||||||
prev_excerpt_id = excerpt_id.clone();
|
prev_excerpt_id = excerpt_id.clone();
|
||||||
first_excerpt_id.get_or_insert_with(|| prev_excerpt_id.clone());
|
first_excerpt_id.get_or_insert_with(|| prev_excerpt_id.clone());
|
||||||
group_state.excerpts.push(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 {
|
if is_first_excerpt_for_group {
|
||||||
is_first_excerpt_for_group = false;
|
is_first_excerpt_for_group = false;
|
||||||
|
@ -367,8 +367,7 @@ impl ProjectDiagnosticsEditor {
|
||||||
range_a
|
range_a
|
||||||
.start
|
.start
|
||||||
.cmp(&range_b.start, &snapshot)
|
.cmp(&range_b.start, &snapshot)
|
||||||
.unwrap()
|
.then_with(|| range_a.end.cmp(&range_b.end, &snapshot))
|
||||||
.then_with(|| range_a.end.cmp(&range_b.end, &snapshot).unwrap())
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if path_state.diagnostic_groups.is_empty() {
|
if path_state.diagnostic_groups.is_empty() {
|
||||||
|
|
|
@ -490,7 +490,10 @@ impl ToDisplayPoint for Anchor {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::movement;
|
use crate::{
|
||||||
|
movement,
|
||||||
|
test::{marked_text_ranges},
|
||||||
|
};
|
||||||
use gpui::{color::Color, elements::*, test::observe, MutableAppContext};
|
use gpui::{color::Color, elements::*, test::observe, MutableAppContext};
|
||||||
use language::{Buffer, Language, LanguageConfig, RandomCharIter, SelectionGoal};
|
use language::{Buffer, Language, LanguageConfig, RandomCharIter, SelectionGoal};
|
||||||
use rand::{prelude::*, Rng};
|
use rand::{prelude::*, Rng};
|
||||||
|
@ -930,7 +933,7 @@ mod tests {
|
||||||
let map = cx
|
let map = cx
|
||||||
.add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, 1, 1, cx));
|
.add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, 1, 1, cx));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| chunks(0..5, &map, &theme, cx)),
|
cx.update(|cx| syntax_chunks(0..5, &map, &theme, cx)),
|
||||||
vec![
|
vec![
|
||||||
("fn ".to_string(), None),
|
("fn ".to_string(), None),
|
||||||
("outer".to_string(), Some(Color::blue())),
|
("outer".to_string(), Some(Color::blue())),
|
||||||
|
@ -941,7 +944,7 @@ mod tests {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| chunks(3..5, &map, &theme, cx)),
|
cx.update(|cx| syntax_chunks(3..5, &map, &theme, cx)),
|
||||||
vec![
|
vec![
|
||||||
(" fn ".to_string(), Some(Color::red())),
|
(" fn ".to_string(), Some(Color::red())),
|
||||||
("inner".to_string(), Some(Color::blue())),
|
("inner".to_string(), Some(Color::blue())),
|
||||||
|
@ -953,7 +956,7 @@ mod tests {
|
||||||
map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)
|
map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)
|
||||||
});
|
});
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.update(|cx| chunks(0..2, &map, &theme, cx)),
|
cx.update(|cx| syntax_chunks(0..2, &map, &theme, cx)),
|
||||||
vec![
|
vec![
|
||||||
("fn ".to_string(), None),
|
("fn ".to_string(), None),
|
||||||
("out".to_string(), Some(Color::blue())),
|
("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)
|
DisplayMap::new(buffer, tab_size, font_id, font_size, Some(40.0), 1, 1, cx)
|
||||||
});
|
});
|
||||||
assert_eq!(
|
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),
|
("fn \n".to_string(), None),
|
||||||
("oute\nr".to_string(), Some(Color::blue())),
|
("oute\nr".to_string(), Some(Color::blue())),
|
||||||
|
@ -1027,7 +1030,7 @@ mod tests {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
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)]
|
[("{}\n\n".to_string(), None)]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1035,7 +1038,7 @@ mod tests {
|
||||||
map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)
|
map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx)
|
||||||
});
|
});
|
||||||
assert_eq!(
|
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())),
|
("out".to_string(), Some(Color::blue())),
|
||||||
("…\n".to_string(), None),
|
("…\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]
|
#[gpui::test]
|
||||||
fn test_clip_point(cx: &mut gpui::MutableAppContext) {
|
fn test_clip_point(cx: &mut gpui::MutableAppContext) {
|
||||||
use Bias::{Left, Right};
|
use Bias::{Left, Right};
|
||||||
|
@ -1171,27 +1257,38 @@ mod tests {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chunks<'a>(
|
fn syntax_chunks<'a>(
|
||||||
rows: Range<u32>,
|
rows: Range<u32>,
|
||||||
map: &ModelHandle<DisplayMap>,
|
map: &ModelHandle<DisplayMap>,
|
||||||
theme: &'a SyntaxTheme,
|
theme: &'a SyntaxTheme,
|
||||||
cx: &mut MutableAppContext,
|
cx: &mut MutableAppContext,
|
||||||
) -> Vec<(String, Option<Color>)> {
|
) -> 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 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) {
|
for chunk in snapshot.chunks(rows, true) {
|
||||||
let color = chunk
|
let syntax_color = chunk
|
||||||
.syntax_highlight_id
|
.syntax_highlight_id
|
||||||
.and_then(|id| id.style(theme)?.color);
|
.and_then(|id| id.style(theme)?.color);
|
||||||
if let Some((last_chunk, last_color)) = chunks.last_mut() {
|
let highlight_color = chunk.highlight_style.and_then(|style| style.color);
|
||||||
if color == *last_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);
|
last_chunk.push_str(chunk.text);
|
||||||
} else {
|
continue;
|
||||||
chunks.push((chunk.text.to_string(), color));
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
chunks.push((chunk.text.to_string(), color));
|
|
||||||
}
|
}
|
||||||
|
chunks.push((chunk.text.to_string(), syntax_color, highlight_color));
|
||||||
}
|
}
|
||||||
chunks
|
chunks
|
||||||
}
|
}
|
||||||
|
|
|
@ -499,7 +499,7 @@ impl<'a> BlockMapWriter<'a> {
|
||||||
let block_ix = match self
|
let block_ix = match self
|
||||||
.0
|
.0
|
||||||
.blocks
|
.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,
|
Ok(ix) | Err(ix) => ix,
|
||||||
};
|
};
|
||||||
|
|
|
@ -257,7 +257,7 @@ impl FoldMap {
|
||||||
let mut folds = self.folds.iter().peekable();
|
let mut folds = self.folds.iter().peekable();
|
||||||
while let Some(fold) = folds.next() {
|
while let Some(fold) = folds.next() {
|
||||||
if let Some(next_fold) = folds.peek() {
|
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());
|
assert!(comparison.is_le());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -700,10 +700,7 @@ impl FoldSnapshot {
|
||||||
let ranges = &highlights.1;
|
let ranges = &highlights.1;
|
||||||
|
|
||||||
let start_ix = match ranges.binary_search_by(|probe| {
|
let start_ix = match ranges.binary_search_by(|probe| {
|
||||||
let cmp = probe
|
let cmp = probe.end.cmp(&transform_start, &self.buffer_snapshot());
|
||||||
.end
|
|
||||||
.cmp(&transform_start, &self.buffer_snapshot())
|
|
||||||
.unwrap();
|
|
||||||
if cmp.is_gt() {
|
if cmp.is_gt() {
|
||||||
Ordering::Greater
|
Ordering::Greater
|
||||||
} else {
|
} else {
|
||||||
|
@ -716,7 +713,6 @@ impl FoldSnapshot {
|
||||||
if range
|
if range
|
||||||
.start
|
.start
|
||||||
.cmp(&transform_end, &self.buffer_snapshot)
|
.cmp(&transform_end, &self.buffer_snapshot)
|
||||||
.unwrap()
|
|
||||||
.is_ge()
|
.is_ge()
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -821,8 +817,8 @@ where
|
||||||
let start = buffer.anchor_before(range.start.to_offset(buffer));
|
let start = buffer.anchor_before(range.start.to_offset(buffer));
|
||||||
let end = buffer.anchor_after(range.end.to_offset(buffer));
|
let end = buffer.anchor_after(range.end.to_offset(buffer));
|
||||||
let mut cursor = folds.filter::<_, usize>(move |summary| {
|
let mut cursor = folds.filter::<_, usize>(move |summary| {
|
||||||
let start_cmp = start.cmp(&summary.max_end, buffer).unwrap();
|
let start_cmp = start.cmp(&summary.max_end, buffer);
|
||||||
let end_cmp = end.cmp(&summary.min_start, buffer).unwrap();
|
let end_cmp = end.cmp(&summary.min_start, buffer);
|
||||||
|
|
||||||
if inclusive {
|
if inclusive {
|
||||||
start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal
|
start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal
|
||||||
|
@ -963,19 +959,19 @@ impl sum_tree::Summary for FoldSummary {
|
||||||
type Context = MultiBufferSnapshot;
|
type Context = MultiBufferSnapshot;
|
||||||
|
|
||||||
fn add_summary(&mut self, other: &Self, buffer: &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();
|
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();
|
self.max_end = other.max_end.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[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);
|
assert!(start_comparison <= Ordering::Equal);
|
||||||
if 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 {
|
impl<'a> sum_tree::SeekTarget<'a, FoldSummary, Fold> for Fold {
|
||||||
fn cmp(&self, other: &Self, buffer: &MultiBufferSnapshot) -> Ordering {
|
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 {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.offset
|
self.offset
|
||||||
.cmp(&other.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| {
|
.filter(|fold| {
|
||||||
let start = buffer_snapshot.anchor_before(start);
|
let start = buffer_snapshot.anchor_before(start);
|
||||||
let end = buffer_snapshot.anchor_after(end);
|
let end = buffer_snapshot.anchor_after(end);
|
||||||
start.cmp(&fold.0.end, &buffer_snapshot).unwrap() == Ordering::Less
|
start.cmp(&fold.0.end, &buffer_snapshot) == Ordering::Less
|
||||||
&& end.cmp(&fold.0.start, &buffer_snapshot).unwrap()
|
&& end.cmp(&fold.0.start, &buffer_snapshot) == Ordering::Greater
|
||||||
== Ordering::Greater
|
|
||||||
})
|
})
|
||||||
.map(|fold| fold.0)
|
.map(|fold| fold.0)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
@ -1686,7 +1681,7 @@ mod tests {
|
||||||
let buffer = self.buffer.lock().clone();
|
let buffer = self.buffer.lock().clone();
|
||||||
let mut folds = self.folds.items(&buffer);
|
let mut folds = self.folds.items(&buffer);
|
||||||
// Ensure sorting doesn't change how folds get merged and displayed.
|
// 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
|
let mut fold_ranges = folds
|
||||||
.iter()
|
.iter()
|
||||||
.map(|fold| fold.0.start.to_offset(&buffer)..fold.0.end.to_offset(&buffer))
|
.map(|fold| fold.0.start.to_offset(&buffer)..fold.0.end.to_offset(&buffer))
|
||||||
|
|
|
@ -1744,22 +1744,22 @@ impl Editor {
|
||||||
pub fn handle_input(&mut self, action: &Input, cx: &mut ViewContext<Self>) {
|
pub fn handle_input(&mut self, action: &Input, cx: &mut ViewContext<Self>) {
|
||||||
let text = action.0.as_ref();
|
let text = action.0.as_ref();
|
||||||
if !self.skip_autoclose_end(text, cx) {
|
if !self.skip_autoclose_end(text, cx) {
|
||||||
self.start_transaction(cx);
|
self.transact(cx, |this, cx| {
|
||||||
if !self.surround_with_bracket_pair(text, cx) {
|
if !this.surround_with_bracket_pair(text, cx) {
|
||||||
self.insert(text, cx);
|
this.insert(text, cx);
|
||||||
self.autoclose_bracket_pairs(cx);
|
this.autoclose_bracket_pairs(cx);
|
||||||
}
|
}
|
||||||
self.end_transaction(cx);
|
});
|
||||||
self.trigger_completion_on_input(text, cx);
|
self.trigger_completion_on_input(text, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
|
pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
|
||||||
self.start_transaction(cx);
|
self.transact(cx, |this, cx| {
|
||||||
let mut old_selections = SmallVec::<[_; 32]>::new();
|
let mut old_selections = SmallVec::<[_; 32]>::new();
|
||||||
{
|
{
|
||||||
let selections = self.local_selections::<usize>(cx);
|
let selections = this.local_selections::<usize>(cx);
|
||||||
let buffer = self.buffer.read(cx).snapshot(cx);
|
let buffer = this.buffer.read(cx).snapshot(cx);
|
||||||
for selection in selections.iter() {
|
for selection in selections.iter() {
|
||||||
let start_point = selection.start.to_point(&buffer);
|
let start_point = selection.start.to_point(&buffer);
|
||||||
let indent = buffer
|
let indent = buffer
|
||||||
|
@ -1789,7 +1789,8 @@ impl Editor {
|
||||||
pair.newline
|
pair.newline
|
||||||
&& buffer.contains_str_at(end + trailing_whitespace_len, pair_end)
|
&& buffer.contains_str_at(end + trailing_whitespace_len, pair_end)
|
||||||
&& buffer.contains_str_at(
|
&& buffer.contains_str_at(
|
||||||
(start - leading_whitespace_len).saturating_sub(pair_start.len()),
|
(start - leading_whitespace_len)
|
||||||
|
.saturating_sub(pair_start.len()),
|
||||||
pair_start,
|
pair_start,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -1805,7 +1806,7 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
let mut delta = 0_isize;
|
let mut delta = 0_isize;
|
||||||
let mut pending_edit: Option<PendingEdit> = None;
|
let mut pending_edit: Option<PendingEdit> = None;
|
||||||
for (_, _, range, indent, insert_extra_newline) in &old_selections {
|
for (_, _, range, indent, insert_extra_newline) in &old_selections {
|
||||||
|
@ -1848,7 +1849,7 @@ impl Editor {
|
||||||
buffer.edit_with_autoindent(pending.ranges, new_text, cx);
|
buffer.edit_with_autoindent(pending.ranges, new_text, cx);
|
||||||
|
|
||||||
let buffer = buffer.read(cx);
|
let buffer = buffer.read(cx);
|
||||||
self.selections = self
|
this.selections = this
|
||||||
.selections
|
.selections
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -1869,8 +1870,8 @@ impl Editor {
|
||||||
.collect();
|
.collect();
|
||||||
});
|
});
|
||||||
|
|
||||||
self.request_autoscroll(Autoscroll::Fit, cx);
|
this.request_autoscroll(Autoscroll::Fit, cx);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct PendingEdit {
|
struct PendingEdit {
|
||||||
|
@ -1882,10 +1883,9 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
|
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 old_selections = self.local_selections::<usize>(cx);
|
let selection_anchors = this.buffer.update(cx, |buffer, cx| {
|
||||||
let selection_anchors = self.buffer.update(cx, |buffer, cx| {
|
|
||||||
let anchors = {
|
let anchors = {
|
||||||
let snapshot = buffer.read(cx);
|
let snapshot = buffer.read(cx);
|
||||||
old_selections
|
old_selections
|
||||||
|
@ -1899,7 +1899,7 @@ impl Editor {
|
||||||
});
|
});
|
||||||
|
|
||||||
let selections = {
|
let selections = {
|
||||||
let snapshot = self.buffer.read(cx).read(cx);
|
let snapshot = this.buffer.read(cx).read(cx);
|
||||||
selection_anchors
|
selection_anchors
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, goal, position)| {
|
.map(|(id, goal, position)| {
|
||||||
|
@ -1914,8 +1914,8 @@ impl Editor {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
self.update_selections(selections, Some(Autoscroll::Fit), cx);
|
this.update_selections(selections, Some(Autoscroll::Fit), cx);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
|
fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -2284,7 +2284,7 @@ impl Editor {
|
||||||
}
|
}
|
||||||
let text = &text[common_prefix_len..];
|
let text = &text[common_prefix_len..];
|
||||||
|
|
||||||
self.start_transaction(cx);
|
self.transact(cx, |this, cx| {
|
||||||
if let Some(mut snippet) = snippet {
|
if let Some(mut snippet) = snippet {
|
||||||
snippet.text = text.to_string();
|
snippet.text = text.to_string();
|
||||||
for tabstop in snippet.tabstops.iter_mut().flatten() {
|
for tabstop in snippet.tabstops.iter_mut().flatten() {
|
||||||
|
@ -2292,13 +2292,13 @@ impl Editor {
|
||||||
tabstop.end -= common_prefix_len as isize;
|
tabstop.end -= common_prefix_len as isize;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.insert_snippet(&ranges, snippet, cx).log_err();
|
this.insert_snippet(&ranges, snippet, cx).log_err();
|
||||||
} else {
|
} else {
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
buffer.edit_with_autoindent(ranges, text, cx);
|
buffer.edit_with_autoindent(ranges, text, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self.end_transaction(cx);
|
});
|
||||||
|
|
||||||
let project = self.project.clone()?;
|
let project = self.project.clone()?;
|
||||||
let apply_edits = project.update(cx, |project, cx| {
|
let apply_edits = project.update(cx, |project, cx| {
|
||||||
|
@ -2397,7 +2397,7 @@ impl Editor {
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
|
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.
|
// avoid opening a new editor to display them.
|
||||||
let mut entries = transaction.0.iter();
|
let mut entries = transaction.0.iter();
|
||||||
if let Some((buffer, transaction)) = entries.next() {
|
if let Some((buffer, transaction)) = entries.next() {
|
||||||
|
@ -2519,7 +2519,6 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer_id = cursor_position.buffer_id;
|
let buffer_id = cursor_position.buffer_id;
|
||||||
let excerpt_id = cursor_position.excerpt_id.clone();
|
|
||||||
let style = this.style(cx);
|
let style = this.style(cx);
|
||||||
let read_background = style.document_highlight_read_background;
|
let read_background = style.document_highlight_read_background;
|
||||||
let write_background = style.document_highlight_write_background;
|
let write_background = style.document_highlight_write_background;
|
||||||
|
@ -2531,17 +2530,33 @@ impl Editor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cursor_buffer_snapshot = cursor_buffer.read(cx);
|
||||||
let mut write_ranges = Vec::new();
|
let mut write_ranges = Vec::new();
|
||||||
let mut read_ranges = Vec::new();
|
let mut read_ranges = Vec::new();
|
||||||
for highlight in highlights {
|
for highlight in highlights {
|
||||||
|
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 {
|
let range = Anchor {
|
||||||
buffer_id,
|
buffer_id,
|
||||||
excerpt_id: excerpt_id.clone(),
|
excerpt_id: excerpt_id.clone(),
|
||||||
text_anchor: highlight.range.start,
|
text_anchor: start,
|
||||||
}..Anchor {
|
}..Anchor {
|
||||||
buffer_id,
|
buffer_id,
|
||||||
excerpt_id: excerpt_id.clone(),
|
excerpt_id,
|
||||||
text_anchor: highlight.range.end,
|
text_anchor: end,
|
||||||
};
|
};
|
||||||
if highlight.kind == lsp::DocumentHighlightKind::WRITE {
|
if highlight.kind == lsp::DocumentHighlightKind::WRITE {
|
||||||
write_ranges.push(range);
|
write_ranges.push(range);
|
||||||
|
@ -2549,6 +2564,7 @@ impl Editor {
|
||||||
read_ranges.push(range);
|
read_ranges.push(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.highlight_background::<DocumentHighlightRead>(
|
this.highlight_background::<DocumentHighlightRead>(
|
||||||
read_ranges,
|
read_ranges,
|
||||||
|
@ -2656,8 +2672,7 @@ impl Editor {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
tabstop_ranges
|
tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
|
||||||
.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot).unwrap());
|
|
||||||
tabstop_ranges
|
tabstop_ranges
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
@ -2732,14 +2747,13 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
|
pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
self.start_transaction(cx);
|
self.transact(cx, |this, cx| {
|
||||||
self.select_all(&SelectAll, cx);
|
this.select_all(&SelectAll, cx);
|
||||||
self.insert("", cx);
|
this.insert("", cx);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
|
pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
|
||||||
self.start_transaction(cx);
|
|
||||||
let mut selections = self.local_selections::<Point>(cx);
|
let mut selections = self.local_selections::<Point>(cx);
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
for selection in &mut selections {
|
for selection in &mut selections {
|
||||||
|
@ -2765,9 +2779,11 @@ impl Editor {
|
||||||
selection.set_head(new_head, SelectionGoal::None);
|
selection.set_head(new_head, SelectionGoal::None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.update_selections(selections, Some(Autoscroll::Fit), cx);
|
|
||||||
self.insert("", cx);
|
self.transact(cx, |this, cx| {
|
||||||
self.end_transaction(cx);
|
this.update_selections(selections, Some(Autoscroll::Fit), cx);
|
||||||
|
this.insert("", cx);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
|
pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -2787,11 +2803,11 @@ impl Editor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.start_transaction(cx);
|
|
||||||
let tab_size = cx.global::<Settings>().tab_size;
|
let tab_size = cx.global::<Settings>().tab_size;
|
||||||
let mut selections = self.local_selections::<Point>(cx);
|
let mut selections = self.local_selections::<Point>(cx);
|
||||||
|
self.transact(cx, |this, cx| {
|
||||||
let mut last_indent = None;
|
let mut last_indent = None;
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
for selection in &mut selections {
|
for selection in &mut selections {
|
||||||
if selection.is_empty() {
|
if selection.is_empty() {
|
||||||
let char_column = buffer
|
let char_column = buffer
|
||||||
|
@ -2831,7 +2847,8 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
for row in start_row..end_row {
|
for row in start_row..end_row {
|
||||||
let indent_column = buffer.read(cx).indent_column_for_line(row) as usize;
|
let indent_column =
|
||||||
|
buffer.read(cx).indent_column_for_line(row) as usize;
|
||||||
let columns_to_next_tab_stop = tab_size - (indent_column % tab_size);
|
let columns_to_next_tab_stop = tab_size - (indent_column % tab_size);
|
||||||
let row_start = Point::new(row, 0);
|
let row_start = Point::new(row, 0);
|
||||||
buffer.edit(
|
buffer.edit(
|
||||||
|
@ -2854,8 +2871,8 @@ impl Editor {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.update_selections(selections, Some(Autoscroll::Fit), cx);
|
this.update_selections(selections, Some(Autoscroll::Fit), cx);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
|
pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -2864,7 +2881,6 @@ impl Editor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.start_transaction(cx);
|
|
||||||
let tab_size = cx.global::<Settings>().tab_size;
|
let tab_size = cx.global::<Settings>().tab_size;
|
||||||
let selections = self.local_selections::<Point>(cx);
|
let selections = self.local_selections::<Point>(cx);
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(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| {
|
|
||||||
|
self.transact(cx, |this, cx| {
|
||||||
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
buffer.edit(deletion_ranges, "", cx);
|
buffer.edit(deletion_ranges, "", cx);
|
||||||
});
|
});
|
||||||
|
this.update_selections(
|
||||||
self.update_selections(
|
this.local_selections::<usize>(cx),
|
||||||
self.local_selections::<usize>(cx),
|
|
||||||
Some(Autoscroll::Fit),
|
Some(Autoscroll::Fit),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
|
pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
|
||||||
self.start_transaction(cx);
|
|
||||||
|
|
||||||
let selections = self.local_selections::<Point>(cx);
|
let selections = self.local_selections::<Point>(cx);
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
let buffer = self.buffer.read(cx).snapshot(cx);
|
let buffer = self.buffer.read(cx).snapshot(cx);
|
||||||
|
@ -2960,7 +2975,8 @@ impl Editor {
|
||||||
edit_ranges.push(edit_start..edit_end);
|
edit_ranges.push(edit_start..edit_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = self.buffer.update(cx, |buffer, cx| {
|
self.transact(cx, |this, cx| {
|
||||||
|
let buffer = this.buffer.update(cx, |buffer, cx| {
|
||||||
buffer.edit(edit_ranges, "", cx);
|
buffer.edit(edit_ranges, "", cx);
|
||||||
buffer.snapshot(cx)
|
buffer.snapshot(cx)
|
||||||
});
|
});
|
||||||
|
@ -2977,13 +2993,11 @@ impl Editor {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
|
this.update_selections(new_selections, Some(Autoscroll::Fit), cx);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
|
pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
|
||||||
self.start_transaction(cx);
|
|
||||||
|
|
||||||
let selections = self.local_selections::<Point>(cx);
|
let selections = self.local_selections::<Point>(cx);
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
let buffer = &display_map.buffer_snapshot;
|
let buffer = &display_map.buffer_snapshot;
|
||||||
|
@ -3014,14 +3028,15 @@ impl Editor {
|
||||||
edits.push((start, text, rows.len() as u32));
|
edits.push((start, text, rows.len() as u32));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
self.transact(cx, |this, cx| {
|
||||||
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
for (point, text, _) in edits.into_iter().rev() {
|
for (point, text, _) in edits.into_iter().rev() {
|
||||||
buffer.edit(Some(point..point), text, cx);
|
buffer.edit(Some(point..point), text, cx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.request_autoscroll(Autoscroll::Fit, cx);
|
this.request_autoscroll(Autoscroll::Fit, cx);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
|
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(..));
|
new_selections.extend(contiguous_row_selections.drain(..));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.start_transaction(cx);
|
self.transact(cx, |this, cx| {
|
||||||
self.unfold_ranges(unfold_ranges, true, cx);
|
this.unfold_ranges(unfold_ranges, true, cx);
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
for (range, text) in edits {
|
for (range, text) in edits {
|
||||||
buffer.edit([range], text, cx);
|
buffer.edit([range], text, cx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.fold_ranges(refold_ranges, cx);
|
this.fold_ranges(refold_ranges, cx);
|
||||||
self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
|
this.update_selections(new_selections, Some(Autoscroll::Fit), cx);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
|
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(..));
|
new_selections.extend(contiguous_row_selections.drain(..));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.start_transaction(cx);
|
self.transact(cx, |this, cx| {
|
||||||
self.unfold_ranges(unfold_ranges, true, cx);
|
this.unfold_ranges(unfold_ranges, true, cx);
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
for (range, text) in edits {
|
for (range, text) in edits {
|
||||||
buffer.edit([range], text, cx);
|
buffer.edit([range], text, cx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.fold_ranges(refold_ranges, cx);
|
this.fold_ranges(refold_ranges, cx);
|
||||||
self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
|
this.update_selections(new_selections, Some(Autoscroll::Fit), cx);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
|
pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
|
||||||
self.start_transaction(cx);
|
|
||||||
let mut text = String::new();
|
let mut text = String::new();
|
||||||
let mut selections = self.local_selections::<Point>(cx);
|
let mut selections = self.local_selections::<Point>(cx);
|
||||||
let mut clipboard_selections = Vec::with_capacity(selections.len());
|
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()
|
self.transact(cx, |this, cx| {
|
||||||
.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
|
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>) {
|
pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -3298,15 +3312,15 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.as_mut()
|
cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
|
||||||
.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
|
pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
|
||||||
|
self.transact(cx, |this, cx| {
|
||||||
if let Some(item) = cx.as_mut().read_from_clipboard() {
|
if let Some(item) = cx.as_mut().read_from_clipboard() {
|
||||||
let clipboard_text = item.text();
|
let clipboard_text = item.text();
|
||||||
if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
|
if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
|
||||||
let mut selections = self.local_selections::<usize>(cx);
|
let mut selections = this.local_selections::<usize>(cx);
|
||||||
let all_selections_were_entire_line =
|
let all_selections_were_entire_line =
|
||||||
clipboard_selections.iter().all(|s| s.is_entire_line);
|
clipboard_selections.iter().all(|s| s.is_entire_line);
|
||||||
if clipboard_selections.len() != selections.len() {
|
if clipboard_selections.len() != selections.len() {
|
||||||
|
@ -3331,13 +3345,14 @@ impl Editor {
|
||||||
selection.start = (selection.start as isize + delta) as usize;
|
selection.start = (selection.start as isize + delta) as usize;
|
||||||
selection.end = (selection.end as isize + delta) as usize;
|
selection.end = (selection.end as isize + delta) as usize;
|
||||||
|
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
// If the corresponding selection was empty when this slice of the
|
// If the corresponding selection was empty when this slice of the
|
||||||
// clipboard text was written, then the entire line containing the
|
// clipboard text was written, then the entire line containing the
|
||||||
// selection was copied. If this selection is also currently empty,
|
// selection was copied. If this selection is also currently empty,
|
||||||
// then paste the line before the current line of the buffer.
|
// then paste the line before the current line of the buffer.
|
||||||
let range = if selection.is_empty() && entire_line {
|
let range = if selection.is_empty() && entire_line {
|
||||||
let column = selection.start.to_point(&buffer.read(cx)).column as usize;
|
let column =
|
||||||
|
selection.start.to_point(&buffer.read(cx)).column as usize;
|
||||||
let line_start = selection.start - column;
|
let line_start = selection.start - column;
|
||||||
line_start..line_start
|
line_start..line_start
|
||||||
} else {
|
} else {
|
||||||
|
@ -3350,11 +3365,12 @@ impl Editor {
|
||||||
selection.end = selection.start;
|
selection.end = selection.start;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self.update_selections(selections, Some(Autoscroll::Fit), cx);
|
this.update_selections(selections, Some(Autoscroll::Fit), cx);
|
||||||
} else {
|
} else {
|
||||||
self.insert(clipboard_text, cx);
|
this.insert(clipboard_text, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
|
pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -3363,6 +3379,7 @@ impl Editor {
|
||||||
self.set_selections(selections, None, true, cx);
|
self.set_selections(selections, None, true, cx);
|
||||||
}
|
}
|
||||||
self.request_autoscroll(Autoscroll::Fit, 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.set_selections(selections, None, true, cx);
|
||||||
}
|
}
|
||||||
self.request_autoscroll(Autoscroll::Fit, cx);
|
self.request_autoscroll(Autoscroll::Fit, cx);
|
||||||
|
cx.emit(Event::Edited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3964,12 +3982,12 @@ impl Editor {
|
||||||
let comment_prefix = full_comment_prefix.trim_end_matches(' ');
|
let comment_prefix = full_comment_prefix.trim_end_matches(' ');
|
||||||
let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
|
let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
|
||||||
|
|
||||||
self.start_transaction(cx);
|
self.transact(cx, |this, cx| {
|
||||||
let mut selections = self.local_selections::<Point>(cx);
|
let mut selections = this.local_selections::<Point>(cx);
|
||||||
let mut all_selection_lines_are_comments = true;
|
let mut all_selection_lines_are_comments = true;
|
||||||
let mut edit_ranges = Vec::new();
|
let mut edit_ranges = Vec::new();
|
||||||
let mut last_toggled_row = None;
|
let mut last_toggled_row = None;
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
this.buffer.update(cx, |buffer, cx| {
|
||||||
for selection in &mut selections {
|
for selection in &mut selections {
|
||||||
edit_ranges.clear();
|
edit_ranges.clear();
|
||||||
let snapshot = buffer.snapshot(cx);
|
let snapshot = buffer.snapshot(cx);
|
||||||
|
@ -4012,10 +4030,13 @@ impl Editor {
|
||||||
let matching_whitespace_len = line_bytes
|
let matching_whitespace_len = line_bytes
|
||||||
.zip(comment_prefix_whitespace.bytes())
|
.zip(comment_prefix_whitespace.bytes())
|
||||||
.take_while(|(a, b)| a == b)
|
.take_while(|(a, b)| a == b)
|
||||||
.count() as u32;
|
.count()
|
||||||
|
as u32;
|
||||||
let end = Point::new(
|
let end = Point::new(
|
||||||
row,
|
row,
|
||||||
start.column + comment_prefix.len() as u32 + matching_whitespace_len,
|
start.column
|
||||||
|
+ comment_prefix.len() as u32
|
||||||
|
+ matching_whitespace_len,
|
||||||
);
|
);
|
||||||
edit_ranges.push(start..end);
|
edit_ranges.push(start..end);
|
||||||
}
|
}
|
||||||
|
@ -4031,7 +4052,8 @@ impl Editor {
|
||||||
if all_selection_lines_are_comments {
|
if all_selection_lines_are_comments {
|
||||||
buffer.edit(edit_ranges.iter().cloned(), "", cx);
|
buffer.edit(edit_ranges.iter().cloned(), "", cx);
|
||||||
} else {
|
} else {
|
||||||
let min_column = edit_ranges.iter().map(|r| r.start.column).min().unwrap();
|
let min_column =
|
||||||
|
edit_ranges.iter().map(|r| r.start.column).min().unwrap();
|
||||||
let edit_ranges = edit_ranges.iter().map(|range| {
|
let edit_ranges = edit_ranges.iter().map(|range| {
|
||||||
let position = Point::new(range.start.row, min_column);
|
let position = Point::new(range.start.row, min_column);
|
||||||
position..position
|
position..position
|
||||||
|
@ -4042,12 +4064,12 @@ impl Editor {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.update_selections(
|
this.update_selections(
|
||||||
self.local_selections::<usize>(cx),
|
this.local_selections::<usize>(cx),
|
||||||
Some(Autoscroll::Fit),
|
Some(Autoscroll::Fit),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
self.end_transaction(cx);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_larger_syntax_node(
|
pub fn select_larger_syntax_node(
|
||||||
|
@ -4407,6 +4429,7 @@ impl Editor {
|
||||||
.flat_map(|(_, ranges)| ranges),
|
.flat_map(|(_, ranges)| ranges),
|
||||||
)
|
)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
this.highlight_text::<Rename>(
|
this.highlight_text::<Rename>(
|
||||||
ranges,
|
ranges,
|
||||||
HighlightStyle {
|
HighlightStyle {
|
||||||
|
@ -4685,13 +4708,13 @@ impl Editor {
|
||||||
|
|
||||||
let start_ix = match self
|
let start_ix = match self
|
||||||
.selections
|
.selections
|
||||||
.binary_search_by(|probe| probe.end.cmp(&range.start, &buffer).unwrap())
|
.binary_search_by(|probe| probe.end.cmp(&range.start, &buffer))
|
||||||
{
|
{
|
||||||
Ok(ix) | Err(ix) => ix,
|
Ok(ix) | Err(ix) => ix,
|
||||||
};
|
};
|
||||||
let end_ix = match self
|
let end_ix = match self
|
||||||
.selections
|
.selections
|
||||||
.binary_search_by(|probe| probe.start.cmp(&range.end, &buffer).unwrap())
|
.binary_search_by(|probe| probe.start.cmp(&range.end, &buffer))
|
||||||
{
|
{
|
||||||
Ok(ix) => ix + 1,
|
Ok(ix) => ix + 1,
|
||||||
Err(ix) => ix,
|
Err(ix) => ix,
|
||||||
|
@ -4913,8 +4936,7 @@ impl Editor {
|
||||||
selections.sort_by(|a, b| {
|
selections.sort_by(|a, b| {
|
||||||
a.start
|
a.start
|
||||||
.cmp(&b.start, &*buffer)
|
.cmp(&b.start, &*buffer)
|
||||||
.unwrap()
|
.then_with(|| b.end.cmp(&a.end, &*buffer))
|
||||||
.then_with(|| b.end.cmp(&a.end, &*buffer).unwrap())
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Merge overlapping selections
|
// Merge overlapping selections
|
||||||
|
@ -4923,24 +4945,17 @@ impl Editor {
|
||||||
if selections[i - 1]
|
if selections[i - 1]
|
||||||
.end
|
.end
|
||||||
.cmp(&selections[i].start, &*buffer)
|
.cmp(&selections[i].start, &*buffer)
|
||||||
.unwrap()
|
|
||||||
.is_ge()
|
.is_ge()
|
||||||
{
|
{
|
||||||
let removed = selections.remove(i);
|
let removed = selections.remove(i);
|
||||||
if removed
|
if removed
|
||||||
.start
|
.start
|
||||||
.cmp(&selections[i - 1].start, &*buffer)
|
.cmp(&selections[i - 1].start, &*buffer)
|
||||||
.unwrap()
|
|
||||||
.is_lt()
|
.is_lt()
|
||||||
{
|
{
|
||||||
selections[i - 1].start = removed.start;
|
selections[i - 1].start = removed.start;
|
||||||
}
|
}
|
||||||
if removed
|
if removed.end.cmp(&selections[i - 1].end, &*buffer).is_gt() {
|
||||||
.end
|
|
||||||
.cmp(&selections[i - 1].end, &*buffer)
|
|
||||||
.unwrap()
|
|
||||||
.is_gt()
|
|
||||||
{
|
|
||||||
selections[i - 1].end = removed.end;
|
selections[i - 1].end = removed.end;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -5119,13 +5134,9 @@ impl Editor {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
|
update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
|
||||||
) {
|
) {
|
||||||
self.start_transaction(cx);
|
|
||||||
update(self, cx);
|
|
||||||
self.end_transaction(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_transaction(&mut self, cx: &mut ViewContext<Self>) {
|
|
||||||
self.start_transaction_at(Instant::now(), cx);
|
self.start_transaction_at(Instant::now(), cx);
|
||||||
|
update(self, cx);
|
||||||
|
self.end_transaction_at(Instant::now(), cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
|
fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -5139,10 +5150,6 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_transaction(&mut self, cx: &mut ViewContext<Self>) {
|
|
||||||
self.end_transaction_at(Instant::now(), cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
|
fn end_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(tx_id) = self
|
if let Some(tx_id) = self
|
||||||
.buffer
|
.buffer
|
||||||
|
@ -5153,6 +5160,8 @@ impl Editor {
|
||||||
} else {
|
} else {
|
||||||
log::error!("unexpectedly ended a transaction that wasn't started by this editor");
|
log::error!("unexpectedly ended a transaction that wasn't started by this editor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cx.emit(Event::Edited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5328,11 +5337,13 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_text(&mut self, text: impl Into<String>, cx: &mut ViewContext<Self>) {
|
pub fn set_text(&mut self, text: impl Into<String>, cx: &mut ViewContext<Self>) {
|
||||||
self.buffer
|
self.transact(cx, |this, cx| {
|
||||||
|
this.buffer
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.as_singleton()
|
.as_singleton()
|
||||||
.expect("you can only call set_text on editors for singleton buffers")
|
.expect("you can only call set_text on editors for singleton buffers")
|
||||||
.update(cx, |buffer, cx| buffer.set_text(text, cx));
|
.update(cx, |buffer, cx| buffer.set_text(text, cx));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
|
pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
|
||||||
|
@ -5420,7 +5431,7 @@ impl Editor {
|
||||||
let buffer = &display_snapshot.buffer_snapshot;
|
let buffer = &display_snapshot.buffer_snapshot;
|
||||||
for (color, ranges) in self.background_highlights.values() {
|
for (color, ranges) in self.background_highlights.values() {
|
||||||
let start_ix = match ranges.binary_search_by(|probe| {
|
let start_ix = match ranges.binary_search_by(|probe| {
|
||||||
let cmp = probe.end.cmp(&search_range.start, &buffer).unwrap();
|
let cmp = probe.end.cmp(&search_range.start, &buffer);
|
||||||
if cmp.is_gt() {
|
if cmp.is_gt() {
|
||||||
Ordering::Greater
|
Ordering::Greater
|
||||||
} else {
|
} else {
|
||||||
|
@ -5430,7 +5441,7 @@ impl Editor {
|
||||||
Ok(i) | Err(i) => i,
|
Ok(i) | Err(i) => i,
|
||||||
};
|
};
|
||||||
for range in &ranges[start_ix..] {
|
for range in &ranges[start_ix..] {
|
||||||
if range.start.cmp(&search_range.end, &buffer).unwrap().is_ge() {
|
if range.start.cmp(&search_range.end, &buffer).is_ge() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let start = range
|
let start = range
|
||||||
|
@ -5535,10 +5546,10 @@ impl Editor {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
language::Event::Edited { local } => {
|
language::Event::Edited => {
|
||||||
self.refresh_active_diagnostics(cx);
|
self.refresh_active_diagnostics(cx);
|
||||||
self.refresh_code_actions(cx);
|
self.refresh_code_actions(cx);
|
||||||
cx.emit(Event::Edited { local: *local });
|
cx.emit(Event::BufferEdited);
|
||||||
}
|
}
|
||||||
language::Event::Dirtied => cx.emit(Event::Dirtied),
|
language::Event::Dirtied => cx.emit(Event::Dirtied),
|
||||||
language::Event::Saved => cx.emit(Event::Saved),
|
language::Event::Saved => cx.emit(Event::Saved),
|
||||||
|
@ -5662,10 +5673,11 @@ fn compute_scroll_position(
|
||||||
scroll_position
|
scroll_position
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Activate,
|
Activate,
|
||||||
Edited { local: bool },
|
BufferEdited,
|
||||||
|
Edited,
|
||||||
Blurred,
|
Blurred,
|
||||||
Dirtied,
|
Dirtied,
|
||||||
Saved,
|
Saved,
|
||||||
|
@ -6144,6 +6156,114 @@ mod tests {
|
||||||
use util::test::sample_text;
|
use util::test::sample_text;
|
||||||
use workspace::FollowableItem;
|
use workspace::FollowableItem;
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn test_edit_events(cx: &mut MutableAppContext) {
|
||||||
|
populate_settings(cx);
|
||||||
|
let buffer = cx.add_model(|cx| language::Buffer::new(0, "123456", cx));
|
||||||
|
|
||||||
|
let events = Rc::new(RefCell::new(Vec::new()));
|
||||||
|
let (_, editor1) = cx.add_window(Default::default(), {
|
||||||
|
let events = events.clone();
|
||||||
|
|cx| {
|
||||||
|
cx.subscribe(&cx.handle(), move |_, _, event, _| {
|
||||||
|
if matches!(event, Event::Edited | Event::BufferEdited | Event::Dirtied) {
|
||||||
|
events.borrow_mut().push(("editor1", *event));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
Editor::for_buffer(buffer.clone(), None, cx)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let (_, editor2) = cx.add_window(Default::default(), {
|
||||||
|
let events = events.clone();
|
||||||
|
|cx| {
|
||||||
|
cx.subscribe(&cx.handle(), move |_, _, event, _| {
|
||||||
|
if matches!(event, Event::Edited | Event::BufferEdited | Event::Dirtied) {
|
||||||
|
events.borrow_mut().push(("editor2", *event));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
Editor::for_buffer(buffer.clone(), None, cx)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert_eq!(mem::take(&mut *events.borrow_mut()), []);
|
||||||
|
|
||||||
|
// Mutating editor 1 will emit an `Edited` event only for that editor.
|
||||||
|
editor1.update(cx, |editor, cx| editor.insert("X", cx));
|
||||||
|
assert_eq!(
|
||||||
|
mem::take(&mut *events.borrow_mut()),
|
||||||
|
[
|
||||||
|
("editor1", Event::Edited),
|
||||||
|
("editor1", Event::BufferEdited),
|
||||||
|
("editor2", Event::BufferEdited),
|
||||||
|
("editor1", Event::Dirtied),
|
||||||
|
("editor2", Event::Dirtied)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mutating editor 2 will emit an `Edited` event only for that editor.
|
||||||
|
editor2.update(cx, |editor, cx| editor.delete(&Delete, cx));
|
||||||
|
assert_eq!(
|
||||||
|
mem::take(&mut *events.borrow_mut()),
|
||||||
|
[
|
||||||
|
("editor2", Event::Edited),
|
||||||
|
("editor1", Event::BufferEdited),
|
||||||
|
("editor2", Event::BufferEdited),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Undoing on editor 1 will emit an `Edited` event only for that editor.
|
||||||
|
editor1.update(cx, |editor, cx| editor.undo(&Undo, cx));
|
||||||
|
assert_eq!(
|
||||||
|
mem::take(&mut *events.borrow_mut()),
|
||||||
|
[
|
||||||
|
("editor1", Event::Edited),
|
||||||
|
("editor1", Event::BufferEdited),
|
||||||
|
("editor2", Event::BufferEdited),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Redoing on editor 1 will emit an `Edited` event only for that editor.
|
||||||
|
editor1.update(cx, |editor, cx| editor.redo(&Redo, cx));
|
||||||
|
assert_eq!(
|
||||||
|
mem::take(&mut *events.borrow_mut()),
|
||||||
|
[
|
||||||
|
("editor1", Event::Edited),
|
||||||
|
("editor1", Event::BufferEdited),
|
||||||
|
("editor2", Event::BufferEdited),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Undoing on editor 2 will emit an `Edited` event only for that editor.
|
||||||
|
editor2.update(cx, |editor, cx| editor.undo(&Undo, cx));
|
||||||
|
assert_eq!(
|
||||||
|
mem::take(&mut *events.borrow_mut()),
|
||||||
|
[
|
||||||
|
("editor2", Event::Edited),
|
||||||
|
("editor1", Event::BufferEdited),
|
||||||
|
("editor2", Event::BufferEdited),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Redoing on editor 2 will emit an `Edited` event only for that editor.
|
||||||
|
editor2.update(cx, |editor, cx| editor.redo(&Redo, cx));
|
||||||
|
assert_eq!(
|
||||||
|
mem::take(&mut *events.borrow_mut()),
|
||||||
|
[
|
||||||
|
("editor2", Event::Edited),
|
||||||
|
("editor1", Event::BufferEdited),
|
||||||
|
("editor2", Event::BufferEdited),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// No event is emitted when the mutation is a no-op.
|
||||||
|
editor2.update(cx, |editor, cx| {
|
||||||
|
editor.select_ranges([0..0], None, cx);
|
||||||
|
editor.backspace(&Backspace, cx);
|
||||||
|
});
|
||||||
|
assert_eq!(mem::take(&mut *events.borrow_mut()), []);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
fn test_undo_redo_with_selection_restoration(cx: &mut MutableAppContext) {
|
fn test_undo_redo_with_selection_restoration(cx: &mut MutableAppContext) {
|
||||||
populate_settings(cx);
|
populate_settings(cx);
|
||||||
|
|
|
@ -198,7 +198,7 @@ impl FollowableItem for Editor {
|
||||||
|
|
||||||
fn should_unfollow_on_event(event: &Self::Event, _: &AppContext) -> bool {
|
fn should_unfollow_on_event(event: &Self::Event, _: &AppContext) -> bool {
|
||||||
match event {
|
match event {
|
||||||
Event::Edited { local } => *local,
|
Event::Edited => true,
|
||||||
Event::SelectionsChanged { local } => *local,
|
Event::SelectionsChanged { local } => *local,
|
||||||
Event::ScrollPositionChanged { local } => *local,
|
Event::ScrollPositionChanged { local } => *local,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
@ -211,7 +211,7 @@ impl MultiBuffer {
|
||||||
pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
|
pub fn singleton(buffer: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
|
||||||
let mut this = Self::new(buffer.read(cx).replica_id());
|
let mut this = Self::new(buffer.read(cx).replica_id());
|
||||||
this.singleton = true;
|
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.snapshot.borrow_mut().singleton = true;
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
@ -522,24 +522,14 @@ impl MultiBuffer {
|
||||||
self.buffers.borrow()[&buffer_id]
|
self.buffers.borrow()[&buffer_id]
|
||||||
.buffer
|
.buffer
|
||||||
.update(cx, |buffer, cx| {
|
.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 mut selections = selections.into_iter().peekable();
|
||||||
let merged_selections = Arc::from_iter(iter::from_fn(|| {
|
let merged_selections = Arc::from_iter(iter::from_fn(|| {
|
||||||
let mut selection = selections.next()?;
|
let mut selection = selections.next()?;
|
||||||
while let Some(next_selection) = selections.peek() {
|
while let Some(next_selection) = selections.peek() {
|
||||||
if selection
|
if selection.end.cmp(&next_selection.start, buffer).is_ge() {
|
||||||
.end
|
|
||||||
.cmp(&next_selection.start, buffer)
|
|
||||||
.unwrap()
|
|
||||||
.is_ge()
|
|
||||||
{
|
|
||||||
let next_selection = selections.next().unwrap();
|
let next_selection = selections.next().unwrap();
|
||||||
if next_selection
|
if next_selection.end.cmp(&selection.end, buffer).is_ge() {
|
||||||
.end
|
|
||||||
.cmp(&selection.end, buffer)
|
|
||||||
.unwrap()
|
|
||||||
.is_ge()
|
|
||||||
{
|
|
||||||
selection.end = next_selection.end;
|
selection.end = next_selection.end;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -814,11 +804,30 @@ impl MultiBuffer {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn excerpt_ids_for_buffer(&self, buffer: &ModelHandle<Buffer>) -> Vec<ExcerptId> {
|
pub fn excerpts_for_buffer(
|
||||||
self.buffers
|
&self,
|
||||||
.borrow()
|
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())
|
.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> {
|
pub fn excerpt_ids(&self) -> Vec<ExcerptId> {
|
||||||
|
@ -1917,11 +1926,7 @@ impl MultiBufferSnapshot {
|
||||||
.range
|
.range
|
||||||
.start
|
.start
|
||||||
.bias(anchor.text_anchor.bias, &excerpt.buffer);
|
.bias(anchor.text_anchor.bias, &excerpt.buffer);
|
||||||
if text_anchor
|
if text_anchor.cmp(&excerpt.range.end, &excerpt.buffer).is_gt() {
|
||||||
.cmp(&excerpt.range.end, &excerpt.buffer)
|
|
||||||
.unwrap()
|
|
||||||
.is_gt()
|
|
||||||
{
|
|
||||||
text_anchor = excerpt.range.end.clone();
|
text_anchor = excerpt.range.end.clone();
|
||||||
}
|
}
|
||||||
Anchor {
|
Anchor {
|
||||||
|
@ -1936,7 +1941,6 @@ impl MultiBufferSnapshot {
|
||||||
.bias(anchor.text_anchor.bias, &excerpt.buffer);
|
.bias(anchor.text_anchor.bias, &excerpt.buffer);
|
||||||
if text_anchor
|
if text_anchor
|
||||||
.cmp(&excerpt.range.start, &excerpt.buffer)
|
.cmp(&excerpt.range.start, &excerpt.buffer)
|
||||||
.unwrap()
|
|
||||||
.is_lt()
|
.is_lt()
|
||||||
{
|
{
|
||||||
text_anchor = excerpt.range.start.clone();
|
text_anchor = excerpt.range.start.clone();
|
||||||
|
@ -1956,7 +1960,7 @@ impl MultiBufferSnapshot {
|
||||||
result.push((anchor_ix, anchor, kept_position));
|
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
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2303,10 +2307,10 @@ impl MultiBufferSnapshot {
|
||||||
excerpt_id: excerpt.id.clone(),
|
excerpt_id: excerpt.id.clone(),
|
||||||
text_anchor: selection.end.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();
|
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();
|
end = range.end.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2530,17 +2534,9 @@ impl Excerpt {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
|
fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor {
|
||||||
if text_anchor
|
if text_anchor.cmp(&self.range.start, &self.buffer).is_lt() {
|
||||||
.cmp(&self.range.start, &self.buffer)
|
|
||||||
.unwrap()
|
|
||||||
.is_lt()
|
|
||||||
{
|
|
||||||
self.range.start.clone()
|
self.range.start.clone()
|
||||||
} else if text_anchor
|
} else if text_anchor.cmp(&self.range.end, &self.buffer).is_gt() {
|
||||||
.cmp(&self.range.end, &self.buffer)
|
|
||||||
.unwrap()
|
|
||||||
.is_gt()
|
|
||||||
{
|
|
||||||
self.range.end.clone()
|
self.range.end.clone()
|
||||||
} else {
|
} else {
|
||||||
text_anchor
|
text_anchor
|
||||||
|
@ -2553,13 +2549,11 @@ impl Excerpt {
|
||||||
.range
|
.range
|
||||||
.start
|
.start
|
||||||
.cmp(&anchor.text_anchor, &self.buffer)
|
.cmp(&anchor.text_anchor, &self.buffer)
|
||||||
.unwrap()
|
|
||||||
.is_le()
|
.is_le()
|
||||||
&& self
|
&& self
|
||||||
.range
|
.range
|
||||||
.end
|
.end
|
||||||
.cmp(&anchor.text_anchor, &self.buffer)
|
.cmp(&anchor.text_anchor, &self.buffer)
|
||||||
.unwrap()
|
|
||||||
.is_ge()
|
.is_ge()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3070,7 +3064,8 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
let snapshot = multibuffer.update(cx, |multibuffer, cx| {
|
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.remove_excerpts(&[buffer_2_excerpt_id], cx);
|
||||||
multibuffer.snapshot(cx)
|
multibuffer.snapshot(cx)
|
||||||
});
|
});
|
||||||
|
@ -3365,7 +3360,7 @@ mod tests {
|
||||||
let bias = if rng.gen() { Bias::Left } else { Bias::Right };
|
let bias = if rng.gen() { Bias::Left } else { Bias::Right };
|
||||||
log::info!("Creating anchor at {} with bias {:?}", offset, bias);
|
log::info!("Creating anchor at {} with bias {:?}", offset, bias);
|
||||||
anchors.push(multibuffer.anchor_at(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() => {
|
40..=44 if !anchors.is_empty() => {
|
||||||
let multibuffer = multibuffer.read(cx).read(cx);
|
let multibuffer = multibuffer.read(cx).read(cx);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
|
use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
|
||||||
use anyhow::Result;
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
ops::{Range, Sub},
|
ops::{Range, Sub},
|
||||||
|
@ -19,7 +18,7 @@ impl Anchor {
|
||||||
Self {
|
Self {
|
||||||
buffer_id: None,
|
buffer_id: None,
|
||||||
excerpt_id: ExcerptId::min(),
|
excerpt_id: ExcerptId::min(),
|
||||||
text_anchor: text::Anchor::min(),
|
text_anchor: text::Anchor::MIN,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ impl Anchor {
|
||||||
Self {
|
Self {
|
||||||
buffer_id: None,
|
buffer_id: None,
|
||||||
excerpt_id: ExcerptId::max(),
|
excerpt_id: ExcerptId::max(),
|
||||||
text_anchor: text::Anchor::max(),
|
text_anchor: text::Anchor::MAX,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,18 +34,18 @@ impl Anchor {
|
||||||
&self.excerpt_id
|
&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);
|
let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id);
|
||||||
if excerpt_id_cmp.is_eq() {
|
if excerpt_id_cmp.is_eq() {
|
||||||
if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
|
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) {
|
} else if let Some(excerpt) = snapshot.excerpt(&self.excerpt_id) {
|
||||||
self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer)
|
self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer)
|
||||||
} else {
|
} else {
|
||||||
Ok(Ordering::Equal)
|
Ordering::Equal
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(excerpt_id_cmp)
|
excerpt_id_cmp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,17 +96,17 @@ impl ToPoint for Anchor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AnchorRangeExt {
|
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_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
|
||||||
fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
|
fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnchorRangeExt for Range<Anchor> {
|
impl AnchorRangeExt for Range<Anchor> {
|
||||||
fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering> {
|
fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering {
|
||||||
Ok(match self.start.cmp(&other.start, buffer)? {
|
match self.start.cmp(&other.start, buffer) {
|
||||||
Ordering::Equal => other.end.cmp(&self.end, buffer)?,
|
Ordering::Equal => other.end.cmp(&self.end, buffer),
|
||||||
ord @ _ => ord,
|
ord @ _ => ord,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
|
fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[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!['|']);
|
let (unmarked_text, mut markers) = marked_text_by(marked_text, vec!['|']);
|
||||||
(unmarked_text, markers.remove(&'|').unwrap_or_else(Vec::new))
|
(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>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
editor::Event::Edited { .. } => {
|
editor::Event::BufferEdited { .. } => {
|
||||||
let query = self.query_editor.update(cx, |buffer, cx| buffer.text(cx));
|
let query = self.query_editor.update(cx, |buffer, cx| buffer.text(cx));
|
||||||
if query.is_empty() {
|
if query.is_empty() {
|
||||||
self.latest_search_id = post_inc(&mut self.search_count);
|
self.latest_search_id = post_inc(&mut self.search_count);
|
||||||
|
|
|
@ -102,7 +102,7 @@ impl GoToLine {
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
editor::Event::Blurred => cx.emit(Event::Dismissed),
|
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 line_editor = self.line_editor.read(cx).buffer().read(cx).read(cx).text();
|
||||||
let mut components = line_editor.trim().split(&[',', ':'][..]);
|
let mut components = line_editor.trim().split(&[',', ':'][..]);
|
||||||
let row = components.next().and_then(|row| row.parse::<u32>().ok());
|
let row = components.next().and_then(|row| row.parse::<u32>().ok());
|
||||||
|
|
|
@ -142,7 +142,7 @@ pub enum Operation {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Operation(Operation),
|
Operation(Operation),
|
||||||
Edited { local: bool },
|
Edited,
|
||||||
Dirtied,
|
Dirtied,
|
||||||
Saved,
|
Saved,
|
||||||
FileHandleChanged,
|
FileHandleChanged,
|
||||||
|
@ -967,7 +967,7 @@ impl Buffer {
|
||||||
) -> Option<TransactionId> {
|
) -> Option<TransactionId> {
|
||||||
if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
|
if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) {
|
||||||
let was_dirty = start_version != self.saved_version;
|
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)
|
Some(transaction_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -1160,7 +1160,6 @@ impl Buffer {
|
||||||
&mut self,
|
&mut self,
|
||||||
old_version: &clock::Global,
|
old_version: &clock::Global,
|
||||||
was_dirty: bool,
|
was_dirty: bool,
|
||||||
local: bool,
|
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) {
|
) {
|
||||||
if self.edits_since::<usize>(old_version).next().is_none() {
|
if self.edits_since::<usize>(old_version).next().is_none() {
|
||||||
|
@ -1169,7 +1168,7 @@ impl Buffer {
|
||||||
|
|
||||||
self.reparse(cx);
|
self.reparse(cx);
|
||||||
|
|
||||||
cx.emit(Event::Edited { local });
|
cx.emit(Event::Edited);
|
||||||
if !was_dirty {
|
if !was_dirty {
|
||||||
cx.emit(Event::Dirtied);
|
cx.emit(Event::Dirtied);
|
||||||
}
|
}
|
||||||
|
@ -1206,7 +1205,7 @@ impl Buffer {
|
||||||
self.text.apply_ops(buffer_ops)?;
|
self.text.apply_ops(buffer_ops)?;
|
||||||
self.deferred_ops.insert(deferred_ops);
|
self.deferred_ops.insert(deferred_ops);
|
||||||
self.flush_deferred_ops(cx);
|
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
|
// Notify independently of whether the buffer was edited as the operations could include a
|
||||||
// selection update.
|
// selection update.
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -1321,7 +1320,7 @@ impl Buffer {
|
||||||
|
|
||||||
if let Some((transaction_id, operation)) = self.text.undo() {
|
if let Some((transaction_id, operation)) = self.text.undo() {
|
||||||
self.send_operation(Operation::Buffer(operation), cx);
|
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)
|
Some(transaction_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -1342,7 +1341,7 @@ impl Buffer {
|
||||||
self.send_operation(Operation::Buffer(operation), cx);
|
self.send_operation(Operation::Buffer(operation), cx);
|
||||||
}
|
}
|
||||||
if undone {
|
if undone {
|
||||||
self.did_edit(&old_version, was_dirty, true, cx)
|
self.did_edit(&old_version, was_dirty, cx)
|
||||||
}
|
}
|
||||||
undone
|
undone
|
||||||
}
|
}
|
||||||
|
@ -1353,7 +1352,7 @@ impl Buffer {
|
||||||
|
|
||||||
if let Some((transaction_id, operation)) = self.text.redo() {
|
if let Some((transaction_id, operation)) = self.text.redo() {
|
||||||
self.send_operation(Operation::Buffer(operation), cx);
|
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)
|
Some(transaction_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -1374,7 +1373,7 @@ impl Buffer {
|
||||||
self.send_operation(Operation::Buffer(operation), cx);
|
self.send_operation(Operation::Buffer(operation), cx);
|
||||||
}
|
}
|
||||||
if redone {
|
if redone {
|
||||||
self.did_edit(&old_version, was_dirty, true, cx)
|
self.did_edit(&old_version, was_dirty, cx)
|
||||||
}
|
}
|
||||||
redone
|
redone
|
||||||
}
|
}
|
||||||
|
@ -1440,7 +1439,7 @@ impl Buffer {
|
||||||
if !ops.is_empty() {
|
if !ops.is_empty() {
|
||||||
for op in ops {
|
for op in ops {
|
||||||
self.send_operation(Operation::Buffer(op), cx);
|
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)| {
|
.map(move |(replica_id, set)| {
|
||||||
let start_ix = match set.selections.binary_search_by(|probe| {
|
let start_ix = match set.selections.binary_search_by(|probe| {
|
||||||
probe
|
probe.end.cmp(&range.start, self).then(Ordering::Greater)
|
||||||
.end
|
|
||||||
.cmp(&range.start, self)
|
|
||||||
.unwrap()
|
|
||||||
.then(Ordering::Greater)
|
|
||||||
}) {
|
}) {
|
||||||
Ok(ix) | Err(ix) => ix,
|
Ok(ix) | Err(ix) => ix,
|
||||||
};
|
};
|
||||||
let end_ix = match set.selections.binary_search_by(|probe| {
|
let end_ix = match set.selections.binary_search_by(|probe| {
|
||||||
probe
|
probe.start.cmp(&range.end, self).then(Ordering::Less)
|
||||||
.start
|
|
||||||
.cmp(&range.end, self)
|
|
||||||
.unwrap()
|
|
||||||
.then(Ordering::Less)
|
|
||||||
}) {
|
}) {
|
||||||
Ok(ix) | Err(ix) => ix,
|
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 range = buffer.anchor_before(range.start)..buffer.anchor_at(range.end, end_bias);
|
||||||
let mut cursor = self.diagnostics.filter::<_, ()>({
|
let mut cursor = self.diagnostics.filter::<_, ()>({
|
||||||
move |summary: &Summary| {
|
move |summary: &Summary| {
|
||||||
let start_cmp = range.start.cmp(&summary.max_end, buffer).unwrap();
|
let start_cmp = range.start.cmp(&summary.max_end, buffer);
|
||||||
let end_cmp = range.end.cmp(&summary.min_start, buffer).unwrap();
|
let end_cmp = range.end.cmp(&summary.min_start, buffer);
|
||||||
if inclusive {
|
if inclusive {
|
||||||
start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal
|
start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal
|
||||||
} else {
|
} else {
|
||||||
|
@ -123,7 +123,7 @@ impl DiagnosticSet {
|
||||||
|
|
||||||
let start_ix = output.len();
|
let start_ix = output.len();
|
||||||
output.extend(groups.into_values().filter_map(|mut entries| {
|
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
|
entries
|
||||||
.iter()
|
.iter()
|
||||||
.position(|entry| entry.diagnostic.is_primary)
|
.position(|entry| entry.diagnostic.is_primary)
|
||||||
|
@ -137,7 +137,6 @@ impl DiagnosticSet {
|
||||||
.range
|
.range
|
||||||
.start
|
.start
|
||||||
.cmp(&b.entries[b.primary_ix].range.start, buffer)
|
.cmp(&b.entries[b.primary_ix].range.start, buffer)
|
||||||
.unwrap()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,10 +186,10 @@ impl DiagnosticEntry<Anchor> {
|
||||||
impl Default for Summary {
|
impl Default for Summary {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
start: Anchor::min(),
|
start: Anchor::MIN,
|
||||||
end: Anchor::max(),
|
end: Anchor::MAX,
|
||||||
min_start: Anchor::max(),
|
min_start: Anchor::MAX,
|
||||||
max_end: Anchor::min(),
|
max_end: Anchor::MIN,
|
||||||
count: 0,
|
count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,15 +199,10 @@ impl sum_tree::Summary for Summary {
|
||||||
type Context = text::BufferSnapshot;
|
type Context = text::BufferSnapshot;
|
||||||
|
|
||||||
fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {
|
fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {
|
||||||
if other
|
if other.min_start.cmp(&self.min_start, buffer).is_lt() {
|
||||||
.min_start
|
|
||||||
.cmp(&self.min_start, buffer)
|
|
||||||
.unwrap()
|
|
||||||
.is_lt()
|
|
||||||
{
|
|
||||||
self.min_start = other.min_start.clone();
|
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.max_end = other.max_end.clone();
|
||||||
}
|
}
|
||||||
self.start = other.start.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();
|
let buffer_1_events = buffer_1_events.borrow();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*buffer_1_events,
|
*buffer_1_events,
|
||||||
vec![
|
vec![Event::Edited, Event::Dirtied, Event::Edited, Event::Edited]
|
||||||
Event::Edited { local: true },
|
|
||||||
Event::Dirtied,
|
|
||||||
Event::Edited { local: true },
|
|
||||||
Event::Edited { local: true }
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let buffer_2_events = buffer_2_events.borrow();
|
let buffer_2_events = buffer_2_events.borrow();
|
||||||
assert_eq!(
|
assert_eq!(*buffer_2_events, vec![Event::Edited, Event::Dirtied]);
|
||||||
*buffer_2_events,
|
|
||||||
vec![Event::Edited { local: false }, Event::Dirtied]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
|
@ -827,7 +819,7 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
|
||||||
for buffer in &buffers {
|
for buffer in &buffers {
|
||||||
let buffer = buffer.read(cx).snapshot();
|
let buffer = buffer.read(cx).snapshot();
|
||||||
let actual_remote_selections = buffer
|
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<_>>()))
|
.map(|(replica_id, selections)| (replica_id, selections.collect::<Vec<_>>()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let expected_remote_selections = active_selections
|
let expected_remote_selections = active_selections
|
||||||
|
|
|
@ -224,7 +224,7 @@ impl OutlineView {
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
editor::Event::Blurred => cx.emit(Event::Dismissed),
|
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!(buffer.is_dirty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*events.borrow(),
|
*events.borrow(),
|
||||||
&[
|
&[language::Event::Edited, language::Event::Dirtied]
|
||||||
language::Event::Edited { local: true },
|
|
||||||
language::Event::Dirtied
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
events.borrow_mut().clear();
|
events.borrow_mut().clear();
|
||||||
buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), None, cx);
|
buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), None, cx);
|
||||||
|
@ -6255,9 +6252,9 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*events.borrow(),
|
*events.borrow(),
|
||||||
&[
|
&[
|
||||||
language::Event::Edited { local: true },
|
language::Event::Edited,
|
||||||
language::Event::Dirtied,
|
language::Event::Dirtied,
|
||||||
language::Event::Edited { local: true },
|
language::Event::Edited,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
events.borrow_mut().clear();
|
events.borrow_mut().clear();
|
||||||
|
@ -6269,7 +6266,7 @@ mod tests {
|
||||||
assert!(buffer.is_dirty());
|
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.
|
// When a file is deleted, the buffer is considered dirty.
|
||||||
let events = Rc::new(RefCell::new(Vec::new()));
|
let events = Rc::new(RefCell::new(Vec::new()));
|
||||||
|
|
|
@ -328,7 +328,7 @@ impl ProjectSymbolsView {
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
editor::Event::Blurred => cx.emit(Event::Dismissed),
|
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>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
editor::Event::Edited { .. } => {
|
editor::Event::BufferEdited { .. } => {
|
||||||
self.query_contains_error = false;
|
self.query_contains_error = false;
|
||||||
self.clear_matches(cx);
|
self.clear_matches(cx);
|
||||||
self.update_matches(true, cx);
|
self.update_matches(true, cx);
|
||||||
|
@ -375,7 +375,7 @@ impl SearchBar {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
match event {
|
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),
|
editor::Event::SelectionsChanged { .. } => self.update_match_index(cx),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,9 @@ pub(crate) fn active_match_index(
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
match ranges.binary_search_by(|probe| {
|
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
|
Ordering::Less
|
||||||
} else if probe.start.cmp(&cursor, &*buffer).unwrap().is_gt() {
|
} else if probe.start.cmp(&cursor, &*buffer).is_gt() {
|
||||||
Ordering::Greater
|
Ordering::Greater
|
||||||
} else {
|
} else {
|
||||||
Ordering::Equal
|
Ordering::Equal
|
||||||
|
@ -59,7 +59,7 @@ pub(crate) fn match_index_for_direction(
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
buffer: &MultiBufferSnapshot,
|
buffer: &MultiBufferSnapshot,
|
||||||
) -> usize {
|
) -> 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 direction == Direction::Prev {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
index = ranges.len() - 1;
|
index = ranges.len() - 1;
|
||||||
|
@ -67,7 +67,7 @@ pub(crate) fn match_index_for_direction(
|
||||||
index -= 1;
|
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 {
|
if direction == Direction::Next {
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,23 +12,19 @@ pub struct Anchor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Anchor {
|
impl Anchor {
|
||||||
pub fn min() -> Self {
|
pub const MIN: Self = Self {
|
||||||
Self {
|
|
||||||
timestamp: clock::Local::MIN,
|
timestamp: clock::Local::MIN,
|
||||||
offset: usize::MIN,
|
offset: usize::MIN,
|
||||||
bias: Bias::Left,
|
bias: Bias::Left,
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
pub fn max() -> Self {
|
pub const MAX: Self = Self {
|
||||||
Self {
|
|
||||||
timestamp: clock::Local::MAX,
|
timestamp: clock::Local::MAX,
|
||||||
offset: usize::MAX,
|
offset: usize::MAX,
|
||||||
bias: Bias::Right,
|
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 {
|
let fragment_id_comparison = if self.timestamp == other.timestamp {
|
||||||
Ordering::Equal
|
Ordering::Equal
|
||||||
} else {
|
} else {
|
||||||
|
@ -37,9 +33,25 @@ impl Anchor {
|
||||||
.cmp(&buffer.fragment_id_for_anchor(other))
|
.cmp(&buffer.fragment_id_for_anchor(other))
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(fragment_id_comparison
|
fragment_id_comparison
|
||||||
.then_with(|| self.offset.cmp(&other.offset))
|
.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 {
|
pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor {
|
||||||
|
@ -105,8 +117,8 @@ pub trait AnchorRangeExt {
|
||||||
|
|
||||||
impl AnchorRangeExt for Range<Anchor> {
|
impl AnchorRangeExt for Range<Anchor> {
|
||||||
fn cmp(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering> {
|
fn cmp(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering> {
|
||||||
Ok(match self.start.cmp(&other.start, buffer)? {
|
Ok(match self.start.cmp(&other.start, buffer) {
|
||||||
Ordering::Equal => other.end.cmp(&self.end, buffer)?,
|
Ordering::Equal => other.end.cmp(&self.end, buffer),
|
||||||
ord @ _ => ord,
|
ord @ _ => ord,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,59 +340,41 @@ fn test_anchors() {
|
||||||
let anchor_at_offset_2 = buffer.anchor_before(2);
|
let anchor_at_offset_2 = buffer.anchor_before(2);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
anchor_at_offset_0
|
anchor_at_offset_0.cmp(&anchor_at_offset_0, &buffer),
|
||||||
.cmp(&anchor_at_offset_0, &buffer)
|
|
||||||
.unwrap(),
|
|
||||||
Ordering::Equal
|
Ordering::Equal
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
anchor_at_offset_1
|
anchor_at_offset_1.cmp(&anchor_at_offset_1, &buffer),
|
||||||
.cmp(&anchor_at_offset_1, &buffer)
|
|
||||||
.unwrap(),
|
|
||||||
Ordering::Equal
|
Ordering::Equal
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
anchor_at_offset_2
|
anchor_at_offset_2.cmp(&anchor_at_offset_2, &buffer),
|
||||||
.cmp(&anchor_at_offset_2, &buffer)
|
|
||||||
.unwrap(),
|
|
||||||
Ordering::Equal
|
Ordering::Equal
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
anchor_at_offset_0
|
anchor_at_offset_0.cmp(&anchor_at_offset_1, &buffer),
|
||||||
.cmp(&anchor_at_offset_1, &buffer)
|
|
||||||
.unwrap(),
|
|
||||||
Ordering::Less
|
Ordering::Less
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
anchor_at_offset_1
|
anchor_at_offset_1.cmp(&anchor_at_offset_2, &buffer),
|
||||||
.cmp(&anchor_at_offset_2, &buffer)
|
|
||||||
.unwrap(),
|
|
||||||
Ordering::Less
|
Ordering::Less
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
anchor_at_offset_0
|
anchor_at_offset_0.cmp(&anchor_at_offset_2, &buffer),
|
||||||
.cmp(&anchor_at_offset_2, &buffer)
|
|
||||||
.unwrap(),
|
|
||||||
Ordering::Less
|
Ordering::Less
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
anchor_at_offset_1
|
anchor_at_offset_1.cmp(&anchor_at_offset_0, &buffer),
|
||||||
.cmp(&anchor_at_offset_0, &buffer)
|
|
||||||
.unwrap(),
|
|
||||||
Ordering::Greater
|
Ordering::Greater
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
anchor_at_offset_2
|
anchor_at_offset_2.cmp(&anchor_at_offset_1, &buffer),
|
||||||
.cmp(&anchor_at_offset_1, &buffer)
|
|
||||||
.unwrap(),
|
|
||||||
Ordering::Greater
|
Ordering::Greater
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
anchor_at_offset_2
|
anchor_at_offset_2.cmp(&anchor_at_offset_0, &buffer),
|
||||||
.cmp(&anchor_at_offset_0, &buffer)
|
|
||||||
.unwrap(),
|
|
||||||
Ordering::Greater
|
Ordering::Greater
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1318,8 +1318,8 @@ impl Buffer {
|
||||||
let mut futures = Vec::new();
|
let mut futures = Vec::new();
|
||||||
for anchor in anchors {
|
for anchor in anchors {
|
||||||
if !self.version.observed(anchor.timestamp)
|
if !self.version.observed(anchor.timestamp)
|
||||||
&& *anchor != Anchor::max()
|
&& *anchor != Anchor::MAX
|
||||||
&& *anchor != Anchor::min()
|
&& *anchor != Anchor::MIN
|
||||||
{
|
{
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
self.edit_id_resolvers
|
self.edit_id_resolvers
|
||||||
|
@ -1638,9 +1638,9 @@ impl BufferSnapshot {
|
||||||
let mut position = D::default();
|
let mut position = D::default();
|
||||||
|
|
||||||
anchors.map(move |anchor| {
|
anchors.map(move |anchor| {
|
||||||
if *anchor == Anchor::min() {
|
if *anchor == Anchor::MIN {
|
||||||
return D::default();
|
return D::default();
|
||||||
} else if *anchor == Anchor::max() {
|
} else if *anchor == Anchor::MAX {
|
||||||
return D::from_text_summary(&self.visible_text.summary());
|
return D::from_text_summary(&self.visible_text.summary());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1680,9 +1680,9 @@ impl BufferSnapshot {
|
||||||
where
|
where
|
||||||
D: TextDimension,
|
D: TextDimension,
|
||||||
{
|
{
|
||||||
if *anchor == Anchor::min() {
|
if *anchor == Anchor::MIN {
|
||||||
D::default()
|
D::default()
|
||||||
} else if *anchor == Anchor::max() {
|
} else if *anchor == Anchor::MAX {
|
||||||
D::from_text_summary(&self.visible_text.summary())
|
D::from_text_summary(&self.visible_text.summary())
|
||||||
} else {
|
} else {
|
||||||
let anchor_key = InsertionFragmentKey {
|
let anchor_key = InsertionFragmentKey {
|
||||||
|
@ -1718,9 +1718,9 @@ impl BufferSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
|
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
|
||||||
if *anchor == Anchor::min() {
|
if *anchor == Anchor::MIN {
|
||||||
&locator::MIN
|
&locator::MIN
|
||||||
} else if *anchor == Anchor::max() {
|
} else if *anchor == Anchor::MAX {
|
||||||
&locator::MAX
|
&locator::MAX
|
||||||
} else {
|
} else {
|
||||||
let anchor_key = InsertionFragmentKey {
|
let anchor_key = InsertionFragmentKey {
|
||||||
|
@ -1758,9 +1758,9 @@ impl BufferSnapshot {
|
||||||
pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
|
pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
|
||||||
let offset = position.to_offset(self);
|
let offset = position.to_offset(self);
|
||||||
if bias == Bias::Left && offset == 0 {
|
if bias == Bias::Left && offset == 0 {
|
||||||
Anchor::min()
|
Anchor::MIN
|
||||||
} else if bias == Bias::Right && offset == self.len() {
|
} else if bias == Bias::Right && offset == self.len() {
|
||||||
Anchor::max()
|
Anchor::MAX
|
||||||
} else {
|
} else {
|
||||||
let mut fragment_cursor = self.fragments.cursor::<usize>();
|
let mut fragment_cursor = self.fragments.cursor::<usize>();
|
||||||
fragment_cursor.seek(&offset, bias, &None);
|
fragment_cursor.seek(&offset, bias, &None);
|
||||||
|
@ -1775,9 +1775,7 @@ impl BufferSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_resolve(&self, anchor: &Anchor) -> bool {
|
pub fn can_resolve(&self, anchor: &Anchor) -> bool {
|
||||||
*anchor == Anchor::min()
|
*anchor == Anchor::MIN || *anchor == Anchor::MAX || self.version.observed(anchor.timestamp)
|
||||||
|| *anchor == Anchor::max()
|
|
||||||
|| self.version.observed(anchor.timestamp)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
|
pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
|
||||||
|
@ -1799,7 +1797,7 @@ impl BufferSnapshot {
|
||||||
where
|
where
|
||||||
D: TextDimension + Ord,
|
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>(
|
pub fn edited_ranges_for_transaction<'a, D>(
|
||||||
|
|
|
@ -204,7 +204,7 @@ impl ThemeSelector {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
editor::Event::Edited { .. } => {
|
editor::Event::BufferEdited { .. } => {
|
||||||
self.update_matches(cx);
|
self.update_matches(cx);
|
||||||
self.select_if_matching(&cx.global::<Settings>().theme.name);
|
self.select_if_matching(&cx.global::<Settings>().theme.name);
|
||||||
self.show_selected_theme(cx);
|
self.show_selected_theme(cx);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue