@@ -1,11 +1,11 @@
use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{
- black, div, point, px, red, relative, transparent_black, AnyElement, AvailableSpace, Bounds,
- DispatchPhase, Element, ElementId, ElementInputHandler, FocusHandle, Font, FontStyle,
+ black, div, point, px, red, relative, transparent_black, AnyElement, AsyncWindowContext,
+ AvailableSpace, Bounds, DispatchPhase, Element, ElementId, FocusHandle, Font, FontStyle,
FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState, IntoElement,
- LayoutId, ModelContext, ModifiersChangedEvent, MouseButton, Pixels, Point, Rgba, ShapedLine,
- Size, StatefulInteractiveElement, Styled, TextRun, TextStyle, TextSystem, UnderlineStyle, View,
- WeakModel, WhiteSpace, WindowContext,
+ LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, Pixels,
+ PlatformInputHandler, Point, Rgba, ShapedLine, Size, StatefulInteractiveElement, Styled,
+ TextRun, TextStyle, TextSystem, UnderlineStyle, View, WhiteSpace, WindowContext,
};
use itertools::Itertools;
use language::CursorShape;
@@ -148,7 +148,7 @@ impl LayoutRect {
///The GPUI element that paints the terminal.
///We need to keep a reference to the view for mouse events, do we need it for any other terminal stuff, or can we move that to connection?
pub struct TerminalElement {
- terminal: WeakModel<Terminal>,
+ terminal: Model<Terminal>,
terminal_view: View<TerminalView>,
focus: FocusHandle,
focused: bool,
@@ -167,7 +167,7 @@ impl StatefulInteractiveElement for TerminalElement {}
impl TerminalElement {
pub fn new(
- terminal: WeakModel<Terminal>,
+ terminal: Model<Terminal>,
terminal_view: View<TerminalView>,
focus: FocusHandle,
focused: bool,
@@ -461,16 +461,11 @@ impl TerminalElement {
TerminalSize::new(line_height, cell_width, size)
};
- let search_matches = if let Some(terminal_model) = self.terminal.upgrade() {
- terminal_model.read(cx).matches.clone()
- } else {
- Default::default()
- };
+ let search_matches = self.terminal.read(cx).matches.clone();
let background_color = theme.colors().background;
- let terminal_handle = self.terminal.upgrade().unwrap();
- let last_hovered_word = terminal_handle.update(cx, |terminal, cx| {
+ let last_hovered_word = self.terminal.update(cx, |terminal, cx| {
terminal.set_size(dimensions);
terminal.try_sync(cx);
if self.can_navigate_to_selected_word && terminal.can_navigate_to_selected_word() {
@@ -495,7 +490,7 @@ impl TerminalElement {
selection,
cursor,
..
- } = &terminal_handle.read(cx).last_content;
+ } = &self.terminal.read(cx).last_content;
// searches, highlights to a single range representations
let mut relative_highlighted_ranges = Vec::new();
@@ -592,20 +587,18 @@ impl TerminalElement {
}
fn generic_button_handler<E>(
- connection: WeakModel<Terminal>,
+ connection: Model<Terminal>,
origin: Point<Pixels>,
focus_handle: FocusHandle,
f: impl Fn(&mut Terminal, Point<Pixels>, &E, &mut ModelContext<Terminal>),
) -> impl Fn(&E, &mut WindowContext) {
move |event, cx| {
cx.focus(&focus_handle);
- if let Some(conn_handle) = connection.upgrade() {
- conn_handle.update(cx, |terminal, cx| {
- f(terminal, origin, event, cx);
+ connection.update(cx, |terminal, cx| {
+ f(terminal, origin, event, cx);
- cx.notify();
- })
- }
+ cx.notify();
+ })
}
}
@@ -617,10 +610,10 @@ impl TerminalElement {
return;
}
- let handled = this
- .update(cx, |term, _| term.try_modifiers_change(&event.modifiers))
- .ok();
- if handled == Some(true) {
+ let handled =
+ this.update(cx, |term, _| term.try_modifiers_change(&event.modifiers));
+
+ if handled {
cx.notify();
}
}
@@ -645,13 +638,11 @@ impl TerminalElement {
cx.focus(&focus);
//todo!(context menu)
// v.context_menu.update(cx, |menu, _cx| menu.delay_cancel());
- if let Some(conn_handle) = connection.upgrade() {
- conn_handle.update(cx, |terminal, cx| {
- terminal.mouse_down(&e, origin);
+ connection.update(cx, |terminal, cx| {
+ terminal.mouse_down(&e, origin);
- cx.notify();
- })
- }
+ cx.notify();
+ })
}
})
.on_mouse_move({
@@ -660,12 +651,10 @@ impl TerminalElement {
move |e, cx| {
if e.pressed_button.is_some() {
if focus.is_focused(cx) {
- if let Some(conn_handle) = connection.upgrade() {
- conn_handle.update(cx, |terminal, cx| {
- terminal.mouse_drag(e, origin, bounds);
- cx.notify();
- })
- }
+ connection.update(cx, |terminal, cx| {
+ terminal.mouse_drag(e, origin, bounds);
+ cx.notify();
+ })
}
}
}
@@ -685,14 +674,10 @@ impl TerminalElement {
let connection = connection.clone();
move |e, cx| {
if e.down.button == MouseButton::Right {
- let mouse_mode = if let Some(conn_handle) = connection.upgrade() {
- conn_handle.update(cx, |terminal, _cx| {
- terminal.mouse_mode(e.down.modifiers.shift)
- })
- } else {
- // If we can't get the model handle, probably can't deploy the context menu
- true
- };
+ let mouse_mode = connection.update(cx, |terminal, _cx| {
+ terminal.mouse_mode(e.down.modifiers.shift)
+ });
+
if !mouse_mode {
//todo!(context menu)
// view.deploy_context_menu(e.position, cx);
@@ -705,24 +690,20 @@ impl TerminalElement {
let focus = focus.clone();
move |e, cx| {
if focus.is_focused(cx) {
- if let Some(conn_handle) = connection.upgrade() {
- conn_handle.update(cx, |terminal, cx| {
- terminal.mouse_move(&e, origin);
- cx.notify();
- })
- }
+ connection.update(cx, |terminal, cx| {
+ terminal.mouse_move(&e, origin);
+ cx.notify();
+ })
}
}
})
.on_scroll_wheel({
let connection = connection.clone();
move |e, cx| {
- if let Some(conn_handle) = connection.upgrade() {
- conn_handle.update(cx, |terminal, cx| {
- terminal.scroll_wheel(e, origin);
- cx.notify();
- })
- }
+ connection.update(cx, |terminal, cx| {
+ terminal.scroll_wheel(e, origin);
+ cx.notify();
+ })
}
});
@@ -822,13 +803,21 @@ 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
+ .as_ref()
+ .map(|cursor| cursor.bounding_rect(origin)),
+ };
+
let mut this = self.register_mouse_listeners(origin, layout.mode, bounds, cx);
let interactivity = mem::take(&mut this.interactivity);
interactivity.paint(bounds, bounds.size, state, cx, |_, _, cx| {
- let input_handler = ElementInputHandler::new(bounds, this.terminal_view.clone(), cx);
- cx.handle_input(&this.focus, input_handler);
+ cx.handle_input(&this.focus, terminal_input_handler);
this.register_key_listeners(cx);
@@ -890,6 +879,69 @@ impl IntoElement for TerminalElement {
}
}
+struct TerminalInputHandler {
+ cx: AsyncWindowContext,
+ terminal: Model<Terminal>,
+ 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()
+ }
+
+ fn marked_text_range(&mut self) -> Option<std::ops::Range<usize>> {
+ None
+ }
+
+ fn text_for_range(&mut self, range_utf16: std::ops::Range<usize>) -> Option<String> {
+ None
+ }
+
+ fn replace_text_in_range(
+ &mut self,
+ _replacement_range: Option<std::ops::Range<usize>>,
+ text: &str,
+ ) {
+ self.cx
+ .update(|_, cx| {
+ self.terminal.update(cx, |terminal, _| {
+ terminal.input(text.into());
+ })
+ })
+ .ok();
+ }
+
+ fn replace_and_mark_text_in_range(
+ &mut self,
+ _range_utf16: Option<std::ops::Range<usize>>,
+ _new_text: &str,
+ _new_selected_range: Option<std::ops::Range<usize>>,
+ ) {
+ }
+
+ fn unmark_text(&mut self) {}
+
+ fn bounds_for_range(&mut self, _range_utf16: std::ops::Range<usize>) -> Option<Bounds<Pixels>> {
+ self.cursor_bounds
+ }
+}
+
fn is_blank(cell: &IndexedCell) -> bool {
if cell.c != ' ' {
return false;
@@ -9,10 +9,9 @@ pub mod terminal_panel;
// use crate::terminal_element::TerminalElement;
use editor::{scroll::autoscroll::Autoscroll, Editor};
use gpui::{
- actions, div, point, px, size, Action, AnyElement, AppContext, Bounds, Div, EventEmitter,
- FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView, Font, FontStyle,
- FontWeight, InputHandler, KeyContext, KeyDownEvent, Keystroke, Model, MouseButton,
- MouseDownEvent, Pixels, Render, Task, View, VisualContext, WeakView, Subscription
+ actions, div, Action, AnyElement, AppContext, Div, EventEmitter, FocusEvent, FocusHandle,
+ Focusable, FocusableElement, FocusableView, KeyContext, KeyDownEvent, Keystroke, Model,
+ MouseButton, MouseDownEvent, Pixels, Render, Subscription, Task, View, VisualContext, WeakView,
};
use language::Bias;
use persistence::TERMINAL_DB;
@@ -26,7 +25,6 @@ use terminal::{
Event, MaybeNavigationTarget, Terminal,
};
use terminal_element::TerminalElement;
-use theme::ThemeSettings;
use ui::{h_stack, prelude::*, ContextMenu, Icon, IconElement, Label};
use util::{paths::PathLikeWithPosition, ResultExt};
use workspace::{
@@ -624,7 +622,7 @@ impl Render for TerminalView {
type Element = Focusable<Div>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
- let terminal_handle = self.terminal.clone().downgrade();
+ let terminal_handle = self.terminal.clone();
let this_view = cx.view().clone();
let self_id = cx.entity_id();
@@ -673,124 +671,6 @@ impl Render for TerminalView {
}
}
-//todo!(Implement IME)
-impl InputHandler for TerminalView {
- fn text_for_range(
- &mut self,
- range: std::ops::Range<usize>,
- cx: &mut ViewContext<Self>,
- ) -> Option<String> {
- None
- }
-
- fn selected_text_range(
- &mut self,
- cx: &mut ViewContext<Self>,
- ) -> 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(&self, _cx: &mut ViewContext<Self>) -> Option<std::ops::Range<usize>> {
- None
- }
-
- fn unmark_text(&mut self, _cx: &mut ViewContext<Self>) {}
-
- fn replace_text_in_range(
- &mut self,
- _: Option<std::ops::Range<usize>>,
- text: &str,
- cx: &mut ViewContext<Self>,
- ) {
- self.terminal.update(cx, |terminal, _| {
- terminal.input(text.into());
- });
- }
-
- fn replace_and_mark_text_in_range(
- &mut self,
- _range: Option<std::ops::Range<usize>>,
- _new_text: &str,
- _new_selected_range: Option<std::ops::Range<usize>>,
- _cx: &mut ViewContext<Self>,
- ) {
- }
-
- // todo!(Check that this works correctly, why aren't we reading the range?)
- fn bounds_for_range(
- &mut self,
- _range_utf16: std::ops::Range<usize>,
- bounds: gpui::Bounds<Pixels>,
- cx: &mut ViewContext<Self>,
- ) -> Option<gpui::Bounds<Pixels>> {
- let settings = ThemeSettings::get_global(cx).clone();
-
- let buffer_font_size = settings.buffer_font_size(cx);
-
- let terminal_settings = TerminalSettings::get_global(cx);
- let font_family = terminal_settings
- .font_family
- .as_ref()
- .map(|string| string.clone().into())
- .unwrap_or(settings.buffer_font.family);
-
- let line_height = terminal_settings
- .line_height
- .value()
- .to_pixels(cx.rem_size());
-
- let font_size = terminal_settings.font_size.clone();
- let features = terminal_settings
- .font_features
- .clone()
- .unwrap_or(settings.buffer_font.features.clone());
-
- let font_size =
- font_size.map_or(buffer_font_size, |size| theme::adjusted_font_size(size, cx));
-
- let font_id = cx
- .text_system()
- .font_id(&Font {
- family: font_family,
- style: FontStyle::Normal,
- weight: FontWeight::NORMAL,
- features,
- })
- .unwrap();
-
- let cell_width = cx
- .text_system()
- .advance(font_id, font_size, 'm')
- .unwrap()
- .width;
-
- let mut origin = bounds.origin + point(cell_width, px(0.));
-
- // TODO - Why is it necessary to move downward one line to get correct
- // positioning? I would think that we'd want the same rect that is
- // painted for the cursor.
- origin += point(px(0.), line_height);
-
- let cursor = Bounds {
- origin,
- //todo!(correctly calculate this width and height based on the text the line is over)
- size: size(cell_width, line_height),
- };
-
- Some(cursor)
- }
-}
-
impl Item for TerminalView {
type Event = ItemEvent;