Merge pull request #75 from zed-industries/naming-cleanup

Clean up naming conventions project-wide
This commit is contained in:
Nathan Sobo
2021-05-28 16:42:20 -06:00
committed by GitHub
39 changed files with 2925 additions and 3126 deletions
+10 -10
View File
@@ -10,9 +10,9 @@ use simplelog::SimpleLogger;
fn main() {
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
gpui::App::new(()).unwrap().run(|ctx| {
ctx.platform().activate(true);
ctx.add_window(|_| TextView);
gpui::App::new(()).unwrap().run(|cx| {
cx.platform().activate(true);
cx.add_window(|_| TextView);
});
}
@@ -58,15 +58,15 @@ impl gpui::Element for TextElement {
&mut self,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut gpui::PaintContext,
cx: &mut gpui::PaintContext,
) -> Self::PaintState {
let font_size = 12.;
let family = ctx.font_cache.load_family(&["SF Pro Display"]).unwrap();
let normal = ctx
let family = cx.font_cache.load_family(&["SF Pro Display"]).unwrap();
let normal = cx
.font_cache
.select_font(family, &Default::default())
.unwrap();
let bold = ctx
let bold = cx
.font_cache
.select_font(
family,
@@ -78,7 +78,7 @@ impl gpui::Element for TextElement {
.unwrap();
let text = "Hello world!";
let line = ctx.text_layout_cache.layout_str(
let line = cx.text_layout_cache.layout_str(
text,
font_size,
&[
@@ -90,12 +90,12 @@ impl gpui::Element for TextElement {
],
);
ctx.scene.push_quad(Quad {
cx.scene.push_quad(Quad {
bounds: bounds,
background: Some(ColorU::white()),
..Default::default()
});
line.paint(bounds.origin(), bounds, ctx);
line.paint(bounds.origin(), bounds, cx);
}
fn dispatch_event(
+381 -465
View File
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,36 @@
mod align;
mod canvas;
mod constrained_box;
mod container;
mod empty;
mod event_handler;
mod flex;
mod label;
mod line_box;
mod mouse_event_handler;
mod stack;
mod svg;
mod uniform_list;
pub use crate::presenter::ChildView;
pub use align::*;
pub use canvas::*;
pub use constrained_box::*;
pub use container::*;
pub use empty::*;
pub use event_handler::*;
pub use flex::*;
pub use label::*;
pub use line_box::*;
pub use mouse_event_handler::*;
pub use stack::*;
pub use svg::*;
pub use uniform_list::*;
use crate::{
geometry::{rect::RectF, vector::Vector2F},
json, AfterLayoutContext, DebugContext, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
json, AfterLayoutContext, AppContext, DebugContext, Event, EventContext, LayoutContext,
PaintContext, SizeConstraint,
};
use core::panic;
use json::ToJson;
@@ -9,11 +38,11 @@ use replace_with::replace_with_or_abort;
use std::{any::Any, borrow::Cow};
trait AnyElement {
fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F;
fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
fn after_layout(&mut self, _: &mut AfterLayoutContext) {}
fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext);
fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool;
fn debug(&self, ctx: &DebugContext) -> serde_json::Value;
fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext);
fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
fn debug(&self, cx: &DebugContext) -> serde_json::Value;
fn size(&self) -> Vector2F;
fn metadata(&self) -> Option<&dyn Any>;
@@ -26,21 +55,21 @@ pub trait Element {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState);
fn after_layout(
&mut self,
size: Vector2F,
layout: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
);
fn paint(
&mut self,
bounds: RectF,
layout: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState;
fn dispatch_event(
@@ -49,7 +78,7 @@ pub trait Element {
bounds: RectF,
layout: &mut Self::LayoutState,
paint: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool;
fn metadata(&self) -> Option<&dyn Any> {
@@ -61,7 +90,7 @@ pub trait Element {
bounds: RectF,
layout: &Self::LayoutState,
paint: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> serde_json::Value;
fn boxed(self) -> ElementBox
@@ -109,13 +138,13 @@ pub struct ElementBox {
}
impl<T: Element> AnyElement for Lifecycle<T> {
fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
let mut result = None;
replace_with_or_abort(self, |me| match me {
Lifecycle::Init { mut element }
| Lifecycle::PostLayout { mut element, .. }
| Lifecycle::PostPaint { mut element, .. } => {
let (size, layout) = element.layout(constraint, ctx);
let (size, layout) = element.layout(constraint, cx);
debug_assert!(size.x().is_finite());
debug_assert!(size.y().is_finite());
@@ -131,7 +160,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
result.unwrap()
}
fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
fn after_layout(&mut self, cx: &mut AfterLayoutContext) {
if let Lifecycle::PostLayout {
element,
size,
@@ -139,13 +168,13 @@ impl<T: Element> AnyElement for Lifecycle<T> {
..
} = self
{
element.after_layout(*size, layout, ctx);
element.after_layout(*size, layout, cx);
} else {
panic!("invalid element lifecycle state");
}
}
fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
replace_with_or_abort(self, |me| {
if let Lifecycle::PostLayout {
mut element,
@@ -155,7 +184,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
} = me
{
let bounds = RectF::new(origin, size);
let paint = element.paint(bounds, &mut layout, ctx);
let paint = element.paint(bounds, &mut layout, cx);
Lifecycle::PostPaint {
element,
constraint,
@@ -169,7 +198,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
});
}
fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
if let Lifecycle::PostPaint {
element,
bounds,
@@ -178,7 +207,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
..
} = self
{
element.dispatch_event(event, *bounds, layout, paint, ctx)
element.dispatch_event(event, *bounds, layout, paint, cx)
} else {
panic!("invalid element lifecycle state");
}
@@ -200,7 +229,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
}
}
fn debug(&self, ctx: &DebugContext) -> serde_json::Value {
fn debug(&self, cx: &DebugContext) -> serde_json::Value {
match self {
Lifecycle::PostPaint {
element,
@@ -209,7 +238,7 @@ impl<T: Element> AnyElement for Lifecycle<T> {
layout,
paint,
} => {
let mut value = element.debug(*bounds, layout, paint, ctx);
let mut value = element.debug(*bounds, layout, paint, cx);
if let json::Value::Object(map) = &mut value {
let mut new_map: crate::json::Map<String, serde_json::Value> =
Default::default();
@@ -229,20 +258,20 @@ impl<T: Element> AnyElement for Lifecycle<T> {
}
impl ElementBox {
pub fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
self.element.layout(constraint, ctx)
pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
self.element.layout(constraint, cx)
}
pub fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
self.element.after_layout(ctx);
pub fn after_layout(&mut self, cx: &mut AfterLayoutContext) {
self.element.after_layout(cx);
}
pub fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
self.element.paint(origin, ctx);
pub fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
self.element.paint(origin, cx);
}
pub fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
self.element.dispatch_event(event, ctx)
pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
self.element.dispatch_event(event, cx)
}
pub fn size(&self) -> Vector2F {
@@ -253,8 +282,8 @@ impl ElementBox {
self.element.metadata()
}
pub fn debug(&self, ctx: &DebugContext) -> json::Value {
let mut value = self.element.debug(ctx);
pub fn debug(&self, cx: &DebugContext) -> json::Value {
let mut value = self.element.debug(cx);
if let Some(name) = &self.name {
if let json::Value::Object(map) = &mut value {
@@ -268,3 +297,24 @@ impl ElementBox {
value
}
}
pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
self.extend(children);
}
fn add_child(&mut self, child: ElementBox) {
self.add_children(Some(child));
}
fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
self.add_children(children);
self
}
fn with_child(self, child: ElementBox) -> Self {
self.with_children(Some(child))
}
}
impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}
+10 -10
View File
@@ -37,11 +37,11 @@ impl Element for Align {
fn layout(
&mut self,
mut constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let mut size = constraint.max;
constraint.min = Vector2F::zero();
let child_size = self.child.layout(constraint, ctx);
let child_size = self.child.layout(constraint, cx);
if size.x().is_infinite() {
size.set_x(child_size.x());
}
@@ -55,16 +55,16 @@ impl Element for Align {
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
self.child.after_layout(ctx);
self.child.after_layout(cx);
}
fn paint(
&mut self,
bounds: pathfinder_geometry::rect::RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
let my_center = bounds.size() / 2.;
let my_target = my_center + my_center * self.alignment;
@@ -73,7 +73,7 @@ impl Element for Align {
let child_target = child_center + child_center * self.alignment;
self.child
.paint(bounds.origin() - (child_target - my_target), ctx);
.paint(bounds.origin() - (child_target - my_target), cx);
}
fn dispatch_event(
@@ -82,9 +82,9 @@ impl Element for Align {
_: pathfinder_geometry::rect::RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
self.child.dispatch_event(event, ctx)
self.child.dispatch_event(event, cx)
}
fn debug(
@@ -92,13 +92,13 @@ impl Element for Align {
bounds: pathfinder_geometry::rect::RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> json::Value {
json!({
"type": "Align",
"bounds": bounds.to_json(),
"alignment": self.alignment.to_json(),
"child": self.child.debug(ctx),
"child": self.child.debug(cx),
})
}
}
+2 -2
View File
@@ -51,9 +51,9 @@ where
&mut self,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
self.0(bounds, ctx)
self.0(bounds, cx)
}
fn after_layout(
+10 -10
View File
@@ -58,12 +58,12 @@ impl Element for ConstrainedBox {
fn layout(
&mut self,
mut constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
constraint.min = constraint.min.max(self.constraint.min);
constraint.max = constraint.max.min(self.constraint.max);
constraint.max = constraint.max.max(constraint.min);
let size = self.child.layout(constraint, ctx);
let size = self.child.layout(constraint, cx);
(size, ())
}
@@ -71,18 +71,18 @@ impl Element for ConstrainedBox {
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
self.child.after_layout(ctx);
self.child.after_layout(cx);
}
fn paint(
&mut self,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
self.child.paint(bounds.origin(), ctx);
self.child.paint(bounds.origin(), cx);
}
fn dispatch_event(
@@ -91,9 +91,9 @@ impl Element for ConstrainedBox {
_: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
self.child.dispatch_event(event, ctx)
self.child.dispatch_event(event, cx)
}
fn debug(
@@ -101,8 +101,8 @@ impl Element for ConstrainedBox {
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> json::Value {
json!({"type": "ConstrainedBox", "set_constraint": self.constraint.to_json(), "child": self.child.debug(ctx)})
json!({"type": "ConstrainedBox", "set_constraint": self.constraint.to_json(), "child": self.child.debug(cx)})
}
}
+12 -12
View File
@@ -141,14 +141,14 @@ impl Element for Container {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let size_buffer = self.margin_size() + self.padding_size() + self.border_size();
let child_constraint = SizeConstraint {
min: (constraint.min - size_buffer).max(Vector2F::zero()),
max: (constraint.max - size_buffer).max(Vector2F::zero()),
};
let child_size = self.child.layout(child_constraint, ctx);
let child_size = self.child.layout(child_constraint, cx);
(child_size + size_buffer, ())
}
@@ -156,16 +156,16 @@ impl Element for Container {
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
self.child.after_layout(ctx);
self.child.after_layout(cx);
}
fn paint(
&mut self,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
let quad_bounds = RectF::from_points(
bounds.origin() + vec2f(self.margin.left, self.margin.top),
@@ -173,14 +173,14 @@ impl Element for Container {
);
if let Some(shadow) = self.shadow.as_ref() {
ctx.scene.push_shadow(scene::Shadow {
cx.scene.push_shadow(scene::Shadow {
bounds: quad_bounds + shadow.offset,
corner_radius: self.corner_radius,
sigma: shadow.blur,
color: shadow.color,
});
}
ctx.scene.push_quad(Quad {
cx.scene.push_quad(Quad {
bounds: quad_bounds,
background: self.background_color,
border: self.border,
@@ -190,7 +190,7 @@ impl Element for Container {
let child_origin = quad_bounds.origin()
+ vec2f(self.padding.left, self.padding.top)
+ vec2f(self.border.left_width(), self.border.top_width());
self.child.paint(child_origin, ctx);
self.child.paint(child_origin, cx);
}
fn dispatch_event(
@@ -199,9 +199,9 @@ impl Element for Container {
_: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
self.child.dispatch_event(event, ctx)
self.child.dispatch_event(event, cx)
}
fn debug(
@@ -209,7 +209,7 @@ impl Element for Container {
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &crate::DebugContext,
cx: &crate::DebugContext,
) -> serde_json::Value {
json!({
"type": "Container",
@@ -222,7 +222,7 @@ impl Element for Container {
"corner_radius": self.corner_radius,
"shadow": self.shadow.to_json(),
},
"child": self.child.debug(ctx),
"child": self.child.debug(cx),
})
}
}
+11 -11
View File
@@ -35,9 +35,9 @@ impl Element for EventHandler {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let size = self.child.layout(constraint, ctx);
let size = self.child.layout(constraint, cx);
(size, ())
}
@@ -45,18 +45,18 @@ impl Element for EventHandler {
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
self.child.after_layout(ctx);
self.child.after_layout(cx);
}
fn paint(
&mut self,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
self.child.paint(bounds.origin(), ctx);
self.child.paint(bounds.origin(), cx);
}
fn dispatch_event(
@@ -65,16 +65,16 @@ impl Element for EventHandler {
bounds: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
if self.child.dispatch_event(event, ctx) {
if self.child.dispatch_event(event, cx) {
true
} else {
match event {
Event::LeftMouseDown { position, .. } => {
if let Some(callback) = self.mouse_down.as_mut() {
if bounds.contains_point(*position) {
return callback(ctx);
return callback(cx);
}
}
false
@@ -89,11 +89,11 @@ impl Element for EventHandler {
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> serde_json::Value {
json!({
"type": "EventHandler",
"child": self.child.debug(ctx),
"child": self.child.debug(cx),
})
}
}
+21 -21
View File
@@ -53,7 +53,7 @@ impl Element for Flex {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let mut total_flex = 0.0;
let mut fixed_space = 0.0;
@@ -74,7 +74,7 @@ impl Element for Flex {
vec2f(constraint.max.x(), INFINITY),
),
};
let size = child.layout(child_constraint, ctx);
let size = child.layout(child_constraint, cx);
fixed_space += size.along(self.axis);
cross_axis_max = cross_axis_max.max(size.along(cross_axis));
}
@@ -105,7 +105,7 @@ impl Element for Flex {
vec2f(constraint.max.x(), child_max),
),
};
let child_size = child.layout(child_constraint, ctx);
let child_size = child.layout(child_constraint, cx);
remaining_space -= child_size.along(self.axis);
remaining_flex -= flex;
cross_axis_max = cross_axis_max.max(child_size.along(cross_axis));
@@ -138,10 +138,10 @@ impl Element for Flex {
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
for child in &mut self.children {
child.after_layout(ctx);
child.after_layout(cx);
}
}
@@ -149,11 +149,11 @@ impl Element for Flex {
&mut self,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
let mut child_origin = bounds.origin();
for child in &mut self.children {
child.paint(child_origin, ctx);
child.paint(child_origin, cx);
match self.axis {
Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),
Axis::Vertical => child_origin += vec2f(0.0, child.size().y()),
@@ -167,11 +167,11 @@ impl Element for Flex {
_: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
let mut handled = false;
for child in &mut self.children {
handled = child.dispatch_event(event, ctx) || handled;
handled = child.dispatch_event(event, cx) || handled;
}
handled
}
@@ -181,13 +181,13 @@ impl Element for Flex {
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> json::Value {
json!({
"type": "Flex",
"bounds": bounds.to_json(),
"axis": self.axis.to_json(),
"children": self.children.iter().map(|child| child.debug(ctx)).collect::<Vec<json::Value>>()
"children": self.children.iter().map(|child| child.debug(cx)).collect::<Vec<json::Value>>()
})
}
}
@@ -217,9 +217,9 @@ impl Element for Expanded {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let size = self.child.layout(constraint, ctx);
let size = self.child.layout(constraint, cx);
(size, ())
}
@@ -227,18 +227,18 @@ impl Element for Expanded {
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
self.child.after_layout(ctx);
self.child.after_layout(cx);
}
fn paint(
&mut self,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
self.child.paint(bounds.origin(), ctx)
self.child.paint(bounds.origin(), cx)
}
fn dispatch_event(
@@ -247,9 +247,9 @@ impl Element for Expanded {
_: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
self.child.dispatch_event(event, ctx)
self.child.dispatch_event(event, cx)
}
fn metadata(&self) -> Option<&dyn Any> {
@@ -261,12 +261,12 @@ impl Element for Expanded {
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> Value {
json!({
"type": "Expanded",
"flex": self.metadata.flex,
"child": self.child.debug(ctx)
"child": self.child.debug(cx)
})
}
}
+14 -14
View File
@@ -109,20 +109,20 @@ impl Element for Label {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let font_id = ctx
let font_id = cx
.font_cache
.select_font(self.family_id, &self.font_properties)
.unwrap();
let runs = self.compute_runs(&ctx.font_cache, font_id);
let runs = self.compute_runs(&cx.font_cache, font_id);
let line =
ctx.text_layout_cache
cx.text_layout_cache
.layout_str(self.text.as_str(), self.font_size, runs.as_slice());
let size = vec2f(
line.width().max(constraint.min.x()).min(constraint.max.x()),
ctx.font_cache.line_height(font_id, self.font_size).ceil(),
cx.font_cache.line_height(font_id, self.font_size).ceil(),
);
(size, line)
@@ -135,12 +135,12 @@ impl Element for Label {
&mut self,
bounds: RectF,
line: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
line.paint(
bounds.origin(),
RectF::new(vec2f(0., 0.), bounds.size()),
ctx,
cx,
)
}
@@ -160,12 +160,12 @@ impl Element for Label {
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> Value {
json!({
"type": "Label",
"bounds": bounds.to_json(),
"font_family": ctx.font_cache.family_name(self.family_id).unwrap(),
"font_family": cx.font_cache.family_name(self.family_id).unwrap(),
"font_size": self.font_size,
"font_properties": self.font_properties.to_json(),
"text": &self.text,
@@ -191,13 +191,13 @@ mod tests {
use super::*;
#[crate::test(self)]
fn test_layout_label_with_highlights(app: &mut crate::MutableAppContext) {
let menlo = app.font_cache().load_family(&["Menlo"]).unwrap();
let menlo_regular = app
fn test_layout_label_with_highlights(cx: &mut crate::MutableAppContext) {
let menlo = cx.font_cache().load_family(&["Menlo"]).unwrap();
let menlo_regular = cx
.font_cache()
.select_font(menlo, &Properties::new())
.unwrap();
let menlo_bold = app
let menlo_bold = cx
.font_cache()
.select_font(menlo, Properties::new().weight(Weight::BOLD))
.unwrap();
@@ -216,7 +216,7 @@ mod tests {
],
);
let runs = label.compute_runs(app.font_cache().as_ref(), menlo_regular);
let runs = label.compute_runs(cx.font_cache().as_ref(), menlo_regular);
assert_eq!(
runs.as_slice(),
&[
+15 -15
View File
@@ -35,20 +35,20 @@ impl Element for LineBox {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
match ctx
match cx
.font_cache
.select_font(self.family_id, &self.font_properties)
{
Ok(font_id) => {
let line_height = ctx.font_cache.line_height(font_id, self.font_size);
let character_height = ctx.font_cache.ascent(font_id, self.font_size)
+ ctx.font_cache.descent(font_id, self.font_size);
let line_height = cx.font_cache.line_height(font_id, self.font_size);
let character_height = cx.font_cache.ascent(font_id, self.font_size)
+ cx.font_cache.descent(font_id, self.font_size);
let child_max = vec2f(constraint.max.x(), character_height);
let child_size = self.child.layout(
SizeConstraint::new(constraint.min.min(child_max), child_max),
ctx,
cx,
);
let size = vec2f(child_size.x(), line_height);
(size, (line_height - character_height) / 2.)
@@ -64,19 +64,19 @@ impl Element for LineBox {
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
self.child.after_layout(ctx);
self.child.after_layout(cx);
}
fn paint(
&mut self,
bounds: pathfinder_geometry::rect::RectF,
padding_top: &mut f32,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
self.child
.paint(bounds.origin() + vec2f(0., *padding_top), ctx);
.paint(bounds.origin() + vec2f(0., *padding_top), cx);
}
fn dispatch_event(
@@ -85,9 +85,9 @@ impl Element for LineBox {
_: pathfinder_geometry::rect::RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
self.child.dispatch_event(event, ctx)
self.child.dispatch_event(event, cx)
}
fn debug(
@@ -95,14 +95,14 @@ impl Element for LineBox {
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> serde_json::Value {
json!({
"bounds": bounds.to_json(),
"font_family": ctx.font_cache.family_name(self.family_id).unwrap(),
"font_family": cx.font_cache.family_name(self.family_id).unwrap(),
"font_size": self.font_size,
"font_properties": self.font_properties.to_json(),
"child": self.child.debug(ctx),
"child": self.child.debug(cx),
})
}
}
-56
View File
@@ -1,56 +0,0 @@
mod align;
mod canvas;
mod constrained_box;
mod container;
mod empty;
mod event_handler;
mod flex;
mod label;
mod line_box;
mod mouse_event_handler;
mod new;
mod stack;
mod svg;
mod uniform_list;
pub use crate::presenter::ChildView;
pub use align::*;
pub use canvas::*;
pub use constrained_box::*;
pub use container::*;
pub use empty::*;
pub use event_handler::*;
pub use flex::*;
pub use label::*;
pub use line_box::*;
pub use mouse_event_handler::*;
pub use new::*;
pub use stack::*;
pub use svg::*;
pub use uniform_list::*;
use crate::{
AfterLayoutContext, AppContext, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
};
pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
self.extend(children);
}
fn add_child(&mut self, child: ElementBox) {
self.add_children(Some(child));
}
fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
self.add_children(children);
self
}
fn with_child(self, child: ElementBox) -> Self {
self.with_children(Some(child))
}
}
impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}
+18 -18
View File
@@ -18,13 +18,13 @@ pub struct MouseState {
}
impl MouseEventHandler {
pub fn new<Tag, F>(id: usize, ctx: &AppContext, render_child: F) -> Self
pub fn new<Tag, F>(id: usize, cx: &AppContext, render_child: F) -> Self
where
Tag: 'static,
F: FnOnce(MouseState) -> ElementBox,
{
let state_handle = ctx.value::<Tag, _>(id);
let state = state_handle.read(ctx, |state| *state);
let state_handle = cx.value::<Tag, _>(id);
let state = state_handle.read(cx, |state| *state);
let child = render_child(state);
Self {
state: state_handle,
@@ -46,27 +46,27 @@ impl Element for MouseEventHandler {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
(self.child.layout(constraint, ctx), ())
(self.child.layout(constraint, cx), ())
}
fn after_layout(
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
self.child.after_layout(ctx);
self.child.after_layout(cx);
}
fn paint(
&mut self,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
self.child.paint(bounds.origin(), ctx);
self.child.paint(bounds.origin(), cx);
}
fn dispatch_event(
@@ -75,18 +75,18 @@ impl Element for MouseEventHandler {
bounds: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
let click_handler = self.click_handler.as_mut();
let handled_in_child = self.child.dispatch_event(event, ctx);
let handled_in_child = self.child.dispatch_event(event, cx);
self.state.update(ctx.app, |state| match event {
self.state.update(cx.app, |state| match event {
Event::MouseMoved { position } => {
let mouse_in = bounds.contains_point(*position);
if state.hovered != mouse_in {
state.hovered = mouse_in;
ctx.notify();
cx.notify();
true
} else {
handled_in_child
@@ -95,7 +95,7 @@ impl Element for MouseEventHandler {
Event::LeftMouseDown { position, .. } => {
if !handled_in_child && bounds.contains_point(*position) {
state.clicked = true;
ctx.notify();
cx.notify();
true
} else {
handled_in_child
@@ -104,10 +104,10 @@ impl Element for MouseEventHandler {
Event::LeftMouseUp { position, .. } => {
if !handled_in_child && state.clicked {
state.clicked = false;
ctx.notify();
cx.notify();
if let Some(handler) = click_handler {
if bounds.contains_point(*position) {
handler(ctx);
handler(cx);
}
}
true
@@ -124,11 +124,11 @@ impl Element for MouseEventHandler {
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> serde_json::Value {
json!({
"type": "MouseEventHandler",
"child": self.child.debug(ctx),
"child": self.child.debug(cx),
})
}
}
+12 -12
View File
@@ -24,11 +24,11 @@ impl Element for Stack {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let mut size = constraint.min;
for child in &mut self.children {
size = size.max(child.layout(constraint, ctx));
size = size.max(child.layout(constraint, cx));
}
(size, ())
}
@@ -37,10 +37,10 @@ impl Element for Stack {
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
for child in &mut self.children {
child.after_layout(ctx);
child.after_layout(cx);
}
}
@@ -48,12 +48,12 @@ impl Element for Stack {
&mut self,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
for child in &mut self.children {
ctx.scene.push_layer(None);
child.paint(bounds.origin(), ctx);
ctx.scene.pop_layer();
cx.scene.push_layer(None);
child.paint(bounds.origin(), cx);
cx.scene.pop_layer();
}
}
@@ -63,10 +63,10 @@ impl Element for Stack {
_: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
for child in self.children.iter_mut().rev() {
if child.dispatch_event(event, ctx) {
if child.dispatch_event(event, cx) {
return true;
}
}
@@ -78,12 +78,12 @@ impl Element for Stack {
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> json::Value {
json!({
"type": "Stack",
"bounds": bounds.to_json(),
"children": self.children.iter().map(|child| child.debug(ctx)).collect::<Vec<json::Value>>()
"children": self.children.iter().map(|child| child.debug(cx)).collect::<Vec<json::Value>>()
})
}
}
+4 -4
View File
@@ -38,9 +38,9 @@ impl Element for Svg {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
match ctx.asset_cache.svg(&self.path) {
match cx.asset_cache.svg(&self.path) {
Ok(tree) => {
let size = if constraint.max.x().is_infinite() && constraint.max.y().is_infinite() {
let rect = from_usvg_rect(tree.svg_node().view_box.rect);
@@ -69,9 +69,9 @@ impl Element for Svg {
fn after_layout(&mut self, _: Vector2F, _: &mut Self::LayoutState, _: &mut AfterLayoutContext) {
}
fn paint(&mut self, bounds: RectF, svg: &mut Self::LayoutState, ctx: &mut PaintContext) {
fn paint(&mut self, bounds: RectF, svg: &mut Self::LayoutState, cx: &mut PaintContext) {
if let Some(svg) = svg.clone() {
ctx.scene.push_icon(scene::Icon {
cx.scene.push_icon(scene::Icon {
bounds,
svg,
path: self.path.clone(),
+18 -18
View File
@@ -72,7 +72,7 @@ where
delta: Vector2F,
precise: bool,
scroll_max: f32,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
if !precise {
todo!("still need to handle non-precise scroll events from a mouse wheel");
@@ -80,7 +80,7 @@ where
let mut state = self.state.0.lock();
state.scroll_top = (state.scroll_top - delta.y()).max(0.0).min(scroll_max);
ctx.dispatch_action("uniform_list:scroll", state.scroll_top);
cx.dispatch_action("uniform_list:scroll", state.scroll_top);
true
}
@@ -119,7 +119,7 @@ where
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
if constraint.max.y().is_infinite() {
unimplemented!(
@@ -133,9 +133,9 @@ where
let mut scroll_max = 0.;
let mut items = Vec::new();
(self.append_items)(0..1, &mut items, ctx.app);
(self.append_items)(0..1, &mut items, cx.app);
if let Some(first_item) = items.first_mut() {
let mut item_size = first_item.layout(item_constraint, ctx);
let mut item_size = first_item.layout(item_constraint, cx);
item_size.set_x(size.x());
item_constraint.min = item_size;
item_constraint.max = item_size;
@@ -155,9 +155,9 @@ where
self.item_count,
start + (size.y() / item_height).ceil() as usize + 1,
);
(self.append_items)(start..end, &mut items, ctx.app);
(self.append_items)(start..end, &mut items, cx.app);
for item in &mut items {
item.layout(item_constraint, ctx);
item.layout(item_constraint, cx);
}
}
@@ -175,10 +175,10 @@ where
&mut self,
_: Vector2F,
layout: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
for item in &mut layout.items {
item.after_layout(ctx);
item.after_layout(cx);
}
}
@@ -186,19 +186,19 @@ where
&mut self,
bounds: RectF,
layout: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
ctx.scene.push_layer(Some(bounds));
cx.scene.push_layer(Some(bounds));
let mut item_origin =
bounds.origin() - vec2f(0.0, self.state.scroll_top() % layout.item_height);
for item in &mut layout.items {
item.paint(item_origin, ctx);
item.paint(item_origin, cx);
item_origin += vec2f(0.0, layout.item_height);
}
ctx.scene.pop_layer();
cx.scene.pop_layer();
}
fn dispatch_event(
@@ -207,11 +207,11 @@ where
bounds: RectF,
layout: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
let mut handled = false;
for item in &mut layout.items {
handled = item.dispatch_event(event, ctx) || handled;
handled = item.dispatch_event(event, cx) || handled;
}
match event {
@@ -221,7 +221,7 @@ where
precise,
} => {
if bounds.contains_point(*position) {
if self.scroll(*position, *delta, *precise, layout.scroll_max, ctx) {
if self.scroll(*position, *delta, *precise, layout.scroll_max, cx) {
handled = true;
}
}
@@ -237,14 +237,14 @@ where
bounds: RectF,
layout: &Self::LayoutState,
_: &Self::PaintState,
ctx: &crate::DebugContext,
cx: &crate::DebugContext,
) -> json::Value {
json!({
"type": "UniformList",
"bounds": bounds.to_json(),
"scroll_max": layout.scroll_max,
"item_height": layout.item_height,
"items": layout.items.iter().map(|item| item.debug(ctx)).collect::<Vec<json::Value>>()
"items": layout.items.iter().map(|item| item.debug(cx)).collect::<Vec<json::Value>>()
})
}
+15 -21
View File
@@ -98,12 +98,12 @@ impl Matcher {
&mut self,
keystroke: Keystroke,
view_id: usize,
ctx: &Context,
cx: &Context,
) -> MatchResult {
let pending = self.pending.entry(view_id).or_default();
if let Some(pending_ctx) = pending.context.as_ref() {
if pending_ctx != ctx {
if pending_ctx != cx {
pending.keystrokes.clear();
}
}
@@ -113,11 +113,7 @@ impl Matcher {
let mut retain_pending = false;
for binding in self.keymap.0.iter().rev() {
if binding.keystrokes.starts_with(&pending.keystrokes)
&& binding
.context
.as_ref()
.map(|c| c.eval(ctx))
.unwrap_or(true)
&& binding.context.as_ref().map(|c| c.eval(cx)).unwrap_or(true)
{
if binding.keystrokes.len() == pending.keystrokes.len() {
self.pending.remove(&view_id);
@@ -127,7 +123,7 @@ impl Matcher {
};
} else {
retain_pending = true;
pending.context = Some(ctx.clone());
pending.context = Some(cx.clone());
}
}
}
@@ -312,22 +308,20 @@ impl ContextPredicate {
}
}
fn eval(&self, ctx: &Context) -> bool {
fn eval(&self, cx: &Context) -> bool {
match self {
Self::Identifier(name) => ctx.set.contains(name.as_str()),
Self::Equal(left, right) => ctx
Self::Identifier(name) => cx.set.contains(name.as_str()),
Self::Equal(left, right) => cx
.map
.get(left)
.map(|value| value == right)
.unwrap_or(false),
Self::NotEqual(left, right) => ctx
.map
.get(left)
.map(|value| value != right)
.unwrap_or(true),
Self::Not(pred) => !pred.eval(ctx),
Self::And(left, right) => left.eval(ctx) && right.eval(ctx),
Self::Or(left, right) => left.eval(ctx) || right.eval(ctx),
Self::NotEqual(left, right) => {
cx.map.get(left).map(|value| value != right).unwrap_or(true)
}
Self::Not(pred) => !pred.eval(cx),
Self::And(left, right) => left.eval(cx) && right.eval(cx),
Self::Or(left, right) => left.eval(cx) || right.eval(cx),
}
}
}
@@ -488,10 +482,10 @@ mod tests {
&mut self,
keystroke: &str,
view_id: usize,
ctx: &Context,
cx: &Context,
) -> Option<(String, Option<A>)> {
if let MatchResult::Action { name, arg } =
self.push_keystroke(Keystroke::parse(keystroke).unwrap(), view_id, ctx)
self.push_keystroke(Keystroke::parse(keystroke).unwrap(), view_id, cx)
{
Some((name, arg.and_then(|arg| arg.downcast_ref::<A>().cloned())))
} else {
+6 -6
View File
@@ -145,7 +145,7 @@ impl FontSystemState {
// Make room for subpixel variants.
let bounds = RectI::new(bounds.origin(), bounds.size() + vec2i(1, 1));
let mut pixels = vec![0; bounds.width() as usize * bounds.height() as usize];
let ctx = CGContext::create_bitmap_context(
let cx = CGContext::create_bitmap_context(
Some(pixels.as_mut_ptr() as *mut _),
bounds.width() as usize,
bounds.height() as usize,
@@ -157,9 +157,9 @@ impl FontSystemState {
// Move the origin to bottom left and account for scaling, this
// makes drawing text consistent with the font-kit's raster_bounds.
ctx.translate(0.0, bounds.height() as CGFloat);
cx.translate(0.0, bounds.height() as CGFloat);
let transform = scale.translate(-bounds.origin().to_f32());
ctx.set_text_matrix(&CGAffineTransform {
cx.set_text_matrix(&CGAffineTransform {
a: transform.matrix.m11() as CGFloat,
b: -transform.matrix.m21() as CGFloat,
c: -transform.matrix.m12() as CGFloat,
@@ -168,9 +168,9 @@ impl FontSystemState {
ty: -transform.vector.y() as CGFloat,
});
ctx.set_font(&font.native_font().copy_to_CGFont());
ctx.set_font_size(font_size as CGFloat);
ctx.show_glyphs_at_positions(
cx.set_font(&font.native_font().copy_to_CGFont());
cx.set_font_size(font_size as CGFloat);
cx.show_glyphs_at_positions(
&[glyph_id as CGGlyph],
&[CGPoint::new(
(subpixel_shift.x() / scale_factor) as CGFloat,
+48 -48
View File
@@ -31,11 +31,11 @@ impl Presenter {
font_cache: Arc<FontCache>,
text_layout_cache: TextLayoutCache,
asset_cache: Arc<AssetCache>,
app: &MutableAppContext,
cx: &MutableAppContext,
) -> Self {
Self {
window_id,
rendered_views: app.render_views(window_id),
rendered_views: cx.render_views(window_id),
parents: HashMap::new(),
font_cache,
text_layout_cache,
@@ -55,7 +55,7 @@ impl Presenter {
path
}
pub fn invalidate(&mut self, mut invalidation: WindowInvalidation, app: &AppContext) {
pub fn invalidate(&mut self, mut invalidation: WindowInvalidation, cx: &AppContext) {
for view_id in invalidation.removed {
invalidation.updated.remove(&view_id);
self.rendered_views.remove(&view_id);
@@ -63,7 +63,7 @@ impl Presenter {
}
for view_id in invalidation.updated {
self.rendered_views
.insert(view_id, app.render_view(self.window_id, view_id).unwrap());
.insert(view_id, cx.render_view(self.window_id, view_id).unwrap());
}
}
@@ -71,25 +71,25 @@ impl Presenter {
&mut self,
window_size: Vector2F,
scale_factor: f32,
app: &mut MutableAppContext,
cx: &mut MutableAppContext,
) -> Scene {
let mut scene = Scene::new(scale_factor);
if let Some(root_view_id) = app.root_view_id(self.window_id) {
self.layout(window_size, app.as_ref());
self.after_layout(app);
let mut ctx = PaintContext {
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
self.layout(window_size, cx.as_ref());
self.after_layout(cx);
let mut paint_cx = PaintContext {
scene: &mut scene,
font_cache: &self.font_cache,
text_layout_cache: &self.text_layout_cache,
rendered_views: &mut self.rendered_views,
app: app.as_ref(),
app: cx.as_ref(),
};
ctx.paint(root_view_id, Vector2F::zero());
paint_cx.paint(root_view_id, Vector2F::zero());
self.text_layout_cache.finish_frame();
if let Some(event) = self.last_mouse_moved_event.clone() {
self.dispatch_event(event, app)
self.dispatch_event(event, cx)
}
} else {
log::error!("could not find root_view_id for window {}", self.window_id);
@@ -98,8 +98,8 @@ impl Presenter {
scene
}
fn layout(&mut self, size: Vector2F, app: &AppContext) {
if let Some(root_view_id) = app.root_view_id(self.window_id) {
fn layout(&mut self, size: Vector2F, cx: &AppContext) {
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
let mut layout_ctx = LayoutContext {
rendered_views: &mut self.rendered_views,
parents: &mut self.parents,
@@ -107,49 +107,49 @@ impl Presenter {
text_layout_cache: &self.text_layout_cache,
asset_cache: &self.asset_cache,
view_stack: Vec::new(),
app,
app: cx,
};
layout_ctx.layout(root_view_id, SizeConstraint::strict(size));
}
}
fn after_layout(&mut self, app: &mut MutableAppContext) {
if let Some(root_view_id) = app.root_view_id(self.window_id) {
let mut ctx = AfterLayoutContext {
fn after_layout(&mut self, cx: &mut MutableAppContext) {
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
let mut layout_cx = AfterLayoutContext {
rendered_views: &mut self.rendered_views,
font_cache: &self.font_cache,
text_layout_cache: &self.text_layout_cache,
app,
app: cx,
};
ctx.after_layout(root_view_id);
layout_cx.after_layout(root_view_id);
}
}
pub fn dispatch_event(&mut self, event: Event, app: &mut MutableAppContext) {
if let Some(root_view_id) = app.root_view_id(self.window_id) {
pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) {
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
if matches!(event, Event::MouseMoved { .. }) {
self.last_mouse_moved_event = Some(event.clone());
}
let mut ctx = EventContext {
let mut event_cx = EventContext {
rendered_views: &mut self.rendered_views,
actions: Default::default(),
font_cache: &self.font_cache,
text_layout_cache: &self.text_layout_cache,
view_stack: Default::default(),
invalidated_views: Default::default(),
app: app.as_ref(),
app: cx.as_ref(),
};
ctx.dispatch_event(root_view_id, &event);
event_cx.dispatch_event(root_view_id, &event);
let invalidated_views = ctx.invalidated_views;
let actions = ctx.actions;
let invalidated_views = event_cx.invalidated_views;
let actions = event_cx.actions;
for view_id in invalidated_views {
app.notify_view(self.window_id, view_id);
cx.notify_view(self.window_id, view_id);
}
for action in actions {
app.dispatch_action_any(
cx.dispatch_action_any(
self.window_id,
&action.path,
action.name,
@@ -159,14 +159,14 @@ impl Presenter {
}
}
pub fn debug_elements(&self, ctx: &AppContext) -> Option<json::Value> {
ctx.root_view_id(self.window_id)
pub fn debug_elements(&self, cx: &AppContext) -> Option<json::Value> {
cx.root_view_id(self.window_id)
.and_then(|root_view_id| self.rendered_views.get(&root_view_id))
.map(|root_element| {
root_element.debug(&DebugContext {
rendered_views: &self.rendered_views,
font_cache: &self.font_cache,
app: ctx,
app: cx,
})
})
}
@@ -380,9 +380,9 @@ impl Element for ChildView {
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let size = ctx.layout(self.view_id, constraint);
let size = cx.layout(self.view_id, constraint);
(size, ())
}
@@ -390,18 +390,18 @@ impl Element for ChildView {
&mut self,
_: Vector2F,
_: &mut Self::LayoutState,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
ctx.after_layout(self.view_id);
cx.after_layout(self.view_id);
}
fn paint(
&mut self,
bounds: pathfinder_geometry::rect::RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
ctx.paint(self.view_id, bounds.origin());
cx.paint(self.view_id, bounds.origin());
}
fn dispatch_event(
@@ -410,9 +410,9 @@ impl Element for ChildView {
_: pathfinder_geometry::rect::RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
ctx.dispatch_event(self.view_id, event)
cx.dispatch_event(self.view_id, event)
}
fn debug(
@@ -420,14 +420,14 @@ impl Element for ChildView {
bounds: pathfinder_geometry::rect::RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
cx: &DebugContext,
) -> serde_json::Value {
json!({
"type": "ChildView",
"view_id": self.view_id,
"bounds": bounds.to_json(),
"child": if let Some(view) = ctx.rendered_views.get(&self.view_id) {
view.debug(ctx)
"child": if let Some(view) = cx.rendered_views.get(&self.view_id) {
view.debug(cx)
} else {
json!(null)
}
@@ -441,9 +441,9 @@ mod tests {
// fn test_responder_chain() {
// let settings = settings_rx(None);
// let mut app = App::new().unwrap();
// let workspace = app.add_model(|ctx| Workspace::new(Vec::new(), ctx));
// let workspace = app.add_model(|cx| Workspace::new(Vec::new(), cx));
// let (window_id, workspace_view) =
// app.add_window(|ctx| WorkspaceView::new(workspace.clone(), settings, ctx));
// app.add_window(|cx| WorkspaceView::new(workspace.clone(), settings, cx));
// let invalidations = Rc::new(RefCell::new(Vec::new()));
// let invalidations_ = invalidations.clone();
@@ -451,8 +451,8 @@ mod tests {
// invalidations_.borrow_mut().push(invalidation)
// });
// let active_pane_id = workspace_view.update(&mut app, |view, ctx| {
// ctx.focus(view.active_pane());
// let active_pane_id = workspace_view.update(&mut app, |view, cx| {
// cx.focus(view.active_pane());
// view.active_pane().id()
// });
@@ -468,7 +468,7 @@ mod tests {
// }
// assert_eq!(
// presenter.responder_chain(app.ctx()).unwrap(),
// presenter.responder_chain(app.cx()).unwrap(),
// vec![workspace_view.id(), active_pane_id]
// );
// });
+3 -3
View File
@@ -200,7 +200,7 @@ impl Line {
}
}
pub fn paint(&self, origin: Vector2F, visible_bounds: RectF, ctx: &mut PaintContext) {
pub fn paint(&self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
let padding_top = (visible_bounds.height() - self.layout.ascent - self.layout.descent) / 2.;
let baseline_origin = vec2f(0., padding_top + self.layout.ascent);
@@ -209,7 +209,7 @@ impl Line {
let mut color = ColorU::black();
for run in &self.layout.runs {
let max_glyph_width = ctx
let max_glyph_width = cx
.font_cache
.bounding_box(run.font_id, self.layout.font_size)
.x();
@@ -234,7 +234,7 @@ impl Line {
}
}
ctx.scene.push_glyph(scene::Glyph {
cx.scene.push_glyph(scene::Glyph {
font_id: run.font_id,
font_size: self.layout.font_size,
id: glyph.id,
+4 -4
View File
@@ -34,8 +34,8 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
fn #outer_fn_name() {
#inner_fn
#namespace::App::test_async((), move |ctx| async {
#inner_fn_name(ctx).await;
#namespace::App::test_async((), move |cx| async {
#inner_fn_name(cx).await;
});
}
}
@@ -45,8 +45,8 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
fn #outer_fn_name() {
#inner_fn
#namespace::App::test((), |ctx| {
#inner_fn_name(ctx);
#namespace::App::test((), |cx| {
#inner_fn_name(cx);
});
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -81,9 +81,9 @@ impl Selection {
}
}
pub fn display_range(&self, map: &DisplayMap, app: &AppContext) -> Range<DisplayPoint> {
let start = self.start.to_display_point(map, app);
let end = self.end.to_display_point(map, app);
pub fn display_range(&self, map: &DisplayMap, cx: &AppContext) -> Range<DisplayPoint> {
let start = self.start.to_display_point(map, cx);
let end = self.end.to_display_point(map, cx);
if self.reversed {
end..start
} else {
@@ -95,22 +95,22 @@ impl Selection {
&self,
include_end_if_at_line_start: bool,
map: &DisplayMap,
ctx: &AppContext,
cx: &AppContext,
) -> (Range<u32>, Range<u32>) {
let display_start = self.start.to_display_point(map, ctx);
let display_start = self.start.to_display_point(map, cx);
let buffer_start =
DisplayPoint::new(display_start.row(), 0).to_buffer_point(map, Bias::Left, ctx);
DisplayPoint::new(display_start.row(), 0).to_buffer_point(map, Bias::Left, cx);
let mut display_end = self.end.to_display_point(map, ctx);
let mut display_end = self.end.to_display_point(map, cx);
if !include_end_if_at_line_start
&& display_end.row() != map.max_point(ctx).row()
&& display_end.row() != map.max_point(cx).row()
&& display_start.row() != display_end.row()
&& display_end.column() == 0
{
*display_end.row_mut() -= 1;
}
let buffer_end = DisplayPoint::new(display_end.row(), map.line_len(display_end.row(), ctx))
.to_buffer_point(map, Bias::Left, ctx);
let buffer_end = DisplayPoint::new(display_end.row(), map.line_len(display_end.row(), cx))
.to_buffer_point(map, Bias::Left, cx);
(
buffer_start.row..buffer_end.row + 1,
@@ -15,17 +15,17 @@ pub struct DisplayMap {
}
impl DisplayMap {
pub fn new(buffer: ModelHandle<Buffer>, tab_size: usize, ctx: &AppContext) -> Self {
pub fn new(buffer: ModelHandle<Buffer>, tab_size: usize, cx: &AppContext) -> Self {
DisplayMap {
buffer: buffer.clone(),
fold_map: FoldMap::new(buffer, ctx),
fold_map: FoldMap::new(buffer, cx),
tab_size,
}
}
pub fn snapshot(&self, ctx: &AppContext) -> DisplayMapSnapshot {
pub fn snapshot(&self, cx: &AppContext) -> DisplayMapSnapshot {
DisplayMapSnapshot {
folds_snapshot: self.fold_map.snapshot(ctx),
folds_snapshot: self.fold_map.snapshot(cx),
tab_size: self.tab_size,
}
}
@@ -33,46 +33,46 @@ impl DisplayMap {
pub fn folds_in_range<'a, T>(
&'a self,
range: Range<T>,
app: &'a AppContext,
cx: &'a AppContext,
) -> impl Iterator<Item = &'a Range<Anchor>>
where
T: ToOffset,
{
self.fold_map.folds_in_range(range, app)
self.fold_map.folds_in_range(range, cx)
}
pub fn fold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
ctx: &AppContext,
cx: &AppContext,
) {
self.fold_map.fold(ranges, ctx)
self.fold_map.fold(ranges, cx)
}
pub fn unfold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
ctx: &AppContext,
cx: &AppContext,
) {
self.fold_map.unfold(ranges, ctx)
self.fold_map.unfold(ranges, cx)
}
pub fn intersects_fold<T: ToOffset>(&self, offset: T, ctx: &AppContext) -> bool {
self.fold_map.intersects_fold(offset, ctx)
pub fn intersects_fold<T: ToOffset>(&self, offset: T, cx: &AppContext) -> bool {
self.fold_map.intersects_fold(offset, cx)
}
pub fn is_line_folded(&self, display_row: u32, ctx: &AppContext) -> bool {
self.fold_map.is_line_folded(display_row, ctx)
pub fn is_line_folded(&self, display_row: u32, cx: &AppContext) -> bool {
self.fold_map.is_line_folded(display_row, cx)
}
pub fn text(&self, ctx: &AppContext) -> String {
self.snapshot(ctx).chunks_at(DisplayPoint::zero()).collect()
pub fn text(&self, cx: &AppContext) -> String {
self.snapshot(cx).chunks_at(DisplayPoint::zero()).collect()
}
pub fn line(&self, display_row: u32, ctx: &AppContext) -> String {
pub fn line(&self, display_row: u32, cx: &AppContext) -> String {
let mut result = String::new();
for chunk in self
.snapshot(ctx)
.snapshot(cx)
.chunks_at(DisplayPoint::new(display_row, 0))
{
if let Some(ix) = chunk.find('\n') {
@@ -85,11 +85,11 @@ impl DisplayMap {
result
}
pub fn line_indent(&self, display_row: u32, ctx: &AppContext) -> (u32, bool) {
pub fn line_indent(&self, display_row: u32, cx: &AppContext) -> (u32, bool) {
let mut indent = 0;
let mut is_blank = true;
for c in self
.snapshot(ctx)
.snapshot(cx)
.chars_at(DisplayPoint::new(display_row, 0))
{
if c == ' ' {
@@ -102,30 +102,30 @@ impl DisplayMap {
(indent, is_blank)
}
pub fn line_len(&self, row: u32, ctx: &AppContext) -> u32 {
DisplayPoint::new(row, self.fold_map.line_len(row, ctx))
.expand_tabs(self, ctx)
pub fn line_len(&self, row: u32, cx: &AppContext) -> u32 {
DisplayPoint::new(row, self.fold_map.line_len(row, cx))
.expand_tabs(self, cx)
.column()
}
pub fn max_point(&self, ctx: &AppContext) -> DisplayPoint {
self.snapshot(ctx).max_point().expand_tabs(self, ctx)
pub fn max_point(&self, cx: &AppContext) -> DisplayPoint {
self.snapshot(cx).max_point().expand_tabs(self, cx)
}
pub fn longest_row(&self, ctx: &AppContext) -> u32 {
self.fold_map.longest_row(ctx)
pub fn longest_row(&self, cx: &AppContext) -> u32 {
self.fold_map.longest_row(cx)
}
pub fn anchor_before(&self, point: DisplayPoint, bias: Bias, app: &AppContext) -> Anchor {
pub fn anchor_before(&self, point: DisplayPoint, bias: Bias, cx: &AppContext) -> Anchor {
self.buffer
.read(app)
.anchor_before(point.to_buffer_point(self, bias, app))
.read(cx)
.anchor_before(point.to_buffer_point(self, bias, cx))
}
pub fn anchor_after(&self, point: DisplayPoint, bias: Bias, app: &AppContext) -> Anchor {
pub fn anchor_after(&self, point: DisplayPoint, bias: Bias, cx: &AppContext) -> Anchor {
self.buffer
.read(app)
.anchor_after(point.to_buffer_point(self, bias, app))
.read(cx)
.anchor_after(point.to_buffer_point(self, bias, cx))
}
}
@@ -257,29 +257,29 @@ impl DisplayPoint {
&mut self.0.column
}
pub fn to_buffer_point(self, map: &DisplayMap, bias: Bias, ctx: &AppContext) -> Point {
pub fn to_buffer_point(self, map: &DisplayMap, bias: Bias, cx: &AppContext) -> Point {
map.fold_map
.to_buffer_point(self.collapse_tabs(map, bias, ctx), ctx)
.to_buffer_point(self.collapse_tabs(map, bias, cx), cx)
}
pub fn to_buffer_offset(self, map: &DisplayMap, bias: Bias, ctx: &AppContext) -> usize {
pub fn to_buffer_offset(self, map: &DisplayMap, bias: Bias, cx: &AppContext) -> usize {
map.fold_map
.to_buffer_offset(self.collapse_tabs(&map, bias, ctx), ctx)
.to_buffer_offset(self.collapse_tabs(&map, bias, cx), cx)
}
fn expand_tabs(self, map: &DisplayMap, ctx: &AppContext) -> Self {
map.snapshot(ctx).expand_tabs(self)
fn expand_tabs(self, map: &DisplayMap, cx: &AppContext) -> Self {
map.snapshot(cx).expand_tabs(self)
}
fn collapse_tabs(self, map: &DisplayMap, bias: Bias, ctx: &AppContext) -> Self {
map.snapshot(ctx).collapse_tabs(self, bias).0
fn collapse_tabs(self, map: &DisplayMap, bias: Bias, cx: &AppContext) -> Self {
map.snapshot(cx).collapse_tabs(self, bias).0
}
}
impl Point {
pub fn to_display_point(self, map: &DisplayMap, ctx: &AppContext) -> DisplayPoint {
let mut display_point = map.fold_map.to_display_point(self, ctx);
let snapshot = map.fold_map.snapshot(ctx);
pub fn to_display_point(self, map: &DisplayMap, cx: &AppContext) -> DisplayPoint {
let mut display_point = map.fold_map.to_display_point(self, cx);
let snapshot = map.fold_map.snapshot(cx);
let chars = snapshot.chars_at(DisplayPoint::new(display_point.row(), 0));
*display_point.column_mut() =
expand_tabs(chars, display_point.column() as usize, map.tab_size) as u32;
@@ -288,9 +288,8 @@ impl Point {
}
impl Anchor {
pub fn to_display_point(&self, map: &DisplayMap, app: &AppContext) -> DisplayPoint {
self.to_point(map.buffer.read(app))
.to_display_point(map, app)
pub fn to_display_point(&self, map: &DisplayMap, cx: &AppContext) -> DisplayPoint {
self.to_point(map.buffer.read(cx)).to_display_point(map, cx)
}
}
@@ -463,12 +462,12 @@ mod tests {
use std::sync::Arc;
#[gpui::test]
fn test_chunks_at(app: &mut gpui::MutableAppContext) {
fn test_chunks_at(cx: &mut gpui::MutableAppContext) {
let text = sample_text(6, 6);
let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
let map = DisplayMap::new(buffer.clone(), 4, app.as_ref());
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
let map = DisplayMap::new(buffer.clone(), 4, cx.as_ref());
buffer
.update(app, |buffer, ctx| {
.update(cx, |buffer, cx| {
buffer.edit(
vec![
Point::new(1, 0)..Point::new(1, 0),
@@ -476,25 +475,25 @@ mod tests {
Point::new(2, 1)..Point::new(2, 1),
],
"\t",
Some(ctx),
Some(cx),
)
})
.unwrap();
assert_eq!(
&map.snapshot(app.as_ref())
&map.snapshot(cx.as_ref())
.chunks_at(DisplayPoint::new(1, 0))
.collect::<String>()[0..10],
" b bb"
);
assert_eq!(
&map.snapshot(app.as_ref())
&map.snapshot(cx.as_ref())
.chunks_at(DisplayPoint::new(1, 2))
.collect::<String>()[0..10],
" b bbbb"
);
assert_eq!(
&map.snapshot(app.as_ref())
&map.snapshot(cx.as_ref())
.chunks_at(DisplayPoint::new(1, 6))
.collect::<String>()[0..13],
" bbbbb\nc c"
@@ -502,7 +501,7 @@ mod tests {
}
#[gpui::test]
async fn test_highlighted_chunks_at(mut app: gpui::TestAppContext) {
async fn test_highlighted_chunks_at(mut cx: gpui::TestAppContext) {
use unindent::Unindent as _;
let grammar = tree_sitter_rust::language();
@@ -540,14 +539,14 @@ mod tests {
});
lang.set_theme(&theme);
let buffer = app.add_model(|ctx| {
Buffer::from_history(0, History::new(text.into()), None, Some(lang), ctx)
let buffer = cx.add_model(|cx| {
Buffer::from_history(0, History::new(text.into()), None, Some(lang), cx)
});
buffer.condition(&app, |buf, _| !buf.is_parsing()).await;
buffer.condition(&cx, |buf, _| !buf.is_parsing()).await;
let mut map = app.read(|ctx| DisplayMap::new(buffer, 2, ctx));
let mut map = cx.read(|cx| DisplayMap::new(buffer, 2, cx));
assert_eq!(
app.read(|ctx| highlighted_chunks(0..5, &map, &theme, ctx)),
cx.read(|cx| highlighted_chunks(0..5, &map, &theme, cx)),
vec![
("fn ".to_string(), None),
("outer".to_string(), Some("fn.name")),
@@ -558,7 +557,7 @@ mod tests {
]
);
assert_eq!(
app.read(|ctx| highlighted_chunks(3..5, &map, &theme, ctx)),
cx.read(|cx| highlighted_chunks(3..5, &map, &theme, cx)),
vec![
(" fn ".to_string(), Some("mod.body")),
("inner".to_string(), Some("fn.name")),
@@ -566,9 +565,9 @@ mod tests {
]
);
app.read(|ctx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], ctx));
cx.read(|cx| map.fold(vec![Point::new(0, 6)..Point::new(3, 2)], cx));
assert_eq!(
app.read(|ctx| highlighted_chunks(0..2, &map, &theme, ctx)),
cx.read(|cx| highlighted_chunks(0..2, &map, &theme, cx)),
vec![
("fn ".to_string(), None),
("out".to_string(), Some("fn.name")),
@@ -583,10 +582,10 @@ mod tests {
rows: Range<u32>,
map: &DisplayMap,
theme: &'a Theme,
ctx: &AppContext,
cx: &AppContext,
) -> Vec<(String, Option<&'a str>)> {
let mut chunks: Vec<(String, Option<&str>)> = Vec::new();
for (chunk, style_id) in map.snapshot(ctx).highlighted_chunks_for_rows(rows) {
for (chunk, style_id) in map.snapshot(cx).highlighted_chunks_for_rows(rows) {
let style_name = theme.syntax_style_name(style_id);
if let Some((last_chunk, last_style_name)) = chunks.last_mut() {
if style_name == *last_style_name {
@@ -603,17 +602,17 @@ mod tests {
}
#[gpui::test]
fn test_clip_point(app: &mut gpui::MutableAppContext) {
fn test_clip_point(cx: &mut gpui::MutableAppContext) {
use Bias::{Left, Right};
let text = "\n'a', 'α',\t'✋',\t'❎', '🍐'\n";
let display_text = "\n'a', 'α', '✋', '❎', '🍐'\n";
let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
let ctx = app.as_ref();
let map = DisplayMap::new(buffer.clone(), 4, ctx);
assert_eq!(map.text(ctx), display_text);
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
let cx = cx.as_ref();
let map = DisplayMap::new(buffer.clone(), 4, cx);
assert_eq!(map.text(cx), display_text);
let map = map.snapshot(ctx);
let map = map.snapshot(cx);
for (input_column, bias, output_column) in vec![
("'a', '".len(), Left, "'a', '".len()),
("'a', '".len() + 1, Left, "'a', '".len()),
@@ -648,53 +647,53 @@ mod tests {
}
#[gpui::test]
fn test_tabs_with_multibyte_chars(app: &mut gpui::MutableAppContext) {
fn test_tabs_with_multibyte_chars(cx: &mut gpui::MutableAppContext) {
let text = "\t\tα\nβ\t\n🏀β\t\tγ";
let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
let ctx = app.as_ref();
let map = DisplayMap::new(buffer.clone(), 4, ctx);
assert_eq!(map.text(ctx), "α\nβ \n🏀β γ");
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
let cx = cx.as_ref();
let map = DisplayMap::new(buffer.clone(), 4, cx);
assert_eq!(map.text(cx), "α\nβ \n🏀β γ");
let point = Point::new(0, "\t\t".len() as u32);
let display_point = DisplayPoint::new(0, "".len() as u32);
assert_eq!(point.to_display_point(&map, ctx), display_point);
assert_eq!(display_point.to_buffer_point(&map, Bias::Left, ctx), point,);
assert_eq!(point.to_display_point(&map, cx), display_point);
assert_eq!(display_point.to_buffer_point(&map, Bias::Left, cx), point,);
let point = Point::new(1, "β\t".len() as u32);
let display_point = DisplayPoint::new(1, "β ".len() as u32);
assert_eq!(point.to_display_point(&map, ctx), display_point);
assert_eq!(display_point.to_buffer_point(&map, Bias::Left, ctx), point,);
assert_eq!(point.to_display_point(&map, cx), display_point);
assert_eq!(display_point.to_buffer_point(&map, Bias::Left, cx), point,);
let point = Point::new(2, "🏀β\t\t".len() as u32);
let display_point = DisplayPoint::new(2, "🏀β ".len() as u32);
assert_eq!(point.to_display_point(&map, ctx), display_point);
assert_eq!(display_point.to_buffer_point(&map, Bias::Left, ctx), point,);
assert_eq!(point.to_display_point(&map, cx), display_point);
assert_eq!(display_point.to_buffer_point(&map, Bias::Left, cx), point,);
// Display points inside of expanded tabs
assert_eq!(
DisplayPoint::new(0, "".len() as u32).to_buffer_point(&map, Bias::Right, ctx),
DisplayPoint::new(0, "".len() as u32).to_buffer_point(&map, Bias::Right, cx),
Point::new(0, "\t\t".len() as u32),
);
assert_eq!(
DisplayPoint::new(0, "".len() as u32).to_buffer_point(&map, Bias::Left, ctx),
DisplayPoint::new(0, "".len() as u32).to_buffer_point(&map, Bias::Left, cx),
Point::new(0, "\t".len() as u32),
);
assert_eq!(
map.snapshot(ctx)
map.snapshot(cx)
.chunks_at(DisplayPoint::new(0, "".len() as u32))
.collect::<String>(),
" α\nβ \n🏀β γ"
);
assert_eq!(
DisplayPoint::new(0, "".len() as u32).to_buffer_point(&map, Bias::Right, ctx),
DisplayPoint::new(0, "".len() as u32).to_buffer_point(&map, Bias::Right, cx),
Point::new(0, "\t".len() as u32),
);
assert_eq!(
DisplayPoint::new(0, "".len() as u32).to_buffer_point(&map, Bias::Left, ctx),
DisplayPoint::new(0, "".len() as u32).to_buffer_point(&map, Bias::Left, cx),
Point::new(0, "".len() as u32),
);
assert_eq!(
map.snapshot(ctx)
map.snapshot(cx)
.chunks_at(DisplayPoint::new(0, "".len() as u32))
.collect::<String>(),
" α\nβ \n🏀β γ"
@@ -702,21 +701,21 @@ mod tests {
// Clipping display points inside of multi-byte characters
assert_eq!(
map.snapshot(ctx)
map.snapshot(cx)
.clip_point(DisplayPoint::new(0, "".len() as u32 - 1), Bias::Left),
DisplayPoint::new(0, 0)
);
assert_eq!(
map.snapshot(ctx)
map.snapshot(cx)
.clip_point(DisplayPoint::new(0, "".len() as u32 - 1), Bias::Right),
DisplayPoint::new(0, "".len() as u32)
);
}
#[gpui::test]
fn test_max_point(app: &mut gpui::MutableAppContext) {
let buffer = app.add_model(|ctx| Buffer::new(0, "aaa\n\t\tbbb", ctx));
let map = DisplayMap::new(buffer.clone(), 4, app.as_ref());
assert_eq!(map.max_point(app.as_ref()), DisplayPoint::new(1, 11))
fn test_max_point(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, "aaa\n\t\tbbb", cx));
let map = DisplayMap::new(buffer.clone(), 4, cx.as_ref());
assert_eq!(map.max_point(cx.as_ref()), DisplayPoint::new(1, 11))
}
}
+143 -147
View File
@@ -23,8 +23,8 @@ pub struct FoldMap {
}
impl FoldMap {
pub fn new(buffer_handle: ModelHandle<Buffer>, ctx: &AppContext) -> Self {
let buffer = buffer_handle.read(ctx);
pub fn new(buffer_handle: ModelHandle<Buffer>, cx: &AppContext) -> Self {
let buffer = buffer_handle.read(cx);
let text_summary = buffer.text_summary();
Self {
buffer: buffer_handle,
@@ -43,56 +43,56 @@ impl FoldMap {
}
}
pub fn snapshot(&self, ctx: &AppContext) -> FoldMapSnapshot {
pub fn snapshot(&self, cx: &AppContext) -> FoldMapSnapshot {
FoldMapSnapshot {
transforms: self.sync(ctx).clone(),
buffer: self.buffer.read(ctx).snapshot(),
transforms: self.sync(cx).clone(),
buffer: self.buffer.read(cx).snapshot(),
}
}
pub fn len(&self, ctx: &AppContext) -> usize {
self.sync(ctx).summary().display.bytes
pub fn len(&self, cx: &AppContext) -> usize {
self.sync(cx).summary().display.bytes
}
pub fn line_len(&self, row: u32, ctx: &AppContext) -> u32 {
let line_start = self.to_display_offset(DisplayPoint::new(row, 0), ctx).0;
let line_end = if row >= self.max_point(ctx).row() {
self.len(ctx)
pub fn line_len(&self, row: u32, cx: &AppContext) -> u32 {
let line_start = self.to_display_offset(DisplayPoint::new(row, 0), cx).0;
let line_end = if row >= self.max_point(cx).row() {
self.len(cx)
} else {
self.to_display_offset(DisplayPoint::new(row + 1, 0), ctx).0 - 1
self.to_display_offset(DisplayPoint::new(row + 1, 0), cx).0 - 1
};
(line_end - line_start) as u32
}
pub fn max_point(&self, ctx: &AppContext) -> DisplayPoint {
DisplayPoint(self.sync(ctx).summary().display.lines)
pub fn max_point(&self, cx: &AppContext) -> DisplayPoint {
DisplayPoint(self.sync(cx).summary().display.lines)
}
pub fn longest_row(&self, ctx: &AppContext) -> u32 {
self.sync(ctx).summary().display.longest_row
pub fn longest_row(&self, cx: &AppContext) -> u32 {
self.sync(cx).summary().display.longest_row
}
pub fn folds_in_range<'a, T>(
&'a self,
range: Range<T>,
ctx: &'a AppContext,
cx: &'a AppContext,
) -> impl Iterator<Item = &'a Range<Anchor>>
where
T: ToOffset,
{
self.intersecting_folds(range, ctx).map(|f| &f.0)
self.intersecting_folds(range, cx).map(|f| &f.0)
}
pub fn fold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
ctx: &AppContext,
cx: &AppContext,
) {
let _ = self.sync(ctx);
let _ = self.sync(cx);
let mut edits = Vec::new();
let mut folds = Vec::new();
let buffer = self.buffer.read(ctx);
let buffer = self.buffer.read(cx);
for range in ranges.into_iter() {
let range = range.start.to_offset(buffer)..range.end.to_offset(buffer);
if range.start != range.end {
@@ -124,23 +124,23 @@ impl FoldMap {
new_tree.push_tree(cursor.suffix(buffer), buffer);
new_tree
};
self.apply_edits(edits, ctx);
self.apply_edits(edits, cx);
}
pub fn unfold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
ctx: &AppContext,
cx: &AppContext,
) {
let _ = self.sync(ctx);
let _ = self.sync(cx);
let buffer = self.buffer.read(ctx);
let buffer = self.buffer.read(cx);
let mut edits = Vec::new();
let mut fold_ixs_to_delete = Vec::new();
for range in ranges.into_iter() {
// Remove intersecting folds and add their ranges to edits that are passed to apply_edits.
let mut folds_cursor = self.intersecting_folds(range, ctx);
let mut folds_cursor = self.intersecting_folds(range, cx);
while let Some(fold) = folds_cursor.item() {
let offset_range = fold.0.start.to_offset(buffer)..fold.0.end.to_offset(buffer);
edits.push(Edit {
@@ -172,18 +172,18 @@ impl FoldMap {
folds.push_tree(cursor.suffix(buffer), buffer);
folds
};
self.apply_edits(edits, ctx);
self.apply_edits(edits, cx);
}
fn intersecting_folds<'a, T>(
&self,
range: Range<T>,
ctx: &'a AppContext,
cx: &'a AppContext,
) -> FilterCursor<impl 'a + Fn(&FoldSummary) -> bool, Fold, usize>
where
T: ToOffset,
{
let buffer = self.buffer.read(ctx);
let buffer = self.buffer.read(cx);
let start = buffer.anchor_before(range.start.to_offset(buffer));
let end = buffer.anchor_after(range.end.to_offset(buffer));
self.folds.filter::<_, usize>(move |summary| {
@@ -192,20 +192,20 @@ impl FoldMap {
})
}
pub fn intersects_fold<T>(&self, offset: T, ctx: &AppContext) -> bool
pub fn intersects_fold<T>(&self, offset: T, cx: &AppContext) -> bool
where
T: ToOffset,
{
let buffer = self.buffer.read(ctx);
let buffer = self.buffer.read(cx);
let offset = offset.to_offset(buffer);
let transforms = self.sync(ctx);
let transforms = self.sync(cx);
let mut cursor = transforms.cursor::<usize, usize>();
cursor.seek(&offset, SeekBias::Right, &());
cursor.item().map_or(false, |t| t.display_text.is_some())
}
pub fn is_line_folded(&self, display_row: u32, ctx: &AppContext) -> bool {
let transforms = self.sync(ctx);
pub fn is_line_folded(&self, display_row: u32, cx: &AppContext) -> bool {
let transforms = self.sync(cx);
let mut cursor = transforms.cursor::<DisplayPoint, DisplayPoint>();
cursor.seek(&DisplayPoint::new(display_row, 0), SeekBias::Right, &());
while let Some(transform) = cursor.item() {
@@ -221,24 +221,24 @@ impl FoldMap {
false
}
pub fn to_buffer_offset(&self, point: DisplayPoint, ctx: &AppContext) -> usize {
self.snapshot(ctx).to_buffer_offset(point)
pub fn to_buffer_offset(&self, point: DisplayPoint, cx: &AppContext) -> usize {
self.snapshot(cx).to_buffer_offset(point)
}
pub fn to_display_offset(&self, point: DisplayPoint, ctx: &AppContext) -> DisplayOffset {
self.snapshot(ctx).to_display_offset(point)
pub fn to_display_offset(&self, point: DisplayPoint, cx: &AppContext) -> DisplayOffset {
self.snapshot(cx).to_display_offset(point)
}
pub fn to_buffer_point(&self, display_point: DisplayPoint, ctx: &AppContext) -> Point {
let transforms = self.sync(ctx);
pub fn to_buffer_point(&self, display_point: DisplayPoint, cx: &AppContext) -> Point {
let transforms = self.sync(cx);
let mut cursor = transforms.cursor::<DisplayPoint, TransformSummary>();
cursor.seek(&display_point, SeekBias::Right, &());
let overshoot = display_point.0 - cursor.start().display.lines;
cursor.start().buffer.lines + overshoot
}
pub fn to_display_point(&self, point: Point, ctx: &AppContext) -> DisplayPoint {
let transforms = self.sync(ctx);
pub fn to_display_point(&self, point: Point, cx: &AppContext) -> DisplayPoint {
let transforms = self.sync(cx);
let mut cursor = transforms.cursor::<Point, TransformSummary>();
cursor.seek(&point, SeekBias::Right, &());
let overshoot = point - cursor.start().buffer.lines;
@@ -248,18 +248,18 @@ impl FoldMap {
))
}
fn sync(&self, ctx: &AppContext) -> MutexGuard<SumTree<Transform>> {
let buffer = self.buffer.read(ctx);
fn sync(&self, cx: &AppContext) -> MutexGuard<SumTree<Transform>> {
let buffer = self.buffer.read(cx);
let mut edits = buffer.edits_since(self.last_sync.lock().clone()).peekable();
if edits.peek().is_some() {
self.apply_edits(edits, ctx);
self.apply_edits(edits, cx);
}
*self.last_sync.lock() = buffer.version();
self.transforms.lock()
}
fn apply_edits(&self, edits: impl IntoIterator<Item = Edit>, ctx: &AppContext) {
let buffer = self.buffer.read(ctx);
fn apply_edits(&self, edits: impl IntoIterator<Item = Edit>, cx: &AppContext) {
let buffer = self.buffer.read(cx);
let mut edits = edits.into_iter().peekable();
let mut new_transforms = SumTree::new();
@@ -846,20 +846,20 @@ mod tests {
use crate::test::sample_text;
#[gpui::test]
fn test_basic_folds(app: &mut gpui::MutableAppContext) {
let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
fn test_basic_folds(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
map.fold(
vec![
Point::new(0, 2)..Point::new(2, 2),
Point::new(2, 4)..Point::new(4, 1),
],
app.as_ref(),
cx.as_ref(),
);
assert_eq!(map.text(app.as_ref()), "aa…cc…eeeee");
assert_eq!(map.text(cx.as_ref()), "aa…cc…eeeee");
buffer.update(app, |buffer, ctx| {
buffer.update(cx, |buffer, cx| {
buffer
.edit(
vec![
@@ -867,70 +867,70 @@ mod tests {
Point::new(2, 3)..Point::new(2, 3),
],
"123",
Some(ctx),
Some(cx),
)
.unwrap();
});
assert_eq!(map.text(app.as_ref()), "123a…c123c…eeeee");
assert_eq!(map.text(cx.as_ref()), "123a…c123c…eeeee");
buffer.update(app, |buffer, ctx| {
buffer.update(cx, |buffer, cx| {
let start_version = buffer.version.clone();
buffer
.edit(Some(Point::new(2, 6)..Point::new(4, 3)), "456", Some(ctx))
.edit(Some(Point::new(2, 6)..Point::new(4, 3)), "456", Some(cx))
.unwrap();
buffer.edits_since(start_version).collect::<Vec<_>>()
});
assert_eq!(map.text(app.as_ref()), "123a…c123456eee");
assert_eq!(map.text(cx.as_ref()), "123a…c123456eee");
map.unfold(Some(Point::new(0, 4)..Point::new(0, 5)), app.as_ref());
assert_eq!(map.text(app.as_ref()), "123aaaaa\nbbbbbb\nccc123456eee");
map.unfold(Some(Point::new(0, 4)..Point::new(0, 5)), cx.as_ref());
assert_eq!(map.text(cx.as_ref()), "123aaaaa\nbbbbbb\nccc123456eee");
}
#[gpui::test]
fn test_adjacent_folds(app: &mut gpui::MutableAppContext) {
let buffer = app.add_model(|ctx| Buffer::new(0, "abcdefghijkl", ctx));
fn test_adjacent_folds(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, "abcdefghijkl", cx));
{
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
map.fold(vec![5..8], app.as_ref());
map.check_invariants(app.as_ref());
assert_eq!(map.text(app.as_ref()), "abcde…ijkl");
map.fold(vec![5..8], cx.as_ref());
map.check_invariants(cx.as_ref());
assert_eq!(map.text(cx.as_ref()), "abcde…ijkl");
// Create an fold adjacent to the start of the first fold.
map.fold(vec![0..1, 2..5], app.as_ref());
map.check_invariants(app.as_ref());
assert_eq!(map.text(app.as_ref()), "…b…ijkl");
map.fold(vec![0..1, 2..5], cx.as_ref());
map.check_invariants(cx.as_ref());
assert_eq!(map.text(cx.as_ref()), "…b…ijkl");
// Create an fold adjacent to the end of the first fold.
map.fold(vec![11..11, 8..10], app.as_ref());
map.check_invariants(app.as_ref());
assert_eq!(map.text(app.as_ref()), "…b…kl");
map.fold(vec![11..11, 8..10], cx.as_ref());
map.check_invariants(cx.as_ref());
assert_eq!(map.text(cx.as_ref()), "…b…kl");
}
{
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
// Create two adjacent folds.
map.fold(vec![0..2, 2..5], app.as_ref());
map.check_invariants(app.as_ref());
assert_eq!(map.text(app.as_ref()), "…fghijkl");
map.fold(vec![0..2, 2..5], cx.as_ref());
map.check_invariants(cx.as_ref());
assert_eq!(map.text(cx.as_ref()), "…fghijkl");
// Edit within one of the folds.
buffer.update(app, |buffer, ctx| {
buffer.update(cx, |buffer, cx| {
let version = buffer.version();
buffer.edit(vec![0..1], "12345", Some(ctx)).unwrap();
buffer.edit(vec![0..1], "12345", Some(cx)).unwrap();
buffer.edits_since(version).collect::<Vec<_>>()
});
map.check_invariants(app.as_ref());
assert_eq!(map.text(app.as_ref()), "12345…fghijkl");
map.check_invariants(cx.as_ref());
assert_eq!(map.text(cx.as_ref()), "12345…fghijkl");
}
}
#[gpui::test]
fn test_overlapping_folds(app: &mut gpui::MutableAppContext) {
let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
fn test_overlapping_folds(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
map.fold(
vec![
Point::new(0, 2)..Point::new(2, 2),
@@ -938,38 +938,38 @@ mod tests {
Point::new(1, 2)..Point::new(3, 2),
Point::new(3, 1)..Point::new(4, 1),
],
app.as_ref(),
cx.as_ref(),
);
assert_eq!(map.text(app.as_ref()), "aa…eeeee");
assert_eq!(map.text(cx.as_ref()), "aa…eeeee");
}
#[gpui::test]
fn test_merging_folds_via_edit(app: &mut gpui::MutableAppContext) {
let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
fn test_merging_folds_via_edit(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
map.fold(
vec![
Point::new(0, 2)..Point::new(2, 2),
Point::new(3, 1)..Point::new(4, 1),
],
app.as_ref(),
cx.as_ref(),
);
assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee");
assert_eq!(map.text(cx.as_ref()), "aa…cccc\nd…eeeee");
buffer.update(app, |buffer, ctx| {
buffer.update(cx, |buffer, cx| {
buffer
.edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", Some(ctx))
.edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", Some(cx))
.unwrap();
});
assert_eq!(map.text(app.as_ref()), "aa…eeeee");
assert_eq!(map.text(cx.as_ref()), "aa…eeeee");
}
#[gpui::test]
fn test_folds_in_range(app: &mut gpui::MutableAppContext) {
let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx));
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
let buffer = buffer.read(app);
fn test_folds_in_range(cx: &mut gpui::MutableAppContext) {
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6), cx));
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
let buffer = buffer.read(cx);
map.fold(
vec![
@@ -978,10 +978,10 @@ mod tests {
Point::new(1, 2)..Point::new(3, 2),
Point::new(3, 1)..Point::new(4, 1),
],
app.as_ref(),
cx.as_ref(),
);
let fold_ranges = map
.folds_in_range(Point::new(1, 0)..Point::new(1, 3), app.as_ref())
.folds_in_range(Point::new(1, 0)..Point::new(1, 3), cx.as_ref())
.map(|fold| fold.start.to_point(buffer)..fold.end.to_point(buffer))
.collect::<Vec<_>>();
assert_eq!(
@@ -994,7 +994,7 @@ mod tests {
}
#[gpui::test]
fn test_random_folds(app: &mut gpui::MutableAppContext) {
fn test_random_folds(cx: &mut gpui::MutableAppContext) {
use crate::editor::ToPoint;
use crate::util::RandomCharIter;
use rand::prelude::*;
@@ -1018,18 +1018,18 @@ mod tests {
dbg!(seed);
let mut rng = StdRng::seed_from_u64(seed);
let buffer = app.add_model(|ctx| {
let buffer = cx.add_model(|cx| {
let len = rng.gen_range(0..10);
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
Buffer::new(0, text, ctx)
Buffer::new(0, text, cx)
});
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
for _ in 0..operations {
log::info!("text: {:?}", buffer.read(app).text());
log::info!("text: {:?}", buffer.read(cx).text());
match rng.gen_range(0..=100) {
0..=34 => {
let buffer = buffer.read(app);
let buffer = buffer.read(cx);
let mut to_fold = Vec::new();
for _ in 0..rng.gen_range(1..=5) {
let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
@@ -1037,10 +1037,10 @@ mod tests {
to_fold.push(start..end);
}
log::info!("folding {:?}", to_fold);
map.fold(to_fold, app.as_ref());
map.fold(to_fold, cx.as_ref());
}
35..=59 if !map.folds.is_empty() => {
let buffer = buffer.read(app);
let buffer = buffer.read(cx);
let mut to_unfold = Vec::new();
for _ in 0..rng.gen_range(1..=3) {
let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
@@ -1048,25 +1048,25 @@ mod tests {
to_unfold.push(start..end);
}
log::info!("unfolding {:?}", to_unfold);
map.unfold(to_unfold, app.as_ref());
map.unfold(to_unfold, cx.as_ref());
}
_ => {
let edits = buffer.update(app, |buffer, ctx| {
let edits = buffer.update(cx, |buffer, cx| {
let start_version = buffer.version.clone();
let edit_count = rng.gen_range(1..=5);
buffer.randomly_edit(&mut rng, edit_count, Some(ctx));
buffer.randomly_edit(&mut rng, edit_count, Some(cx));
buffer.edits_since(start_version).collect::<Vec<_>>()
});
log::info!("editing {:?}", edits);
}
}
map.check_invariants(app.as_ref());
map.check_invariants(cx.as_ref());
let buffer = map.buffer.read(app);
let buffer = map.buffer.read(cx);
let mut expected_text = buffer.text();
let mut expected_buffer_rows = Vec::new();
let mut next_row = buffer.max_point().row;
for fold_range in map.merged_fold_ranges(app.as_ref()).into_iter().rev() {
for fold_range in map.merged_fold_ranges(cx.as_ref()).into_iter().rev() {
let fold_start = buffer.point_for_offset(fold_range.start).unwrap();
let fold_end = buffer.point_for_offset(fold_range.end).unwrap();
expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev());
@@ -1077,14 +1077,14 @@ mod tests {
expected_buffer_rows.extend((0..=next_row).rev());
expected_buffer_rows.reverse();
assert_eq!(map.text(app.as_ref()), expected_text);
assert_eq!(map.text(cx.as_ref()), expected_text);
for (display_row, line) in expected_text.lines().enumerate() {
let line_len = map.line_len(display_row as u32, app.as_ref());
let line_len = map.line_len(display_row as u32, cx.as_ref());
assert_eq!(line_len, line.len() as u32);
}
let longest_row = map.longest_row(app.as_ref());
let longest_row = map.longest_row(cx.as_ref());
let longest_char_column = expected_text
.split('\n')
.nth(longest_row as usize)
@@ -1095,22 +1095,22 @@ mod tests {
let mut display_offset = DisplayOffset(0);
let mut char_column = 0;
for c in expected_text.chars() {
let buffer_point = map.to_buffer_point(display_point, app.as_ref());
let buffer_point = map.to_buffer_point(display_point, cx.as_ref());
let buffer_offset = buffer_point.to_offset(buffer);
assert_eq!(
map.to_display_point(buffer_point, app.as_ref()),
map.to_display_point(buffer_point, cx.as_ref()),
display_point,
"to_display_point({:?})",
buffer_point,
);
assert_eq!(
map.to_buffer_offset(display_point, app.as_ref()),
map.to_buffer_offset(display_point, cx.as_ref()),
buffer_offset,
"to_buffer_offset({:?})",
display_point,
);
assert_eq!(
map.to_display_offset(display_point, app.as_ref()),
map.to_display_offset(display_point, cx.as_ref()),
display_offset,
"to_display_offset({:?})",
display_point,
@@ -1137,12 +1137,12 @@ mod tests {
}
for _ in 0..5 {
let offset = map.snapshot(app.as_ref()).clip_offset(
DisplayOffset(rng.gen_range(0..=map.len(app.as_ref()))),
let offset = map.snapshot(cx.as_ref()).clip_offset(
DisplayOffset(rng.gen_range(0..=map.len(cx.as_ref()))),
Bias::Right,
);
assert_eq!(
map.snapshot(app.as_ref())
map.snapshot(cx.as_ref())
.chunks_at(offset)
.collect::<String>(),
&expected_text[offset.0..],
@@ -1151,20 +1151,20 @@ mod tests {
for (idx, buffer_row) in expected_buffer_rows.iter().enumerate() {
let display_row = map
.to_display_point(Point::new(*buffer_row, 0), app.as_ref())
.to_display_point(Point::new(*buffer_row, 0), cx.as_ref())
.row();
assert_eq!(
map.snapshot(app.as_ref())
map.snapshot(cx.as_ref())
.buffer_rows(display_row)
.collect::<Vec<_>>(),
expected_buffer_rows[idx..],
);
}
for fold_range in map.merged_fold_ranges(app.as_ref()) {
for fold_range in map.merged_fold_ranges(cx.as_ref()) {
let display_point =
map.to_display_point(fold_range.start.to_point(buffer), app.as_ref());
assert!(map.is_line_folded(display_point.row(), app.as_ref()));
map.to_display_point(fold_range.start.to_point(buffer), cx.as_ref());
assert!(map.is_line_folded(display_point.row(), cx.as_ref()));
}
for _ in 0..5 {
@@ -1184,7 +1184,7 @@ mod tests {
.collect::<Vec<_>>();
assert_eq!(
map.folds_in_range(start..end, app.as_ref())
map.folds_in_range(start..end, cx.as_ref())
.cloned()
.collect::<Vec<_>>(),
expected_folds
@@ -1195,42 +1195,38 @@ mod tests {
}
#[gpui::test]
fn test_buffer_rows(app: &mut gpui::MutableAppContext) {
fn test_buffer_rows(cx: &mut gpui::MutableAppContext) {
let text = sample_text(6, 6) + "\n";
let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx));
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
let mut map = FoldMap::new(buffer.clone(), cx.as_ref());
map.fold(
vec![
Point::new(0, 2)..Point::new(2, 2),
Point::new(3, 1)..Point::new(4, 1),
],
app.as_ref(),
cx.as_ref(),
);
assert_eq!(map.text(app.as_ref()), "aa…cccc\nd…eeeee\nffffff\n");
assert_eq!(map.text(cx.as_ref()), "aa…cccc\nd…eeeee\nffffff\n");
assert_eq!(
map.snapshot(app.as_ref())
.buffer_rows(0)
.collect::<Vec<_>>(),
map.snapshot(cx.as_ref()).buffer_rows(0).collect::<Vec<_>>(),
vec![0, 3, 5, 6]
);
assert_eq!(
map.snapshot(app.as_ref())
.buffer_rows(3)
.collect::<Vec<_>>(),
map.snapshot(cx.as_ref()).buffer_rows(3).collect::<Vec<_>>(),
vec![6]
);
}
impl FoldMap {
fn text(&self, app: &AppContext) -> String {
self.snapshot(app).chunks_at(DisplayOffset(0)).collect()
fn text(&self, cx: &AppContext) -> String {
self.snapshot(cx).chunks_at(DisplayOffset(0)).collect()
}
fn merged_fold_ranges(&self, app: &AppContext) -> Vec<Range<usize>> {
let buffer = self.buffer.read(app);
fn merged_fold_ranges(&self, cx: &AppContext) -> Vec<Range<usize>> {
let buffer = self.buffer.read(cx);
let mut folds = self.folds.items();
// Ensure sorting doesn't change how folds get merged and displayed.
folds.sort_by(|a, b| a.0.cmp(&b.0, buffer).unwrap());
@@ -1258,9 +1254,9 @@ mod tests {
merged_ranges
}
fn check_invariants(&self, ctx: &AppContext) {
let transforms = self.sync(ctx);
let buffer = self.buffer.read(ctx);
fn check_invariants(&self, cx: &AppContext) {
let transforms = self.sync(cx);
let buffer = self.buffer.read(cx);
assert_eq!(
transforms.summary().buffer.bytes,
buffer.len(),
@@ -1,4 +1,4 @@
use super::{BufferView, DisplayPoint, SelectAction};
use super::{DisplayPoint, Editor, SelectAction};
use gpui::{
color::{ColorF, ColorU},
geometry::{
@@ -16,17 +16,17 @@ use smallvec::SmallVec;
use std::cmp::Ordering;
use std::cmp::{self};
pub struct BufferElement {
view: WeakViewHandle<BufferView>,
pub struct EditorElement {
view: WeakViewHandle<Editor>,
}
impl BufferElement {
pub fn new(view: WeakViewHandle<BufferView>) -> Self {
impl EditorElement {
pub fn new(view: WeakViewHandle<Editor>) -> Self {
Self { view }
}
fn view<'a>(&self, ctx: &'a AppContext) -> &'a BufferView {
self.view.upgrade(ctx).unwrap().read(ctx)
fn view<'a>(&self, cx: &'a AppContext) -> &'a Editor {
self.view.upgrade(cx).unwrap().read(cx)
}
fn mouse_down(
@@ -35,22 +35,21 @@ impl BufferElement {
cmd: bool,
layout: &mut LayoutState,
paint: &mut PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
if paint.text_bounds.contains_point(position) {
let view = self.view(ctx.app);
let position =
paint.point_for_position(view, layout, position, ctx.font_cache, ctx.app);
ctx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd });
let view = self.view(cx.app);
let position = paint.point_for_position(view, layout, position, cx.font_cache, cx.app);
cx.dispatch_action("buffer:select", SelectAction::Begin { position, add: cmd });
true
} else {
false
}
}
fn mouse_up(&self, _position: Vector2F, ctx: &mut EventContext) -> bool {
if self.view(ctx.app).is_selecting() {
ctx.dispatch_action("buffer:select", SelectAction::End);
fn mouse_up(&self, _position: Vector2F, cx: &mut EventContext) -> bool {
if self.view(cx.app).is_selecting() {
cx.dispatch_action("buffer:select", SelectAction::End);
true
} else {
false
@@ -62,15 +61,15 @@ impl BufferElement {
position: Vector2F,
layout: &mut LayoutState,
paint: &mut PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
let view = self.view(ctx.app);
let view = self.view(cx.app);
if view.is_selecting() {
let rect = paint.text_bounds;
let mut scroll_delta = Vector2F::zero();
let vertical_margin = view.line_height(ctx.font_cache).min(rect.height() / 3.0);
let vertical_margin = view.line_height(cx.font_cache).min(rect.height() / 3.0);
let top = rect.origin_y() + vertical_margin;
let bottom = rect.lower_left().y() - vertical_margin;
if position.y() < top {
@@ -80,7 +79,7 @@ impl BufferElement {
scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom))
}
let horizontal_margin = view.line_height(ctx.font_cache).min(rect.width() / 3.0);
let horizontal_margin = view.line_height(cx.font_cache).min(rect.width() / 3.0);
let left = rect.origin_x() + horizontal_margin;
let right = rect.upper_right().x() - horizontal_margin;
if position.x() < left {
@@ -94,19 +93,19 @@ impl BufferElement {
))
}
ctx.dispatch_action(
cx.dispatch_action(
"buffer:select",
SelectAction::Update {
position: paint.point_for_position(
view,
layout,
position,
ctx.font_cache,
ctx.app,
cx.font_cache,
cx.app,
),
scroll_position: (view.scroll_position() + scroll_delta).clamp(
Vector2F::zero(),
layout.scroll_max(view, ctx.font_cache, ctx.text_layout_cache, ctx.app),
layout.scroll_max(view, cx.font_cache, cx.text_layout_cache, cx.app),
),
},
);
@@ -116,17 +115,17 @@ impl BufferElement {
}
}
fn key_down(&self, chars: &str, ctx: &mut EventContext) -> bool {
let view = self.view.upgrade(ctx.app).unwrap();
fn key_down(&self, chars: &str, cx: &mut EventContext) -> bool {
let view = self.view.upgrade(cx.app).unwrap();
if view.is_focused(ctx.app) {
if view.is_focused(cx.app) {
if chars.is_empty() {
false
} else {
if chars.chars().any(|c| c.is_control()) {
false
} else {
ctx.dispatch_action("buffer:insert", chars.to_string());
cx.dispatch_action("buffer:insert", chars.to_string());
true
}
}
@@ -142,15 +141,15 @@ impl BufferElement {
precise: bool,
layout: &mut LayoutState,
paint: &mut PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
if !paint.bounds.contains_point(position) {
return false;
}
let view = self.view(ctx.app);
let font_cache = &ctx.font_cache;
let layout_cache = &ctx.text_layout_cache;
let view = self.view(cx.app);
let font_cache = &cx.font_cache;
let layout_cache = &cx.text_layout_cache;
let max_glyph_width = view.em_width(font_cache);
let line_height = view.line_height(font_cache);
if !precise {
@@ -161,21 +160,21 @@ impl BufferElement {
let y = (view.scroll_position().y() * line_height - delta.y()) / line_height;
let scroll_position = vec2f(x, y).clamp(
Vector2F::zero(),
layout.scroll_max(view, font_cache, layout_cache, ctx.app),
layout.scroll_max(view, font_cache, layout_cache, cx.app),
);
ctx.dispatch_action("buffer:scroll", scroll_position);
cx.dispatch_action("buffer:scroll", scroll_position);
true
}
fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, ctx: &mut PaintContext) {
let view = self.view(ctx.app);
let line_height = view.line_height(ctx.font_cache);
fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, cx: &mut PaintContext) {
let view = self.view(cx.app);
let line_height = view.line_height(cx.font_cache);
let scroll_top = view.scroll_position().y() * line_height;
ctx.scene.push_layer(Some(rect));
ctx.scene.push_quad(Quad {
cx.scene.push_layer(Some(rect));
cx.scene.push_quad(Quad {
bounds: rect,
background: Some(ColorU::white()),
border: Border::new(0., ColorU::transparent_black()),
@@ -191,25 +190,25 @@ impl BufferElement {
line.paint(
line_origin,
RectF::new(vec2f(0., 0.), vec2f(line.width(), line_height)),
ctx,
cx,
);
}
ctx.scene.pop_layer();
cx.scene.pop_layer();
}
fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, ctx: &mut PaintContext) {
let view = self.view(ctx.app);
let line_height = view.line_height(ctx.font_cache);
let descent = view.font_descent(ctx.font_cache);
fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, cx: &mut PaintContext) {
let view = self.view(cx.app);
let line_height = view.line_height(cx.font_cache);
let descent = view.font_descent(cx.font_cache);
let start_row = view.scroll_position().y() as u32;
let scroll_top = view.scroll_position().y() * line_height;
let end_row = ((scroll_top + bounds.height()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
let max_glyph_width = view.em_width(ctx.font_cache);
let max_glyph_width = view.em_width(cx.font_cache);
let scroll_left = view.scroll_position().x() * max_glyph_width;
ctx.scene.push_layer(Some(bounds));
ctx.scene.push_quad(Quad {
cx.scene.push_layer(Some(bounds));
cx.scene.push_quad(Quad {
bounds,
background: Some(ColorU::white()),
border: Border::new(0., ColorU::transparent_black()),
@@ -224,7 +223,7 @@ impl BufferElement {
for selection in view.selections_in_range(
DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
ctx.app,
cx.app,
) {
if selection.start != selection.end {
let range_start = cmp::min(selection.start, selection.end);
@@ -263,7 +262,7 @@ impl BufferElement {
.collect(),
};
selection.paint(bounds, ctx.scene);
selection.paint(bounds, cx.scene);
}
if view.cursors_visible() {
@@ -288,49 +287,49 @@ impl BufferElement {
line.paint(
content_origin + vec2f(-scroll_left, row as f32 * line_height - scroll_top),
RectF::new(vec2f(scroll_left, 0.), vec2f(bounds.width(), line_height)),
ctx,
cx,
);
}
ctx.scene.push_layer(Some(bounds));
cx.scene.push_layer(Some(bounds));
for cursor in cursors {
cursor.paint(ctx);
cursor.paint(cx);
}
ctx.scene.pop_layer();
cx.scene.pop_layer();
ctx.scene.pop_layer();
cx.scene.pop_layer();
}
}
impl Element for BufferElement {
impl Element for EditorElement {
type LayoutState = Option<LayoutState>;
type PaintState = Option<PaintState>;
fn layout(
&mut self,
constraint: SizeConstraint,
ctx: &mut LayoutContext,
cx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
let app = ctx.app;
let app = cx.app;
let mut size = constraint.max;
if size.y().is_infinite() {
let view = self.view(app);
size.set_y((view.max_point(app).row() + 1) as f32 * view.line_height(ctx.font_cache));
size.set_y((view.max_point(app).row() + 1) as f32 * view.line_height(cx.font_cache));
}
if size.x().is_infinite() {
unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
}
let view = self.view(app);
let font_cache = &ctx.font_cache;
let layout_cache = &ctx.text_layout_cache;
let font_cache = &cx.font_cache;
let layout_cache = &cx.text_layout_cache;
let line_height = view.line_height(font_cache);
let gutter_padding;
let gutter_width;
if view.is_gutter_visible() {
gutter_padding = view.em_width(ctx.font_cache);
match view.max_line_number_width(ctx.font_cache, ctx.text_layout_cache, app) {
gutter_padding = view.em_width(cx.font_cache);
match view.max_line_number_width(cx.font_cache, cx.text_layout_cache, app) {
Err(error) => {
log::error!("error computing max line number width: {}", error);
return (size, None);
@@ -348,7 +347,7 @@ impl Element for BufferElement {
let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, app);
let line_number_layouts = if view.is_gutter_visible() {
match view.layout_line_numbers(size.y(), ctx.font_cache, ctx.text_layout_cache, app) {
match view.layout_line_numbers(size.y(), cx.font_cache, cx.text_layout_cache, app) {
Err(error) => {
log::error!("error laying out line numbers: {}", error);
return (size, None);
@@ -400,15 +399,15 @@ impl Element for BufferElement {
&mut self,
_: Vector2F,
layout: &mut Option<LayoutState>,
ctx: &mut AfterLayoutContext,
cx: &mut AfterLayoutContext,
) {
if let Some(layout) = layout {
let app = ctx.app.as_ref();
let app = cx.app.as_ref();
let view = self.view(app);
view.clamp_scroll_left(
layout
.scroll_max(view, ctx.font_cache, ctx.text_layout_cache, app)
.scroll_max(view, cx.font_cache, cx.text_layout_cache, app)
.x(),
);
@@ -416,8 +415,8 @@ impl Element for BufferElement {
view.autoscroll_horizontally(
view.scroll_position().y() as u32,
layout.text_size.x(),
layout.scroll_width(view, ctx.font_cache, ctx.text_layout_cache, app),
view.em_width(ctx.font_cache),
layout.scroll_width(view, cx.font_cache, cx.text_layout_cache, app),
view.em_width(cx.font_cache),
&layout.line_layouts,
app,
);
@@ -429,7 +428,7 @@ impl Element for BufferElement {
&mut self,
bounds: RectF,
layout: &mut Self::LayoutState,
ctx: &mut PaintContext,
cx: &mut PaintContext,
) -> Self::PaintState {
if let Some(layout) = layout {
let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size);
@@ -438,10 +437,10 @@ impl Element for BufferElement {
layout.text_size,
);
if self.view(ctx.app).is_gutter_visible() {
self.paint_gutter(gutter_bounds, layout, ctx);
if self.view(cx.app).is_gutter_visible() {
self.paint_gutter(gutter_bounds, layout, cx);
}
self.paint_text(text_bounds, layout, ctx);
self.paint_text(text_bounds, layout, cx);
Some(PaintState {
bounds,
@@ -458,23 +457,23 @@ impl Element for BufferElement {
_: RectF,
layout: &mut Self::LayoutState,
paint: &mut Self::PaintState,
ctx: &mut EventContext,
cx: &mut EventContext,
) -> bool {
if let (Some(layout), Some(paint)) = (layout, paint) {
match event {
Event::LeftMouseDown { position, cmd } => {
self.mouse_down(*position, *cmd, layout, paint, ctx)
self.mouse_down(*position, *cmd, layout, paint, cx)
}
Event::LeftMouseUp { position } => self.mouse_up(*position, ctx),
Event::LeftMouseUp { position } => self.mouse_up(*position, cx),
Event::LeftMouseDragged { position } => {
self.mouse_dragged(*position, layout, paint, ctx)
self.mouse_dragged(*position, layout, paint, cx)
}
Event::ScrollWheel {
position,
delta,
precise,
} => self.scroll(*position, *delta, *precise, layout, paint, ctx),
Event::KeyDown { chars, .. } => self.key_down(chars, ctx),
} => self.scroll(*position, *delta, *precise, layout, paint, cx),
Event::KeyDown { chars, .. } => self.key_down(chars, cx),
_ => false,
}
} else {
@@ -510,14 +509,14 @@ pub struct LayoutState {
impl LayoutState {
fn scroll_width(
&self,
view: &BufferView,
view: &Editor,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
app: &AppContext,
cx: &AppContext,
) -> f32 {
let row = view.longest_row(app);
let row = view.longest_row(cx);
let longest_line_width = view
.layout_line(row, font_cache, layout_cache, app)
.layout_line(row, font_cache, layout_cache, cx)
.unwrap()
.width();
longest_line_width.max(self.max_visible_line_width) + view.em_width(font_cache)
@@ -525,16 +524,16 @@ impl LayoutState {
fn scroll_max(
&self,
view: &BufferView,
view: &Editor,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
app: &AppContext,
cx: &AppContext,
) -> Vector2F {
vec2f(
((self.scroll_width(view, font_cache, layout_cache, app) - self.text_size.x())
((self.scroll_width(view, font_cache, layout_cache, cx) - self.text_size.x())
/ view.em_width(font_cache))
.max(0.0),
view.max_point(app).row().saturating_sub(1) as f32,
view.max_point(cx).row().saturating_sub(1) as f32,
)
}
}
@@ -547,24 +546,24 @@ pub struct PaintState {
impl PaintState {
fn point_for_position(
&self,
view: &BufferView,
view: &Editor,
layout: &LayoutState,
position: Vector2F,
font_cache: &FontCache,
app: &AppContext,
cx: &AppContext,
) -> DisplayPoint {
let scroll_position = view.scroll_position();
let position = position - self.text_bounds.origin();
let y = position.y().max(0.0).min(layout.size.y());
let row = ((y / view.line_height(font_cache)) + scroll_position.y()) as u32;
let row = cmp::min(row, view.max_point(app).row());
let row = cmp::min(row, view.max_point(cx).row());
let line = &layout.line_layouts[(row - scroll_position.y() as u32) as usize];
let x = position.x() + (scroll_position.x() * view.em_width(font_cache));
let column = if x >= 0.0 {
line.index_for_x(x)
.map(|ix| ix as u32)
.unwrap_or(view.line_len(row, app))
.unwrap_or(view.line_len(row, cx))
} else {
0
};
@@ -579,8 +578,8 @@ struct Cursor {
}
impl Cursor {
fn paint(&self, ctx: &mut PaintContext) {
ctx.scene.push_quad(Quad {
fn paint(&self, cx: &mut PaintContext) {
cx.scene.push_quad(Quad {
bounds: RectF::new(self.origin, vec2f(2.0, self.line_height)),
background: Some(ColorU::black()),
border: Border::new(0., ColorU::black()),
-36
View File
@@ -1,36 +0,0 @@
mod buffer;
mod buffer_element;
pub mod buffer_view;
pub mod display_map;
pub mod movement;
pub use buffer::*;
pub use buffer_element::*;
pub use buffer_view::*;
pub use display_map::DisplayPoint;
use display_map::*;
use std::{
cmp,
ops::{Range, RangeInclusive},
};
#[derive(Copy, Clone)]
pub enum Bias {
Left,
Right,
}
trait RangeExt<T> {
fn sorted(&self) -> Range<T>;
fn to_inclusive(&self) -> RangeInclusive<T>;
}
impl<T: Ord + Clone> RangeExt<T> for Range<T> {
fn sorted(&self) -> Self {
cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
}
fn to_inclusive(&self) -> RangeInclusive<T> {
self.start.clone()..=self.end.clone()
}
}
+21 -21
View File
@@ -2,34 +2,34 @@ use super::{Bias, DisplayMap, DisplayPoint, SelectionGoal};
use anyhow::Result;
use gpui::AppContext;
pub fn left(map: &DisplayMap, mut point: DisplayPoint, app: &AppContext) -> Result<DisplayPoint> {
pub fn left(map: &DisplayMap, mut point: DisplayPoint, cx: &AppContext) -> Result<DisplayPoint> {
if point.column() > 0 {
*point.column_mut() -= 1;
} else if point.row() > 0 {
*point.row_mut() -= 1;
*point.column_mut() = map.line_len(point.row(), app);
*point.column_mut() = map.line_len(point.row(), cx);
}
Ok(map.snapshot(app).clip_point(point, Bias::Left))
Ok(map.snapshot(cx).clip_point(point, Bias::Left))
}
pub fn right(map: &DisplayMap, mut point: DisplayPoint, app: &AppContext) -> Result<DisplayPoint> {
let max_column = map.line_len(point.row(), app);
pub fn right(map: &DisplayMap, mut point: DisplayPoint, cx: &AppContext) -> Result<DisplayPoint> {
let max_column = map.line_len(point.row(), cx);
if point.column() < max_column {
*point.column_mut() += 1;
} else if point.row() < map.max_point(app).row() {
} else if point.row() < map.max_point(cx).row() {
*point.row_mut() += 1;
*point.column_mut() = 0;
}
Ok(map.snapshot(app).clip_point(point, Bias::Right))
Ok(map.snapshot(cx).clip_point(point, Bias::Right))
}
pub fn up(
map: &DisplayMap,
mut point: DisplayPoint,
goal: SelectionGoal,
app: &AppContext,
cx: &AppContext,
) -> Result<(DisplayPoint, SelectionGoal)> {
let map = map.snapshot(app);
let map = map.snapshot(cx);
let goal_column = if let SelectionGoal::Column(column) = goal {
column
} else {
@@ -50,10 +50,10 @@ pub fn down(
map: &DisplayMap,
mut point: DisplayPoint,
goal: SelectionGoal,
app: &AppContext,
cx: &AppContext,
) -> Result<(DisplayPoint, SelectionGoal)> {
let max_point = map.max_point(app);
let map = map.snapshot(app);
let max_point = map.max_point(cx);
let map = map.snapshot(cx);
let goal_column = if let SelectionGoal::Column(column) = goal {
column
} else {
@@ -74,9 +74,9 @@ pub fn line_beginning(
map: &DisplayMap,
point: DisplayPoint,
toggle_indent: bool,
app: &AppContext,
cx: &AppContext,
) -> Result<DisplayPoint> {
let (indent, is_blank) = map.line_indent(point.row(), app);
let (indent, is_blank) = map.line_indent(point.row(), cx);
if toggle_indent && !is_blank && point.column() != indent {
Ok(DisplayPoint::new(point.row(), indent))
} else {
@@ -84,30 +84,30 @@ pub fn line_beginning(
}
}
pub fn line_end(map: &DisplayMap, point: DisplayPoint, app: &AppContext) -> Result<DisplayPoint> {
pub fn line_end(map: &DisplayMap, point: DisplayPoint, cx: &AppContext) -> Result<DisplayPoint> {
Ok(DisplayPoint::new(
point.row(),
map.line_len(point.row(), app),
map.line_len(point.row(), cx),
))
}
pub fn prev_word_boundary(
map: &DisplayMap,
point: DisplayPoint,
app: &AppContext,
cx: &AppContext,
) -> Result<DisplayPoint> {
if point.column() == 0 {
if point.row() == 0 {
Ok(DisplayPoint::new(0, 0))
} else {
let row = point.row() - 1;
Ok(DisplayPoint::new(row, map.line_len(row, app)))
Ok(DisplayPoint::new(row, map.line_len(row, cx)))
}
} else {
let mut boundary = DisplayPoint::new(point.row(), 0);
let mut column = 0;
let mut prev_c = None;
for c in map.snapshot(app).chars_at(boundary) {
for c in map.snapshot(cx).chars_at(boundary) {
if column >= point.column() {
break;
}
@@ -126,10 +126,10 @@ pub fn prev_word_boundary(
pub fn next_word_boundary(
map: &DisplayMap,
mut point: DisplayPoint,
app: &AppContext,
cx: &AppContext,
) -> Result<DisplayPoint> {
let mut prev_c = None;
for c in map.snapshot(app).chars_at(point) {
for c in map.snapshot(cx).chars_at(point) {
if prev_c.is_some() && (c == '\n' || char_kind(prev_c.unwrap()) != char_kind(c)) {
break;
}
+137 -138
View File
@@ -1,5 +1,5 @@
use crate::{
editor::{buffer_view, BufferView},
editor::{self, Editor},
settings::Settings,
util,
workspace::Workspace,
@@ -28,7 +28,7 @@ pub struct FileFinder {
handle: WeakViewHandle<Self>,
settings: watch::Receiver<Settings>,
workspace: WeakViewHandle<Workspace>,
query_buffer: ViewHandle<BufferView>,
query_buffer: ViewHandle<Editor>,
search_count: usize,
latest_search_id: usize,
latest_search_did_cancel: bool,
@@ -39,15 +39,15 @@ pub struct FileFinder {
list_state: UniformListState,
}
pub fn init(app: &mut MutableAppContext) {
app.add_action("file_finder:toggle", FileFinder::toggle);
app.add_action("file_finder:confirm", FileFinder::confirm);
app.add_action("file_finder:select", FileFinder::select);
app.add_action("menu:select_prev", FileFinder::select_prev);
app.add_action("menu:select_next", FileFinder::select_next);
app.add_action("uniform_list:scroll", FileFinder::scroll);
pub fn init(cx: &mut MutableAppContext) {
cx.add_action("file_finder:toggle", FileFinder::toggle);
cx.add_action("file_finder:confirm", FileFinder::confirm);
cx.add_action("file_finder:select", FileFinder::select);
cx.add_action("menu:select_prev", FileFinder::select_prev);
cx.add_action("menu:select_next", FileFinder::select_next);
cx.add_action("uniform_list:scroll", FileFinder::scroll);
app.add_bindings(vec![
cx.add_bindings(vec![
Binding::new("cmd-p", "file_finder:toggle", None),
Binding::new("escape", "file_finder:toggle", Some("FileFinder")),
Binding::new("enter", "file_finder:confirm", Some("FileFinder")),
@@ -92,14 +92,14 @@ impl View for FileFinder {
.named("file finder")
}
fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
ctx.focus(&self.query_buffer);
fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
cx.focus(&self.query_buffer);
}
fn keymap_context(&self, _: &AppContext) -> keymap::Context {
let mut ctx = Self::default_keymap_context();
ctx.set.insert("menu".into());
ctx
let mut cx = Self::default_keymap_context();
cx.set.insert("menu".into());
cx
}
}
@@ -123,13 +123,13 @@ impl FileFinder {
let list = UniformList::new(
self.list_state.clone(),
self.matches.len(),
move |mut range, items, app| {
let finder = handle.upgrade(app).unwrap();
let finder = finder.read(app);
move |mut range, items, cx| {
let finder = handle.upgrade(cx).unwrap();
let finder = finder.read(cx);
let start = range.start;
range.end = cmp::min(range.end, finder.matches.len());
items.extend(finder.matches[range].iter().enumerate().filter_map(
move |(i, path_match)| finder.render_match(path_match, start + i, app),
move |(i, path_match)| finder.render_match(path_match, start + i, cx),
));
},
);
@@ -145,9 +145,9 @@ impl FileFinder {
&self,
path_match: &PathMatch,
index: usize,
app: &AppContext,
cx: &AppContext,
) -> Option<ElementBox> {
self.labels_for_match(path_match, app).map(
self.labels_for_match(path_match, cx).map(
|(file_name, file_name_positions, full_path, full_path_positions)| {
let settings = self.settings.borrow();
let highlight_color = ColorU::from_u32(0x304ee2ff);
@@ -208,8 +208,8 @@ impl FileFinder {
let entry = (path_match.tree_id, path_match.path.clone());
EventHandler::new(container.boxed())
.on_mouse_down(move |ctx| {
ctx.dispatch_action("file_finder:select", entry.clone());
.on_mouse_down(move |cx| {
cx.dispatch_action("file_finder:select", entry.clone());
true
})
.named("match")
@@ -220,9 +220,9 @@ impl FileFinder {
fn labels_for_match(
&self,
path_match: &PathMatch,
app: &AppContext,
cx: &AppContext,
) -> Option<(String, Vec<usize>, String, Vec<usize>)> {
self.worktree(path_match.tree_id, app).map(|tree| {
self.worktree(path_match.tree_id, cx).map(|tree| {
let prefix = if path_match.include_root_name {
tree.root_name()
} else {
@@ -254,12 +254,12 @@ impl FileFinder {
})
}
fn toggle(workspace_view: &mut Workspace, _: &(), ctx: &mut ViewContext<Workspace>) {
workspace_view.toggle_modal(ctx, |ctx, workspace_view| {
let workspace = ctx.handle();
fn toggle(workspace_view: &mut Workspace, _: &(), cx: &mut ViewContext<Workspace>) {
workspace_view.toggle_modal(cx, |cx, workspace_view| {
let workspace = cx.handle();
let finder =
ctx.add_view(|ctx| Self::new(workspace_view.settings.clone(), workspace, ctx));
ctx.subscribe_to_view(&finder, Self::on_event);
cx.add_view(|cx| Self::new(workspace_view.settings.clone(), workspace, cx));
cx.subscribe_to_view(&finder, Self::on_event);
finder
});
}
@@ -268,17 +268,17 @@ impl FileFinder {
workspace_view: &mut Workspace,
_: ViewHandle<FileFinder>,
event: &Event,
ctx: &mut ViewContext<Workspace>,
cx: &mut ViewContext<Workspace>,
) {
match event {
Event::Selected(tree_id, path) => {
workspace_view
.open_entry((*tree_id, path.clone()), ctx)
.open_entry((*tree_id, path.clone()), cx)
.map(|d| d.detach());
workspace_view.dismiss_modal(ctx);
workspace_view.dismiss_modal(cx);
}
Event::Dismissed => {
workspace_view.dismiss_modal(ctx);
workspace_view.dismiss_modal(cx);
}
}
}
@@ -286,15 +286,15 @@ impl FileFinder {
pub fn new(
settings: watch::Receiver<Settings>,
workspace: ViewHandle<Workspace>,
ctx: &mut ViewContext<Self>,
cx: &mut ViewContext<Self>,
) -> Self {
ctx.observe_view(&workspace, Self::workspace_updated);
cx.observe_view(&workspace, Self::workspace_updated);
let query_buffer = ctx.add_view(|ctx| BufferView::single_line(settings.clone(), ctx));
ctx.subscribe_to_view(&query_buffer, Self::on_query_buffer_event);
let query_buffer = cx.add_view(|cx| Editor::single_line(settings.clone(), cx));
cx.subscribe_to_view(&query_buffer, Self::on_query_editor_event);
Self {
handle: ctx.handle().downgrade(),
handle: cx.handle().downgrade(),
settings,
workspace: workspace.downgrade(),
query_buffer,
@@ -309,33 +309,32 @@ impl FileFinder {
}
}
fn workspace_updated(&mut self, _: ViewHandle<Workspace>, ctx: &mut ViewContext<Self>) {
if let Some(task) = self.spawn_search(self.query_buffer.read(ctx).text(ctx.as_ref()), ctx) {
fn workspace_updated(&mut self, _: ViewHandle<Workspace>, cx: &mut ViewContext<Self>) {
if let Some(task) = self.spawn_search(self.query_buffer.read(cx).text(cx.as_ref()), cx) {
task.detach();
}
}
fn on_query_buffer_event(
fn on_query_editor_event(
&mut self,
_: ViewHandle<BufferView>,
event: &buffer_view::Event,
ctx: &mut ViewContext<Self>,
_: ViewHandle<Editor>,
event: &editor::Event,
cx: &mut ViewContext<Self>,
) {
use buffer_view::Event::*;
match event {
Edited => {
let query = self.query_buffer.read(ctx).text(ctx.as_ref());
editor::Event::Edited => {
let query = self.query_buffer.read(cx).text(cx.as_ref());
if query.is_empty() {
self.latest_search_id = util::post_inc(&mut self.search_count);
self.matches.clear();
ctx.notify();
cx.notify();
} else {
if let Some(task) = self.spawn_search(query, ctx) {
if let Some(task) = self.spawn_search(query, cx) {
task.detach();
}
}
}
Blurred => ctx.emit(Event::Dismissed),
editor::Event::Blurred => cx.emit(Event::Dismissed),
_ => {}
}
}
@@ -353,7 +352,7 @@ impl FileFinder {
0
}
fn select_prev(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
fn select_prev(&mut self, _: &(), cx: &mut ViewContext<Self>) {
let mut selected_index = self.selected_index();
if selected_index > 0 {
selected_index -= 1;
@@ -361,10 +360,10 @@ impl FileFinder {
self.selected = Some((mat.tree_id, mat.path.clone()));
}
self.list_state.scroll_to(selected_index);
ctx.notify();
cx.notify();
}
fn select_next(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
fn select_next(&mut self, _: &(), cx: &mut ViewContext<Self>) {
let mut selected_index = self.selected_index();
if selected_index + 1 < self.matches.len() {
selected_index += 1;
@@ -372,39 +371,39 @@ impl FileFinder {
self.selected = Some((mat.tree_id, mat.path.clone()));
}
self.list_state.scroll_to(selected_index);
ctx.notify();
cx.notify();
}
fn scroll(&mut self, _: &f32, ctx: &mut ViewContext<Self>) {
ctx.notify();
fn scroll(&mut self, _: &f32, cx: &mut ViewContext<Self>) {
cx.notify();
}
fn confirm(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
fn confirm(&mut self, _: &(), cx: &mut ViewContext<Self>) {
if let Some(m) = self.matches.get(self.selected_index()) {
ctx.emit(Event::Selected(m.tree_id, m.path.clone()));
cx.emit(Event::Selected(m.tree_id, m.path.clone()));
}
}
fn select(&mut self, (tree_id, path): &(usize, Arc<Path>), ctx: &mut ViewContext<Self>) {
ctx.emit(Event::Selected(*tree_id, path.clone()));
fn select(&mut self, (tree_id, path): &(usize, Arc<Path>), cx: &mut ViewContext<Self>) {
cx.emit(Event::Selected(*tree_id, path.clone()));
}
#[must_use]
fn spawn_search(&mut self, query: String, ctx: &mut ViewContext<Self>) -> Option<Task<()>> {
fn spawn_search(&mut self, query: String, cx: &mut ViewContext<Self>) -> Option<Task<()>> {
let snapshots = self
.workspace
.upgrade(&ctx)?
.read(ctx)
.upgrade(&cx)?
.read(cx)
.worktrees()
.iter()
.map(|tree| tree.read(ctx).snapshot())
.map(|tree| tree.read(cx).snapshot())
.collect::<Vec<_>>();
let search_id = util::post_inc(&mut self.search_count);
let pool = ctx.as_ref().thread_pool().clone();
let pool = cx.as_ref().thread_pool().clone();
self.cancel_flag.store(true, atomic::Ordering::Relaxed);
self.cancel_flag = Arc::new(AtomicBool::new(false));
let cancel_flag = self.cancel_flag.clone();
let background_task = ctx.background_executor().spawn(async move {
let background_task = cx.background_executor().spawn(async move {
let include_root_name = snapshots.len() > 1;
let matches = match_paths(
snapshots.iter(),
@@ -420,16 +419,16 @@ impl FileFinder {
(search_id, did_cancel, query, matches)
});
Some(ctx.spawn(|this, mut ctx| async move {
Some(cx.spawn(|this, mut cx| async move {
let matches = background_task.await;
this.update(&mut ctx, |this, ctx| this.update_matches(matches, ctx));
this.update(&mut cx, |this, cx| this.update_matches(matches, cx));
}))
}
fn update_matches(
&mut self,
(search_id, did_cancel, query, matches): (usize, bool, String, Vec<PathMatch>),
ctx: &mut ViewContext<Self>,
cx: &mut ViewContext<Self>,
) {
if search_id >= self.latest_search_id {
self.latest_search_id = search_id;
@@ -441,17 +440,17 @@ impl FileFinder {
self.latest_search_query = query;
self.latest_search_did_cancel = did_cancel;
self.list_state.scroll_to(self.selected_index());
ctx.notify();
cx.notify();
}
}
fn worktree<'a>(&'a self, tree_id: usize, app: &'a AppContext) -> Option<&'a Worktree> {
fn worktree<'a>(&'a self, tree_id: usize, cx: &'a AppContext) -> Option<&'a Worktree> {
self.workspace
.upgrade(app)?
.read(app)
.upgrade(cx)?
.read(cx)
.worktrees()
.get(&tree_id)
.map(|worktree| worktree.read(app))
.map(|worktree| worktree.read(cx))
}
}
@@ -468,75 +467,75 @@ mod tests {
use tempdir::TempDir;
#[gpui::test]
async fn test_matching_paths(mut app: gpui::TestAppContext) {
async fn test_matching_paths(mut cx: gpui::TestAppContext) {
let tmp_dir = TempDir::new("example").unwrap();
fs::create_dir(tmp_dir.path().join("a")).unwrap();
fs::write(tmp_dir.path().join("a/banana"), "banana").unwrap();
fs::write(tmp_dir.path().join("a/bandana"), "bandana").unwrap();
app.update(|ctx| {
super::init(ctx);
editor::init(ctx);
cx.update(|cx| {
super::init(cx);
editor::init(cx);
});
let app_state = app.read(build_app_state);
let (window_id, workspace) = app.add_window(|ctx| {
let app_state = cx.read(build_app_state);
let (window_id, workspace) = cx.add_window(|cx| {
let mut workspace =
Workspace::new(0, app_state.settings, app_state.language_registry, ctx);
workspace.add_worktree(tmp_dir.path(), ctx);
Workspace::new(0, app_state.settings, app_state.language_registry, cx);
workspace.add_worktree(tmp_dir.path(), cx);
workspace
});
app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx))
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
.await;
app.dispatch_action(
cx.dispatch_action(
window_id,
vec![workspace.id()],
"file_finder:toggle".into(),
(),
);
let finder = app.read(|ctx| {
let finder = cx.read(|cx| {
workspace
.read(ctx)
.read(cx)
.modal()
.cloned()
.unwrap()
.downcast::<FileFinder>()
.unwrap()
});
let query_buffer = app.read(|ctx| finder.read(ctx).query_buffer.clone());
let query_buffer = cx.read(|cx| finder.read(cx).query_buffer.clone());
let chain = vec![finder.id(), query_buffer.id()];
app.dispatch_action(window_id, chain.clone(), "buffer:insert", "b".to_string());
app.dispatch_action(window_id, chain.clone(), "buffer:insert", "n".to_string());
app.dispatch_action(window_id, chain.clone(), "buffer:insert", "a".to_string());
cx.dispatch_action(window_id, chain.clone(), "buffer:insert", "b".to_string());
cx.dispatch_action(window_id, chain.clone(), "buffer:insert", "n".to_string());
cx.dispatch_action(window_id, chain.clone(), "buffer:insert", "a".to_string());
finder
.condition(&app, |finder, _| finder.matches.len() == 2)
.condition(&cx, |finder, _| finder.matches.len() == 2)
.await;
let active_pane = app.read(|ctx| workspace.read(ctx).active_pane().clone());
app.dispatch_action(
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
cx.dispatch_action(
window_id,
vec![workspace.id(), finder.id()],
"menu:select_next",
(),
);
app.dispatch_action(
cx.dispatch_action(
window_id,
vec![workspace.id(), finder.id()],
"file_finder:confirm",
(),
);
active_pane
.condition(&app, |pane, _| pane.active_item().is_some())
.condition(&cx, |pane, _| pane.active_item().is_some())
.await;
app.read(|ctx| {
let active_item = active_pane.read(ctx).active_item().unwrap();
assert_eq!(active_item.title(ctx), "bandana");
cx.read(|cx| {
let active_item = active_pane.read(cx).active_item().unwrap();
assert_eq!(active_item.title(cx), "bandana");
});
}
#[gpui::test]
async fn test_matching_cancellation(mut app: gpui::TestAppContext) {
async fn test_matching_cancellation(mut cx: gpui::TestAppContext) {
let tmp_dir = temp_tree(json!({
"hello": "",
"goodbye": "",
@@ -546,35 +545,35 @@ mod tests {
"hi": "",
"hiccup": "",
}));
let app_state = app.read(build_app_state);
let (_, workspace) = app.add_window(|ctx| {
let app_state = cx.read(build_app_state);
let (_, workspace) = cx.add_window(|cx| {
let mut workspace = Workspace::new(
0,
app_state.settings.clone(),
app_state.language_registry.clone(),
ctx,
cx,
);
workspace.add_worktree(tmp_dir.path(), ctx);
workspace.add_worktree(tmp_dir.path(), cx);
workspace
});
app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx))
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
.await;
let (_, finder) =
app.add_window(|ctx| FileFinder::new(app_state.settings, workspace.clone(), ctx));
cx.add_window(|cx| FileFinder::new(app_state.settings, workspace.clone(), cx));
let query = "hi".to_string();
finder
.update(&mut app, |f, ctx| f.spawn_search(query.clone(), ctx))
.update(&mut cx, |f, cx| f.spawn_search(query.clone(), cx))
.unwrap()
.await;
finder.read_with(&app, |f, _| assert_eq!(f.matches.len(), 5));
finder.read_with(&cx, |f, _| assert_eq!(f.matches.len(), 5));
finder.update(&mut app, |finder, ctx| {
finder.update(&mut cx, |finder, cx| {
let matches = finder.matches.clone();
// Simulate a search being cancelled after the time limit,
// returning only a subset of the matches that would have been found.
finder.spawn_search(query.clone(), ctx).unwrap().detach();
finder.spawn_search(query.clone(), cx).unwrap().detach();
finder.update_matches(
(
finder.latest_search_id,
@@ -582,11 +581,11 @@ mod tests {
query.clone(),
vec![matches[1].clone(), matches[3].clone()],
),
ctx,
cx,
);
// Simulate another cancellation.
finder.spawn_search(query.clone(), ctx).unwrap().detach();
finder.spawn_search(query.clone(), cx).unwrap().detach();
finder.update_matches(
(
finder.latest_search_id,
@@ -594,7 +593,7 @@ mod tests {
query.clone(),
vec![matches[0].clone(), matches[2].clone(), matches[3].clone()],
),
ctx,
cx,
);
assert_eq!(finder.matches, matches[0..4])
@@ -602,41 +601,41 @@ mod tests {
}
#[gpui::test]
async fn test_single_file_worktrees(mut app: gpui::TestAppContext) {
async fn test_single_file_worktrees(mut cx: gpui::TestAppContext) {
let temp_dir = TempDir::new("test-single-file-worktrees").unwrap();
let dir_path = temp_dir.path().join("the-parent-dir");
let file_path = dir_path.join("the-file");
fs::create_dir(&dir_path).unwrap();
fs::write(&file_path, "").unwrap();
let app_state = app.read(build_app_state);
let (_, workspace) = app.add_window(|ctx| {
let app_state = cx.read(build_app_state);
let (_, workspace) = cx.add_window(|cx| {
let mut workspace = Workspace::new(
0,
app_state.settings.clone(),
app_state.language_registry.clone(),
ctx,
cx,
);
workspace.add_worktree(&file_path, ctx);
workspace.add_worktree(&file_path, cx);
workspace
});
app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx))
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
.await;
let (_, finder) =
app.add_window(|ctx| FileFinder::new(app_state.settings, workspace.clone(), ctx));
cx.add_window(|cx| FileFinder::new(app_state.settings, workspace.clone(), cx));
// Even though there is only one worktree, that worktree's filename
// is included in the matching, because the worktree is a single file.
finder
.update(&mut app, |f, ctx| f.spawn_search("thf".into(), ctx))
.update(&mut cx, |f, cx| f.spawn_search("thf".into(), cx))
.unwrap()
.await;
app.read(|ctx| {
let finder = finder.read(ctx);
cx.read(|cx| {
let finder = finder.read(cx);
assert_eq!(finder.matches.len(), 1);
let (file_name, file_name_positions, full_path, full_path_positions) =
finder.labels_for_match(&finder.matches[0], ctx).unwrap();
finder.labels_for_match(&finder.matches[0], cx).unwrap();
assert_eq!(file_name, "the-file");
assert_eq!(file_name_positions, &[0, 1, 4]);
assert_eq!(full_path, "the-file");
@@ -646,57 +645,57 @@ mod tests {
// Since the worktree root is a file, searching for its name followed by a slash does
// not match anything.
finder
.update(&mut app, |f, ctx| f.spawn_search("thf/".into(), ctx))
.update(&mut cx, |f, cx| f.spawn_search("thf/".into(), cx))
.unwrap()
.await;
finder.read_with(&app, |f, _| assert_eq!(f.matches.len(), 0));
finder.read_with(&cx, |f, _| assert_eq!(f.matches.len(), 0));
}
#[gpui::test]
async fn test_multiple_matches_with_same_relative_path(mut app: gpui::TestAppContext) {
async fn test_multiple_matches_with_same_relative_path(mut cx: gpui::TestAppContext) {
let tmp_dir = temp_tree(json!({
"dir1": { "a.txt": "" },
"dir2": { "a.txt": "" }
}));
let app_state = app.read(build_app_state);
let app_state = cx.read(build_app_state);
let (_, workspace) = app.add_window(|ctx| {
let (_, workspace) = cx.add_window(|cx| {
Workspace::new(
0,
app_state.settings.clone(),
app_state.language_registry.clone(),
ctx,
cx,
)
});
workspace
.update(&mut app, |workspace, ctx| {
.update(&mut cx, |workspace, cx| {
workspace.open_paths(
&[tmp_dir.path().join("dir1"), tmp_dir.path().join("dir2")],
ctx,
cx,
)
})
.await;
app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx))
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
.await;
let (_, finder) =
app.add_window(|ctx| FileFinder::new(app_state.settings, workspace.clone(), ctx));
cx.add_window(|cx| FileFinder::new(app_state.settings, workspace.clone(), cx));
// Run a search that matches two files with the same relative path.
finder
.update(&mut app, |f, ctx| f.spawn_search("a.t".into(), ctx))
.update(&mut cx, |f, cx| f.spawn_search("a.t".into(), cx))
.unwrap()
.await;
// Can switch between different matches with the same relative path.
finder.update(&mut app, |f, ctx| {
finder.update(&mut cx, |f, cx| {
assert_eq!(f.matches.len(), 2);
assert_eq!(f.selected_index(), 0);
f.select_next(&(), ctx);
f.select_next(&(), cx);
assert_eq!(f.selected_index(), 1);
f.select_prev(&(), ctx);
f.select_prev(&(), cx);
assert_eq!(f.selected_index(), 0);
});
}
+7 -7
View File
@@ -24,19 +24,19 @@ fn main() {
settings,
};
app.run(move |ctx| {
ctx.set_menus(menus::menus(app_state.settings.clone()));
workspace::init(ctx);
editor::init(ctx);
file_finder::init(ctx);
app.run(move |cx| {
cx.set_menus(menus::menus(app_state.settings.clone()));
workspace::init(cx);
editor::init(cx);
file_finder::init(cx);
if stdout_is_a_pty() {
ctx.platform().activate(true);
cx.platform().activate(true);
}
let paths = collect_path_args();
if !paths.is_empty() {
ctx.dispatch_global_action(
cx.dispatch_global_action(
"workspace:open_paths",
OpenParams {
paths,
+45 -45
View File
@@ -25,7 +25,7 @@ pub trait KeyedItem: Item {
pub trait Summary: Default + Clone + fmt::Debug {
type Context;
fn add_summary(&mut self, summary: &Self, ctx: &Self::Context);
fn add_summary(&mut self, summary: &Self, cx: &Self::Context);
}
pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug + Default {
@@ -37,7 +37,7 @@ impl<'a, T: Summary> Dimension<'a, T> for () {
}
pub trait SeekDimension<'a, T: Summary>: Dimension<'a, T> {
fn cmp(&self, other: &Self, ctx: &T::Context) -> Ordering;
fn cmp(&self, other: &Self, cx: &T::Context) -> Ordering;
}
impl<'a, S: Summary, T: Dimension<'a, S> + Ord> SeekDimension<'a, S> for T {
@@ -64,9 +64,9 @@ impl<T: Item> SumTree<T> {
}))
}
pub fn from_item(item: T, ctx: &<T::Summary as Summary>::Context) -> Self {
pub fn from_item(item: T, cx: &<T::Summary as Summary>::Context) -> Self {
let mut tree = Self::new();
tree.push(item, ctx);
tree.push(item, cx);
tree
}
@@ -101,14 +101,14 @@ impl<T: Item> SumTree<T> {
self.rightmost_leaf().0.items().last()
}
pub fn update_last(&mut self, f: impl FnOnce(&mut T), ctx: &<T::Summary as Summary>::Context) {
self.update_last_recursive(f, ctx);
pub fn update_last(&mut self, f: impl FnOnce(&mut T), cx: &<T::Summary as Summary>::Context) {
self.update_last_recursive(f, cx);
}
fn update_last_recursive(
&mut self,
f: impl FnOnce(&mut T),
ctx: &<T::Summary as Summary>::Context,
cx: &<T::Summary as Summary>::Context,
) -> Option<T::Summary> {
match Arc::make_mut(&mut self.0) {
Node::Internal {
@@ -119,8 +119,8 @@ impl<T: Item> SumTree<T> {
} => {
let last_summary = child_summaries.last_mut().unwrap();
let last_child = child_trees.last_mut().unwrap();
*last_summary = last_child.update_last_recursive(f, ctx).unwrap();
*summary = sum(child_summaries.iter(), ctx);
*last_summary = last_child.update_last_recursive(f, cx).unwrap();
*summary = sum(child_summaries.iter(), cx);
Some(summary.clone())
}
Node::Leaf {
@@ -132,7 +132,7 @@ impl<T: Item> SumTree<T> {
{
(f)(item);
*item_summary = item.summary();
*summary = sum(item_summaries.iter(), ctx);
*summary = sum(item_summaries.iter(), cx);
Some(summary.clone())
} else {
None
@@ -165,7 +165,7 @@ impl<T: Item> SumTree<T> {
}
}
pub fn extend<I>(&mut self, iter: I, ctx: &<T::Summary as Summary>::Context)
pub fn extend<I>(&mut self, iter: I, cx: &<T::Summary as Summary>::Context)
where
I: IntoIterator<Item = T>,
{
@@ -173,7 +173,7 @@ impl<T: Item> SumTree<T> {
for item in iter {
if leaf.is_some() && leaf.as_ref().unwrap().items().len() == 2 * TREE_BASE {
self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), ctx);
self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), cx);
}
if leaf.is_none() {
@@ -191,7 +191,7 @@ impl<T: Item> SumTree<T> {
}) = leaf.as_mut()
{
let item_summary = item.summary();
summary.add_summary(&item_summary, ctx);
summary.add_summary(&item_summary, cx);
items.push(item);
item_summaries.push(item_summary);
} else {
@@ -200,11 +200,11 @@ impl<T: Item> SumTree<T> {
}
if leaf.is_some() {
self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), ctx);
self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), cx);
}
}
pub fn push(&mut self, item: T, ctx: &<T::Summary as Summary>::Context) {
pub fn push(&mut self, item: T, cx: &<T::Summary as Summary>::Context) {
let summary = item.summary();
self.push_tree(
SumTree(Arc::new(Node::Leaf {
@@ -212,18 +212,18 @@ impl<T: Item> SumTree<T> {
items: ArrayVec::from_iter(Some(item)),
item_summaries: ArrayVec::from_iter(Some(summary)),
})),
ctx,
cx,
);
}
pub fn push_tree(&mut self, other: Self, ctx: &<T::Summary as Summary>::Context) {
pub fn push_tree(&mut self, other: Self, cx: &<T::Summary as Summary>::Context) {
if !other.0.is_leaf() || other.0.items().len() > 0 {
if self.0.height() < other.0.height() {
for tree in other.0.child_trees() {
self.push_tree(tree.clone(), ctx);
self.push_tree(tree.clone(), cx);
}
} else if let Some(split_tree) = self.push_tree_recursive(other, ctx) {
*self = Self::from_child_trees(self.clone(), split_tree, ctx);
} else if let Some(split_tree) = self.push_tree_recursive(other, cx) {
*self = Self::from_child_trees(self.clone(), split_tree, cx);
}
}
}
@@ -231,7 +231,7 @@ impl<T: Item> SumTree<T> {
fn push_tree_recursive(
&mut self,
other: SumTree<T>,
ctx: &<T::Summary as Summary>::Context,
cx: &<T::Summary as Summary>::Context,
) -> Option<SumTree<T>> {
match Arc::make_mut(&mut self.0) {
Node::Internal {
@@ -242,7 +242,7 @@ impl<T: Item> SumTree<T> {
..
} => {
let other_node = other.0.clone();
summary.add_summary(other_node.summary(), ctx);
summary.add_summary(other_node.summary(), cx);
let height_delta = *height - other_node.height();
let mut summaries_to_append = ArrayVec::<[T::Summary; 2 * TREE_BASE]>::new();
@@ -257,7 +257,7 @@ impl<T: Item> SumTree<T> {
let tree_to_append = child_trees
.last_mut()
.unwrap()
.push_tree_recursive(other, ctx);
.push_tree_recursive(other, cx);
*child_summaries.last_mut().unwrap() =
child_trees.last().unwrap().0.summary().clone();
@@ -287,13 +287,13 @@ impl<T: Item> SumTree<T> {
left_trees = all_trees.by_ref().take(midpoint).collect();
right_trees = all_trees.collect();
}
*summary = sum(left_summaries.iter(), ctx);
*summary = sum(left_summaries.iter(), cx);
*child_summaries = left_summaries;
*child_trees = left_trees;
Some(SumTree(Arc::new(Node::Internal {
height: *height,
summary: sum(right_summaries.iter(), ctx),
summary: sum(right_summaries.iter(), cx),
child_summaries: right_summaries,
child_trees: right_trees,
})))
@@ -332,14 +332,14 @@ impl<T: Item> SumTree<T> {
}
*items = left_items;
*item_summaries = left_summaries;
*summary = sum(item_summaries.iter(), ctx);
*summary = sum(item_summaries.iter(), cx);
Some(SumTree(Arc::new(Node::Leaf {
items: right_items,
summary: sum(right_summaries.iter(), ctx),
summary: sum(right_summaries.iter(), cx),
item_summaries: right_summaries,
})))
} else {
summary.add_summary(other_node.summary(), ctx);
summary.add_summary(other_node.summary(), cx);
items.extend(other_node.items().iter().cloned());
item_summaries.extend(other_node.child_summaries().iter().cloned());
None
@@ -351,7 +351,7 @@ impl<T: Item> SumTree<T> {
fn from_child_trees(
left: SumTree<T>,
right: SumTree<T>,
ctx: &<T::Summary as Summary>::Context,
cx: &<T::Summary as Summary>::Context,
) -> Self {
let height = left.0.height() + 1;
let mut child_summaries = ArrayVec::new();
@@ -362,7 +362,7 @@ impl<T: Item> SumTree<T> {
child_trees.push(right);
SumTree(Arc::new(Node::Internal {
height,
summary: sum(child_summaries.iter(), ctx),
summary: sum(child_summaries.iter(), cx),
child_summaries,
child_trees,
}))
@@ -389,12 +389,12 @@ impl<T: Item> SumTree<T> {
impl<T: KeyedItem> SumTree<T> {
#[allow(unused)]
pub fn insert(&mut self, item: T, ctx: &<T::Summary as Summary>::Context) {
pub fn insert(&mut self, item: T, cx: &<T::Summary as Summary>::Context) {
*self = {
let mut cursor = self.cursor::<T::Key, ()>();
let mut new_tree = cursor.slice(&item.key(), SeekBias::Left, ctx);
new_tree.push(item, ctx);
new_tree.push_tree(cursor.suffix(ctx), ctx);
let mut new_tree = cursor.slice(&item.key(), SeekBias::Left, cx);
new_tree.push(item, cx);
new_tree.push_tree(cursor.suffix(cx), cx);
new_tree
};
}
@@ -402,7 +402,7 @@ impl<T: KeyedItem> SumTree<T> {
pub fn edit(
&mut self,
mut edits: Vec<Edit<T>>,
ctx: &<T::Summary as Summary>::Context,
cx: &<T::Summary as Summary>::Context,
) -> Vec<T> {
if edits.is_empty() {
return Vec::new();
@@ -416,7 +416,7 @@ impl<T: KeyedItem> SumTree<T> {
let mut new_tree = SumTree::new();
let mut buffered_items = Vec::new();
cursor.seek(&T::Key::default(), SeekBias::Left, ctx);
cursor.seek(&T::Key::default(), SeekBias::Left, cx);
for edit in edits {
let new_key = edit.key();
let mut old_item = cursor.item();
@@ -425,9 +425,9 @@ impl<T: KeyedItem> SumTree<T> {
.as_ref()
.map_or(false, |old_item| old_item.key() < new_key)
{
new_tree.extend(buffered_items.drain(..), ctx);
let slice = cursor.slice(&new_key, SeekBias::Left, ctx);
new_tree.push_tree(slice, ctx);
new_tree.extend(buffered_items.drain(..), cx);
let slice = cursor.slice(&new_key, SeekBias::Left, cx);
new_tree.push_tree(slice, cx);
old_item = cursor.item();
}
@@ -446,17 +446,17 @@ impl<T: KeyedItem> SumTree<T> {
}
}
new_tree.extend(buffered_items, ctx);
new_tree.push_tree(cursor.suffix(ctx), ctx);
new_tree.extend(buffered_items, cx);
new_tree.push_tree(cursor.suffix(cx), cx);
new_tree
};
removed
}
pub fn get(&self, key: &T::Key, ctx: &<T::Summary as Summary>::Context) -> Option<&T> {
pub fn get(&self, key: &T::Key, cx: &<T::Summary as Summary>::Context) -> Option<&T> {
let mut cursor = self.cursor::<T::Key, ()>();
if cursor.seek(key, SeekBias::Left, ctx) {
if cursor.seek(key, SeekBias::Left, cx) {
cursor.item()
} else {
None
@@ -553,14 +553,14 @@ impl<T: KeyedItem> Edit<T> {
}
}
fn sum<'a, T, I>(iter: I, ctx: &T::Context) -> T
fn sum<'a, T, I>(iter: I, cx: &T::Context) -> T
where
T: 'a + Summary,
I: Iterator<Item = &'a T>,
{
let mut sum = T::default();
for value in iter {
sum.add_summary(value, ctx);
sum.add_summary(value, cx);
}
sum
}
+25 -30
View File
@@ -342,33 +342,28 @@ where
S: SeekDimension<'a, T::Summary>,
U: Dimension<'a, T::Summary>,
{
pub fn seek(
&mut self,
pos: &S,
bias: SeekBias,
ctx: &<T::Summary as Summary>::Context,
) -> bool {
pub fn seek(&mut self, pos: &S, bias: SeekBias, cx: &<T::Summary as Summary>::Context) -> bool {
self.reset();
self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, ctx)
self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, cx)
}
pub fn seek_forward(
&mut self,
pos: &S,
bias: SeekBias,
ctx: &<T::Summary as Summary>::Context,
cx: &<T::Summary as Summary>::Context,
) -> bool {
self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, ctx)
self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, cx)
}
pub fn slice(
&mut self,
end: &S,
bias: SeekBias,
ctx: &<T::Summary as Summary>::Context,
cx: &<T::Summary as Summary>::Context,
) -> SumTree<T> {
let mut slice = SeekAggregate::Slice(SumTree::new());
self.seek_internal::<()>(end, bias, &mut slice, ctx);
self.seek_internal::<()>(end, bias, &mut slice, cx);
if let SeekAggregate::Slice(slice) = slice {
slice
} else {
@@ -376,10 +371,10 @@ where
}
}
pub fn suffix(&mut self, ctx: &<T::Summary as Summary>::Context) -> SumTree<T> {
pub fn suffix(&mut self, cx: &<T::Summary as Summary>::Context) -> SumTree<T> {
let extent = self.tree.extent::<S>();
let mut slice = SeekAggregate::Slice(SumTree::new());
self.seek_internal::<()>(&extent, SeekBias::Right, &mut slice, ctx);
self.seek_internal::<()>(&extent, SeekBias::Right, &mut slice, cx);
if let SeekAggregate::Slice(slice) = slice {
slice
} else {
@@ -391,13 +386,13 @@ where
&mut self,
end: &S,
bias: SeekBias,
ctx: &<T::Summary as Summary>::Context,
cx: &<T::Summary as Summary>::Context,
) -> D
where
D: Dimension<'a, T::Summary>,
{
let mut summary = SeekAggregate::Summary(D::default());
self.seek_internal(end, bias, &mut summary, ctx);
self.seek_internal(end, bias, &mut summary, cx);
if let SeekAggregate::Summary(summary) = summary {
summary
} else {
@@ -410,12 +405,12 @@ where
target: &S,
bias: SeekBias,
aggregate: &mut SeekAggregate<T, D>,
ctx: &<T::Summary as Summary>::Context,
cx: &<T::Summary as Summary>::Context,
) -> bool
where
D: Dimension<'a, T::Summary>,
{
debug_assert!(target.cmp(&self.seek_dimension, ctx) >= Ordering::Equal);
debug_assert!(target.cmp(&self.seek_dimension, cx) >= Ordering::Equal);
let mut containing_subtree = None;
if self.did_seek {
@@ -435,7 +430,7 @@ where
let mut child_end = self.seek_dimension.clone();
child_end.add_summary(&child_summary);
let comparison = target.cmp(&child_end, ctx);
let comparison = target.cmp(&child_end, cx);
if comparison == Ordering::Greater
|| (comparison == Ordering::Equal && bias == SeekBias::Right)
{
@@ -444,7 +439,7 @@ where
match aggregate {
SeekAggregate::None => {}
SeekAggregate::Slice(slice) => {
slice.push_tree(child_tree.clone(), ctx);
slice.push_tree(child_tree.clone(), cx);
}
SeekAggregate::Summary(summary) => {
summary.add_summary(child_summary);
@@ -477,7 +472,7 @@ where
let mut item_end = self.seek_dimension.clone();
item_end.add_summary(item_summary);
let comparison = target.cmp(&item_end, ctx);
let comparison = target.cmp(&item_end, cx);
if comparison == Ordering::Greater
|| (comparison == Ordering::Equal && bias == SeekBias::Right)
{
@@ -491,7 +486,7 @@ where
slice_items_summary
.as_mut()
.unwrap()
.add_summary(item_summary, ctx);
.add_summary(item_summary, cx);
}
SeekAggregate::Summary(summary) => {
summary.add_summary(item_summary);
@@ -506,7 +501,7 @@ where
items: slice_items,
item_summaries: slice_item_summaries,
})),
ctx,
cx,
);
}
break 'outer;
@@ -521,7 +516,7 @@ where
items: slice_items,
item_summaries: slice_item_summaries,
})),
ctx,
cx,
);
}
}
@@ -551,7 +546,7 @@ where
let mut child_end = self.seek_dimension.clone();
child_end.add_summary(child_summary);
let comparison = target.cmp(&child_end, ctx);
let comparison = target.cmp(&child_end, cx);
if comparison == Ordering::Greater
|| (comparison == Ordering::Equal && bias == SeekBias::Right)
{
@@ -560,7 +555,7 @@ where
match aggregate {
SeekAggregate::None => {}
SeekAggregate::Slice(slice) => {
slice.push_tree(child_trees[index].clone(), ctx);
slice.push_tree(child_trees[index].clone(), cx);
}
SeekAggregate::Summary(summary) => {
summary.add_summary(child_summary);
@@ -597,7 +592,7 @@ where
let mut child_end = self.seek_dimension.clone();
child_end.add_summary(item_summary);
let comparison = target.cmp(&child_end, ctx);
let comparison = target.cmp(&child_end, cx);
if comparison == Ordering::Greater
|| (comparison == Ordering::Equal && bias == SeekBias::Right)
{
@@ -610,7 +605,7 @@ where
slice_items_summary
.as_mut()
.unwrap()
.add_summary(item_summary, ctx);
.add_summary(item_summary, cx);
slice_item_summaries.push(item_summary.clone());
}
SeekAggregate::Summary(summary) => {
@@ -636,7 +631,7 @@ where
items: slice_items,
item_summaries: slice_item_summaries,
})),
ctx,
cx,
);
}
}
@@ -658,9 +653,9 @@ where
if let Some(summary) = self.item_summary() {
end.add_summary(summary);
}
target.cmp(&end, ctx) == Ordering::Equal
target.cmp(&end, cx) == Ordering::Equal
} else {
target.cmp(&self.seek_dimension, ctx) == Ordering::Equal
target.cmp(&self.seek_dimension, cx) == Ordering::Equal
}
}
}
+2 -2
View File
@@ -144,8 +144,8 @@ fn write_tree(path: &Path, tree: serde_json::Value) {
}
}
pub fn build_app_state(ctx: &AppContext) -> AppState {
let settings = settings::channel(&ctx.font_cache()).unwrap().1;
pub fn build_app_state(cx: &AppContext) -> AppState {
let settings = settings::channel(&cx.font_cache()).unwrap().1;
let language_registry = Arc::new(LanguageRegistry::new());
AppState {
settings,
+324 -328
View File
File diff suppressed because it is too large Load Diff
+66 -87
View File
@@ -10,42 +10,39 @@ use gpui::{
use postage::watch;
use std::{cmp, path::Path, sync::Arc};
pub fn init(app: &mut MutableAppContext) {
app.add_action(
pub fn init(cx: &mut MutableAppContext) {
cx.add_action(
"pane:activate_item",
|pane: &mut Pane, index: &usize, ctx| {
pane.activate_item(*index, ctx);
|pane: &mut Pane, index: &usize, cx| {
pane.activate_item(*index, cx);
},
);
app.add_action("pane:activate_prev_item", |pane: &mut Pane, _: &(), ctx| {
pane.activate_prev_item(ctx);
cx.add_action("pane:activate_prev_item", |pane: &mut Pane, _: &(), cx| {
pane.activate_prev_item(cx);
});
app.add_action("pane:activate_next_item", |pane: &mut Pane, _: &(), ctx| {
pane.activate_next_item(ctx);
cx.add_action("pane:activate_next_item", |pane: &mut Pane, _: &(), cx| {
pane.activate_next_item(cx);
});
app.add_action("pane:close_active_item", |pane: &mut Pane, _: &(), ctx| {
pane.close_active_item(ctx);
cx.add_action("pane:close_active_item", |pane: &mut Pane, _: &(), cx| {
pane.close_active_item(cx);
});
app.add_action(
"pane:close_item",
|pane: &mut Pane, item_id: &usize, ctx| {
pane.close_item(*item_id, ctx);
},
);
app.add_action("pane:split_up", |pane: &mut Pane, _: &(), ctx| {
pane.split(SplitDirection::Up, ctx);
cx.add_action("pane:close_item", |pane: &mut Pane, item_id: &usize, cx| {
pane.close_item(*item_id, cx);
});
app.add_action("pane:split_down", |pane: &mut Pane, _: &(), ctx| {
pane.split(SplitDirection::Down, ctx);
cx.add_action("pane:split_up", |pane: &mut Pane, _: &(), cx| {
pane.split(SplitDirection::Up, cx);
});
app.add_action("pane:split_left", |pane: &mut Pane, _: &(), ctx| {
pane.split(SplitDirection::Left, ctx);
cx.add_action("pane:split_down", |pane: &mut Pane, _: &(), cx| {
pane.split(SplitDirection::Down, cx);
});
app.add_action("pane:split_right", |pane: &mut Pane, _: &(), ctx| {
pane.split(SplitDirection::Right, ctx);
cx.add_action("pane:split_left", |pane: &mut Pane, _: &(), cx| {
pane.split(SplitDirection::Left, cx);
});
cx.add_action("pane:split_right", |pane: &mut Pane, _: &(), cx| {
pane.split(SplitDirection::Right, cx);
});
app.add_bindings(vec![
cx.add_bindings(vec![
Binding::new("shift-cmd-{", "pane:activate_prev_item", Some("Pane")),
Binding::new("shift-cmd-}", "pane:activate_next_item", Some("Pane")),
Binding::new("cmd-w", "pane:close_active_item", Some("Pane")),
@@ -88,18 +85,14 @@ impl Pane {
}
}
pub fn activate(&self, ctx: &mut ViewContext<Self>) {
ctx.emit(Event::Activate);
pub fn activate(&self, cx: &mut ViewContext<Self>) {
cx.emit(Event::Activate);
}
pub fn add_item(
&mut self,
item: Box<dyn ItemViewHandle>,
ctx: &mut ViewContext<Self>,
) -> usize {
pub fn add_item(&mut self, item: Box<dyn ItemViewHandle>, cx: &mut ViewContext<Self>) -> usize {
let item_idx = cmp::min(self.active_item + 1, self.items.len());
self.items.insert(item_idx, item);
ctx.notify();
cx.notify();
item_idx
}
@@ -115,13 +108,13 @@ impl Pane {
pub fn activate_entry(
&mut self,
entry_id: (usize, Arc<Path>),
ctx: &mut ViewContext<Self>,
cx: &mut ViewContext<Self>,
) -> bool {
if let Some(index) = self.items.iter().position(|item| {
item.entry_id(ctx.as_ref())
item.entry_id(cx.as_ref())
.map_or(false, |id| id == entry_id)
}) {
self.activate_item(index, ctx);
self.activate_item(index, cx);
true
} else {
false
@@ -132,64 +125,64 @@ impl Pane {
self.items.iter().position(|i| i.id() == item.id())
}
pub fn activate_item(&mut self, index: usize, ctx: &mut ViewContext<Self>) {
pub fn activate_item(&mut self, index: usize, cx: &mut ViewContext<Self>) {
if index < self.items.len() {
self.active_item = index;
self.focus_active_item(ctx);
ctx.notify();
self.focus_active_item(cx);
cx.notify();
}
}
pub fn activate_prev_item(&mut self, ctx: &mut ViewContext<Self>) {
pub fn activate_prev_item(&mut self, cx: &mut ViewContext<Self>) {
if self.active_item > 0 {
self.active_item -= 1;
} else if self.items.len() > 0 {
self.active_item = self.items.len() - 1;
}
self.focus_active_item(ctx);
ctx.notify();
self.focus_active_item(cx);
cx.notify();
}
pub fn activate_next_item(&mut self, ctx: &mut ViewContext<Self>) {
pub fn activate_next_item(&mut self, cx: &mut ViewContext<Self>) {
if self.active_item + 1 < self.items.len() {
self.active_item += 1;
} else {
self.active_item = 0;
}
self.focus_active_item(ctx);
ctx.notify();
self.focus_active_item(cx);
cx.notify();
}
pub fn close_active_item(&mut self, ctx: &mut ViewContext<Self>) {
pub fn close_active_item(&mut self, cx: &mut ViewContext<Self>) {
if !self.items.is_empty() {
self.close_item(self.items[self.active_item].id(), ctx)
self.close_item(self.items[self.active_item].id(), cx)
}
}
pub fn close_item(&mut self, item_id: usize, ctx: &mut ViewContext<Self>) {
pub fn close_item(&mut self, item_id: usize, cx: &mut ViewContext<Self>) {
self.items.retain(|item| item.id() != item_id);
self.active_item = cmp::min(self.active_item, self.items.len().saturating_sub(1));
if self.items.is_empty() {
ctx.emit(Event::Remove);
cx.emit(Event::Remove);
}
ctx.notify();
cx.notify();
}
fn focus_active_item(&mut self, ctx: &mut ViewContext<Self>) {
fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) {
if let Some(active_item) = self.active_item() {
ctx.focus(active_item.to_any());
cx.focus(active_item.to_any());
}
}
pub fn split(&mut self, direction: SplitDirection, ctx: &mut ViewContext<Self>) {
ctx.emit(Event::Split(direction));
pub fn split(&mut self, direction: SplitDirection, cx: &mut ViewContext<Self>) {
cx.emit(Event::Split(direction));
}
fn render_tabs(&self, ctx: &AppContext) -> ElementBox {
fn render_tabs(&self, cx: &AppContext) -> ElementBox {
let settings = self.settings.borrow();
let border_color = ColorU::from_u32(0xdbdbdcff);
let line_height = ctx.font_cache().line_height(
ctx.font_cache().default_font(settings.ui_font_family),
let line_height = cx.font_cache().line_height(
cx.font_cache().default_font(settings.ui_font_family),
settings.ui_font_size,
);
@@ -201,8 +194,8 @@ impl Pane {
row.add_child(
Expanded::new(
1.0,
MouseEventHandler::new::<Tab, _>(item.id(), ctx, |mouse_state| {
let title = item.title(ctx);
MouseEventHandler::new::<Tab, _>(item.id(), cx, |mouse_state| {
let title = item.title(cx);
let mut border = Border::new(1.0, border_color);
border.left = ix > 0;
@@ -227,9 +220,9 @@ impl Pane {
item.id(),
line_height - 2.,
mouse_state.hovered,
item.is_dirty(ctx),
item.has_conflict(ctx),
ctx,
item.is_dirty(cx),
item.has_conflict(cx),
cx,
))
.right()
.boxed(),
@@ -250,8 +243,8 @@ impl Pane {
ConstrainedBox::new(
EventHandler::new(container.boxed())
.on_mouse_down(move |ctx| {
ctx.dispatch_action("pane:activate_item", ix);
.on_mouse_down(move |cx| {
cx.dispatch_action("pane:activate_item", ix);
true
})
.boxed(),
@@ -299,7 +292,7 @@ impl Pane {
tab_hovered: bool,
is_dirty: bool,
has_conflict: bool,
ctx: &AppContext,
cx: &AppContext,
) -> ElementBox {
enum TabCloseButton {}
@@ -319,7 +312,7 @@ impl Pane {
let icon = if tab_hovered {
let mut icon = Svg::new("icons/x.svg");
MouseEventHandler::new::<TabCloseButton, _>(item_id, ctx, |mouse_state| {
MouseEventHandler::new::<TabCloseButton, _>(item_id, cx, |mouse_state| {
if mouse_state.hovered {
Container::new(icon.with_color(ColorU::white()).boxed())
.with_background_color(if mouse_state.clicked {
@@ -336,15 +329,15 @@ impl Pane {
icon.boxed()
}
})
.on_click(move |ctx| ctx.dispatch_action("pane:close_item", item_id))
.on_click(move |cx| cx.dispatch_action("pane:close_item", item_id))
.named("close-tab-icon")
} else {
let diameter = 8.;
ConstrainedBox::new(
Canvas::new(move |bounds, ctx| {
Canvas::new(move |bounds, cx| {
if let Some(current_color) = current_color {
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
ctx.scene.push_quad(Quad {
cx.scene.push_quad(Quad {
bounds: square,
background: Some(current_color),
border: Default::default(),
@@ -374,10 +367,10 @@ impl View for Pane {
"Pane"
}
fn render<'a>(&self, app: &AppContext) -> ElementBox {
fn render<'a>(&self, cx: &AppContext) -> ElementBox {
if let Some(active_item) = self.active_item() {
Flex::column()
.with_child(self.render_tabs(app))
.with_child(self.render_tabs(cx))
.with_child(Expanded::new(1.0, ChildView::new(active_item.id()).boxed()).boxed())
.named("pane")
} else {
@@ -385,21 +378,7 @@ impl View for Pane {
}
}
fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
self.focus_active_item(ctx);
fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
self.focus_active_item(cx);
}
// fn state(&self, app: &AppContext) -> Self::State {
// State {
// tabs: self
// .items
// .iter()
// .enumerate()
// .map(|(idx, item)| TabState {
// title: item.title(app),
// active: idx == self.active_item,
// })
// .collect(),
// }
// }
}
+87 -90
View File
@@ -67,10 +67,10 @@ struct FileHandleState {
}
impl Worktree {
pub fn new(path: impl Into<Arc<Path>>, ctx: &mut ModelContext<Self>) -> Self {
pub fn new(path: impl Into<Arc<Path>>, cx: &mut ModelContext<Self>) -> Self {
let abs_path = path.into();
let (scan_state_tx, scan_state_rx) = smol::channel::unbounded();
let id = ctx.model_id();
let id = cx.model_id();
let snapshot = Snapshot {
id,
scan_id: 0,
@@ -99,14 +99,13 @@ impl Worktree {
scanner.run(event_stream)
});
ctx.spawn(|this, mut ctx| {
cx.spawn(|this, mut cx| {
let this = this.downgrade();
async move {
while let Ok(scan_state) = scan_state_rx.recv().await {
let alive = ctx.update(|ctx| {
if let Some(handle) = this.upgrade(&ctx) {
handle
.update(ctx, |this, ctx| this.observe_scan_state(scan_state, ctx));
let alive = cx.update(|cx| {
if let Some(handle) = this.upgrade(&cx) {
handle.update(cx, |this, cx| this.observe_scan_state(scan_state, cx));
true
} else {
false
@@ -134,21 +133,21 @@ impl Worktree {
}
}
fn observe_scan_state(&mut self, scan_state: ScanState, ctx: &mut ModelContext<Self>) {
fn observe_scan_state(&mut self, scan_state: ScanState, cx: &mut ModelContext<Self>) {
let _ = self.scan_state.0.blocking_send(scan_state);
self.poll_entries(ctx);
self.poll_entries(cx);
}
fn poll_entries(&mut self, ctx: &mut ModelContext<Self>) {
fn poll_entries(&mut self, cx: &mut ModelContext<Self>) {
self.snapshot = self.background_snapshot.lock().clone();
ctx.notify();
cx.notify();
if self.is_scanning() && !self.poll_scheduled {
ctx.spawn(|this, mut ctx| async move {
cx.spawn(|this, mut cx| async move {
smol::Timer::after(Duration::from_millis(100)).await;
this.update(&mut ctx, |this, ctx| {
this.update(&mut cx, |this, cx| {
this.poll_scheduled = false;
this.poll_entries(ctx);
this.poll_entries(cx);
})
})
.detach();
@@ -187,11 +186,11 @@ impl Worktree {
pub fn load_history(
&self,
path: &Path,
ctx: &AppContext,
cx: &AppContext,
) -> impl Future<Output = Result<History>> {
let path = path.to_path_buf();
let abs_path = self.absolutize(&path);
ctx.background_executor().spawn(async move {
cx.background_executor().spawn(async move {
let mut file = fs::File::open(&abs_path)?;
let mut base_text = String::new();
file.read_to_string(&mut base_text)?;
@@ -199,11 +198,11 @@ impl Worktree {
})
}
pub fn save<'a>(&self, path: &Path, content: Rope, ctx: &AppContext) -> Task<Result<()>> {
pub fn save<'a>(&self, path: &Path, content: Rope, cx: &AppContext) -> Task<Result<()>> {
let handles = self.handles.clone();
let path = path.to_path_buf();
let abs_path = self.absolutize(&path);
ctx.background_executor().spawn(async move {
cx.background_executor().spawn(async move {
let buffer_size = content.summary().bytes.min(10 * 1024);
let file = fs::File::create(&abs_path)?;
let mut writer = io::BufWriter::with_capacity(buffer_size, &file);
@@ -430,12 +429,12 @@ impl FileHandle {
/// Returns the last component of this handle's absolute path. If this handle refers to the root
/// of its worktree, then this method will return the name of the worktree itself.
pub fn file_name<'a>(&'a self, ctx: &'a AppContext) -> Option<OsString> {
pub fn file_name<'a>(&'a self, cx: &'a AppContext) -> Option<OsString> {
self.state
.lock()
.path
.file_name()
.or_else(|| self.worktree.read(ctx).abs_path().file_name())
.or_else(|| self.worktree.read(cx).abs_path().file_name())
.map(Into::into)
}
@@ -451,13 +450,13 @@ impl FileHandle {
!self.is_deleted()
}
pub fn load_history(&self, ctx: &AppContext) -> impl Future<Output = Result<History>> {
self.worktree.read(ctx).load_history(&self.path(), ctx)
pub fn load_history(&self, cx: &AppContext) -> impl Future<Output = Result<History>> {
self.worktree.read(cx).load_history(&self.path(), cx)
}
pub fn save<'a>(&self, content: Rope, ctx: &AppContext) -> Task<Result<()>> {
let worktree = self.worktree.read(ctx);
worktree.save(&self.path(), content, ctx)
pub fn save<'a>(&self, content: Rope, cx: &AppContext) -> Task<Result<()>> {
let worktree = self.worktree.read(cx);
worktree.save(&self.path(), content, cx)
}
pub fn worktree_id(&self) -> usize {
@@ -470,12 +469,12 @@ impl FileHandle {
pub fn observe_from_model<T: Entity>(
&self,
ctx: &mut ModelContext<T>,
cx: &mut ModelContext<T>,
mut callback: impl FnMut(&mut T, FileHandle, &mut ModelContext<T>) + 'static,
) {
let mut prev_state = self.state.lock().clone();
let cur_state = Arc::downgrade(&self.state);
ctx.observe(&self.worktree, move |observer, worktree, ctx| {
cx.observe(&self.worktree, move |observer, worktree, cx| {
if let Some(cur_state) = cur_state.upgrade() {
let cur_state_unlocked = cur_state.lock();
if *cur_state_unlocked != prev_state {
@@ -487,7 +486,7 @@ impl FileHandle {
worktree,
state: cur_state,
},
ctx,
cx,
);
}
}
@@ -1201,23 +1200,23 @@ struct UpdateIgnoreStatusJob {
}
pub trait WorktreeHandle {
fn file(&self, path: impl AsRef<Path>, app: &mut MutableAppContext) -> Task<FileHandle>;
fn file(&self, path: impl AsRef<Path>, cx: &mut MutableAppContext) -> Task<FileHandle>;
#[cfg(test)]
fn flush_fs_events<'a>(
&self,
app: &'a gpui::TestAppContext,
cx: &'a gpui::TestAppContext,
) -> futures_core::future::LocalBoxFuture<'a, ()>;
}
impl WorktreeHandle for ModelHandle<Worktree> {
fn file(&self, path: impl AsRef<Path>, app: &mut MutableAppContext) -> Task<FileHandle> {
fn file(&self, path: impl AsRef<Path>, cx: &mut MutableAppContext) -> Task<FileHandle> {
let path = Arc::from(path.as_ref());
let handle = self.clone();
let tree = self.read(app);
let tree = self.read(cx);
let abs_path = tree.absolutize(&path);
app.spawn(|ctx| async move {
let mtime = ctx
cx.spawn(|cx| async move {
let mtime = cx
.background_executor()
.spawn(async move {
if let Ok(metadata) = fs::metadata(&abs_path) {
@@ -1227,7 +1226,7 @@ impl WorktreeHandle for ModelHandle<Worktree> {
}
})
.await;
let state = handle.read_with(&ctx, |tree, _| {
let state = handle.read_with(&cx, |tree, _| {
let mut handles = tree.handles.lock();
if let Some(state) = handles.get(&path).and_then(Weak::upgrade) {
state
@@ -1267,23 +1266,23 @@ impl WorktreeHandle for ModelHandle<Worktree> {
#[cfg(test)]
fn flush_fs_events<'a>(
&self,
app: &'a gpui::TestAppContext,
cx: &'a gpui::TestAppContext,
) -> futures_core::future::LocalBoxFuture<'a, ()> {
use smol::future::FutureExt;
let filename = "fs-event-sentinel";
let root_path = app.read(|ctx| self.read(ctx).abs_path.clone());
let root_path = cx.read(|cx| self.read(cx).abs_path.clone());
let tree = self.clone();
async move {
fs::write(root_path.join(filename), "").unwrap();
tree.condition(&app, |tree, _| tree.entry_for_path(filename).is_some())
tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_some())
.await;
fs::remove_file(root_path.join(filename)).unwrap();
tree.condition(&app, |tree, _| tree.entry_for_path(filename).is_none())
tree.condition(&cx, |tree, _| tree.entry_for_path(filename).is_none())
.await;
app.read(|ctx| tree.read(ctx).scan_complete()).await;
cx.read(|cx| tree.read(cx).scan_complete()).await;
}
.boxed_local()
}
@@ -1408,7 +1407,7 @@ mod tests {
use std::time::{SystemTime, UNIX_EPOCH};
#[gpui::test]
async fn test_populate_and_search(mut app: gpui::TestAppContext) {
async fn test_populate_and_search(mut cx: gpui::TestAppContext) {
let dir = temp_tree(json!({
"root": {
"apple": "",
@@ -1432,11 +1431,11 @@ mod tests {
)
.unwrap();
let tree = app.add_model(|ctx| Worktree::new(root_link_path, ctx));
let tree = cx.add_model(|cx| Worktree::new(root_link_path, cx));
app.read(|ctx| tree.read(ctx).scan_complete()).await;
app.read(|ctx| {
let tree = tree.read(ctx);
cx.read(|cx| tree.read(cx).scan_complete()).await;
cx.read(|cx| {
let tree = tree.read(cx);
assert_eq!(tree.file_count(), 5);
assert_eq!(
@@ -1452,7 +1451,7 @@ mod tests {
false,
10,
Default::default(),
ctx.thread_pool().clone(),
cx.thread_pool().clone(),
)
.into_iter()
.map(|result| result.path)
@@ -1468,60 +1467,58 @@ mod tests {
}
#[gpui::test]
async fn test_save_file(mut app: gpui::TestAppContext) {
async fn test_save_file(mut cx: gpui::TestAppContext) {
let dir = temp_tree(json!({
"file1": "the old contents",
}));
let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx));
app.read(|ctx| tree.read(ctx).scan_complete()).await;
app.read(|ctx| assert_eq!(tree.read(ctx).file_count(), 1));
let tree = cx.add_model(|cx| Worktree::new(dir.path(), cx));
cx.read(|cx| tree.read(cx).scan_complete()).await;
cx.read(|cx| assert_eq!(tree.read(cx).file_count(), 1));
let buffer =
app.add_model(|ctx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), ctx));
let buffer = cx.add_model(|cx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), cx));
let path = tree.update(&mut app, |tree, ctx| {
let path = tree.update(&mut cx, |tree, cx| {
let path = tree.files(0).next().unwrap().path().clone();
assert_eq!(path.file_name().unwrap(), "file1");
smol::block_on(tree.save(&path, buffer.read(ctx).snapshot().text(), ctx.as_ref()))
smol::block_on(tree.save(&path, buffer.read(cx).snapshot().text(), cx.as_ref()))
.unwrap();
path
});
let history = app
.read(|ctx| tree.read(ctx).load_history(&path, ctx))
let history = cx
.read(|cx| tree.read(cx).load_history(&path, cx))
.await
.unwrap();
app.read(|ctx| {
assert_eq!(history.base_text.as_ref(), buffer.read(ctx).text());
cx.read(|cx| {
assert_eq!(history.base_text.as_ref(), buffer.read(cx).text());
});
}
#[gpui::test]
async fn test_save_in_single_file_worktree(mut app: gpui::TestAppContext) {
async fn test_save_in_single_file_worktree(mut cx: gpui::TestAppContext) {
let dir = temp_tree(json!({
"file1": "the old contents",
}));
let tree = app.add_model(|ctx| Worktree::new(dir.path().join("file1"), ctx));
app.read(|ctx| tree.read(ctx).scan_complete()).await;
app.read(|ctx| assert_eq!(tree.read(ctx).file_count(), 1));
let tree = cx.add_model(|cx| Worktree::new(dir.path().join("file1"), cx));
cx.read(|cx| tree.read(cx).scan_complete()).await;
cx.read(|cx| assert_eq!(tree.read(cx).file_count(), 1));
let buffer =
app.add_model(|ctx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), ctx));
let buffer = cx.add_model(|cx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), cx));
let file = app.update(|ctx| tree.file("", ctx)).await;
app.update(|ctx| {
let file = cx.update(|cx| tree.file("", cx)).await;
cx.update(|cx| {
assert_eq!(file.path().file_name(), None);
smol::block_on(file.save(buffer.read(ctx).snapshot().text(), ctx.as_ref())).unwrap();
smol::block_on(file.save(buffer.read(cx).snapshot().text(), cx.as_ref())).unwrap();
});
let history = app.read(|ctx| file.load_history(ctx)).await.unwrap();
app.read(|ctx| assert_eq!(history.base_text.as_ref(), buffer.read(ctx).text()));
let history = cx.read(|cx| file.load_history(cx)).await.unwrap();
cx.read(|cx| assert_eq!(history.base_text.as_ref(), buffer.read(cx).text()));
}
#[gpui::test]
async fn test_rescan_simple(mut app: gpui::TestAppContext) {
async fn test_rescan_simple(mut cx: gpui::TestAppContext) {
let dir = temp_tree(json!({
"a": {
"file1": "",
@@ -1536,31 +1533,31 @@ mod tests {
}
}));
let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx));
let file2 = app.update(|ctx| tree.file("a/file2", ctx)).await;
let file3 = app.update(|ctx| tree.file("a/file3", ctx)).await;
let file4 = app.update(|ctx| tree.file("b/c/file4", ctx)).await;
let file5 = app.update(|ctx| tree.file("b/c/file5", ctx)).await;
let non_existent_file = app.update(|ctx| tree.file("a/file_x", ctx)).await;
let tree = cx.add_model(|cx| Worktree::new(dir.path(), cx));
let file2 = cx.update(|cx| tree.file("a/file2", cx)).await;
let file3 = cx.update(|cx| tree.file("a/file3", cx)).await;
let file4 = cx.update(|cx| tree.file("b/c/file4", cx)).await;
let file5 = cx.update(|cx| tree.file("b/c/file5", cx)).await;
let non_existent_file = cx.update(|cx| tree.file("a/file_x", cx)).await;
// After scanning, the worktree knows which files exist and which don't.
app.read(|ctx| tree.read(ctx).scan_complete()).await;
cx.read(|cx| tree.read(cx).scan_complete()).await;
assert!(!file2.is_deleted());
assert!(!file3.is_deleted());
assert!(!file4.is_deleted());
assert!(!file5.is_deleted());
assert!(non_existent_file.is_deleted());
tree.flush_fs_events(&app).await;
tree.flush_fs_events(&cx).await;
std::fs::rename(dir.path().join("a/file3"), dir.path().join("b/c/file3")).unwrap();
std::fs::remove_file(dir.path().join("b/c/file5")).unwrap();
std::fs::rename(dir.path().join("b/c"), dir.path().join("d")).unwrap();
std::fs::rename(dir.path().join("a/file2"), dir.path().join("a/file2.new")).unwrap();
tree.flush_fs_events(&app).await;
tree.flush_fs_events(&cx).await;
app.read(|ctx| {
cx.read(|cx| {
assert_eq!(
tree.read(ctx)
tree.read(cx)
.paths()
.map(|p| p.to_str().unwrap())
.collect::<Vec<_>>(),
@@ -1591,7 +1588,7 @@ mod tests {
}
#[gpui::test]
async fn test_rescan_with_gitignore(mut app: gpui::TestAppContext) {
async fn test_rescan_with_gitignore(mut cx: gpui::TestAppContext) {
let dir = temp_tree(json!({
".git": {},
".gitignore": "ignored-dir\n",
@@ -1603,11 +1600,11 @@ mod tests {
}
}));
let tree = app.add_model(|ctx| Worktree::new(dir.path(), ctx));
app.read(|ctx| tree.read(ctx).scan_complete()).await;
tree.flush_fs_events(&app).await;
app.read(|ctx| {
let tree = tree.read(ctx);
let tree = cx.add_model(|cx| Worktree::new(dir.path(), cx));
cx.read(|cx| tree.read(cx).scan_complete()).await;
tree.flush_fs_events(&cx).await;
cx.read(|cx| {
let tree = tree.read(cx);
let tracked = tree.entry_for_path("tracked-dir/tracked-file1").unwrap();
let ignored = tree.entry_for_path("ignored-dir/ignored-file1").unwrap();
assert_eq!(tracked.is_ignored(), false);
@@ -1616,9 +1613,9 @@ mod tests {
fs::write(dir.path().join("tracked-dir/tracked-file2"), "").unwrap();
fs::write(dir.path().join("ignored-dir/ignored-file2"), "").unwrap();
tree.flush_fs_events(&app).await;
app.read(|ctx| {
let tree = tree.read(ctx);
tree.flush_fs_events(&cx).await;
cx.read(|cx| {
let tree = tree.read(cx);
let dot_git = tree.entry_for_path(".git").unwrap();
let tracked = tree.entry_for_path("tracked-dir/tracked-file2").unwrap();
let ignored = tree.entry_for_path("ignored-dir/ignored-file2").unwrap();