mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-27 12:54:42 +00:00
Document the gpui platform code (#4180)
In the process I also: - Made the AsyncWindowContext slightly more ergonomic. - Refactored the input handler traits to enable easy, non-view input handlers - Locked down the visibility on all mac-specific GPUI code - Documented all remaining, public types Release Notes: - N/A
This commit is contained in:
commit
76d38525ff
37 changed files with 511 additions and 249 deletions
|
@ -311,7 +311,7 @@ impl PickerDelegate for CommandPaletteDelegate {
|
|||
let action = command.action;
|
||||
cx.focus(&self.previous_focus_handle);
|
||||
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);
|
||||
self.dismissed(cx);
|
||||
}
|
||||
|
|
|
@ -355,7 +355,7 @@ fn initiate_sign_in(cx: &mut WindowContext) {
|
|||
|
||||
cx.spawn(|mut cx| async move {
|
||||
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
|
||||
.update(&mut cx, |workspace, cx| match copilot.read(cx).status() {
|
||||
Status::Authorized => workspace.show_toast(
|
||||
|
|
|
@ -57,9 +57,10 @@ use gpui::{
|
|||
div, impl_actions, point, prelude::*, px, relative, rems, size, uniform_list, Action,
|
||||
AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context,
|
||||
DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontStyle, FontWeight,
|
||||
HighlightStyle, Hsla, InputHandler, InteractiveText, KeyContext, Model, MouseButton,
|
||||
ParentElement, Pixels, Render, SharedString, Styled, StyledText, Subscription, Task, TextStyle,
|
||||
UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WhiteSpace, WindowContext,
|
||||
HighlightStyle, Hsla, InteractiveText, KeyContext, Model, MouseButton, ParentElement, Pixels,
|
||||
Render, SharedString, Styled, StyledText, Subscription, Task, TextStyle,
|
||||
UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext, WeakView,
|
||||
WhiteSpace, WindowContext,
|
||||
};
|
||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||
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 mut entries = transaction.0.into_iter().collect::<Vec<_>>();
|
||||
cx.update(|_, cx| {
|
||||
cx.update(|cx| {
|
||||
entries.sort_unstable_by_key(|(buffer, _)| {
|
||||
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(
|
||||
&mut self,
|
||||
range_utf16: Range<usize>,
|
||||
|
|
|
@ -2951,9 +2951,10 @@ impl Element for EditorElement {
|
|||
self.register_key_listeners(cx);
|
||||
|
||||
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||
let input_handler =
|
||||
ElementInputHandler::new(bounds, self.editor.clone(), cx);
|
||||
cx.handle_input(&focus_handle, input_handler);
|
||||
cx.handle_input(
|
||||
&focus_handle,
|
||||
ElementInputHandler::new(bounds, self.editor.clone()),
|
||||
);
|
||||
|
||||
self.paint_background(gutter_bounds, text_bounds, &layout, cx);
|
||||
if layout.gutter_size.width > Pixels::ZERO {
|
||||
|
|
|
@ -247,7 +247,7 @@ fn show_hover(
|
|||
};
|
||||
|
||||
// query the LSP for hover info
|
||||
let hover_request = cx.update(|_, cx| {
|
||||
let hover_request = cx.update(|cx| {
|
||||
project.update(cx, |project, cx| {
|
||||
project.hover(&buffer, buffer_position, cx)
|
||||
})
|
||||
|
|
|
@ -213,7 +213,12 @@ impl AsyncWindowContext {
|
|||
}
|
||||
|
||||
/// 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,
|
||||
update: impl FnOnce(AnyView, &mut WindowContext) -> R,
|
||||
) -> Result<R> {
|
||||
|
|
|
@ -352,7 +352,7 @@ impl TestAppContext {
|
|||
}
|
||||
|
||||
/// Returns the `TestWindow` backing the given handle.
|
||||
pub fn test_window(&self, window: AnyWindowHandle) -> TestWindow {
|
||||
pub(crate) fn test_window(&self, window: AnyWindowHandle) -> TestWindow {
|
||||
self.app
|
||||
.borrow_mut()
|
||||
.windows
|
||||
|
|
|
@ -1420,7 +1420,7 @@ impl Interactivity {
|
|||
|
||||
move |mut cx| async move {
|
||||
cx.background_executor().timer(TOOLTIP_DELAY).await;
|
||||
cx.update(|_, cx| {
|
||||
cx.update(|cx| {
|
||||
active_tooltip.borrow_mut().replace(
|
||||
ActiveTooltip {
|
||||
tooltip: Some(AnyTooltip {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
use crate::{
|
||||
AsyncWindowContext, Bounds, Pixels, PlatformInputHandler, View, ViewContext, WindowContext,
|
||||
};
|
||||
use crate::{Bounds, InputHandler, Pixels, View, ViewContext, WindowContext};
|
||||
use std::ops::Range;
|
||||
|
||||
/// 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>`].
|
||||
/// 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>)
|
||||
-> Option<String>;
|
||||
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> {
|
||||
view: View<V>,
|
||||
element_bounds: Bounds<Pixels>,
|
||||
cx: AsyncWindowContext,
|
||||
}
|
||||
|
||||
impl<V: 'static> ElementInputHandler<V> {
|
||||
|
@ -47,45 +44,42 @@ impl<V: 'static> ElementInputHandler<V> {
|
|||
/// containing view.
|
||||
///
|
||||
/// [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 {
|
||||
view,
|
||||
element_bounds,
|
||||
cx: cx.to_async(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: InputHandler> PlatformInputHandler for ElementInputHandler<V> {
|
||||
fn selected_text_range(&mut self) -> Option<Range<usize>> {
|
||||
impl<V: ViewInputHandler> InputHandler for ElementInputHandler<V> {
|
||||
fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>> {
|
||||
self.view
|
||||
.update(&mut self.cx, |view, cx| view.selected_text_range(cx))
|
||||
.ok()
|
||||
.flatten()
|
||||
.update(cx, |view, cx| view.selected_text_range(cx))
|
||||
}
|
||||
|
||||
fn marked_text_range(&mut self) -> Option<Range<usize>> {
|
||||
self.view
|
||||
.update(&mut self.cx, |view, cx| view.marked_text_range(cx))
|
||||
.ok()
|
||||
.flatten()
|
||||
fn marked_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>> {
|
||||
self.view.update(cx, |view, cx| view.marked_text_range(cx))
|
||||
}
|
||||
|
||||
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
|
||||
.update(&mut self.cx, |view, cx| {
|
||||
view.text_for_range(range_utf16, cx)
|
||||
})
|
||||
.ok()
|
||||
.flatten()
|
||||
.update(cx, |view, cx| view.text_for_range(range_utf16, cx))
|
||||
}
|
||||
|
||||
fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str) {
|
||||
self.view
|
||||
.update(&mut self.cx, |view, cx| {
|
||||
view.replace_text_in_range(replacement_range, text, cx)
|
||||
})
|
||||
.ok();
|
||||
fn replace_text_in_range(
|
||||
&mut self,
|
||||
replacement_range: Option<Range<usize>>,
|
||||
text: &str,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
self.view.update(cx, |view, cx| {
|
||||
view.replace_text_in_range(replacement_range, text, cx)
|
||||
});
|
||||
}
|
||||
|
||||
fn replace_and_mark_text_in_range(
|
||||
|
@ -93,26 +87,24 @@ impl<V: InputHandler> PlatformInputHandler for ElementInputHandler<V> {
|
|||
range_utf16: Option<Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<Range<usize>>,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
self.view
|
||||
.update(&mut self.cx, |view, cx| {
|
||||
view.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx)
|
||||
})
|
||||
.ok();
|
||||
self.view.update(cx, |view, cx| {
|
||||
view.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx)
|
||||
});
|
||||
}
|
||||
|
||||
fn unmark_text(&mut self) {
|
||||
self.view
|
||||
.update(&mut self.cx, |view, cx| view.unmark_text(cx))
|
||||
.ok();
|
||||
fn unmark_text(&mut self, cx: &mut WindowContext) {
|
||||
self.view.update(cx, |view, cx| view.unmark_text(cx));
|
||||
}
|
||||
|
||||
fn bounds_for_range(&mut self, range_utf16: Range<usize>) -> Option<Bounds<Pixels>> {
|
||||
self.view
|
||||
.update(&mut self.cx, |view, cx| {
|
||||
view.bounds_for_range(range_utf16, self.element_bounds, cx)
|
||||
})
|
||||
.ok()
|
||||
.flatten()
|
||||
fn bounds_for_range(
|
||||
&mut self,
|
||||
range_utf16: Range<usize>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<Bounds<Pixels>> {
|
||||
self.view.update(cx, |view, cx| {
|
||||
view.bounds_for_range(range_utf16, self.element_bounds, cx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
mod app_menu;
|
||||
mod keystroke;
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -6,10 +8,10 @@ mod mac;
|
|||
mod test;
|
||||
|
||||
use crate::{
|
||||
Action, AnyWindowHandle, BackgroundExecutor, Bounds, DevicePixels, Font, FontId, FontMetrics,
|
||||
FontRun, ForegroundExecutor, GlobalPixels, GlyphId, Keymap, LineLayout, Pixels, PlatformInput,
|
||||
Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Result, Scene, SharedString,
|
||||
Size, TaskLabel,
|
||||
Action, AnyWindowHandle, AsyncWindowContext, BackgroundExecutor, Bounds, DevicePixels, Font,
|
||||
FontId, FontMetrics, FontRun, ForegroundExecutor, GlobalPixels, GlyphId, Keymap, LineLayout,
|
||||
Pixels, PlatformInput, Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Result,
|
||||
Scene, SharedString, Size, TaskLabel, WindowContext,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use async_task::Runnable;
|
||||
|
@ -34,9 +36,9 @@ use uuid::Uuid;
|
|||
pub use app_menu::*;
|
||||
pub use keystroke::*;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use mac::*;
|
||||
pub(crate) use mac::*;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub use test::*;
|
||||
pub(crate) use test::*;
|
||||
use time::UtcOffset;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -69,11 +71,10 @@ pub(crate) trait Platform: 'static {
|
|||
fn set_display_link_output_callback(
|
||||
&self,
|
||||
display_id: DisplayId,
|
||||
callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp) + Send>,
|
||||
callback: Box<dyn FnMut() + Send>,
|
||||
);
|
||||
fn start_display_link(&self, display_id: DisplayId);
|
||||
fn stop_display_link(&self, display_id: DisplayId);
|
||||
// fn add_status_item(&self, _handle: AnyWindowHandle) -> Box<dyn PlatformWindow>;
|
||||
|
||||
fn open_url(&self, url: &str);
|
||||
fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);
|
||||
|
@ -149,8 +150,8 @@ pub(crate) trait PlatformWindow {
|
|||
fn mouse_position(&self) -> Point<Pixels>;
|
||||
fn modifiers(&self) -> Modifiers;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
fn set_input_handler(&mut self, input_handler: Box<dyn PlatformInputHandler>);
|
||||
fn take_input_handler(&mut self) -> Option<Box<dyn PlatformInputHandler>>;
|
||||
fn set_input_handler(&mut self, input_handler: PlatformInputHandler);
|
||||
fn take_input_handler(&mut self) -> Option<PlatformInputHandler>;
|
||||
fn prompt(&self, level: PromptLevel, msg: &str, answers: &[&str]) -> oneshot::Receiver<usize>;
|
||||
fn activate(&self);
|
||||
fn set_title(&mut self, title: &str);
|
||||
|
@ -325,30 +326,168 @@ impl From<TileId> for etagere::AllocId {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait PlatformInputHandler: 'static {
|
||||
fn selected_text_range(&mut self) -> Option<Range<usize>>;
|
||||
fn marked_text_range(&mut self) -> Option<Range<usize>>;
|
||||
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);
|
||||
pub(crate) struct PlatformInputHandler {
|
||||
cx: AsyncWindowContext,
|
||||
handler: Box<dyn InputHandler>,
|
||||
}
|
||||
|
||||
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(
|
||||
&mut self,
|
||||
range_utf16: Option<Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<Range<usize>>,
|
||||
);
|
||||
fn unmark_text(&mut self);
|
||||
fn bounds_for_range(&mut self, range_utf16: Range<usize>) -> Option<Bounds<Pixels>>;
|
||||
) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
/// Zed's interface for handling text input from the platform's IME system
|
||||
/// This is currently a 1:1 exposure of the NSTextInputClient API:
|
||||
///
|
||||
/// <https://developer.apple.com/documentation/appkit/nstextinputclient>
|
||||
pub trait InputHandler: 'static {
|
||||
/// Get the range of the user's currently selected text, if any
|
||||
/// Corresponds to [selectedRange()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438242-selectedrange)
|
||||
///
|
||||
/// Return value is in terms of UTF-16 characters, from 0 to the length of the document
|
||||
fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
||||
|
||||
/// Get the range of the currently marked text, if any
|
||||
/// Corresponds to [markedRange()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438250-markedrange)
|
||||
///
|
||||
/// Return value is in terms of UTF-16 characters, from 0 to the length of the document
|
||||
fn marked_text_range(&mut self, cx: &mut WindowContext) -> Option<Range<usize>>;
|
||||
|
||||
/// Get the text for the given document range in UTF-16 characters
|
||||
/// Corresponds to [attributedSubstring(forProposedRange: actualRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438238-attributedsubstring)
|
||||
///
|
||||
/// range_utf16 is in terms of UTF-16 characters
|
||||
fn text_for_range(
|
||||
&mut self,
|
||||
range_utf16: Range<usize>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<String>;
|
||||
|
||||
/// Replace the text in the given document range with the given text
|
||||
/// Corresponds to [insertText(_:replacementRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438258-inserttext)
|
||||
///
|
||||
/// replacement_range is in terms of UTF-16 characters
|
||||
fn replace_text_in_range(
|
||||
&mut self,
|
||||
replacement_range: Option<Range<usize>>,
|
||||
text: &str,
|
||||
cx: &mut WindowContext,
|
||||
);
|
||||
|
||||
/// Replace the text in the given document range with the given text,
|
||||
/// and mark the given text as part of of an IME 'composing' state
|
||||
/// Corresponds to [setMarkedText(_:selectedRange:replacementRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438246-setmarkedtext)
|
||||
///
|
||||
/// range_utf16 is in terms of UTF-16 characters
|
||||
/// new_selected_range is in terms of UTF-16 characters
|
||||
fn replace_and_mark_text_in_range(
|
||||
&mut self,
|
||||
range_utf16: Option<Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<Range<usize>>,
|
||||
cx: &mut WindowContext,
|
||||
);
|
||||
|
||||
/// Remove the IME 'composing' state from the document
|
||||
/// Corresponds to [unmarkText()](https://developer.apple.com/documentation/appkit/nstextinputclient/1438239-unmarktext)
|
||||
fn unmark_text(&mut self, cx: &mut WindowContext);
|
||||
|
||||
/// Get the bounds of the given document range in screen coordinates
|
||||
/// Corresponds to [firstRect(forCharacterRange:actualRange:)](https://developer.apple.com/documentation/appkit/nstextinputclient/1438240-firstrect)
|
||||
///
|
||||
/// This is used for positioning the IME candidate window
|
||||
fn bounds_for_range(
|
||||
&mut self,
|
||||
range_utf16: Range<usize>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<Bounds<Pixels>>;
|
||||
}
|
||||
|
||||
/// The variables that can be configured when creating a new window
|
||||
#[derive(Debug)]
|
||||
pub struct WindowOptions {
|
||||
/// The initial bounds of the window
|
||||
pub bounds: WindowBounds,
|
||||
|
||||
/// The titlebar configuration of the window
|
||||
pub titlebar: Option<TitlebarOptions>,
|
||||
|
||||
/// Whether the window should be centered on the screen
|
||||
pub center: bool,
|
||||
|
||||
/// Whether the window should be focused when created
|
||||
pub focus: bool,
|
||||
|
||||
/// Whether the window should be shown when created
|
||||
pub show: bool,
|
||||
|
||||
/// The kind of window to create
|
||||
pub kind: WindowKind,
|
||||
|
||||
/// Whether the window should be movable by the user
|
||||
pub is_movable: bool,
|
||||
|
||||
/// The display to create the window on
|
||||
pub display_id: Option<DisplayId>,
|
||||
}
|
||||
|
||||
|
@ -371,46 +510,67 @@ impl Default for WindowOptions {
|
|||
}
|
||||
}
|
||||
|
||||
/// The options that can be configured for a window's titlebar
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TitlebarOptions {
|
||||
/// The initial title of the window
|
||||
pub title: Option<SharedString>,
|
||||
|
||||
/// Whether the titlebar should appear transparent
|
||||
pub appears_transparent: bool,
|
||||
|
||||
/// The position of the macOS traffic light buttons
|
||||
pub traffic_light_position: Option<Point<Pixels>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Appearance {
|
||||
Light,
|
||||
VibrantLight,
|
||||
Dark,
|
||||
VibrantDark,
|
||||
}
|
||||
|
||||
impl Default for Appearance {
|
||||
fn default() -> Self {
|
||||
Self::Light
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of window to create
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum WindowKind {
|
||||
/// A normal application window
|
||||
Normal,
|
||||
|
||||
/// A window that appears above all other windows, usually used for alerts or popups
|
||||
/// use sparingly!
|
||||
PopUp,
|
||||
}
|
||||
|
||||
/// Which bounds algorithm to use for the initial size a window
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
||||
pub enum WindowBounds {
|
||||
/// The window should be full screen, on macOS this corresponds to the full screen feature
|
||||
Fullscreen,
|
||||
|
||||
/// Make the window as large as the current display's size.
|
||||
#[default]
|
||||
Maximized,
|
||||
|
||||
/// Set the window to the given size in pixels
|
||||
Fixed(Bounds<GlobalPixels>),
|
||||
}
|
||||
|
||||
/// The appearance of the window, as defined by the operating system
|
||||
/// On macOS, this corresponds to named [NSAppearance](https://developer.apple.com/documentation/appkit/nsappearance)
|
||||
/// values
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum WindowAppearance {
|
||||
/// A light appearance
|
||||
///
|
||||
/// on macOS, this corresponds to the `aqua` appearance
|
||||
Light,
|
||||
|
||||
/// A light appearance with vibrant colors
|
||||
///
|
||||
/// on macOS, this corresponds to the `NSAppearanceNameVibrantLight` appearance
|
||||
VibrantLight,
|
||||
|
||||
/// A dark appearance
|
||||
///
|
||||
/// on macOS, this corresponds to the `darkAqua` appearance
|
||||
Dark,
|
||||
|
||||
/// A dark appearance with vibrant colors
|
||||
///
|
||||
/// on macOS, this corresponds to the `NSAppearanceNameVibrantDark` appearance
|
||||
VibrantDark,
|
||||
}
|
||||
|
||||
|
@ -420,40 +580,102 @@ impl Default for WindowAppearance {
|
|||
}
|
||||
}
|
||||
|
||||
/// The options that can be configured for a file dialog prompt
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PathPromptOptions {
|
||||
/// Should the prompt allow files to be selected?
|
||||
pub files: bool,
|
||||
/// Should the prompt allow directories to be selected?
|
||||
pub directories: bool,
|
||||
/// Should the prompt allow multiple files to be selected?
|
||||
pub multiple: bool,
|
||||
}
|
||||
|
||||
/// What kind of prompt styling to show
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PromptLevel {
|
||||
/// A prompt that is shown when the user should be notified of something
|
||||
Info,
|
||||
|
||||
/// A prompt that is shown when the user needs to be warned of a potential problem
|
||||
Warning,
|
||||
|
||||
/// A prompt that is shown when a critical problem has occurred
|
||||
Critical,
|
||||
}
|
||||
|
||||
/// The style of the cursor (pointer)
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CursorStyle {
|
||||
/// The default cursor
|
||||
Arrow,
|
||||
|
||||
/// A text input cursor
|
||||
/// corresponds to the CSS cursor value `text`
|
||||
IBeam,
|
||||
|
||||
/// A crosshair cursor
|
||||
/// corresponds to the CSS cursor value `crosshair`
|
||||
Crosshair,
|
||||
|
||||
/// A closed hand cursor
|
||||
/// corresponds to the CSS cursor value `grabbing`
|
||||
ClosedHand,
|
||||
|
||||
/// An open hand cursor
|
||||
/// corresponds to the CSS cursor value `grab`
|
||||
OpenHand,
|
||||
|
||||
/// A pointing hand cursor
|
||||
/// corresponds to the CSS cursor value `pointer`
|
||||
PointingHand,
|
||||
|
||||
/// A resize left cursor
|
||||
/// corresponds to the CSS cursor value `w-resize`
|
||||
ResizeLeft,
|
||||
|
||||
/// A resize right cursor
|
||||
/// corresponds to the CSS cursor value `e-resize`
|
||||
ResizeRight,
|
||||
|
||||
/// A resize cursor to the left and right
|
||||
/// corresponds to the CSS cursor value `col-resize`
|
||||
ResizeLeftRight,
|
||||
|
||||
/// A resize up cursor
|
||||
/// corresponds to the CSS cursor value `n-resize`
|
||||
ResizeUp,
|
||||
|
||||
/// A resize down cursor
|
||||
/// corresponds to the CSS cursor value `s-resize`
|
||||
ResizeDown,
|
||||
|
||||
/// A resize cursor directing up and down
|
||||
/// corresponds to the CSS cursor value `row-resize`
|
||||
ResizeUpDown,
|
||||
|
||||
/// A cursor indicating that something will disappear if moved here
|
||||
/// Does not correspond to a CSS cursor value
|
||||
DisappearingItem,
|
||||
|
||||
/// A text input cursor for vertical layout
|
||||
/// corresponds to the CSS cursor value `vertical-text`
|
||||
IBeamCursorForVerticalLayout,
|
||||
|
||||
/// A cursor indicating that the operation is not allowed
|
||||
/// corresponds to the CSS cursor value `not-allowed`
|
||||
OperationNotAllowed,
|
||||
|
||||
/// A cursor indicating that the operation will result in a link
|
||||
/// corresponds to the CSS cursor value `alias`
|
||||
DragLink,
|
||||
|
||||
/// A cursor indicating that the operation will result in a copy
|
||||
/// corresponds to the CSS cursor value `copy`
|
||||
DragCopy,
|
||||
|
||||
/// A cursor indicating that the operation will result in a context menu
|
||||
/// corresponds to the CSS cursor value `context-menu`
|
||||
ContextualMenu,
|
||||
}
|
||||
|
||||
|
@ -463,6 +685,7 @@ impl Default for CursorStyle {
|
|||
}
|
||||
}
|
||||
|
||||
/// A datastructure representing a semantic version number
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
pub struct SemanticVersion {
|
||||
major: usize,
|
||||
|
@ -501,6 +724,7 @@ impl Display for SemanticVersion {
|
|||
}
|
||||
}
|
||||
|
||||
/// A clipboard item that should be copied to the clipboard
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ClipboardItem {
|
||||
pub(crate) text: String,
|
||||
|
@ -508,6 +732,7 @@ pub struct ClipboardItem {
|
|||
}
|
||||
|
||||
impl ClipboardItem {
|
||||
/// Create a new clipboard item with the given text
|
||||
pub fn new(text: String) -> Self {
|
||||
Self {
|
||||
text,
|
||||
|
@ -515,15 +740,18 @@ impl ClipboardItem {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new clipboard item with the given text and metadata
|
||||
pub fn with_metadata<T: Serialize>(mut self, metadata: T) -> Self {
|
||||
self.metadata = Some(serde_json::to_string(&metadata).unwrap());
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the text of the clipboard item
|
||||
pub fn text(&self) -> &String {
|
||||
&self.text
|
||||
}
|
||||
|
||||
/// Get the metadata of the clipboard item
|
||||
pub fn metadata<T>(&self) -> Option<T>
|
||||
where
|
||||
T: for<'a> Deserialize<'a>,
|
||||
|
|
|
@ -1,30 +1,49 @@
|
|||
use crate::{Action, AppContext, Platform};
|
||||
use util::ResultExt;
|
||||
|
||||
/// A menu of the application, either a main menu or a submenu
|
||||
pub struct Menu<'a> {
|
||||
/// The name of the menu
|
||||
pub name: &'a str,
|
||||
|
||||
/// The items in the menu
|
||||
pub items: Vec<MenuItem<'a>>,
|
||||
}
|
||||
|
||||
/// The different kinds of items that can be in a menu
|
||||
pub enum MenuItem<'a> {
|
||||
/// A separator between items
|
||||
Separator,
|
||||
|
||||
/// A submenu
|
||||
Submenu(Menu<'a>),
|
||||
|
||||
/// An action that can be performed
|
||||
Action {
|
||||
/// The name of this menu item
|
||||
name: &'a str,
|
||||
|
||||
/// the action to perform when this menu item is selected
|
||||
action: Box<dyn Action>,
|
||||
|
||||
/// The OS Action that corresponds to this action, if any
|
||||
/// See [`OsAction`] for more information
|
||||
os_action: Option<OsAction>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> MenuItem<'a> {
|
||||
/// Creates a new menu item that is a separator
|
||||
pub fn separator() -> Self {
|
||||
Self::Separator
|
||||
}
|
||||
|
||||
/// Creates a new menu item that is a submenu
|
||||
pub fn submenu(menu: Menu<'a>) -> Self {
|
||||
Self::Submenu(menu)
|
||||
}
|
||||
|
||||
/// Creates a new menu item that invokes an action
|
||||
pub fn action(name: &'a str, action: impl Action) -> Self {
|
||||
Self::Action {
|
||||
name,
|
||||
|
@ -33,6 +52,7 @@ impl<'a> MenuItem<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new menu item that invokes an action and has an OS action
|
||||
pub fn os_action(name: &'a str, action: impl Action, os_action: OsAction) -> Self {
|
||||
Self::Action {
|
||||
name,
|
||||
|
@ -42,13 +62,31 @@ impl<'a> MenuItem<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: As part of the global selections refactor, these should
|
||||
// be moved to GPUI-provided actions that make this association
|
||||
// without leaking the platform details to GPUI users
|
||||
|
||||
/// OS actions are actions that are recognized by the operating system
|
||||
/// This allows the operating system to provide specialized behavior for
|
||||
/// these actions
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum OsAction {
|
||||
/// The 'cut' action
|
||||
Cut,
|
||||
|
||||
/// The 'copy' action
|
||||
Copy,
|
||||
|
||||
/// The 'paste' action
|
||||
Paste,
|
||||
|
||||
/// The 'select all' action
|
||||
SelectAll,
|
||||
|
||||
/// The 'undo' action
|
||||
Undo,
|
||||
|
||||
/// The 'redo' action
|
||||
Redo,
|
||||
}
|
||||
|
||||
|
|
|
@ -3,24 +3,31 @@ use serde::Deserialize;
|
|||
use smallvec::SmallVec;
|
||||
use std::fmt::Write;
|
||||
|
||||
/// A keystroke and associated metadata generated by the platform
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default, Deserialize, Hash)]
|
||||
pub struct Keystroke {
|
||||
/// the state of the modifier keys at the time the keystroke was generated
|
||||
pub modifiers: Modifiers,
|
||||
|
||||
/// key is the character printed on the key that was pressed
|
||||
/// e.g. for option-s, key is "s"
|
||||
pub key: String,
|
||||
|
||||
/// ime_key is the character inserted by the IME engine when that key was pressed.
|
||||
/// e.g. for option-s, ime_key is "ß"
|
||||
pub ime_key: Option<String>,
|
||||
}
|
||||
|
||||
impl Keystroke {
|
||||
// When matching a key we cannot know whether the user intended to type
|
||||
// the ime_key or the key. On some non-US keyboards keys we use in our
|
||||
// bindings are behind option (for example `$` is typed `alt-ç` on a Czech keyboard),
|
||||
// and on some keyboards the IME handler converts a sequence of keys into a
|
||||
// specific character (for example `"` is typed as `" space` on a brazilian keyboard).
|
||||
pub fn match_candidates(&self) -> SmallVec<[Keystroke; 2]> {
|
||||
/// When matching a key we cannot know whether the user intended to type
|
||||
/// the ime_key or the key itself. On some non-US keyboards keys we use in our
|
||||
/// bindings are behind option (for example `$` is typed `alt-ç` on a Czech keyboard),
|
||||
/// and on some keyboards the IME handler converts a sequence of keys into a
|
||||
/// specific character (for example `"` is typed as `" space` on a brazilian keyboard).
|
||||
///
|
||||
/// This method generates a list of potential keystroke candidates that could be matched
|
||||
/// against when resolving a keybinding.
|
||||
pub(crate) fn match_candidates(&self) -> SmallVec<[Keystroke; 2]> {
|
||||
let mut possibilities = SmallVec::new();
|
||||
match self.ime_key.as_ref() {
|
||||
None => possibilities.push(self.clone()),
|
||||
|
@ -47,7 +54,7 @@ impl Keystroke {
|
|||
|
||||
/// key syntax is:
|
||||
/// [ctrl-][alt-][shift-][cmd-][fn-]key[->ime_key]
|
||||
/// ime_key is only used for generating test events,
|
||||
/// ime_key syntax is only used for generating test events,
|
||||
/// when matching a key with an ime_key set will be matched without it.
|
||||
pub fn parse(source: &str) -> anyhow::Result<Self> {
|
||||
let mut control = false;
|
||||
|
@ -135,16 +142,29 @@ impl std::fmt::Display for Keystroke {
|
|||
}
|
||||
}
|
||||
|
||||
/// The state of the modifier keys at some point in time
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Deserialize, Hash)]
|
||||
pub struct Modifiers {
|
||||
/// The control key
|
||||
pub control: bool,
|
||||
|
||||
/// The alt key
|
||||
/// Sometimes also known as the 'meta' key
|
||||
pub alt: bool,
|
||||
|
||||
/// The shift key
|
||||
pub shift: bool,
|
||||
|
||||
/// The command key, on macos
|
||||
/// the windows key, on windows
|
||||
pub command: bool,
|
||||
|
||||
/// The function key
|
||||
pub function: bool,
|
||||
}
|
||||
|
||||
impl Modifiers {
|
||||
/// Returns true if any modifier key is pressed
|
||||
pub fn modified(&self) -> bool {
|
||||
self.control || self.alt || self.shift || self.command || self.function
|
||||
}
|
||||
|
|
|
@ -21,13 +21,13 @@ use metal_renderer::*;
|
|||
use objc::runtime::{BOOL, NO, YES};
|
||||
use std::ops::Range;
|
||||
|
||||
pub use dispatcher::*;
|
||||
pub use display::*;
|
||||
pub use display_linker::*;
|
||||
pub use metal_atlas::*;
|
||||
pub use platform::*;
|
||||
pub use text_system::*;
|
||||
pub use window::*;
|
||||
pub(crate) use dispatcher::*;
|
||||
pub(crate) use display::*;
|
||||
pub(crate) use display_linker::*;
|
||||
pub(crate) use metal_atlas::*;
|
||||
pub(crate) use platform::*;
|
||||
pub(crate) use text_system::*;
|
||||
pub(crate) use window::*;
|
||||
|
||||
trait BoolExt {
|
||||
fn to_objc(self) -> BOOL;
|
||||
|
|
|
@ -24,7 +24,7 @@ pub(crate) fn dispatch_get_main_queue() -> dispatch_queue_t {
|
|||
unsafe { &_dispatch_main_q as *const _ as dispatch_queue_t }
|
||||
}
|
||||
|
||||
pub struct MacDispatcher {
|
||||
pub(crate) struct MacDispatcher {
|
||||
parker: Arc<Mutex<Parker>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use objc::{msg_send, sel, sel_impl};
|
|||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MacDisplay(pub(crate) CGDirectDisplayID);
|
||||
pub(crate) struct MacDisplay(pub(crate) CGDirectDisplayID);
|
||||
|
||||
unsafe impl Send for MacDisplay {}
|
||||
|
||||
|
@ -21,11 +21,6 @@ impl MacDisplay {
|
|||
Self::all().find(|screen| screen.id() == id)
|
||||
}
|
||||
|
||||
/// Get the screen with the given persistent [`Uuid`].
|
||||
pub fn find_by_uuid(uuid: Uuid) -> Option<Self> {
|
||||
Self::all().find(|screen| screen.uuid().ok() == Some(uuid))
|
||||
}
|
||||
|
||||
/// Get the primary screen - the one with the menu bar, and whose bottom left
|
||||
/// corner is at the origin of the AppKit coordinate system.
|
||||
pub fn primary() -> Self {
|
||||
|
|
|
@ -7,8 +7,6 @@ use std::{
|
|||
use crate::DisplayId;
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
pub use sys::CVSMPTETime as SmtpeTime;
|
||||
pub use sys::CVTimeStamp as VideoTimestamp;
|
||||
|
||||
pub(crate) struct MacDisplayLinker {
|
||||
links: HashMap<DisplayId, MacDisplayLink>,
|
||||
|
@ -27,13 +25,13 @@ impl MacDisplayLinker {
|
|||
}
|
||||
}
|
||||
|
||||
type OutputCallback = Mutex<Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp) + Send>>;
|
||||
type OutputCallback = Mutex<Box<dyn FnMut() + Send>>;
|
||||
|
||||
impl MacDisplayLinker {
|
||||
pub fn set_output_callback(
|
||||
&mut self,
|
||||
display_id: DisplayId,
|
||||
output_callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp) + Send>,
|
||||
output_callback: Box<dyn FnMut() + Send>,
|
||||
) {
|
||||
if let Some(mut system_link) = unsafe { sys::DisplayLink::on_display(display_id.0) } {
|
||||
let callback = Arc::new(Mutex::new(output_callback));
|
||||
|
@ -81,11 +79,11 @@ unsafe extern "C" fn trampoline(
|
|||
_flags_out: *mut i64,
|
||||
user_data: *mut c_void,
|
||||
) -> i32 {
|
||||
if let Some((current_time, output_time)) = current_time.as_ref().zip(output_time.as_ref()) {
|
||||
if let Some((_current_time, _output_time)) = current_time.as_ref().zip(output_time.as_ref()) {
|
||||
let output_callback: Weak<OutputCallback> =
|
||||
Weak::from_raw(user_data as *mut OutputCallback);
|
||||
if let Some(output_callback) = output_callback.upgrade() {
|
||||
(output_callback.lock())(current_time, output_time)
|
||||
(output_callback.lock())()
|
||||
}
|
||||
mem::forget(output_callback);
|
||||
}
|
||||
|
@ -126,7 +124,7 @@ mod sys {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CVTimeStamp {
|
||||
pub(crate) struct CVTimeStamp {
|
||||
pub version: u32,
|
||||
pub video_time_scale: i32,
|
||||
pub video_time: i64,
|
||||
|
@ -154,7 +152,7 @@ mod sys {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct CVSMPTETime {
|
||||
pub(crate) struct CVSMPTETime {
|
||||
pub subframes: i16,
|
||||
pub subframe_divisor: i16,
|
||||
pub counter: u32,
|
||||
|
|
|
@ -83,7 +83,10 @@ unsafe fn read_modifiers(native_event: id) -> Modifiers {
|
|||
}
|
||||
|
||||
impl PlatformInput {
|
||||
pub unsafe fn from_native(native_event: id, window_height: Option<Pixels>) -> Option<Self> {
|
||||
pub(crate) unsafe fn from_native(
|
||||
native_event: id,
|
||||
window_height: Option<Pixels>,
|
||||
) -> Option<Self> {
|
||||
let event_type = native_event.eventType();
|
||||
|
||||
// Filter out event types that aren't in the NSEventType enum.
|
||||
|
|
|
@ -10,10 +10,10 @@ use metal::Device;
|
|||
use parking_lot::Mutex;
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub struct MetalAtlas(Mutex<MetalAtlasState>);
|
||||
pub(crate) struct MetalAtlas(Mutex<MetalAtlasState>);
|
||||
|
||||
impl MetalAtlas {
|
||||
pub fn new(device: Device) -> Self {
|
||||
pub(crate) fn new(device: Device) -> Self {
|
||||
MetalAtlas(Mutex::new(MetalAtlasState {
|
||||
device: AssertSend(device),
|
||||
monochrome_textures: Default::default(),
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
|
||||
ForegroundExecutor, Keymap, MacDispatcher, MacDisplay, MacDisplayLinker, MacTextSystem,
|
||||
MacWindow, Menu, MenuItem, PathPromptOptions, Platform, PlatformDisplay, PlatformInput,
|
||||
PlatformTextSystem, PlatformWindow, Result, SemanticVersion, VideoTimestamp, WindowOptions,
|
||||
PlatformTextSystem, PlatformWindow, Result, SemanticVersion, WindowOptions,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use block::ConcreteBlock;
|
||||
|
@ -139,9 +139,9 @@ unsafe fn build_classes() {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct MacPlatform(Mutex<MacPlatformState>);
|
||||
pub(crate) struct MacPlatform(Mutex<MacPlatformState>);
|
||||
|
||||
pub struct MacPlatformState {
|
||||
pub(crate) struct MacPlatformState {
|
||||
background_executor: BackgroundExecutor,
|
||||
foreground_executor: ForegroundExecutor,
|
||||
text_system: Arc<MacTextSystem>,
|
||||
|
@ -169,7 +169,7 @@ impl Default for MacPlatform {
|
|||
}
|
||||
|
||||
impl MacPlatform {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new() -> Self {
|
||||
let dispatcher = Arc::new(MacDispatcher::new());
|
||||
Self(Mutex::new(MacPlatformState {
|
||||
background_executor: BackgroundExecutor::new(dispatcher.clone()),
|
||||
|
@ -475,10 +475,6 @@ impl Platform for MacPlatform {
|
|||
}
|
||||
}
|
||||
|
||||
// fn add_status_item(&self, _handle: AnyWindowHandle) -> Box<dyn platform::Window> {
|
||||
// Box::new(StatusItem::add(self.fonts()))
|
||||
// }
|
||||
|
||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
||||
MacDisplay::all()
|
||||
.map(|screen| Rc::new(screen) as Rc<_>)
|
||||
|
@ -504,7 +500,7 @@ impl Platform for MacPlatform {
|
|||
fn set_display_link_output_callback(
|
||||
&self,
|
||||
display_id: DisplayId,
|
||||
callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp) + Send>,
|
||||
callback: Box<dyn FnMut() + Send>,
|
||||
) {
|
||||
self.0
|
||||
.lock()
|
||||
|
|
|
@ -41,7 +41,7 @@ use super::open_type;
|
|||
#[allow(non_upper_case_globals)]
|
||||
const kCGImageAlphaOnly: u32 = 7;
|
||||
|
||||
pub struct MacTextSystem(RwLock<MacTextSystemState>);
|
||||
pub(crate) struct MacTextSystem(RwLock<MacTextSystemState>);
|
||||
|
||||
struct MacTextSystemState {
|
||||
memory_source: MemSource,
|
||||
|
@ -54,7 +54,7 @@ struct MacTextSystemState {
|
|||
}
|
||||
|
||||
impl MacTextSystem {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self(RwLock::new(MacTextSystemState {
|
||||
memory_source: MemSource::empty(),
|
||||
system_source: SystemSource::new(),
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use super::{global_bounds_from_ns_rect, ns_string, MacDisplay, MetalRenderer, NSRange};
|
||||
use crate::{
|
||||
global_bounds_to_ns_rect, point, px, size, AnyWindowHandle, Bounds, ExternalPaths,
|
||||
FileDropEvent, ForegroundExecutor, GlobalPixels, KeyDownEvent, Keystroke, Modifiers,
|
||||
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
|
||||
PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point,
|
||||
global_bounds_to_ns_rect, platform::PlatformInputHandler, point, px, size, AnyWindowHandle,
|
||||
Bounds, ExternalPaths, FileDropEvent, ForegroundExecutor, GlobalPixels, KeyDownEvent,
|
||||
Keystroke, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent,
|
||||
MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformWindow, Point,
|
||||
PromptLevel, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
|
||||
};
|
||||
use block::ConcreteBlock;
|
||||
|
@ -220,7 +220,7 @@ unsafe fn build_classes() {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn convert_mouse_position(position: NSPoint, window_height: Pixels) -> Point<Pixels> {
|
||||
pub(crate) fn convert_mouse_position(position: NSPoint, window_height: Pixels) -> Point<Pixels> {
|
||||
point(
|
||||
px(position.x as f32),
|
||||
// MacOS screen coordinates are relative to bottom left
|
||||
|
@ -327,7 +327,7 @@ struct MacWindowState {
|
|||
should_close_callback: Option<Box<dyn FnMut() -> bool>>,
|
||||
close_callback: Option<Box<dyn FnOnce()>>,
|
||||
appearance_changed_callback: Option<Box<dyn FnMut()>>,
|
||||
input_handler: Option<Box<dyn PlatformInputHandler>>,
|
||||
input_handler: Option<PlatformInputHandler>,
|
||||
pending_key_down: Option<(KeyDownEvent, Option<InsertText>)>,
|
||||
last_key_equivalent: Option<KeyDownEvent>,
|
||||
synthetic_drag_counter: usize,
|
||||
|
@ -446,7 +446,7 @@ impl MacWindowState {
|
|||
|
||||
unsafe impl Send for MacWindowState {}
|
||||
|
||||
pub struct MacWindow(Arc<Mutex<MacWindowState>>);
|
||||
pub(crate) struct MacWindow(Arc<Mutex<MacWindowState>>);
|
||||
|
||||
impl MacWindow {
|
||||
pub fn open(
|
||||
|
@ -764,11 +764,11 @@ impl PlatformWindow for MacWindow {
|
|||
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);
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
where
|
||||
F: FnOnce(&mut dyn PlatformInputHandler) -> R,
|
||||
F: FnOnce(&mut PlatformInputHandler) -> R,
|
||||
{
|
||||
let window_state = unsafe { get_window_state(window) };
|
||||
let mut lock = window_state.as_ref().lock();
|
||||
if let Some(mut input_handler) = lock.input_handler.take() {
|
||||
drop(lock);
|
||||
let result = f(input_handler.as_mut());
|
||||
let result = f(&mut input_handler);
|
||||
window_state.lock().input_handler = Some(input_handler);
|
||||
Some(result)
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,7 @@ use objc::{msg_send, sel, sel_impl};
|
|||
use std::ffi::CStr;
|
||||
|
||||
impl WindowAppearance {
|
||||
pub unsafe fn from_native(appearance: id) -> Self {
|
||||
pub(crate) unsafe fn from_native(appearance: id) -> Self {
|
||||
let name: id = msg_send![appearance, name];
|
||||
if name == NSAppearanceNameVibrantLight {
|
||||
Self::VibrantLight
|
||||
|
|
|
@ -3,7 +3,7 @@ mod display;
|
|||
mod platform;
|
||||
mod window;
|
||||
|
||||
pub use dispatcher::*;
|
||||
pub use display::*;
|
||||
pub use platform::*;
|
||||
pub use window::*;
|
||||
pub(crate) use dispatcher::*;
|
||||
pub(crate) use display::*;
|
||||
pub(crate) use platform::*;
|
||||
pub(crate) use window::*;
|
||||
|
|
|
@ -18,6 +18,7 @@ use util::post_inc;
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct TestDispatcherId(usize);
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct TestDispatcher {
|
||||
id: TestDispatcherId,
|
||||
state: Arc<Mutex<TestDispatcherState>>,
|
||||
|
|
|
@ -3,7 +3,7 @@ use anyhow::{Ok, Result};
|
|||
use crate::{Bounds, DisplayId, GlobalPixels, PlatformDisplay, Point};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TestDisplay {
|
||||
pub(crate) struct TestDisplay {
|
||||
id: DisplayId,
|
||||
uuid: uuid::Uuid,
|
||||
bounds: Bounds<GlobalPixels>,
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::{
|
|||
};
|
||||
|
||||
/// TestPlatform implements the Platform trait for use in tests.
|
||||
pub struct TestPlatform {
|
||||
pub(crate) struct TestPlatform {
|
||||
background_executor: BackgroundExecutor,
|
||||
foreground_executor: ForegroundExecutor,
|
||||
|
||||
|
@ -178,20 +178,9 @@ impl Platform for TestPlatform {
|
|||
fn set_display_link_output_callback(
|
||||
&self,
|
||||
_display_id: DisplayId,
|
||||
mut callback: Box<dyn FnMut(&crate::VideoTimestamp, &crate::VideoTimestamp) + Send>,
|
||||
mut callback: Box<dyn FnMut() + Send>,
|
||||
) {
|
||||
let timestamp = crate::VideoTimestamp {
|
||||
version: 0,
|
||||
video_time_scale: 0,
|
||||
video_time: 0,
|
||||
host_time: 0,
|
||||
rate_scalar: 0.0,
|
||||
video_refresh_period: 0,
|
||||
smpte_time: crate::SmtpeTime::default(),
|
||||
flags: 0,
|
||||
reserved: 0,
|
||||
};
|
||||
callback(×tamp, ×tamp)
|
||||
callback()
|
||||
}
|
||||
|
||||
fn start_display_link(&self, _display_id: DisplayId) {}
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::{
|
|||
sync::{self, Arc},
|
||||
};
|
||||
|
||||
pub struct TestWindowState {
|
||||
pub(crate) struct TestWindowState {
|
||||
pub(crate) bounds: WindowBounds,
|
||||
pub(crate) handle: AnyWindowHandle,
|
||||
display: Rc<dyn PlatformDisplay>,
|
||||
|
@ -23,11 +23,11 @@ pub struct TestWindowState {
|
|||
active_status_change_callback: Option<Box<dyn FnMut(bool)>>,
|
||||
resize_callback: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
|
||||
moved_callback: Option<Box<dyn FnMut()>>,
|
||||
input_handler: Option<Box<dyn PlatformInputHandler>>,
|
||||
input_handler: Option<PlatformInputHandler>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TestWindow(pub(crate) Arc<Mutex<TestWindowState>>);
|
||||
pub(crate) struct TestWindow(pub(crate) Arc<Mutex<TestWindowState>>);
|
||||
|
||||
impl TestWindow {
|
||||
pub fn new(
|
||||
|
@ -117,9 +117,6 @@ impl TestWindow {
|
|||
|
||||
self.0.lock().input_handler = Some(input_handler);
|
||||
}
|
||||
pub fn edited(&self) -> bool {
|
||||
self.0.lock().edited
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformWindow for TestWindow {
|
||||
|
@ -163,11 +160,11 @@ impl PlatformWindow for TestWindow {
|
|||
self
|
||||
}
|
||||
|
||||
fn set_input_handler(&mut self, input_handler: Box<dyn crate::PlatformInputHandler>) {
|
||||
fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {
|
||||
self.0.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.lock().input_handler.take()
|
||||
}
|
||||
|
||||
|
@ -269,12 +266,12 @@ impl PlatformWindow for TestWindow {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct TestAtlasState {
|
||||
pub(crate) struct TestAtlasState {
|
||||
next_id: u32,
|
||||
tiles: HashMap<AtlasKey, AtlasTile>,
|
||||
}
|
||||
|
||||
pub struct TestAtlas(Mutex<TestAtlasState>);
|
||||
pub(crate) struct TestAtlas(Mutex<TestAtlasState>);
|
||||
|
||||
impl TestAtlas {
|
||||
pub fn new() -> Self {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::{
|
||||
self as gpui, hsla, point, px, relative, rems, AbsoluteLength, AlignItems, CursorStyle,
|
||||
DefiniteLength, Display, Fill, FlexDirection, FontWeight, Hsla, JustifyContent, Length,
|
||||
Position, SharedString, StyleRefinement, Visibility, WhiteSpace,
|
||||
DefiniteLength, Fill, FlexDirection, FontWeight, Hsla, JustifyContent, Length, Position,
|
||||
SharedString, StyleRefinement, Visibility, WhiteSpace,
|
||||
};
|
||||
use crate::{BoxShadow, TextStyleRefinement};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use taffy::style::Overflow;
|
||||
use taffy::style::{Display, Overflow};
|
||||
|
||||
pub trait Styled: Sized {
|
||||
fn style(&mut self) -> &mut StyleRefinement;
|
||||
|
|
|
@ -5,13 +5,13 @@ use crate::{
|
|||
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
|
||||
DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect,
|
||||
Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla,
|
||||
ImageData, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, KeystrokeEvent, LayoutId,
|
||||
Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent,
|
||||
MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
|
||||
PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render,
|
||||
RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, Scene, Shadow,
|
||||
SharedString, Size, Style, SubscriberSet, Subscription, Surface, TaffyLayoutEngine, Task,
|
||||
Underline, UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions,
|
||||
ImageData, InputHandler, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent,
|
||||
KeystrokeEvent, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton,
|
||||
MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay,
|
||||
PlatformInput, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel,
|
||||
Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, Scene,
|
||||
Shadow, SharedString, Size, Style, SubscriberSet, Subscription, Surface, TaffyLayoutEngine,
|
||||
Task, Underline, UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions,
|
||||
SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
|
@ -298,7 +298,7 @@ pub(crate) struct ElementStateBox {
|
|||
|
||||
struct RequestedInputHandler {
|
||||
view_id: EntityId,
|
||||
handler: Option<Box<dyn PlatformInputHandler>>,
|
||||
handler: Option<PlatformInputHandler>,
|
||||
}
|
||||
|
||||
struct TooltipRequest {
|
||||
|
@ -737,7 +737,7 @@ impl<'a> WindowContext<'a> {
|
|||
let (tx, mut rx) = mpsc::unbounded::<()>();
|
||||
self.platform.set_display_link_output_callback(
|
||||
display_id,
|
||||
Box::new(move |_current_time, _output_time| _ = tx.unbounded_send(())),
|
||||
Box::new(move || _ = tx.unbounded_send(())),
|
||||
);
|
||||
|
||||
let consumer_task = self.app.spawn(|cx| async move {
|
||||
|
@ -2188,16 +2188,15 @@ impl<'a> WindowContext<'a> {
|
|||
/// rendered.
|
||||
///
|
||||
/// [element_input_handler]: crate::ElementInputHandler
|
||||
pub fn handle_input(
|
||||
&mut self,
|
||||
focus_handle: &FocusHandle,
|
||||
input_handler: impl PlatformInputHandler,
|
||||
) {
|
||||
pub fn handle_input(&mut self, focus_handle: &FocusHandle, input_handler: impl InputHandler) {
|
||||
if focus_handle.is_focused(self) {
|
||||
let view_id = self.parent_view_id();
|
||||
self.window.next_frame.requested_input_handler = Some(RequestedInputHandler {
|
||||
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
|
||||
.platform_window
|
||||
.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
|
||||
// by always pre-empting the system close event.
|
||||
if f(cx) {
|
||||
|
|
|
@ -102,7 +102,7 @@ pub fn new_journal_entry(app_state: Arc<AppState>, cx: &mut WindowContext) {
|
|||
cx.spawn(|mut cx| async move {
|
||||
let (journal_dir, entry_path) = create_entry.await?;
|
||||
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?;
|
||||
|
||||
let opened = workspace
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
|
||||
use gpui::{
|
||||
div, fill, point, px, relative, AnyElement, AsyncWindowContext, AvailableSpace, BorrowWindow,
|
||||
Bounds, DispatchPhase, Element, ElementId, FocusHandle, Font, FontStyle, FontWeight,
|
||||
HighlightStyle, Hsla, InteractiveBounds, InteractiveElement, InteractiveElementState,
|
||||
div, fill, point, px, relative, AnyElement, AvailableSpace, BorrowWindow, Bounds,
|
||||
DispatchPhase, Element, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle,
|
||||
Hsla, InputHandler, InteractiveBounds, InteractiveElement, InteractiveElementState,
|
||||
Interactivity, IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton,
|
||||
MouseMoveEvent, Pixels, PlatformInputHandler, Point, ShapedLine, StatefulInteractiveElement,
|
||||
Styled, TextRun, TextStyle, TextSystem, UnderlineStyle, WeakView, WhiteSpace, WindowContext,
|
||||
MouseMoveEvent, Pixels, Point, ShapedLine, StatefulInteractiveElement, Styled, TextRun,
|
||||
TextStyle, TextSystem, UnderlineStyle, WeakView, WhiteSpace, WindowContext,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::CursorShape;
|
||||
|
@ -749,7 +749,6 @@ impl Element for TerminalElement {
|
|||
let origin = bounds.origin + Point::new(layout.gutter, px(0.));
|
||||
|
||||
let terminal_input_handler = TerminalInputHandler {
|
||||
cx: cx.to_async(),
|
||||
terminal: self.terminal.clone(),
|
||||
cursor_bounds: layout
|
||||
.cursor
|
||||
|
@ -838,37 +837,35 @@ impl IntoElement for TerminalElement {
|
|||
}
|
||||
|
||||
struct TerminalInputHandler {
|
||||
cx: AsyncWindowContext,
|
||||
terminal: Model<Terminal>,
|
||||
workspace: WeakView<Workspace>,
|
||||
cursor_bounds: Option<Bounds<Pixels>>,
|
||||
}
|
||||
|
||||
impl PlatformInputHandler for TerminalInputHandler {
|
||||
fn selected_text_range(&mut self) -> Option<std::ops::Range<usize>> {
|
||||
self.cx
|
||||
.update(|_, cx| {
|
||||
if self
|
||||
.terminal
|
||||
.read(cx)
|
||||
.last_content
|
||||
.mode
|
||||
.contains(TermMode::ALT_SCREEN)
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(0..0)
|
||||
}
|
||||
})
|
||||
.ok()
|
||||
.flatten()
|
||||
impl InputHandler for TerminalInputHandler {
|
||||
fn selected_text_range(&mut self, cx: &mut WindowContext) -> Option<std::ops::Range<usize>> {
|
||||
if self
|
||||
.terminal
|
||||
.read(cx)
|
||||
.last_content
|
||||
.mode
|
||||
.contains(TermMode::ALT_SCREEN)
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(0..0)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -876,19 +873,16 @@ impl PlatformInputHandler for TerminalInputHandler {
|
|||
&mut self,
|
||||
_replacement_range: Option<std::ops::Range<usize>>,
|
||||
text: &str,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
self.cx
|
||||
.update(|_, cx| {
|
||||
self.terminal.update(cx, |terminal, _| {
|
||||
terminal.input(text.into());
|
||||
});
|
||||
self.terminal.update(cx, |terminal, _| {
|
||||
terminal.input(text.into());
|
||||
});
|
||||
|
||||
self.workspace
|
||||
.update(cx, |this, cx| {
|
||||
let telemetry = this.project().read(cx).client().telemetry().clone();
|
||||
telemetry.log_edit_event("terminal");
|
||||
})
|
||||
.ok();
|
||||
self.workspace
|
||||
.update(cx, |this, cx| {
|
||||
let telemetry = this.project().read(cx).client().telemetry().clone();
|
||||
telemetry.log_edit_event("terminal");
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
@ -898,12 +892,17 @@ impl PlatformInputHandler for TerminalInputHandler {
|
|||
_range_utf16: Option<std::ops::Range<usize>>,
|
||||
_new_text: &str,
|
||||
_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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -772,7 +772,7 @@ impl Item for TerminalView {
|
|||
.log_err()
|
||||
.flatten()
|
||||
.or_else(|| {
|
||||
cx.update(|_, cx| {
|
||||
cx.update(|cx| {
|
||||
let strategy = TerminalSettings::get_global(cx).working_directory.clone();
|
||||
workspace
|
||||
.upgrade()
|
||||
|
|
|
@ -202,7 +202,7 @@ mod test {
|
|||
use futures::StreamExt;
|
||||
use indoc::indoc;
|
||||
|
||||
use gpui::InputHandler;
|
||||
use gpui::ViewInputHandler;
|
||||
|
||||
use crate::{
|
||||
state::Mode,
|
||||
|
|
|
@ -281,7 +281,7 @@ where
|
|||
Ok(value) => Some(value),
|
||||
Err(err) => {
|
||||
log::error!("TODO {err:?}");
|
||||
cx.update(|view, cx| {
|
||||
cx.update_root(|view, cx| {
|
||||
if let Ok(workspace) = view.downcast::<Workspace>() {
|
||||
workspace.update(cx, |workspace, cx| workspace.show_error(&err, cx))
|
||||
}
|
||||
|
|
|
@ -1092,7 +1092,7 @@ impl Pane {
|
|||
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.is_dirty(cx),
|
||||
|
@ -1132,7 +1132,7 @@ impl Pane {
|
|||
}
|
||||
} else if is_dirty && (can_save || can_save_as) {
|
||||
if save_intent == SaveIntent::Close {
|
||||
let will_autosave = cx.update(|_, cx| {
|
||||
let will_autosave = cx.update(|cx| {
|
||||
matches!(
|
||||
WorkspaceSettings::get_global(cx).autosave,
|
||||
AutosaveSetting::OnFocusChange | AutosaveSetting::OnWindowChange
|
||||
|
@ -1166,7 +1166,7 @@ impl Pane {
|
|||
})?
|
||||
.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() {
|
||||
pane.update(cx, |_, cx| item.save_as(project, abs_path, cx))?
|
||||
.await?;
|
||||
|
|
|
@ -1233,7 +1233,7 @@ impl Workspace {
|
|||
}
|
||||
for (pane, item) in dirty_items {
|
||||
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 let Some(ix) =
|
||||
pane.update(&mut cx, |pane, _| pane.index_for_item(item.as_ref()))?
|
||||
|
@ -1307,7 +1307,7 @@ impl Workspace {
|
|||
} else {
|
||||
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?;
|
||||
Ok(())
|
||||
})
|
||||
|
@ -1912,7 +1912,7 @@ impl Workspace {
|
|||
let project_item = project.update(cx, |project, cx| project.open_path(path, cx));
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
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>()
|
||||
.get(&project_item.entity_type())
|
||||
.ok_or_else(|| anyhow!("no item builder for project item"))
|
||||
|
@ -2709,7 +2709,7 @@ impl Workspace {
|
|||
) -> Result<()> {
|
||||
let this = this.upgrade().context("workspace dropped")?;
|
||||
|
||||
let item_builders = cx.update(|_, cx| {
|
||||
let item_builders = cx.update(|cx| {
|
||||
cx.default_global::<FollowableItemBuilders>()
|
||||
.values()
|
||||
.map(|b| b.0)
|
||||
|
@ -2728,7 +2728,7 @@ impl Workspace {
|
|||
Err(anyhow!("missing view variant"))?;
|
||||
}
|
||||
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)
|
||||
})?;
|
||||
if let Some(task) = task {
|
||||
|
@ -3141,7 +3141,7 @@ impl Workspace {
|
|||
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
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
|
@ -3407,7 +3407,7 @@ fn open_items(
|
|||
let restored_project_paths = restored_items
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
cx.update(|_, cx| item.as_ref()?.project_path(cx))
|
||||
cx.update(|cx| item.as_ref()?.project_path(cx))
|
||||
.ok()
|
||||
.flatten()
|
||||
})
|
||||
|
|
|
@ -875,7 +875,7 @@ mod tests {
|
|||
let window = cx.update(|cx| cx.windows()[0].downcast::<Workspace>().unwrap());
|
||||
|
||||
let window_is_edited = |window: WindowHandle<Workspace>, cx: &mut TestAppContext| {
|
||||
cx.test_window(window.into()).edited()
|
||||
cx.update(|cx| window.read(cx).unwrap().is_edited())
|
||||
};
|
||||
let pane = window
|
||||
.read_with(cx, |workspace, _| workspace.active_pane().clone())
|
||||
|
|
Loading…
Reference in a new issue