Make platform input handler private

Automatically record the context on non-view input handlers
Simplify the async window context update() method
This commit is contained in:
Mikayla 2024-01-20 06:56:04 -08:00
parent 0858db9ebb
commit 33105486aa
No known key found for this signature in database
17 changed files with 229 additions and 148 deletions

View file

@ -311,7 +311,7 @@ impl PickerDelegate for CommandPaletteDelegate {
let action = command.action; let action = command.action;
cx.focus(&self.previous_focus_handle); cx.focus(&self.previous_focus_handle);
cx.window_context() cx.window_context()
.spawn(move |mut cx| async move { cx.update(|_, cx| cx.dispatch_action(action)) }) .spawn(move |mut cx| async move { cx.update(|cx| cx.dispatch_action(action)) })
.detach_and_log_err(cx); .detach_and_log_err(cx);
self.dismissed(cx); self.dismissed(cx);
} }

View file

@ -355,7 +355,7 @@ fn initiate_sign_in(cx: &mut WindowContext) {
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
task.await; task.await;
if let Some(copilot) = cx.update(|_, cx| Copilot::global(cx)).ok().flatten() { if let Some(copilot) = cx.update(|cx| Copilot::global(cx)).ok().flatten() {
workspace workspace
.update(&mut cx, |workspace, cx| match copilot.read(cx).status() { .update(&mut cx, |workspace, cx| match copilot.read(cx).status() {
Status::Authorized => workspace.show_toast( Status::Authorized => workspace.show_toast(

View file

@ -57,9 +57,10 @@ use gpui::{
div, impl_actions, point, prelude::*, px, relative, rems, size, uniform_list, Action, div, impl_actions, point, prelude::*, px, relative, rems, size, uniform_list, Action,
AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context, AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context,
DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontStyle, FontWeight, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontStyle, FontWeight,
HighlightStyle, Hsla, InputHandler, InteractiveText, KeyContext, Model, MouseButton, HighlightStyle, Hsla, InteractiveText, KeyContext, Model, MouseButton, ParentElement, Pixels,
ParentElement, Pixels, Render, SharedString, Styled, StyledText, Subscription, Task, TextStyle, Render, SharedString, Styled, StyledText, Subscription, Task, TextStyle,
UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WhiteSpace, WindowContext, UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext, WeakView,
WhiteSpace, WindowContext,
}; };
use highlight_matching_bracket::refresh_matching_bracket_highlights; use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState}; use hover_popover::{hide_hover, HoverState};
@ -3378,7 +3379,7 @@ impl Editor {
let replica_id = this.update(&mut cx, |this, cx| this.replica_id(cx))?; let replica_id = this.update(&mut cx, |this, cx| this.replica_id(cx))?;
let mut entries = transaction.0.into_iter().collect::<Vec<_>>(); let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
cx.update(|_, cx| { cx.update(|cx| {
entries.sort_unstable_by_key(|(buffer, _)| { entries.sort_unstable_by_key(|(buffer, _)| {
buffer.read(cx).file().map(|f| f.path().clone()) buffer.read(cx).file().map(|f| f.path().clone())
}); });
@ -9166,7 +9167,7 @@ impl Render for Editor {
} }
} }
impl InputHandler for Editor { impl ViewInputHandler for Editor {
fn text_for_range( fn text_for_range(
&mut self, &mut self,
range_utf16: Range<usize>, range_utf16: Range<usize>,

View file

@ -2951,9 +2951,10 @@ impl Element for EditorElement {
self.register_key_listeners(cx); self.register_key_listeners(cx);
cx.with_content_mask(Some(ContentMask { bounds }), |cx| { cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
let input_handler = cx.handle_input(
ElementInputHandler::new(bounds, self.editor.clone(), cx); &focus_handle,
cx.handle_input(&focus_handle, input_handler); ElementInputHandler::new(bounds, self.editor.clone()),
);
self.paint_background(gutter_bounds, text_bounds, &layout, cx); self.paint_background(gutter_bounds, text_bounds, &layout, cx);
if layout.gutter_size.width > Pixels::ZERO { if layout.gutter_size.width > Pixels::ZERO {

View file

@ -247,7 +247,7 @@ fn show_hover(
}; };
// query the LSP for hover info // query the LSP for hover info
let hover_request = cx.update(|_, cx| { let hover_request = cx.update(|cx| {
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
project.hover(&buffer, buffer_position, cx) project.hover(&buffer, buffer_position, cx)
}) })

View file

@ -213,7 +213,12 @@ impl AsyncWindowContext {
} }
/// A convenience method for [WindowContext::update()] /// A convenience method for [WindowContext::update()]
pub fn update<R>( pub fn update<R>(&mut self, update: impl FnOnce(&mut WindowContext) -> R) -> Result<R> {
self.app.update_window(self.window, |_, cx| update(cx))
}
/// A convenience method for [WindowContext::update()]
pub fn update_root<R>(
&mut self, &mut self,
update: impl FnOnce(AnyView, &mut WindowContext) -> R, update: impl FnOnce(AnyView, &mut WindowContext) -> R,
) -> Result<R> { ) -> Result<R> {

View file

@ -1420,7 +1420,7 @@ impl Interactivity {
move |mut cx| async move { move |mut cx| async move {
cx.background_executor().timer(TOOLTIP_DELAY).await; cx.background_executor().timer(TOOLTIP_DELAY).await;
cx.update(|_, cx| { cx.update(|cx| {
active_tooltip.borrow_mut().replace( active_tooltip.borrow_mut().replace(
ActiveTooltip { ActiveTooltip {
tooltip: Some(AnyTooltip { tooltip: Some(AnyTooltip {

View file

@ -1,13 +1,11 @@
use crate::{ use crate::{Bounds, InputHandler, Pixels, View, ViewContext, WindowContext};
AsyncWindowContext, Bounds, Pixels, PlatformInputHandler, View, ViewContext, WindowContext,
};
use std::ops::Range; use std::ops::Range;
/// Implement this trait to allow views to handle textual input when implementing an editor, field, etc. /// Implement this trait to allow views to handle textual input when implementing an editor, field, etc.
/// ///
/// Once your view `V` implements this trait, you can use it to construct an [`ElementInputHandler<V>`]. /// Once your view `V` implements this trait, you can use it to construct an [`ElementInputHandler<V>`].
/// This input handler can then be assigned during paint by calling [`WindowContext::handle_input`]. /// This input handler can then be assigned during paint by calling [`WindowContext::handle_input`].
pub trait InputHandler: 'static + Sized { pub trait ViewInputHandler: 'static + Sized {
fn text_for_range(&mut self, range: Range<usize>, cx: &mut ViewContext<Self>) fn text_for_range(&mut self, range: Range<usize>, cx: &mut ViewContext<Self>)
-> Option<String>; -> Option<String>;
fn selected_text_range(&mut self, cx: &mut ViewContext<Self>) -> Option<Range<usize>>; fn selected_text_range(&mut self, cx: &mut ViewContext<Self>) -> Option<Range<usize>>;
@ -39,7 +37,6 @@ pub trait InputHandler: 'static + Sized {
pub struct ElementInputHandler<V> { pub struct ElementInputHandler<V> {
view: View<V>, view: View<V>,
element_bounds: Bounds<Pixels>, element_bounds: Bounds<Pixels>,
cx: AsyncWindowContext,
} }
impl<V: 'static> ElementInputHandler<V> { impl<V: 'static> ElementInputHandler<V> {
@ -47,45 +44,42 @@ impl<V: 'static> ElementInputHandler<V> {
/// containing view. /// containing view.
/// ///
/// [element_paint]: crate::Element::paint /// [element_paint]: crate::Element::paint
pub fn new(element_bounds: Bounds<Pixels>, view: View<V>, cx: &mut WindowContext) -> Self { pub fn new(element_bounds: Bounds<Pixels>, view: View<V>) -> Self {
ElementInputHandler { ElementInputHandler {
view, view,
element_bounds, element_bounds,
cx: cx.to_async(),
} }
} }
} }
impl<V: InputHandler> PlatformInputHandler for ElementInputHandler<V> { impl<V: ViewInputHandler> InputHandler for ElementInputHandler<V> {
fn selected_text_range(&mut self) -> Option<Range<usize>> { fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>> {
self.view self.view
.update(&mut self.cx, |view, cx| view.selected_text_range(cx)) .update(cx, |view, cx| view.selected_text_range(cx))
.ok()
.flatten()
} }
fn marked_text_range(&mut self) -> Option<Range<usize>> { fn marked_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>> {
self.view self.view.update(cx, |view, cx| view.marked_text_range(cx))
.update(&mut self.cx, |view, cx| view.marked_text_range(cx))
.ok()
.flatten()
} }
fn text_for_range(&mut self, range_utf16: Range<usize>) -> Option<String> { fn text_for_range(
&mut self,
range_utf16: Range<usize>,
cx: &mut WindowContext,
) -> Option<String> {
self.view self.view
.update(&mut self.cx, |view, cx| { .update(cx, |view, cx| view.text_for_range(range_utf16, cx))
view.text_for_range(range_utf16, cx)
})
.ok()
.flatten()
} }
fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str) { fn replace_text_in_range(
self.view &mut self,
.update(&mut self.cx, |view, cx| { replacement_range: Option<Range<usize>>,
view.replace_text_in_range(replacement_range, text, cx) text: &str,
}) cx: &mut WindowContext,
.ok(); ) {
self.view.update(cx, |view, cx| {
view.replace_text_in_range(replacement_range, text, cx)
});
} }
fn replace_and_mark_text_in_range( fn replace_and_mark_text_in_range(
@ -93,26 +87,24 @@ impl<V: InputHandler> PlatformInputHandler for ElementInputHandler<V> {
range_utf16: Option<Range<usize>>, range_utf16: Option<Range<usize>>,
new_text: &str, new_text: &str,
new_selected_range: Option<Range<usize>>, new_selected_range: Option<Range<usize>>,
cx: &mut WindowContext,
) { ) {
self.view self.view.update(cx, |view, cx| {
.update(&mut self.cx, |view, cx| { view.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx)
view.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx) });
})
.ok();
} }
fn unmark_text(&mut self) { fn unmark_text(&mut self, cx: &mut WindowContext) {
self.view self.view.update(cx, |view, cx| view.unmark_text(cx));
.update(&mut self.cx, |view, cx| view.unmark_text(cx))
.ok();
} }
fn bounds_for_range(&mut self, range_utf16: Range<usize>) -> Option<Bounds<Pixels>> { fn bounds_for_range(
self.view &mut self,
.update(&mut self.cx, |view, cx| { range_utf16: Range<usize>,
view.bounds_for_range(range_utf16, self.element_bounds, cx) cx: &mut WindowContext,
}) ) -> Option<Bounds<Pixels>> {
.ok() self.view.update(cx, |view, cx| {
.flatten() view.bounds_for_range(range_utf16, self.element_bounds, cx)
})
} }
} }

View file

@ -6,10 +6,10 @@ mod mac;
mod test; mod test;
use crate::{ use crate::{
Action, AnyWindowHandle, BackgroundExecutor, Bounds, DevicePixels, Font, FontId, FontMetrics, Action, AnyWindowHandle, AsyncWindowContext, BackgroundExecutor, Bounds, DevicePixels, Font,
FontRun, ForegroundExecutor, GlobalPixels, GlyphId, Keymap, LineLayout, Pixels, PlatformInput, FontId, FontMetrics, FontRun, ForegroundExecutor, GlobalPixels, GlyphId, Keymap, LineLayout,
Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Result, Scene, SharedString, Pixels, PlatformInput, Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Result,
Size, TaskLabel, Scene, SharedString, Size, TaskLabel, WindowContext,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use async_task::Runnable; use async_task::Runnable;
@ -149,8 +149,8 @@ pub(crate) trait PlatformWindow {
fn mouse_position(&self) -> Point<Pixels>; fn mouse_position(&self) -> Point<Pixels>;
fn modifiers(&self) -> Modifiers; fn modifiers(&self) -> Modifiers;
fn as_any_mut(&mut self) -> &mut dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any;
fn set_input_handler(&mut self, input_handler: Box<dyn PlatformInputHandler>); fn set_input_handler(&mut self, input_handler: PlatformInputHandler);
fn take_input_handler(&mut self) -> Option<Box<dyn PlatformInputHandler>>; fn take_input_handler(&mut self) -> Option<PlatformInputHandler>;
fn prompt(&self, level: PromptLevel, msg: &str, answers: &[&str]) -> oneshot::Receiver<usize>; fn prompt(&self, level: PromptLevel, msg: &str, answers: &[&str]) -> oneshot::Receiver<usize>;
fn activate(&self); fn activate(&self);
fn set_title(&mut self, title: &str); fn set_title(&mut self, title: &str);
@ -325,19 +325,103 @@ impl From<TileId> for etagere::AllocId {
} }
} }
pub trait PlatformInputHandler: 'static { pub(crate) struct PlatformInputHandler {
fn selected_text_range(&mut self) -> Option<Range<usize>>; cx: AsyncWindowContext,
fn marked_text_range(&mut self) -> Option<Range<usize>>; handler: Box<dyn InputHandler>,
fn text_for_range(&mut self, range_utf16: Range<usize>) -> Option<String>; }
fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str);
impl PlatformInputHandler {
pub fn new(cx: AsyncWindowContext, handler: Box<dyn InputHandler>) -> Self {
Self { cx, handler }
}
fn selected_text_range(&mut self) -> Option<Range<usize>> {
self.cx
.update(|cx| self.handler.selected_text_range(cx))
.ok()
.flatten()
}
fn marked_text_range(&mut self) -> Option<Range<usize>> {
self.cx
.update(|cx| self.handler.marked_text_range(cx))
.ok()
.flatten()
}
fn text_for_range(&mut self, range_utf16: Range<usize>) -> Option<String> {
self.cx
.update(|cx| self.handler.text_for_range(range_utf16, cx))
.ok()
.flatten()
}
fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str) {
self.cx
.update(|cx| {
self.handler
.replace_text_in_range(replacement_range, text, cx)
})
.ok();
}
fn replace_and_mark_text_in_range( fn replace_and_mark_text_in_range(
&mut self, &mut self,
range_utf16: Option<Range<usize>>, range_utf16: Option<Range<usize>>,
new_text: &str, new_text: &str,
new_selected_range: Option<Range<usize>>, new_selected_range: Option<Range<usize>>,
) {
self.cx
.update(|cx| {
self.handler.replace_and_mark_text_in_range(
range_utf16,
new_text,
new_selected_range,
cx,
)
})
.ok();
}
fn unmark_text(&mut self) {
self.cx.update(|cx| self.handler.unmark_text(cx)).ok();
}
fn bounds_for_range(&mut self, range_utf16: Range<usize>) -> Option<Bounds<Pixels>> {
self.cx
.update(|cx| self.handler.bounds_for_range(range_utf16, cx))
.ok()
.flatten()
}
}
pub trait InputHandler: 'static {
fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
fn marked_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
fn text_for_range(
&mut self,
range_utf16: Range<usize>,
cx: &mut WindowContext,
) -> Option<String>;
fn replace_text_in_range(
&mut self,
replacement_range: Option<Range<usize>>,
text: &str,
cx: &mut WindowContext,
); );
fn unmark_text(&mut self); fn replace_and_mark_text_in_range(
fn bounds_for_range(&mut self, range_utf16: Range<usize>) -> Option<Bounds<Pixels>>; &mut self,
range_utf16: Option<Range<usize>>,
new_text: &str,
new_selected_range: Option<Range<usize>>,
cx: &mut WindowContext,
);
fn unmark_text(&mut self, cx: &mut WindowContext);
fn bounds_for_range(
&mut self,
range_utf16: Range<usize>,
cx: &mut WindowContext,
) -> Option<Bounds<Pixels>>;
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,9 +1,9 @@
use super::{global_bounds_from_ns_rect, ns_string, MacDisplay, MetalRenderer, NSRange}; use super::{global_bounds_from_ns_rect, ns_string, MacDisplay, MetalRenderer, NSRange};
use crate::{ use crate::{
global_bounds_to_ns_rect, point, px, size, AnyWindowHandle, Bounds, ExternalPaths, global_bounds_to_ns_rect, platform::PlatformInputHandler, point, px, size, AnyWindowHandle,
FileDropEvent, ForegroundExecutor, GlobalPixels, KeyDownEvent, Keystroke, Modifiers, Bounds, ExternalPaths, FileDropEvent, ForegroundExecutor, GlobalPixels, KeyDownEvent,
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent,
PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformWindow, Point,
PromptLevel, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions, PromptLevel, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
}; };
use block::ConcreteBlock; use block::ConcreteBlock;
@ -327,7 +327,7 @@ struct MacWindowState {
should_close_callback: Option<Box<dyn FnMut() -> bool>>, should_close_callback: Option<Box<dyn FnMut() -> bool>>,
close_callback: Option<Box<dyn FnOnce()>>, close_callback: Option<Box<dyn FnOnce()>>,
appearance_changed_callback: Option<Box<dyn FnMut()>>, appearance_changed_callback: Option<Box<dyn FnMut()>>,
input_handler: Option<Box<dyn PlatformInputHandler>>, input_handler: Option<PlatformInputHandler>,
pending_key_down: Option<(KeyDownEvent, Option<InsertText>)>, pending_key_down: Option<(KeyDownEvent, Option<InsertText>)>,
last_key_equivalent: Option<KeyDownEvent>, last_key_equivalent: Option<KeyDownEvent>,
synthetic_drag_counter: usize, synthetic_drag_counter: usize,
@ -764,11 +764,11 @@ impl PlatformWindow for MacWindow {
self self
} }
fn set_input_handler(&mut self, input_handler: Box<dyn PlatformInputHandler>) { fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {
self.0.as_ref().lock().input_handler = Some(input_handler); self.0.as_ref().lock().input_handler = Some(input_handler);
} }
fn take_input_handler(&mut self) -> Option<Box<dyn PlatformInputHandler>> { fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
self.0.as_ref().lock().input_handler.take() self.0.as_ref().lock().input_handler.take()
} }
@ -1761,13 +1761,13 @@ fn drag_event_position(window_state: &Mutex<MacWindowState>, dragging_info: id)
fn with_input_handler<F, R>(window: &Object, f: F) -> Option<R> fn with_input_handler<F, R>(window: &Object, f: F) -> Option<R>
where where
F: FnOnce(&mut dyn PlatformInputHandler) -> R, F: FnOnce(&mut PlatformInputHandler) -> R,
{ {
let window_state = unsafe { get_window_state(window) }; let window_state = unsafe { get_window_state(window) };
let mut lock = window_state.as_ref().lock(); let mut lock = window_state.as_ref().lock();
if let Some(mut input_handler) = lock.input_handler.take() { if let Some(mut input_handler) = lock.input_handler.take() {
drop(lock); drop(lock);
let result = f(input_handler.as_mut()); let result = f(&mut input_handler);
window_state.lock().input_handler = Some(input_handler); window_state.lock().input_handler = Some(input_handler);
Some(result) Some(result)
} else { } else {

View file

@ -5,13 +5,13 @@ use crate::{
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect,
Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla, Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla,
ImageData, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, KeystrokeEvent, LayoutId, ImageData, InputHandler, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent,
Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, KeystrokeEvent, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton,
MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay,
PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel,
RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, Scene, Shadow, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, Scene,
SharedString, Size, Style, SubscriberSet, Subscription, Surface, TaffyLayoutEngine, Task, Shadow, SharedString, Size, Style, SubscriberSet, Subscription, Surface, TaffyLayoutEngine,
Underline, UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, Task, Underline, UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions,
SUBPIXEL_VARIANTS, SUBPIXEL_VARIANTS,
}; };
use anyhow::{anyhow, Context as _, Result}; use anyhow::{anyhow, Context as _, Result};
@ -298,7 +298,7 @@ pub(crate) struct ElementStateBox {
struct RequestedInputHandler { struct RequestedInputHandler {
view_id: EntityId, view_id: EntityId,
handler: Option<Box<dyn PlatformInputHandler>>, handler: Option<PlatformInputHandler>,
} }
struct TooltipRequest { struct TooltipRequest {
@ -2188,16 +2188,15 @@ impl<'a> WindowContext<'a> {
/// rendered. /// rendered.
/// ///
/// [element_input_handler]: crate::ElementInputHandler /// [element_input_handler]: crate::ElementInputHandler
pub fn handle_input( pub fn handle_input(&mut self, focus_handle: &FocusHandle, input_handler: impl InputHandler) {
&mut self,
focus_handle: &FocusHandle,
input_handler: impl PlatformInputHandler,
) {
if focus_handle.is_focused(self) { if focus_handle.is_focused(self) {
let view_id = self.parent_view_id(); let view_id = self.parent_view_id();
self.window.next_frame.requested_input_handler = Some(RequestedInputHandler { self.window.next_frame.requested_input_handler = Some(RequestedInputHandler {
view_id, view_id,
handler: Some(Box::new(input_handler)), handler: Some(PlatformInputHandler::new(
self.to_async(),
Box::new(input_handler),
)),
}) })
} }
} }
@ -2209,7 +2208,7 @@ impl<'a> WindowContext<'a> {
self.window self.window
.platform_window .platform_window
.on_should_close(Box::new(move || { .on_should_close(Box::new(move || {
this.update(|_, cx| { this.update(|cx| {
// Ensure that the window is removed from the app if it's been closed // Ensure that the window is removed from the app if it's been closed
// by always pre-empting the system close event. // by always pre-empting the system close event.
if f(cx) { if f(cx) {

View file

@ -102,7 +102,7 @@ pub fn new_journal_entry(app_state: Arc<AppState>, cx: &mut WindowContext) {
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
let (journal_dir, entry_path) = create_entry.await?; let (journal_dir, entry_path) = create_entry.await?;
let (workspace, _) = cx let (workspace, _) = cx
.update(|_, cx| workspace::open_paths(&[journal_dir], &app_state, None, cx))? .update(|cx| workspace::open_paths(&[journal_dir], &app_state, None, cx))?
.await?; .await?;
let opened = workspace let opened = workspace

View file

@ -1,11 +1,11 @@
use editor::{Cursor, HighlightedRange, HighlightedRangeLine}; use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{ use gpui::{
div, fill, point, px, relative, AnyElement, AsyncWindowContext, AvailableSpace, BorrowWindow, div, fill, point, px, relative, AnyElement, AvailableSpace, BorrowWindow, Bounds,
Bounds, DispatchPhase, Element, ElementId, FocusHandle, Font, FontStyle, FontWeight, DispatchPhase, Element, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle,
HighlightStyle, Hsla, InteractiveBounds, InteractiveElement, InteractiveElementState, Hsla, InputHandler, InteractiveBounds, InteractiveElement, InteractiveElementState,
Interactivity, IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, Interactivity, IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton,
MouseMoveEvent, Pixels, PlatformInputHandler, Point, ShapedLine, StatefulInteractiveElement, MouseMoveEvent, Pixels, Point, ShapedLine, StatefulInteractiveElement, Styled, TextRun,
Styled, TextRun, TextStyle, TextSystem, UnderlineStyle, WeakView, WhiteSpace, WindowContext, TextStyle, TextSystem, UnderlineStyle, WeakView, WhiteSpace, WindowContext,
}; };
use itertools::Itertools; use itertools::Itertools;
use language::CursorShape; use language::CursorShape;
@ -749,7 +749,6 @@ impl Element for TerminalElement {
let origin = bounds.origin + Point::new(layout.gutter, px(0.)); let origin = bounds.origin + Point::new(layout.gutter, px(0.));
let terminal_input_handler = TerminalInputHandler { let terminal_input_handler = TerminalInputHandler {
cx: cx.to_async(),
terminal: self.terminal.clone(), terminal: self.terminal.clone(),
cursor_bounds: layout cursor_bounds: layout
.cursor .cursor
@ -838,37 +837,35 @@ impl IntoElement for TerminalElement {
} }
struct TerminalInputHandler { struct TerminalInputHandler {
cx: AsyncWindowContext,
terminal: Model<Terminal>, terminal: Model<Terminal>,
workspace: WeakView<Workspace>, workspace: WeakView<Workspace>,
cursor_bounds: Option<Bounds<Pixels>>, cursor_bounds: Option<Bounds<Pixels>>,
} }
impl PlatformInputHandler for TerminalInputHandler { impl InputHandler for TerminalInputHandler {
fn selected_text_range(&mut self) -> Option<std::ops::Range<usize>> { fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<std::ops::Range<usize>> {
self.cx if self
.update(|_, cx| { .terminal
if self .read(cx)
.terminal .last_content
.read(cx) .mode
.last_content .contains(TermMode::ALT_SCREEN)
.mode {
.contains(TermMode::ALT_SCREEN) None
{ } else {
None Some(0..0)
} else { }
Some(0..0)
}
})
.ok()
.flatten()
} }
fn marked_text_range(&mut self) -> Option<std::ops::Range<usize>> { fn marked_text_range(&mut self, _: &mut WindowContext) -> Option<std::ops::Range<usize>> {
None None
} }
fn text_for_range(&mut self, _: std::ops::Range<usize>) -> Option<String> { fn text_for_range(
&mut self,
_: std::ops::Range<usize>,
_: &mut WindowContext,
) -> Option<String> {
None None
} }
@ -876,19 +873,16 @@ impl PlatformInputHandler for TerminalInputHandler {
&mut self, &mut self,
_replacement_range: Option<std::ops::Range<usize>>, _replacement_range: Option<std::ops::Range<usize>>,
text: &str, text: &str,
cx: &mut WindowContext,
) { ) {
self.cx self.terminal.update(cx, |terminal, _| {
.update(|_, cx| { terminal.input(text.into());
self.terminal.update(cx, |terminal, _| { });
terminal.input(text.into());
});
self.workspace self.workspace
.update(cx, |this, cx| { .update(cx, |this, cx| {
let telemetry = this.project().read(cx).client().telemetry().clone(); let telemetry = this.project().read(cx).client().telemetry().clone();
telemetry.log_edit_event("terminal"); telemetry.log_edit_event("terminal");
})
.ok();
}) })
.ok(); .ok();
} }
@ -898,12 +892,17 @@ impl PlatformInputHandler for TerminalInputHandler {
_range_utf16: Option<std::ops::Range<usize>>, _range_utf16: Option<std::ops::Range<usize>>,
_new_text: &str, _new_text: &str,
_new_selected_range: Option<std::ops::Range<usize>>, _new_selected_range: Option<std::ops::Range<usize>>,
_: &mut WindowContext,
) { ) {
} }
fn unmark_text(&mut self) {} fn unmark_text(&mut self, _: &mut WindowContext) {}
fn bounds_for_range(&mut self, _range_utf16: std::ops::Range<usize>) -> Option<Bounds<Pixels>> { fn bounds_for_range(
&mut self,
_range_utf16: std::ops::Range<usize>,
_: &mut WindowContext,
) -> Option<Bounds<Pixels>> {
self.cursor_bounds self.cursor_bounds
} }
} }

View file

@ -772,7 +772,7 @@ impl Item for TerminalView {
.log_err() .log_err()
.flatten() .flatten()
.or_else(|| { .or_else(|| {
cx.update(|_, cx| { cx.update(|cx| {
let strategy = TerminalSettings::get_global(cx).working_directory.clone(); let strategy = TerminalSettings::get_global(cx).working_directory.clone();
workspace workspace
.upgrade() .upgrade()

View file

@ -281,7 +281,7 @@ where
Ok(value) => Some(value), Ok(value) => Some(value),
Err(err) => { Err(err) => {
log::error!("TODO {err:?}"); log::error!("TODO {err:?}");
cx.update(|view, cx| { cx.update_root(|view, cx| {
if let Ok(workspace) = view.downcast::<Workspace>() { if let Ok(workspace) = view.downcast::<Workspace>() {
workspace.update(cx, |workspace, cx| workspace.show_error(&err, cx)) workspace.update(cx, |workspace, cx| workspace.show_error(&err, cx))
} }

View file

@ -1092,7 +1092,7 @@ impl Pane {
return Ok(true); return Ok(true);
} }
let (mut has_conflict, mut is_dirty, mut can_save, can_save_as) = cx.update(|_, cx| { let (mut has_conflict, mut is_dirty, mut can_save, can_save_as) = cx.update(|cx| {
( (
item.has_conflict(cx), item.has_conflict(cx),
item.is_dirty(cx), item.is_dirty(cx),
@ -1132,7 +1132,7 @@ impl Pane {
} }
} else if is_dirty && (can_save || can_save_as) { } else if is_dirty && (can_save || can_save_as) {
if save_intent == SaveIntent::Close { if save_intent == SaveIntent::Close {
let will_autosave = cx.update(|_, cx| { let will_autosave = cx.update(|cx| {
matches!( matches!(
WorkspaceSettings::get_global(cx).autosave, WorkspaceSettings::get_global(cx).autosave,
AutosaveSetting::OnFocusChange | AutosaveSetting::OnWindowChange AutosaveSetting::OnFocusChange | AutosaveSetting::OnWindowChange
@ -1166,7 +1166,7 @@ impl Pane {
})? })?
.unwrap_or_else(|| Path::new("").into()); .unwrap_or_else(|| Path::new("").into());
let abs_path = cx.update(|_, cx| cx.prompt_for_new_path(&start_abs_path))?; let abs_path = cx.update(|cx| cx.prompt_for_new_path(&start_abs_path))?;
if let Some(abs_path) = abs_path.await.ok().flatten() { if let Some(abs_path) = abs_path.await.ok().flatten() {
pane.update(cx, |_, cx| item.save_as(project, abs_path, cx))? pane.update(cx, |_, cx| item.save_as(project, abs_path, cx))?
.await?; .await?;

View file

@ -1233,7 +1233,7 @@ impl Workspace {
} }
for (pane, item) in dirty_items { for (pane, item) in dirty_items {
let (singleton, project_entry_ids) = let (singleton, project_entry_ids) =
cx.update(|_, cx| (item.is_singleton(cx), item.project_entry_ids(cx)))?; cx.update(|cx| (item.is_singleton(cx), item.project_entry_ids(cx)))?;
if singleton || !project_entry_ids.is_empty() { if singleton || !project_entry_ids.is_empty() {
if let Some(ix) = if let Some(ix) =
pane.update(&mut cx, |pane, _| pane.index_for_item(item.as_ref()))? pane.update(&mut cx, |pane, _| pane.index_for_item(item.as_ref()))?
@ -1307,7 +1307,7 @@ impl Workspace {
} else { } else {
None None
}; };
cx.update(|_, cx| open_paths(&paths, &app_state, window_to_replace, cx))? cx.update(|cx| open_paths(&paths, &app_state, window_to_replace, cx))?
.await?; .await?;
Ok(()) Ok(())
}) })
@ -1912,7 +1912,7 @@ impl Workspace {
let project_item = project.update(cx, |project, cx| project.open_path(path, cx)); let project_item = project.update(cx, |project, cx| project.open_path(path, cx));
cx.spawn(|_, mut cx| async move { cx.spawn(|_, mut cx| async move {
let (project_entry_id, project_item) = project_item.await?; let (project_entry_id, project_item) = project_item.await?;
let build_item = cx.update(|_, cx| { let build_item = cx.update(|cx| {
cx.default_global::<ProjectItemBuilders>() cx.default_global::<ProjectItemBuilders>()
.get(&project_item.entity_type()) .get(&project_item.entity_type())
.ok_or_else(|| anyhow!("no item builder for project item")) .ok_or_else(|| anyhow!("no item builder for project item"))
@ -2709,7 +2709,7 @@ impl Workspace {
) -> Result<()> { ) -> Result<()> {
let this = this.upgrade().context("workspace dropped")?; let this = this.upgrade().context("workspace dropped")?;
let item_builders = cx.update(|_, cx| { let item_builders = cx.update(|cx| {
cx.default_global::<FollowableItemBuilders>() cx.default_global::<FollowableItemBuilders>()
.values() .values()
.map(|b| b.0) .map(|b| b.0)
@ -2728,7 +2728,7 @@ impl Workspace {
Err(anyhow!("missing view variant"))?; Err(anyhow!("missing view variant"))?;
} }
for build_item in &item_builders { for build_item in &item_builders {
let task = cx.update(|_, cx| { let task = cx.update(|cx| {
build_item(pane.clone(), this.clone(), id, &mut variant, cx) build_item(pane.clone(), this.clone(), id, &mut variant, cx)
})?; })?;
if let Some(task) = task { if let Some(task) = task {
@ -3141,7 +3141,7 @@ impl Workspace {
center_group = Some((group, active_pane)) center_group = Some((group, active_pane))
} }
let mut items_by_project_path = cx.update(|_, cx| { let mut items_by_project_path = cx.update(|cx| {
center_items center_items
.unwrap_or_default() .unwrap_or_default()
.into_iter() .into_iter()
@ -3407,7 +3407,7 @@ fn open_items(
let restored_project_paths = restored_items let restored_project_paths = restored_items
.iter() .iter()
.filter_map(|item| { .filter_map(|item| {
cx.update(|_, cx| item.as_ref()?.project_path(cx)) cx.update(|cx| item.as_ref()?.project_path(cx))
.ok() .ok()
.flatten() .flatten()
}) })