This commit is contained in:
Nathan Sobo 2023-11-02 21:03:29 -06:00
parent 72b9dc8216
commit dfc7c81500
12 changed files with 8192 additions and 8211 deletions

2
Cargo.lock generated
View file

@ -2648,7 +2648,7 @@ dependencies = [
"lazy_static",
"log",
"lsp2",
"multi_buffer",
"multi_buffer2",
"ordered-float 2.10.0",
"parking_lot 0.11.2",
"postage",

View file

@ -6,17 +6,16 @@ mod wrap_map;
use crate::{
link_go_to_definition::InlayHighlight, movement::TextLayoutDetails, Anchor, AnchorRangeExt,
EditorStyle, InlayId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
InlayId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
};
pub use block_map::{BlockMap, BlockPoint};
use collections::{BTreeMap, HashMap, HashSet};
use fold_map::FoldMap;
use gpui::{FontId, HighlightStyle, Hsla, Line, Model, ModelContext, UnderlineStyle};
use gpui::{FontId, HighlightStyle, Hsla, Line, Model, ModelContext};
use inlay_map::InlayMap;
use language::{
language_settings::language_settings, OffsetUtf16, Point, Subscription as BufferSubscription,
};
use lsp::DiagnosticSeverity;
use std::{any::TypeId, borrow::Cow, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc};
use sum_tree::{Bias, TreeMap};
use tab_map::TabMap;

View file

@ -73,7 +73,7 @@ impl WrapMap {
wrap_width: Option<f32>,
cx: &mut AppContext,
) -> (Model<Self>, WrapSnapshot) {
let handle = cx.add_model(|cx| {
let handle = cx.build_model(|cx| {
let mut this = Self {
font: (font_id, font_size),
wrap_width: None,

File diff suppressed because it is too large Load diff

View file

@ -48,106 +48,108 @@ impl FollowableItem for Editor {
state: &mut Option<proto::view::Variant>,
cx: &mut AppContext,
) -> Option<Task<Result<View<Self>>>> {
let project = workspace.read(cx).project().to_owned();
let Some(proto::view::Variant::Editor(_)) = state else {
return None;
};
let Some(proto::view::Variant::Editor(state)) = state.take() else {
unreachable!()
};
let client = project.read(cx).client();
let replica_id = project.read(cx).replica_id();
let buffer_ids = state
.excerpts
.iter()
.map(|excerpt| excerpt.buffer_id)
.collect::<HashSet<_>>();
let buffers = project.update(cx, |project, cx| {
buffer_ids
.iter()
.map(|id| project.open_buffer_by_id(*id, cx))
.collect::<Vec<_>>()
});
let pane = pane.downgrade();
Some(cx.spawn(|mut cx| async move {
let mut buffers = futures::future::try_join_all(buffers).await?;
let editor = pane.read_with(&cx, |pane, cx| {
let mut editors = pane.items_of_type::<Self>();
editors.find(|editor| {
let ids_match = editor.remote_id(&client, cx) == Some(remote_id);
let singleton_buffer_matches = state.singleton
&& buffers.first()
== editor.read(cx).buffer.read(cx).as_singleton().as_ref();
ids_match || singleton_buffer_matches
})
})?;
let editor = if let Some(editor) = editor {
editor
} else {
pane.update(&mut cx, |_, cx| {
let multibuffer = cx.add_model(|cx| {
let mut multibuffer;
if state.singleton && buffers.len() == 1 {
multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx)
} else {
multibuffer = MultiBuffer::new(replica_id);
let mut excerpts = state.excerpts.into_iter().peekable();
while let Some(excerpt) = excerpts.peek() {
let buffer_id = excerpt.buffer_id;
let buffer_excerpts = iter::from_fn(|| {
let excerpt = excerpts.peek()?;
(excerpt.buffer_id == buffer_id)
.then(|| excerpts.next().unwrap())
});
let buffer =
buffers.iter().find(|b| b.read(cx).remote_id() == buffer_id);
if let Some(buffer) = buffer {
multibuffer.push_excerpts(
buffer.clone(),
buffer_excerpts.filter_map(deserialize_excerpt_range),
cx,
);
}
}
};
if let Some(title) = &state.title {
multibuffer = multibuffer.with_title(title.clone())
}
multibuffer
});
cx.add_view(|cx| {
let mut editor =
Editor::for_multibuffer(multibuffer, Some(project.clone()), cx);
editor.remote_id = Some(remote_id);
editor
})
})?
};
update_editor_from_message(
editor.downgrade(),
project,
proto::update_view::Editor {
selections: state.selections,
pending_selection: state.pending_selection,
scroll_top_anchor: state.scroll_top_anchor,
scroll_x: state.scroll_x,
scroll_y: state.scroll_y,
..Default::default()
},
&mut cx,
)
.await?;
Ok(editor)
}))
todo!()
}
// let project = workspace.read(cx).project().to_owned();
// let Some(proto::view::Variant::Editor(_)) = state else {
// return None;
// };
// let Some(proto::view::Variant::Editor(state)) = state.take() else {
// unreachable!()
// };
// let client = project.read(cx).client();
// let replica_id = project.read(cx).replica_id();
// let buffer_ids = state
// .excerpts
// .iter()
// .map(|excerpt| excerpt.buffer_id)
// .collect::<HashSet<_>>();
// let buffers = project.update(cx, |project, cx| {
// buffer_ids
// .iter()
// .map(|id| project.open_buffer_by_id(*id, cx))
// .collect::<Vec<_>>()
// });
// let pane = pane.downgrade();
// Some(cx.spawn(|mut cx| async move {
// let mut buffers = futures::future::try_join_all(buffers).await?;
// let editor = pane.read_with(&cx, |pane, cx| {
// let mut editors = pane.items_of_type::<Self>();
// editors.find(|editor| {
// let ids_match = editor.remote_id(&client, cx) == Some(remote_id);
// let singleton_buffer_matches = state.singleton
// && buffers.first()
// == editor.read(cx).buffer.read(cx).as_singleton().as_ref();
// ids_match || singleton_buffer_matches
// })
// })?;
// let editor = if let Some(editor) = editor {
// editor
// } else {
// pane.update(&mut cx, |_, cx| {
// let multibuffer = cx.add_model(|cx| {
// let mut multibuffer;
// if state.singleton && buffers.len() == 1 {
// multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx)
// } else {
// multibuffer = MultiBuffer::new(replica_id);
// let mut excerpts = state.excerpts.into_iter().peekable();
// while let Some(excerpt) = excerpts.peek() {
// let buffer_id = excerpt.buffer_id;
// let buffer_excerpts = iter::from_fn(|| {
// let excerpt = excerpts.peek()?;
// (excerpt.buffer_id == buffer_id)
// .then(|| excerpts.next().unwrap())
// });
// let buffer =
// buffers.iter().find(|b| b.read(cx).remote_id() == buffer_id);
// if let Some(buffer) = buffer {
// multibuffer.push_excerpts(
// buffer.clone(),
// buffer_excerpts.filter_map(deserialize_excerpt_range),
// cx,
// );
// }
// }
// };
// if let Some(title) = &state.title {
// multibuffer = multibuffer.with_title(title.clone())
// }
// multibuffer
// });
// cx.add_view(|cx| {
// let mut editor =
// Editor::for_multibuffer(multibuffer, Some(project.clone()), cx);
// editor.remote_id = Some(remote_id);
// editor
// })
// })?
// };
// update_editor_from_message(
// editor.downgrade(),
// project,
// proto::update_view::Editor {
// selections: state.selections,
// pending_selection: state.pending_selection,
// scroll_top_anchor: state.scroll_top_anchor,
// scroll_x: state.scroll_x,
// scroll_y: state.scroll_y,
// ..Default::default()
// },
// &mut cx,
// )
// .await?;
// Ok(editor)
// }))
// }
fn set_leader_peer_id(&mut self, leader_peer_id: Option<PeerId>, cx: &mut ViewContext<Self>) {
self.leader_peer_id = leader_peer_id;
@ -197,8 +199,8 @@ impl FollowableItem for Editor {
title: (!buffer.is_singleton()).then(|| buffer.title(cx).into()),
excerpts,
scroll_top_anchor: Some(serialize_anchor(&scroll_anchor.anchor)),
scroll_x: scroll_anchor.offset.x(),
scroll_y: scroll_anchor.offset.y(),
scroll_x: scroll_anchor.offset.x,
scroll_y: scroll_anchor.offset.y,
selections: self
.selections
.disjoint_anchors()
@ -254,8 +256,8 @@ impl FollowableItem for Editor {
Event::ScrollPositionChanged { .. } => {
let scroll_anchor = self.scroll_manager.anchor();
update.scroll_top_anchor = Some(serialize_anchor(&scroll_anchor.anchor));
update.scroll_x = scroll_anchor.offset.x();
update.scroll_y = scroll_anchor.offset.y();
update.scroll_x = scroll_anchor.offset.x;
update.scroll_y = scroll_anchor.offset.y;
true
}
Event::SelectionsChanged { .. } => {
@ -561,8 +563,8 @@ impl Item for Editor {
fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<SharedString> {
match path_for_buffer(&self.buffer, detail, true, cx)? {
Cow::Borrowed(path) => Some(path.to_string_lossy()),
Cow::Owned(path) => Some(path.to_string_lossy().to_string().into()),
Cow::Borrowed(path) => Some(path.to_string_lossy),
Cow::Owned(path) => Some(path.to_string_lossy.to_string().into()),
}
}
@ -598,7 +600,11 @@ impl Item for Editor {
self.buffer.read(cx).is_singleton()
}
fn clone_on_split(&self, _workspace_id: WorkspaceId, cx: &mut ViewContext<Self>) -> Option<Self>
fn clone_on_split(
&self,
_workspace_id: WorkspaceId,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>>
where
Self: Sized,
{
@ -611,7 +617,8 @@ impl Item for Editor {
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
let selection = self.selections.newest_anchor();
self.push_to_nav_history(selection.head(), None, cx);
todo!()
// self.push_to_nav_history(selection.head(), None, cx);
}
fn workspace_deactivated(&mut self, cx: &mut ViewContext<Self>) {
@ -652,7 +659,7 @@ impl Item for Editor {
// we simulate saving by calling `Buffer::did_save`, so that language servers or
// other downstream listeners of save events get notified.
let (dirty_buffers, clean_buffers) = buffers.into_iter().partition(|buffer| {
buffer.read_with(&cx, |buffer, _| buffer.is_dirty() || buffer.has_conflict())
buffer.read_with(&cx, |buffer, _| buffer.is_dirty || buffer.has_conflict())
});
project
@ -686,9 +693,7 @@ impl Item for Editor {
.as_singleton()
.expect("cannot call save_as on an excerpt list");
let file_extension = abs_path
.extension()
.map(|a| a.to_string_lossy().to_string());
let file_extension = abs_path.extension().map(|a| a.to_string_lossy.to_string());
self.report_editor_event("save", file_extension, cx);
project.update(cx, |project, cx| {

View file

@ -2,7 +2,7 @@ use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
use crate::{char_kind, CharKind, EditorStyle, ToOffset, ToPoint};
use gpui::TextSystem;
use language::Point;
use std::{ops::Range, sync::Arc};
use std::ops::Range;
#[derive(Debug, PartialEq)]
pub enum FindRange {
@ -444,483 +444,483 @@ pub fn split_display_range_by_lines(
result
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
display_map::Inlay,
test::{editor_test_context::EditorTestContext, marked_display_snapshot},
Buffer, DisplayMap, ExcerptRange, InlayId, MultiBuffer,
};
use project::Project;
use settings::SettingsStore;
use util::post_inc;
// #[cfg(test)]
// mod tests {
// use super::*;
// use crate::{
// display_map::Inlay,
// test::{},
// Buffer, DisplayMap, ExcerptRange, InlayId, MultiBuffer,
// };
// use project::Project;
// use settings::SettingsStore;
// use util::post_inc;
#[gpui::test]
fn test_previous_word_start(cx: &mut gpui::AppContext) {
init_test(cx);
// #[gpui::test]
// fn test_previous_word_start(cx: &mut gpui::AppContext) {
// init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
previous_word_start(&snapshot, display_points[1]),
display_points[0]
);
}
// fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
// assert_eq!(
// previous_word_start(&snapshot, display_points[1]),
// display_points[0]
// );
// }
assert("\nˇ ˇlorem", cx);
assert("ˇ\nˇ lorem", cx);
assert(" ˇloremˇ", cx);
assert("ˇ ˇlorem", cx);
assert(" ˇlorˇem", cx);
assert("\nlorem\nˇ ˇipsum", cx);
assert("\n\nˇ\nˇ", cx);
assert(" ˇlorem ˇipsum", cx);
assert("loremˇ-ˇipsum", cx);
assert("loremˇ-#$@ˇipsum", cx);
assert("ˇlorem_ˇipsum", cx);
assert(" ˇdefγˇ", cx);
assert(" ˇbcΔˇ", cx);
assert(" abˇ——ˇcd", cx);
}
// assert("\nˇ ˇlorem", cx);
// assert("ˇ\nˇ lorem", cx);
// assert(" ˇloremˇ", cx);
// assert("ˇ ˇlorem", cx);
// assert(" ˇlorˇem", cx);
// assert("\nlorem\nˇ ˇipsum", cx);
// assert("\n\nˇ\nˇ", cx);
// assert(" ˇlorem ˇipsum", cx);
// assert("loremˇ-ˇipsum", cx);
// assert("loremˇ-#$@ˇipsum", cx);
// assert("ˇlorem_ˇipsum", cx);
// assert(" ˇdefγˇ", cx);
// assert(" ˇbcΔˇ", cx);
// assert(" abˇ——ˇcd", cx);
// }
#[gpui::test]
fn test_previous_subword_start(cx: &mut gpui::AppContext) {
init_test(cx);
// #[gpui::test]
// fn test_previous_subword_start(cx: &mut gpui::AppContext) {
// init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
previous_subword_start(&snapshot, display_points[1]),
display_points[0]
);
}
// fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
// assert_eq!(
// previous_subword_start(&snapshot, display_points[1]),
// display_points[0]
// );
// }
// Subword boundaries are respected
assert("lorem_ˇipˇsum", cx);
assert("lorem_ˇipsumˇ", cx);
assert("ˇlorem_ˇipsum", cx);
assert("lorem_ˇipsum_ˇdolor", cx);
assert("loremˇIpˇsum", cx);
assert("loremˇIpsumˇ", cx);
// // Subword boundaries are respected
// assert("lorem_ˇipˇsum", cx);
// assert("lorem_ˇipsumˇ", cx);
// assert("ˇlorem_ˇipsum", cx);
// assert("lorem_ˇipsum_ˇdolor", cx);
// assert("loremˇIpˇsum", cx);
// assert("loremˇIpsumˇ", cx);
// Word boundaries are still respected
assert("\nˇ ˇlorem", cx);
assert(" ˇloremˇ", cx);
assert(" ˇlorˇem", cx);
assert("\nlorem\nˇ ˇipsum", cx);
assert("\n\nˇ\nˇ", cx);
assert(" ˇlorem ˇipsum", cx);
assert("loremˇ-ˇipsum", cx);
assert("loremˇ-#$@ˇipsum", cx);
assert(" ˇdefγˇ", cx);
assert(" bcˇΔˇ", cx);
assert(" ˇbcδˇ", cx);
assert(" abˇ——ˇcd", cx);
}
// // Word boundaries are still respected
// assert("\nˇ ˇlorem", cx);
// assert(" ˇloremˇ", cx);
// assert(" ˇlorˇem", cx);
// assert("\nlorem\nˇ ˇipsum", cx);
// assert("\n\nˇ\nˇ", cx);
// assert(" ˇlorem ˇipsum", cx);
// assert("loremˇ-ˇipsum", cx);
// assert("loremˇ-#$@ˇipsum", cx);
// assert(" ˇdefγˇ", cx);
// assert(" bcˇΔˇ", cx);
// assert(" ˇbcδˇ", cx);
// assert(" abˇ——ˇcd", cx);
// }
#[gpui::test]
fn test_find_preceding_boundary(cx: &mut gpui::AppContext) {
init_test(cx);
// #[gpui::test]
// fn test_find_preceding_boundary(cx: &mut gpui::AppContext) {
// init_test(cx);
fn assert(
marked_text: &str,
cx: &mut gpui::AppContext,
is_boundary: impl FnMut(char, char) -> bool,
) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
find_preceding_boundary(
&snapshot,
display_points[1],
FindRange::MultiLine,
is_boundary
),
display_points[0]
);
}
// fn assert(
// marked_text: &str,
// cx: &mut gpui::AppContext,
// is_boundary: impl FnMut(char, char) -> bool,
// ) {
// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
// assert_eq!(
// find_preceding_boundary(
// &snapshot,
// display_points[1],
// FindRange::MultiLine,
// is_boundary
// ),
// display_points[0]
// );
// }
assert("abcˇdef\ngh\nijˇk", cx, |left, right| {
left == 'c' && right == 'd'
});
assert("abcdef\nˇgh\nijˇk", cx, |left, right| {
left == '\n' && right == 'g'
});
let mut line_count = 0;
assert("abcdef\nˇgh\nijˇk", cx, |left, _| {
if left == '\n' {
line_count += 1;
line_count == 2
} else {
false
}
});
}
// assert("abcˇdef\ngh\nijˇk", cx, |left, right| {
// left == 'c' && right == 'd'
// });
// assert("abcdef\nˇgh\nijˇk", cx, |left, right| {
// left == '\n' && right == 'g'
// });
// let mut line_count = 0;
// assert("abcdef\nˇgh\nijˇk", cx, |left, _| {
// if left == '\n' {
// line_count += 1;
// line_count == 2
// } else {
// false
// }
// });
// }
#[gpui::test]
fn test_find_preceding_boundary_with_inlays(cx: &mut gpui::AppContext) {
init_test(cx);
// #[gpui::test]
// fn test_find_preceding_boundary_with_inlays(cx: &mut gpui::AppContext) {
// init_test(cx);
let input_text = "abcdefghijklmnopqrstuvwxys";
let family_id = cx
.font_cache()
.load_family(&["Helvetica"], &Default::default())
.unwrap();
let font_id = cx
.font_cache()
.select_font(family_id, &Default::default())
.unwrap();
let font_size = 14.0;
let buffer = MultiBuffer::build_simple(input_text, cx);
let buffer_snapshot = buffer.read(cx).snapshot(cx);
let display_map =
cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx));
// let input_text = "abcdefghijklmnopqrstuvwxys";
// let family_id = cx
// .font_cache()
// .load_family(&["Helvetica"], &Default::default())
// .unwrap();
// let font_id = cx
// .font_cache()
// .select_font(family_id, &Default::default())
// .unwrap();
// let font_size = 14.0;
// let buffer = MultiBuffer::build_simple(input_text, cx);
// let buffer_snapshot = buffer.read(cx).snapshot(cx);
// let display_map =
// cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx));
// add all kinds of inlays between two word boundaries: we should be able to cross them all, when looking for another boundary
let mut id = 0;
let inlays = (0..buffer_snapshot.len())
.map(|offset| {
[
Inlay {
id: InlayId::Suggestion(post_inc(&mut id)),
position: buffer_snapshot.anchor_at(offset, Bias::Left),
text: format!("test").into(),
},
Inlay {
id: InlayId::Suggestion(post_inc(&mut id)),
position: buffer_snapshot.anchor_at(offset, Bias::Right),
text: format!("test").into(),
},
Inlay {
id: InlayId::Hint(post_inc(&mut id)),
position: buffer_snapshot.anchor_at(offset, Bias::Left),
text: format!("test").into(),
},
Inlay {
id: InlayId::Hint(post_inc(&mut id)),
position: buffer_snapshot.anchor_at(offset, Bias::Right),
text: format!("test").into(),
},
]
})
.flatten()
.collect();
let snapshot = display_map.update(cx, |map, cx| {
map.splice_inlays(Vec::new(), inlays, cx);
map.snapshot(cx)
});
// // add all kinds of inlays between two word boundaries: we should be able to cross them all, when looking for another boundary
// let mut id = 0;
// let inlays = (0..buffer_snapshot.len())
// .map(|offset| {
// [
// Inlay {
// id: InlayId::Suggestion(post_inc(&mut id)),
// position: buffer_snapshot.anchor_at(offset, Bias::Left),
// text: format!("test").into(),
// },
// Inlay {
// id: InlayId::Suggestion(post_inc(&mut id)),
// position: buffer_snapshot.anchor_at(offset, Bias::Right),
// text: format!("test").into(),
// },
// Inlay {
// id: InlayId::Hint(post_inc(&mut id)),
// position: buffer_snapshot.anchor_at(offset, Bias::Left),
// text: format!("test").into(),
// },
// Inlay {
// id: InlayId::Hint(post_inc(&mut id)),
// position: buffer_snapshot.anchor_at(offset, Bias::Right),
// text: format!("test").into(),
// },
// ]
// })
// .flatten()
// .collect();
// let snapshot = display_map.update(cx, |map, cx| {
// map.splice_inlays(Vec::new(), inlays, cx);
// map.snapshot(cx)
// });
assert_eq!(
find_preceding_boundary(
&snapshot,
buffer_snapshot.len().to_display_point(&snapshot),
FindRange::MultiLine,
|left, _| left == 'e',
),
snapshot
.buffer_snapshot
.offset_to_point(5)
.to_display_point(&snapshot),
"Should not stop at inlays when looking for boundaries"
);
}
// assert_eq!(
// find_preceding_boundary(
// &snapshot,
// buffer_snapshot.len().to_display_point(&snapshot),
// FindRange::MultiLine,
// |left, _| left == 'e',
// ),
// snapshot
// .buffer_snapshot
// .offset_to_point(5)
// .to_display_point(&snapshot),
// "Should not stop at inlays when looking for boundaries"
// );
// }
#[gpui::test]
fn test_next_word_end(cx: &mut gpui::AppContext) {
init_test(cx);
// #[gpui::test]
// fn test_next_word_end(cx: &mut gpui::AppContext) {
// init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
next_word_end(&snapshot, display_points[0]),
display_points[1]
);
}
// fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
// assert_eq!(
// next_word_end(&snapshot, display_points[0]),
// display_points[1]
// );
// }
assert("\nˇ loremˇ", cx);
assert(" ˇloremˇ", cx);
assert(" lorˇemˇ", cx);
assert(" loremˇ ˇ\nipsum\n", cx);
assert("\nˇ\nˇ\n\n", cx);
assert("loremˇ ipsumˇ ", cx);
assert("loremˇ-ˇipsum", cx);
assert("loremˇ#$@-ˇipsum", cx);
assert("loremˇ_ipsumˇ", cx);
assert(" ˇbcΔˇ", cx);
assert(" abˇ——ˇcd", cx);
}
// assert("\nˇ loremˇ", cx);
// assert(" ˇloremˇ", cx);
// assert(" lorˇemˇ", cx);
// assert(" loremˇ ˇ\nipsum\n", cx);
// assert("\nˇ\nˇ\n\n", cx);
// assert("loremˇ ipsumˇ ", cx);
// assert("loremˇ-ˇipsum", cx);
// assert("loremˇ#$@-ˇipsum", cx);
// assert("loremˇ_ipsumˇ", cx);
// assert(" ˇbcΔˇ", cx);
// assert(" abˇ——ˇcd", cx);
// }
#[gpui::test]
fn test_next_subword_end(cx: &mut gpui::AppContext) {
init_test(cx);
// #[gpui::test]
// fn test_next_subword_end(cx: &mut gpui::AppContext) {
// init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
next_subword_end(&snapshot, display_points[0]),
display_points[1]
);
}
// fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
// assert_eq!(
// next_subword_end(&snapshot, display_points[0]),
// display_points[1]
// );
// }
// Subword boundaries are respected
assert("loˇremˇ_ipsum", cx);
assert("ˇloremˇ_ipsum", cx);
assert("loremˇ_ipsumˇ", cx);
assert("loremˇ_ipsumˇ_dolor", cx);
assert("loˇremˇIpsum", cx);
assert("loremˇIpsumˇDolor", cx);
// // Subword boundaries are respected
// assert("loˇremˇ_ipsum", cx);
// assert("ˇloremˇ_ipsum", cx);
// assert("loremˇ_ipsumˇ", cx);
// assert("loremˇ_ipsumˇ_dolor", cx);
// assert("loˇremˇIpsum", cx);
// assert("loremˇIpsumˇDolor", cx);
// Word boundaries are still respected
assert("\nˇ loremˇ", cx);
assert(" ˇloremˇ", cx);
assert(" lorˇemˇ", cx);
assert(" loremˇ ˇ\nipsum\n", cx);
assert("\nˇ\nˇ\n\n", cx);
assert("loremˇ ipsumˇ ", cx);
assert("loremˇ-ˇipsum", cx);
assert("loremˇ#$@-ˇipsum", cx);
assert("loremˇ_ipsumˇ", cx);
assert(" ˇbcˇΔ", cx);
assert(" abˇ——ˇcd", cx);
}
// // Word boundaries are still respected
// assert("\nˇ loremˇ", cx);
// assert(" ˇloremˇ", cx);
// assert(" lorˇemˇ", cx);
// assert(" loremˇ ˇ\nipsum\n", cx);
// assert("\nˇ\nˇ\n\n", cx);
// assert("loremˇ ipsumˇ ", cx);
// assert("loremˇ-ˇipsum", cx);
// assert("loremˇ#$@-ˇipsum", cx);
// assert("loremˇ_ipsumˇ", cx);
// assert(" ˇbcˇΔ", cx);
// assert(" abˇ——ˇcd", cx);
// }
#[gpui::test]
fn test_find_boundary(cx: &mut gpui::AppContext) {
init_test(cx);
// #[gpui::test]
// fn test_find_boundary(cx: &mut gpui::AppContext) {
// init_test(cx);
fn assert(
marked_text: &str,
cx: &mut gpui::AppContext,
is_boundary: impl FnMut(char, char) -> bool,
) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
find_boundary(
&snapshot,
display_points[0],
FindRange::MultiLine,
is_boundary
),
display_points[1]
);
}
// fn assert(
// marked_text: &str,
// cx: &mut gpui::AppContext,
// is_boundary: impl FnMut(char, char) -> bool,
// ) {
// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
// assert_eq!(
// find_boundary(
// &snapshot,
// display_points[0],
// FindRange::MultiLine,
// is_boundary
// ),
// display_points[1]
// );
// }
assert("abcˇdef\ngh\nijˇk", cx, |left, right| {
left == 'j' && right == 'k'
});
assert("abˇcdef\ngh\nˇijk", cx, |left, right| {
left == '\n' && right == 'i'
});
let mut line_count = 0;
assert("abcˇdef\ngh\nˇijk", cx, |left, _| {
if left == '\n' {
line_count += 1;
line_count == 2
} else {
false
}
});
}
// assert("abcˇdef\ngh\nijˇk", cx, |left, right| {
// left == 'j' && right == 'k'
// });
// assert("abˇcdef\ngh\nˇijk", cx, |left, right| {
// left == '\n' && right == 'i'
// });
// let mut line_count = 0;
// assert("abcˇdef\ngh\nˇijk", cx, |left, _| {
// if left == '\n' {
// line_count += 1;
// line_count == 2
// } else {
// false
// }
// });
// }
#[gpui::test]
fn test_surrounding_word(cx: &mut gpui::AppContext) {
init_test(cx);
// #[gpui::test]
// fn test_surrounding_word(cx: &mut gpui::AppContext) {
// init_test(cx);
fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
assert_eq!(
surrounding_word(&snapshot, display_points[1]),
display_points[0]..display_points[2],
"{}",
marked_text.to_string()
);
}
// fn assert(marked_text: &str, cx: &mut gpui::AppContext) {
// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx);
// assert_eq!(
// surrounding_word(&snapshot, display_points[1]),
// display_points[0]..display_points[2],
// "{}",
// marked_text.to_string()
// );
// }
assert("ˇˇloremˇ ipsum", cx);
assert("ˇloˇremˇ ipsum", cx);
assert("ˇloremˇˇ ipsum", cx);
assert("loremˇ ˇ ˇipsum", cx);
assert("lorem\nˇˇˇ\nipsum", cx);
assert("lorem\nˇˇipsumˇ", cx);
assert("loremˇ,ˇˇ ipsum", cx);
assert("ˇloremˇˇ, ipsum", cx);
}
// assert("ˇˇloremˇ ipsum", cx);
// assert("ˇloˇremˇ ipsum", cx);
// assert("ˇloremˇˇ ipsum", cx);
// assert("loremˇ ˇ ˇipsum", cx);
// assert("lorem\nˇˇˇ\nipsum", cx);
// assert("lorem\nˇˇipsumˇ", cx);
// assert("loremˇ,ˇˇ ipsum", cx);
// assert("ˇloremˇˇ, ipsum", cx);
// }
#[gpui::test]
async fn test_move_up_and_down_with_excerpts(cx: &mut gpui::TestAppContext) {
cx.update(|cx| {
init_test(cx);
});
// #[gpui::test]
// async fn test_move_up_and_down_with_excerpts(cx: &mut gpui::TestAppContext) {
// cx.update(|cx| {
// init_test(cx);
// });
let mut cx = EditorTestContext::new(cx).await;
let editor = cx.editor.clone();
let window = cx.window.clone();
cx.update_window(window, |cx| {
let text_layout_details =
editor.read_with(cx, |editor, cx| editor.text_layout_details(cx));
// let mut cx = EditorTestContext::new(cx).await;
// let editor = cx.editor.clone();
// let window = cx.window.clone();
// cx.update_window(window, |cx| {
// let text_layout_details =
// editor.read_with(cx, |editor, cx| editor.text_layout_details(cx));
let family_id = cx
.font_cache()
.load_family(&["Helvetica"], &Default::default())
.unwrap();
let font_id = cx
.font_cache()
.select_font(family_id, &Default::default())
.unwrap();
// let family_id = cx
// .font_cache()
// .load_family(&["Helvetica"], &Default::default())
// .unwrap();
// let font_id = cx
// .font_cache()
// .select_font(family_id, &Default::default())
// .unwrap();
let buffer =
cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abc\ndefg\nhijkl\nmn"));
let multibuffer = cx.add_model(|cx| {
let mut multibuffer = MultiBuffer::new(0);
multibuffer.push_excerpts(
buffer.clone(),
[
ExcerptRange {
context: Point::new(0, 0)..Point::new(1, 4),
primary: None,
},
ExcerptRange {
context: Point::new(2, 0)..Point::new(3, 2),
primary: None,
},
],
cx,
);
multibuffer
});
let display_map =
cx.add_model(|cx| DisplayMap::new(multibuffer, font_id, 14.0, None, 2, 2, cx));
let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));
// let buffer =
// cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abc\ndefg\nhijkl\nmn"));
// let multibuffer = cx.add_model(|cx| {
// let mut multibuffer = MultiBuffer::new(0);
// multibuffer.push_excerpts(
// buffer.clone(),
// [
// ExcerptRange {
// context: Point::new(0, 0)..Point::new(1, 4),
// primary: None,
// },
// ExcerptRange {
// context: Point::new(2, 0)..Point::new(3, 2),
// primary: None,
// },
// ],
// cx,
// );
// multibuffer
// });
// let display_map =
// cx.add_model(|cx| DisplayMap::new(multibuffer, font_id, 14.0, None, 2, 2, cx));
// let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx));
assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn");
// assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn");
let col_2_x = snapshot.x_for_point(DisplayPoint::new(2, 2), &text_layout_details);
// let col_2_x = snapshot.x_for_point(DisplayPoint::new(2, 2), &text_layout_details);
// Can't move up into the first excerpt's header
assert_eq!(
up(
&snapshot,
DisplayPoint::new(2, 2),
SelectionGoal::HorizontalPosition(col_2_x),
false,
&text_layout_details
),
(
DisplayPoint::new(2, 0),
SelectionGoal::HorizontalPosition(0.0)
),
);
assert_eq!(
up(
&snapshot,
DisplayPoint::new(2, 0),
SelectionGoal::None,
false,
&text_layout_details
),
(
DisplayPoint::new(2, 0),
SelectionGoal::HorizontalPosition(0.0)
),
);
// // Can't move up into the first excerpt's header
// assert_eq!(
// up(
// &snapshot,
// DisplayPoint::new(2, 2),
// SelectionGoal::HorizontalPosition(col_2_x),
// false,
// &text_layout_details
// ),
// (
// DisplayPoint::new(2, 0),
// SelectionGoal::HorizontalPosition(0.0)
// ),
// );
// assert_eq!(
// up(
// &snapshot,
// DisplayPoint::new(2, 0),
// SelectionGoal::None,
// false,
// &text_layout_details
// ),
// (
// DisplayPoint::new(2, 0),
// SelectionGoal::HorizontalPosition(0.0)
// ),
// );
let col_4_x = snapshot.x_for_point(DisplayPoint::new(3, 4), &text_layout_details);
// let col_4_x = snapshot.x_for_point(DisplayPoint::new(3, 4), &text_layout_details);
// Move up and down within first excerpt
assert_eq!(
up(
&snapshot,
DisplayPoint::new(3, 4),
SelectionGoal::HorizontalPosition(col_4_x),
false,
&text_layout_details
),
(
DisplayPoint::new(2, 3),
SelectionGoal::HorizontalPosition(col_4_x)
),
);
assert_eq!(
down(
&snapshot,
DisplayPoint::new(2, 3),
SelectionGoal::HorizontalPosition(col_4_x),
false,
&text_layout_details
),
(
DisplayPoint::new(3, 4),
SelectionGoal::HorizontalPosition(col_4_x)
),
);
// // Move up and down within first excerpt
// assert_eq!(
// up(
// &snapshot,
// DisplayPoint::new(3, 4),
// SelectionGoal::HorizontalPosition(col_4_x),
// false,
// &text_layout_details
// ),
// (
// DisplayPoint::new(2, 3),
// SelectionGoal::HorizontalPosition(col_4_x)
// ),
// );
// assert_eq!(
// down(
// &snapshot,
// DisplayPoint::new(2, 3),
// SelectionGoal::HorizontalPosition(col_4_x),
// false,
// &text_layout_details
// ),
// (
// DisplayPoint::new(3, 4),
// SelectionGoal::HorizontalPosition(col_4_x)
// ),
// );
let col_5_x = snapshot.x_for_point(DisplayPoint::new(6, 5), &text_layout_details);
// let col_5_x = snapshot.x_for_point(DisplayPoint::new(6, 5), &text_layout_details);
// Move up and down across second excerpt's header
assert_eq!(
up(
&snapshot,
DisplayPoint::new(6, 5),
SelectionGoal::HorizontalPosition(col_5_x),
false,
&text_layout_details
),
(
DisplayPoint::new(3, 4),
SelectionGoal::HorizontalPosition(col_5_x)
),
);
assert_eq!(
down(
&snapshot,
DisplayPoint::new(3, 4),
SelectionGoal::HorizontalPosition(col_5_x),
false,
&text_layout_details
),
(
DisplayPoint::new(6, 5),
SelectionGoal::HorizontalPosition(col_5_x)
),
);
// // Move up and down across second excerpt's header
// assert_eq!(
// up(
// &snapshot,
// DisplayPoint::new(6, 5),
// SelectionGoal::HorizontalPosition(col_5_x),
// false,
// &text_layout_details
// ),
// (
// DisplayPoint::new(3, 4),
// SelectionGoal::HorizontalPosition(col_5_x)
// ),
// );
// assert_eq!(
// down(
// &snapshot,
// DisplayPoint::new(3, 4),
// SelectionGoal::HorizontalPosition(col_5_x),
// false,
// &text_layout_details
// ),
// (
// DisplayPoint::new(6, 5),
// SelectionGoal::HorizontalPosition(col_5_x)
// ),
// );
let max_point_x = snapshot.x_for_point(DisplayPoint::new(7, 2), &text_layout_details);
// let max_point_x = snapshot.x_for_point(DisplayPoint::new(7, 2), &text_layout_details);
// Can't move down off the end
assert_eq!(
down(
&snapshot,
DisplayPoint::new(7, 0),
SelectionGoal::HorizontalPosition(0.0),
false,
&text_layout_details
),
(
DisplayPoint::new(7, 2),
SelectionGoal::HorizontalPosition(max_point_x)
),
);
assert_eq!(
down(
&snapshot,
DisplayPoint::new(7, 2),
SelectionGoal::HorizontalPosition(max_point_x),
false,
&text_layout_details
),
(
DisplayPoint::new(7, 2),
SelectionGoal::HorizontalPosition(max_point_x)
),
);
});
}
// // Can't move down off the end
// assert_eq!(
// down(
// &snapshot,
// DisplayPoint::new(7, 0),
// SelectionGoal::HorizontalPosition(0.0),
// false,
// &text_layout_details
// ),
// (
// DisplayPoint::new(7, 2),
// SelectionGoal::HorizontalPosition(max_point_x)
// ),
// );
// assert_eq!(
// down(
// &snapshot,
// DisplayPoint::new(7, 2),
// SelectionGoal::HorizontalPosition(max_point_x),
// false,
// &text_layout_details
// ),
// (
// DisplayPoint::new(7, 2),
// SelectionGoal::HorizontalPosition(max_point_x)
// ),
// );
// });
// }
fn init_test(cx: &mut gpui::AppContext) {
cx.set_global(SettingsStore::test(cx));
theme::init(cx);
language::init(cx);
crate::init(cx);
Project::init_settings(cx);
}
}
// fn init_test(cx: &mut gpui::AppContext) {
// cx.set_global(SettingsStore::test(cx));
// theme::init(cx);
// language::init(cx);
// crate::init(cx);
// Project::init_settings(cx);
// }
// }

View file

@ -39,7 +39,7 @@ pub struct ScrollAnchor {
impl ScrollAnchor {
fn new() -> Self {
Self {
offset: Point::zero(),
offset: gpui::Point::zero(),
anchor: Anchor::min(),
}
}
@ -48,7 +48,7 @@ impl ScrollAnchor {
let mut scroll_position = self.offset;
if self.anchor != Anchor::min() {
let scroll_top = self.anchor.to_display_point(snapshot).row() as f32;
scroll_position.set_y(scroll_top + scroll_position.y());
scroll_position.set_y(scroll_top + scroll_position.y);
} else {
scroll_position.set_y(0.);
}
@ -82,7 +82,7 @@ impl OngoingScroll {
pub fn filter(&self, delta: &mut gpui::Point<Pixels>) -> Option<Axis> {
const UNLOCK_PERCENT: f32 = 1.9;
const UNLOCK_LOWER_BOUND: f32 = 6.;
const UNLOCK_LOWER_BOUND: Pixels = px(6.);
let mut axis = self.axis;
let x = delta.x.abs();
@ -116,10 +116,10 @@ impl OngoingScroll {
match axis {
Some(Axis::Vertical) => {
*delta = point(pk(0.), delta.y());
*delta = point(px(0.), delta.y);
}
Some(Axis::Horizontal) => {
*delta = point(delta.x(), px(0.));
*delta = point(delta.x, px(0.));
}
None => {}
}
@ -177,14 +177,14 @@ impl ScrollManager {
fn set_scroll_position(
&mut self,
scroll_position: gpui::Point<Pixels>,
scroll_position: gpui::Point<f32>,
map: &DisplaySnapshot,
local: bool,
autoscroll: bool,
workspace_id: Option<i64>,
cx: &mut ViewContext<Editor>,
) {
let (new_anchor, top_row) = if scroll_position.y() <= 0. {
let (new_anchor, top_row) = if scroll_position.y <= 0. {
(
ScrollAnchor {
anchor: Anchor::min(),
@ -194,7 +194,7 @@ impl ScrollManager {
)
} else {
let scroll_top_buffer_point =
DisplayPoint::new(scroll_position.y() as u32, 0).to_point(&map);
DisplayPoint::new(scroll_position.y as u32, 0).to_point(&map);
let top_anchor = map
.buffer_snapshot
.anchor_at(scroll_top_buffer_point, Bias::Right);
@ -203,8 +203,8 @@ impl ScrollManager {
ScrollAnchor {
anchor: top_anchor,
offset: point(
scroll_position.x(),
scroll_position.y() - top_anchor.to_display_point(&map).row() as f32,
scroll_position.x,
scroll_position.y - top_anchor.to_display_point(&map).row() as f32,
),
},
scroll_top_buffer_point.row,
@ -236,8 +236,8 @@ impl ScrollManager {
item_id,
workspace_id,
top_row,
anchor.offset.x(),
anchor.offset.y(),
anchor.offset.x,
anchor.offset.y,
)
.await
.log_err()
@ -277,8 +277,8 @@ impl ScrollManager {
}
pub fn clamp_scroll_left(&mut self, max: f32) -> bool {
if max < self.anchor.offset.x() {
self.anchor.offset.set_x(max);
if max < self.anchor.offset.x {
self.anchor.offset.x = max;
true
} else {
false

View file

@ -60,7 +60,7 @@ impl Editor {
} else {
display_map.max_point().row() as f32
};
if scroll_position.y() > max_scroll_top {
if scroll_position.y > max_scroll_top {
scroll_position.set_y(max_scroll_top);
self.set_scroll_position(scroll_position, cx);
}
@ -136,7 +136,7 @@ impl Editor {
let margin = margin.min(self.scroll_manager.vertical_scroll_margin);
let target_top = (target_top - margin).max(0.0);
let target_bottom = target_bottom + margin;
let start_row = scroll_position.y();
let start_row = scroll_position.y;
let end_row = start_row + visible_lines;
let needs_scroll_up = target_top < start_row;
@ -222,20 +222,15 @@ impl Editor {
return false;
}
let scroll_left = self.scroll_manager.anchor.offset.x() * max_glyph_width;
let scroll_left = self.scroll_manager.anchor.offset.x * max_glyph_width;
let scroll_right = scroll_left + viewport_width;
if target_left < scroll_left {
self.scroll_manager
.anchor
.offset
.set_x(target_left / max_glyph_width);
self.scroll_manager.anchor.offset.x = (target_left / max_glyph_width);
true
} else if target_right > scroll_right {
self.scroll_manager
.anchor
.offset
.set_x((target_right - viewport_width) / max_glyph_width);
self.scroll_manager.anchor.offset.x =
((target_right - viewport_width) / max_glyph_width);
true
} else {
false

View file

@ -1,297 +1,297 @@
use std::{
borrow::Cow,
ops::{Deref, DerefMut, Range},
sync::Arc,
};
// use std::{
// borrow::Cow,
// ops::{Deref, DerefMut, Range},
// sync::Arc,
// };
use anyhow::Result;
// use anyhow::Result;
use crate::{Editor, ToPoint};
use collections::HashSet;
use futures::Future;
use gpui::{json, View, ViewContext};
use indoc::indoc;
use language::{point_to_lsp, FakeLspAdapter, Language, LanguageConfig, LanguageQueries};
use lsp::{notification, request};
use multi_buffer::ToPointUtf16;
use project::Project;
use smol::stream::StreamExt;
use workspace::{AppState, Workspace, WorkspaceHandle};
// use crate::{Editor, ToPoint};
// use collections::HashSet;
// use futures::Future;
// use gpui::{json, View, ViewContext};
// use indoc::indoc;
// use language::{point_to_lsp, FakeLspAdapter, Language, LanguageConfig, LanguageQueries};
// use lsp::{notification, request};
// use multi_buffer::ToPointUtf16;
// use project::Project;
// use smol::stream::StreamExt;
// use workspace::{AppState, Workspace, WorkspaceHandle};
use super::editor_test_context::EditorTestContext;
// use super::editor_test_context::EditorTestContext;
pub struct EditorLspTestContext<'a> {
pub cx: EditorTestContext<'a>,
pub lsp: lsp::FakeLanguageServer,
pub workspace: ViewHandle<Workspace>,
pub buffer_lsp_url: lsp::Url,
}
// pub struct EditorLspTestContext<'a> {
// pub cx: EditorTestContext<'a>,
// pub lsp: lsp::FakeLanguageServer,
// pub workspace: View<Workspace>,
// pub buffer_lsp_url: lsp::Url,
// }
impl<'a> EditorLspTestContext<'a> {
pub async fn new(
mut language: Language,
capabilities: lsp::ServerCapabilities,
cx: &'a mut gpui::TestAppContext,
) -> EditorLspTestContext<'a> {
use json::json;
// impl<'a> EditorLspTestContext<'a> {
// pub async fn new(
// mut language: Language,
// capabilities: lsp::ServerCapabilities,
// cx: &'a mut gpui::TestAppContext,
// ) -> EditorLspTestContext<'a> {
// use json::json;
let app_state = cx.update(AppState::test);
// let app_state = cx.update(AppState::test);
cx.update(|cx| {
language::init(cx);
crate::init(cx);
workspace::init(app_state.clone(), cx);
Project::init_settings(cx);
});
// cx.update(|cx| {
// language::init(cx);
// crate::init(cx);
// workspace::init(app_state.clone(), cx);
// Project::init_settings(cx);
// });
let file_name = format!(
"file.{}",
language
.path_suffixes()
.first()
.expect("language must have a path suffix for EditorLspTestContext")
);
// let file_name = format!(
// "file.{}",
// language
// .path_suffixes()
// .first()
// .expect("language must have a path suffix for EditorLspTestContext")
// );
let mut fake_servers = language
.set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
capabilities,
..Default::default()
}))
.await;
// let mut fake_servers = language
// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
// capabilities,
// ..Default::default()
// }))
// .await;
let project = Project::test(app_state.fs.clone(), [], cx).await;
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
// let project = Project::test(app_state.fs.clone(), [], cx).await;
// project.update(cx, |project, _| project.languages().add(Arc::new(language)));
app_state
.fs
.as_fake()
.insert_tree("/root", json!({ "dir": { file_name.clone(): "" }}))
.await;
// app_state
// .fs
// .as_fake()
// .insert_tree("/root", json!({ "dir": { file_name.clone(): "" }}))
// .await;
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
let workspace = window.root(cx);
project
.update(cx, |project, cx| {
project.find_or_create_local_worktree("/root", true, cx)
})
.await
.unwrap();
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
.await;
// let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
// let workspace = window.root(cx);
// project
// .update(cx, |project, cx| {
// project.find_or_create_local_worktree("/root", true, cx)
// })
// .await
// .unwrap();
// cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
// .await;
let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone());
let item = workspace
.update(cx, |workspace, cx| {
workspace.open_path(file, None, true, cx)
})
.await
.expect("Could not open test file");
// let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone());
// let item = workspace
// .update(cx, |workspace, cx| {
// workspace.open_path(file, None, true, cx)
// })
// .await
// .expect("Could not open test file");
let editor = cx.update(|cx| {
item.act_as::<Editor>(cx)
.expect("Opened test file wasn't an editor")
});
editor.update(cx, |_, cx| cx.focus_self());
// let editor = cx.update(|cx| {
// item.act_as::<Editor>(cx)
// .expect("Opened test file wasn't an editor")
// });
// editor.update(cx, |_, cx| cx.focus_self());
let lsp = fake_servers.next().await.unwrap();
// let lsp = fake_servers.next().await.unwrap();
Self {
cx: EditorTestContext {
cx,
window: window.into(),
editor,
},
lsp,
workspace,
buffer_lsp_url: lsp::Url::from_file_path(format!("/root/dir/{file_name}")).unwrap(),
}
}
// Self {
// cx: EditorTestContext {
// cx,
// window: window.into(),
// editor,
// },
// lsp,
// workspace,
// buffer_lsp_url: lsp::Url::from_file_path(format!("/root/dir/{file_name}")).unwrap(),
// }
// }
pub async fn new_rust(
capabilities: lsp::ServerCapabilities,
cx: &'a mut gpui::TestAppContext,
) -> EditorLspTestContext<'a> {
let language = Language::new(
LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
..Default::default()
},
Some(tree_sitter_rust::language()),
)
.with_queries(LanguageQueries {
indents: Some(Cow::from(indoc! {r#"
[
((where_clause) _ @end)
(field_expression)
(call_expression)
(assignment_expression)
(let_declaration)
(let_chain)
(await_expression)
] @indent
// pub async fn new_rust(
// capabilities: lsp::ServerCapabilities,
// cx: &'a mut gpui::TestAppContext,
// ) -> EditorLspTestContext<'a> {
// let language = Language::new(
// LanguageConfig {
// name: "Rust".into(),
// path_suffixes: vec!["rs".to_string()],
// ..Default::default()
// },
// Some(tree_sitter_rust::language()),
// )
// .with_queries(LanguageQueries {
// indents: Some(Cow::from(indoc! {r#"
// [
// ((where_clause) _ @end)
// (field_expression)
// (call_expression)
// (assignment_expression)
// (let_declaration)
// (let_chain)
// (await_expression)
// ] @indent
(_ "[" "]" @end) @indent
(_ "<" ">" @end) @indent
(_ "{" "}" @end) @indent
(_ "(" ")" @end) @indent"#})),
brackets: Some(Cow::from(indoc! {r#"
("(" @open ")" @close)
("[" @open "]" @close)
("{" @open "}" @close)
("<" @open ">" @close)
("\"" @open "\"" @close)
(closure_parameters "|" @open "|" @close)"#})),
..Default::default()
})
.expect("Could not parse queries");
// (_ "[" "]" @end) @indent
// (_ "<" ">" @end) @indent
// (_ "{" "}" @end) @indent
// (_ "(" ")" @end) @indent"#})),
// brackets: Some(Cow::from(indoc! {r#"
// ("(" @open ")" @close)
// ("[" @open "]" @close)
// ("{" @open "}" @close)
// ("<" @open ">" @close)
// ("\"" @open "\"" @close)
// (closure_parameters "|" @open "|" @close)"#})),
// ..Default::default()
// })
// .expect("Could not parse queries");
Self::new(language, capabilities, cx).await
}
// Self::new(language, capabilities, cx).await
// }
pub async fn new_typescript(
capabilities: lsp::ServerCapabilities,
cx: &'a mut gpui::TestAppContext,
) -> EditorLspTestContext<'a> {
let mut word_characters: HashSet<char> = Default::default();
word_characters.insert('$');
word_characters.insert('#');
let language = Language::new(
LanguageConfig {
name: "Typescript".into(),
path_suffixes: vec!["ts".to_string()],
brackets: language::BracketPairConfig {
pairs: vec![language::BracketPair {
start: "{".to_string(),
end: "}".to_string(),
close: true,
newline: true,
}],
disabled_scopes_by_bracket_ix: Default::default(),
},
word_characters,
..Default::default()
},
Some(tree_sitter_typescript::language_typescript()),
)
.with_queries(LanguageQueries {
brackets: Some(Cow::from(indoc! {r#"
("(" @open ")" @close)
("[" @open "]" @close)
("{" @open "}" @close)
("<" @open ">" @close)
("\"" @open "\"" @close)"#})),
indents: Some(Cow::from(indoc! {r#"
[
(call_expression)
(assignment_expression)
(member_expression)
(lexical_declaration)
(variable_declaration)
(assignment_expression)
(if_statement)
(for_statement)
] @indent
// pub async fn new_typescript(
// capabilities: lsp::ServerCapabilities,
// cx: &'a mut gpui::TestAppContext,
// ) -> EditorLspTestContext<'a> {
// let mut word_characters: HashSet<char> = Default::default();
// word_characters.insert('$');
// word_characters.insert('#');
// let language = Language::new(
// LanguageConfig {
// name: "Typescript".into(),
// path_suffixes: vec!["ts".to_string()],
// brackets: language::BracketPairConfig {
// pairs: vec![language::BracketPair {
// start: "{".to_string(),
// end: "}".to_string(),
// close: true,
// newline: true,
// }],
// disabled_scopes_by_bracket_ix: Default::default(),
// },
// word_characters,
// ..Default::default()
// },
// Some(tree_sitter_typescript::language_typescript()),
// )
// .with_queries(LanguageQueries {
// brackets: Some(Cow::from(indoc! {r#"
// ("(" @open ")" @close)
// ("[" @open "]" @close)
// ("{" @open "}" @close)
// ("<" @open ">" @close)
// ("\"" @open "\"" @close)"#})),
// indents: Some(Cow::from(indoc! {r#"
// [
// (call_expression)
// (assignment_expression)
// (member_expression)
// (lexical_declaration)
// (variable_declaration)
// (assignment_expression)
// (if_statement)
// (for_statement)
// ] @indent
(_ "[" "]" @end) @indent
(_ "<" ">" @end) @indent
(_ "{" "}" @end) @indent
(_ "(" ")" @end) @indent
"#})),
..Default::default()
})
.expect("Could not parse queries");
// (_ "[" "]" @end) @indent
// (_ "<" ">" @end) @indent
// (_ "{" "}" @end) @indent
// (_ "(" ")" @end) @indent
// "#})),
// ..Default::default()
// })
// .expect("Could not parse queries");
Self::new(language, capabilities, cx).await
}
// Self::new(language, capabilities, cx).await
// }
// Constructs lsp range using a marked string with '[', ']' range delimiters
pub fn lsp_range(&mut self, marked_text: &str) -> lsp::Range {
let ranges = self.ranges(marked_text);
self.to_lsp_range(ranges[0].clone())
}
// // Constructs lsp range using a marked string with '[', ']' range delimiters
// pub fn lsp_range(&mut self, marked_text: &str) -> lsp::Range {
// let ranges = self.ranges(marked_text);
// self.to_lsp_range(ranges[0].clone())
// }
pub fn to_lsp_range(&mut self, range: Range<usize>) -> lsp::Range {
let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
let start_point = range.start.to_point(&snapshot.buffer_snapshot);
let end_point = range.end.to_point(&snapshot.buffer_snapshot);
// pub fn to_lsp_range(&mut self, range: Range<usize>) -> lsp::Range {
// let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
// let start_point = range.start.to_point(&snapshot.buffer_snapshot);
// let end_point = range.end.to_point(&snapshot.buffer_snapshot);
self.editor(|editor, cx| {
let buffer = editor.buffer().read(cx);
let start = point_to_lsp(
buffer
.point_to_buffer_offset(start_point, cx)
.unwrap()
.1
.to_point_utf16(&buffer.read(cx)),
);
let end = point_to_lsp(
buffer
.point_to_buffer_offset(end_point, cx)
.unwrap()
.1
.to_point_utf16(&buffer.read(cx)),
);
// self.editor(|editor, cx| {
// let buffer = editor.buffer().read(cx);
// let start = point_to_lsp(
// buffer
// .point_to_buffer_offset(start_point, cx)
// .unwrap()
// .1
// .to_point_utf16(&buffer.read(cx)),
// );
// let end = point_to_lsp(
// buffer
// .point_to_buffer_offset(end_point, cx)
// .unwrap()
// .1
// .to_point_utf16(&buffer.read(cx)),
// );
lsp::Range { start, end }
})
}
// lsp::Range { start, end }
// })
// }
pub fn to_lsp(&mut self, offset: usize) -> lsp::Position {
let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
let point = offset.to_point(&snapshot.buffer_snapshot);
// pub fn to_lsp(&mut self, offset: usize) -> lsp::Position {
// let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
// let point = offset.to_point(&snapshot.buffer_snapshot);
self.editor(|editor, cx| {
let buffer = editor.buffer().read(cx);
point_to_lsp(
buffer
.point_to_buffer_offset(point, cx)
.unwrap()
.1
.to_point_utf16(&buffer.read(cx)),
)
})
}
// self.editor(|editor, cx| {
// let buffer = editor.buffer().read(cx);
// point_to_lsp(
// buffer
// .point_to_buffer_offset(point, cx)
// .unwrap()
// .1
// .to_point_utf16(&buffer.read(cx)),
// )
// })
// }
pub fn update_workspace<F, T>(&mut self, update: F) -> T
where
F: FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> T,
{
self.workspace.update(self.cx.cx, update)
}
// pub fn update_workspace<F, T>(&mut self, update: F) -> T
// where
// F: FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> T,
// {
// self.workspace.update(self.cx.cx, update)
// }
pub fn handle_request<T, F, Fut>(
&self,
mut handler: F,
) -> futures::channel::mpsc::UnboundedReceiver<()>
where
T: 'static + request::Request,
T::Params: 'static + Send,
F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut,
Fut: 'static + Send + Future<Output = Result<T::Result>>,
{
let url = self.buffer_lsp_url.clone();
self.lsp.handle_request::<T, _, _>(move |params, cx| {
let url = url.clone();
handler(url, params, cx)
})
}
// pub fn handle_request<T, F, Fut>(
// &self,
// mut handler: F,
// ) -> futures::channel::mpsc::UnboundedReceiver<()>
// where
// T: 'static + request::Request,
// T::Params: 'static + Send,
// F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut,
// Fut: 'static + Send + Future<Output = Result<T::Result>>,
// {
// let url = self.buffer_lsp_url.clone();
// self.lsp.handle_request::<T, _, _>(move |params, cx| {
// let url = url.clone();
// handler(url, params, cx)
// })
// }
pub fn notify<T: notification::Notification>(&self, params: T::Params) {
self.lsp.notify::<T>(params);
}
}
// pub fn notify<T: notification::Notification>(&self, params: T::Params) {
// self.lsp.notify::<T>(params);
// }
// }
impl<'a> Deref for EditorLspTestContext<'a> {
type Target = EditorTestContext<'a>;
// impl<'a> Deref for EditorLspTestContext<'a> {
// type Target = EditorTestContext<'a>;
fn deref(&self) -> &Self::Target {
&self.cx
}
}
// fn deref(&self) -> &Self::Target {
// &self.cx
// }
// }
impl<'a> DerefMut for EditorLspTestContext<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cx
}
}
// impl<'a> DerefMut for EditorLspTestContext<'a> {
// fn deref_mut(&mut self) -> &mut Self::Target {
// &mut self.cx
// }
// }

View file

@ -315,17 +315,17 @@ use util::{
// }
// }
// }
//
// impl<'a> Deref for EditorTestContext<'a> {
// type Target = gpui::TestAppContext;
impl<'a> Deref for EditorTestContext<'a> {
type Target = gpui::TestAppContext;
// fn deref(&self) -> &Self::Target {
// self.cx
// }
// }
fn deref(&self) -> &Self::Target {
self.cx
}
}
impl<'a> DerefMut for EditorTestContext<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cx
}
}
// impl<'a> DerefMut for EditorTestContext<'a> {
// fn deref_mut(&mut self) -> &mut Self::Target {
// &mut self.cx
// }
// }

View file

@ -755,6 +755,10 @@ impl Pixels {
pub fn pow(&self, exponent: f32) -> Self {
Self(self.0.powf(exponent))
}
pub fn abs(&self) -> Self {
Self(self.0.abs())
}
}
impl Mul<Pixels> for Pixels {

View file

@ -90,7 +90,7 @@ pub struct BreadcrumbText {
pub highlights: Option<Vec<(Range<usize>, HighlightStyle)>>,
}
pub trait Item: Render + EventEmitter + Send {
pub trait Item: Render + EventEmitter {
fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
fn workspace_deactivated(&mut self, _: &mut ViewContext<Self>) {}
fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool {