@@ -1,10 +1,10 @@
use crate::{
- point, px, Action, AnyDrag, AnyDragState, AnyElement, AnyTooltip, AnyView, AppContext,
- BorrowAppContext, BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId,
- FocusEvent, FocusHandle, IntoElement, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
- MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point,
- Render, ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement, Styled,
- Task, View, Visibility, WindowContext,
+ green, point, px, red, Action, AnyDrag, AnyDragState, AnyElement, AnyTooltip, AnyView,
+ AppContext, BorrowAppContext, BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element,
+ ElementId, FocusEvent, FocusHandle, IntoElement, KeyContext, KeyDownEvent, KeyUpEvent,
+ LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels,
+ Point, Render, ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement,
+ Styled, Task, View, Visibility, WindowContext,
};
use collections::HashMap;
use refineable::Refineable;
@@ -1363,7 +1363,7 @@ impl GroupBounds {
}
pub struct Focusable<E> {
- element: E,
+ pub element: E,
}
impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
@@ -1,10 +1,11 @@
use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{
black, div, point, px, red, relative, transparent_black, AnyElement, AvailableSpace, Bounds,
- Element, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle, Hsla,
- InteractiveElement, InteractiveElementState, IntoElement, LayoutId, ModelContext, Pixels,
- Point, Rgba, ShapedLine, Size, StatefulInteractiveElement, Styled, TextRun, TextStyle,
- TextSystem, UnderlineStyle, WeakModel, WhiteSpace, WindowContext,
+ 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,
};
use itertools::Itertools;
use language::CursorShape;
@@ -26,6 +27,8 @@ use ui::Tooltip;
use std::mem;
use std::{fmt::Debug, ops::RangeInclusive};
+use crate::TerminalView;
+
///The information generated during layout that is necessary for painting
pub struct LayoutState {
cells: Vec<LayoutCell>,
@@ -146,6 +149,7 @@ impl LayoutRect {
///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_view: View<TerminalView>,
focus: FocusHandle,
focused: bool,
cursor_visible: bool,
@@ -164,6 +168,7 @@ impl StatefulInteractiveElement for TerminalElement {}
impl TerminalElement {
pub fn new(
terminal: WeakModel<Terminal>,
+ terminal_view: View<TerminalView>,
focus: FocusHandle,
focused: bool,
cursor_visible: bool,
@@ -171,12 +176,15 @@ impl TerminalElement {
) -> TerminalElement {
TerminalElement {
terminal,
+ terminal_view,
focused,
- focus,
+ focus: focus.clone(),
cursor_visible,
can_navigate_to_selected_word,
interactivity: Default::default(),
}
+ .track_focus(&focus)
+ .element
}
//Vec<Range<AlacPoint>> -> Clip out the parts of the ranges
@@ -601,7 +609,25 @@ impl TerminalElement {
}
}
- fn paint_mouse_listeners(
+ fn register_key_listeners(&self, cx: &mut WindowContext) {
+ cx.on_key_event({
+ let this = self.terminal.clone();
+ move |event: &ModifiersChangedEvent, phase, cx| {
+ if phase != DispatchPhase::Bubble {
+ return;
+ }
+
+ let handled = this
+ .update(cx, |term, _| term.try_modifiers_change(&event.modifiers))
+ .ok();
+ if handled == Some(true) {
+ cx.notify();
+ }
+ }
+ });
+ }
+
+ fn register_mouse_listeners(
self,
origin: Point<Pixels>,
mode: TermMode,
@@ -611,133 +637,153 @@ impl TerminalElement {
let focus = self.focus.clone();
let connection = self.terminal.clone();
- self.on_mouse_down(gpui::MouseButton::Left, {
- let connection = connection.clone();
- let focus = focus.clone();
- move |e, cx| {
- 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);
-
- cx.notify();
- })
- }
- }
- })
- .on_drag_event({
- let connection = connection.clone();
- let focus = focus.clone();
- move |e, cx| {
- if focus.is_focused(cx) {
+ let mut this = self
+ .on_mouse_down(MouseButton::Left, {
+ let connection = connection.clone();
+ let focus = focus.clone();
+ move |e, cx| {
+ dbg!("here");
+ 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_drag(e, origin, bounds);
+ terminal.mouse_down(&e, origin);
+
cx.notify();
})
}
}
- }
- })
- .on_mouse_up(
- gpui::MouseButton::Left,
- TerminalElement::generic_button_handler(
- connection.clone(),
- origin,
- focus.clone(),
- move |terminal, origin, e, cx| {
- terminal.mouse_up(&e, origin, cx);
- },
- ),
- )
- .on_click({
- let connection = connection.clone();
- move |e, cx| {
- if e.down.button == gpui::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)
+ })
+ .on_drag_event({
+ let connection = connection.clone();
+ let focus = focus.clone();
+ move |e, cx| {
+ dbg!("here");
+
+ 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();
+ })
+ }
+ }
+ }
+ })
+ .on_mouse_up(
+ MouseButton::Left,
+ TerminalElement::generic_button_handler(
+ connection.clone(),
+ origin,
+ focus.clone(),
+ move |terminal, origin, e, cx| {
+ terminal.mouse_up(&e, origin, cx);
+ },
+ ),
+ )
+ .on_click({
+ let connection = connection.clone();
+ move |e, cx| {
+ dbg!("here");
+
+ 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
+ };
+ if !mouse_mode {
+ //todo!(context menu)
+ // view.deploy_context_menu(e.position, cx);
+ }
+ }
+ }
+ })
+ .on_mouse_move({
+ let connection = connection.clone();
+ let focus = focus.clone();
+ move |e, cx| {
+ dbg!("here");
+
+ 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();
+ })
+ }
+ }
+ }
+ })
+ .on_scroll_wheel({
+ let connection = connection.clone();
+ move |e, cx| {
+ dbg!("here");
+
+ if let Some(conn_handle) = connection.upgrade() {
+ conn_handle.update(cx, |terminal, cx| {
+ terminal.scroll_wheel(e, origin);
+ cx.notify();
})
- } else {
- // If we can't get the model handle, probably can't deploy the context menu
- true
- };
- if !mouse_mode {
- //todo!(context menu)
- // view.deploy_context_menu(e.position, cx);
}
}
- }
- })
-
- // .on_move(move |event, _: &mut TerminalView, cx| {
- // if cx.is_self_focused() {
- // if let Some(conn_handle) = connection.upgrade() {
- // conn_handle.update(cx, |terminal, cx| {
- // terminal.mouse_move(&event, origin);
- // cx.notify();
- // })
- // }
- // }
- // })
- // .on_scroll(move |event, _: &mut TerminalView, cx| {
- // if let Some(conn_handle) = connection.upgrade() {
- // conn_handle.update(cx, |terminal, cx| {
- // terminal.scroll_wheel(event, origin);
- // cx.notify();
- // })
- // }
- // });
-
- // // Mouse mode handlers:
- // // All mouse modes need the extra click handlers
- // if mode.intersects(TermMode::MOUSE_MODE) {
- // region = region
- // .on_down(
- // MouseButton::Right,
- // TerminalElement::generic_button_handler(
- // connection,
- // origin,
- // move |terminal, origin, e, _cx| {
- // terminal.mouse_down(&e, origin);
- // },
- // ),
- // )
- // .on_down(
- // MouseButton::Middle,
- // TerminalElement::generic_button_handler(
- // connection,
- // origin,
- // move |terminal, origin, e, _cx| {
- // terminal.mouse_down(&e, origin);
- // },
- // ),
- // )
- // .on_up(
- // MouseButton::Right,
- // TerminalElement::generic_button_handler(
- // connection,
- // origin,
- // move |terminal, origin, e, cx| {
- // terminal.mouse_up(&e, origin, cx);
- // },
- // ),
- // )
- // .on_up(
- // MouseButton::Middle,
- // TerminalElement::generic_button_handler(
- // connection,
- // origin,
- // move |terminal, origin, e, cx| {
- // terminal.mouse_up(&e, origin, cx);
- // },
- // ),
- // )
- // }
-
- // cx.scene().push_mouse_region(region);
+ });
+
+ // Mouse mode handlers:
+ // All mouse modes need the extra click handlers
+ if mode.intersects(TermMode::MOUSE_MODE) {
+ this = this
+ .on_mouse_down(
+ MouseButton::Right,
+ TerminalElement::generic_button_handler(
+ connection.clone(),
+ origin,
+ focus.clone(),
+ move |terminal, origin, e, _cx| {
+ terminal.mouse_down(&e, origin);
+ },
+ ),
+ )
+ .on_mouse_down(
+ MouseButton::Middle,
+ TerminalElement::generic_button_handler(
+ connection.clone(),
+ origin,
+ focus.clone(),
+ move |terminal, origin, e, _cx| {
+ terminal.mouse_down(&e, origin);
+ },
+ ),
+ )
+ .on_mouse_up(
+ MouseButton::Right,
+ TerminalElement::generic_button_handler(
+ connection.clone(),
+ origin,
+ focus.clone(),
+ move |terminal, origin, e, cx| {
+ terminal.mouse_up(&e, origin, cx);
+ },
+ ),
+ )
+ .on_mouse_up(
+ MouseButton::Middle,
+ TerminalElement::generic_button_handler(
+ connection,
+ origin,
+ focus,
+ move |terminal, origin, e, cx| {
+ terminal.mouse_up(&e, origin, cx);
+ },
+ ),
+ )
+ }
+
+ this
}
}
@@ -762,11 +808,18 @@ impl Element for TerminalElement {
(layout_id, interactive_state)
}
- fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext<'_>) {
+ fn paint(
+ mut self,
+ bounds: Bounds<Pixels>,
+ state: &mut Self::State,
+ cx: &mut WindowContext<'_>,
+ ) {
let mut layout = self.compute_layout(bounds, cx);
let theme = cx.theme();
+ let dispatch_context = self.terminal_view.read(cx).dispatch_context(cx);
+ self.interactivity().key_context = dispatch_context;
cx.paint_quad(
bounds,
Default::default(),
@@ -776,10 +829,13 @@ impl Element for TerminalElement {
);
let origin = bounds.origin + Point::new(layout.gutter, px(0.));
- let this = self.paint_mouse_listeners(origin, layout.mode, bounds, cx);
+ let mut this = self.register_mouse_listeners(origin, layout.mode, bounds, cx);
+ let interactivity = mem::take(&mut this.interactivity);
+
+ cx.with_z_index(0, |cx| {
+ interactivity.paint(bounds, bounds.size, state, cx, |_, _, cx| {
+ this.register_key_listeners(cx);
- this.interactivity
- .paint(bounds, bounds.size, state, cx, |_, _, cx| {
for rect in &layout.rects {
rect.paint(origin, &layout, cx);
}
@@ -824,47 +880,8 @@ impl Element for TerminalElement {
element.draw(origin, Size { width, height }, cx)
}
});
+ });
}
-
- // todo!() remove?
- // fn metadata(&self) -> Option<&dyn std::any::Any> {
- // None
- // }
-
- // fn debug(
- // &self,
- // _: Bounds<Pixels>,
- // _: &Self::State,
- // _: &Self::PaintState,
- // _: &TerminalView,
- // _: &gpui::ViewContext<TerminalView>,
- // ) -> gpui::serde_json::Value {
- // json!({
- // "type": "TerminalElement",
- // })
- // }
-
- // fn rect_for_text_range(
- // &self,
- // _: Range<usize>,
- // bounds: Bounds<Pixels>,
- // _: Bounds<Pixels>,
- // layout: &Self::State,
- // _: &Self::PaintState,
- // _: &TerminalView,
- // _: &gpui::ViewContext<TerminalView>,
- // ) -> Option<Bounds<Pixels>> {
- // // Use the same origin that's passed to `Cursor::paint` in the paint
- // // method bove.
- // let mut origin = bounds.origin() + point(layout.size.cell_width, 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(0., layout.size.line_height);
-
- // Some(layout.cursor.as_ref()?.bounding_rect(origin))
- // }
}
impl IntoElement for TerminalElement {
@@ -9,10 +9,11 @@ pub mod terminal_panel;
// use crate::terminal_element::TerminalElement;
use editor::{scroll::autoscroll::Autoscroll, Editor};
use gpui::{
- actions, div, Action, AnyElement, AppContext, Div, Element, EventEmitter, FocusEvent,
- FocusHandle, Focusable, FocusableElement, FocusableView, InputHandler, InteractiveElement,
- KeyDownEvent, Keystroke, Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Render,
- SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
+ actions, div, point, px, size, Action, AnyElement, AppContext, Bounds, Div, Element,
+ EventEmitter, FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView, Font,
+ FontStyle, FontWeight, InputHandler, InteractiveElement, KeyContext, KeyDownEvent, Keystroke,
+ Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Render, SharedString, Styled,
+ Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
};
use language::Bias;
use persistence::TERMINAL_DB;
@@ -26,6 +27,7 @@ use terminal::{
Event, MaybeNavigationTarget, Terminal,
};
use terminal_element::TerminalElement;
+use theme::ThemeSettings;
use util::{paths::PathLikeWithPosition, ResultExt};
use workspace::{
item::{BreadcrumbText, Item, ItemEvent},
@@ -91,6 +93,7 @@ pub struct TerminalView {
blink_epoch: usize,
can_navigate_to_selected_word: bool,
workspace_id: WorkspaceId,
+ _subscriptions: Vec<Subscription>,
}
impl EventEmitter<Event> for TerminalView {}
@@ -262,6 +265,20 @@ impl TerminalView {
})
.detach();
+ let focus = cx.focus_handle();
+ let focus_in = cx.on_focus_in(&focus, |this, cx| {
+ this.has_new_content = false;
+ this.terminal.read(cx).focus_in();
+ this.blink_cursors(this.blink_epoch, cx);
+ cx.notify();
+ });
+ let focus_out = cx.on_focus_out(&focus, |this, cx| {
+ this.terminal.update(cx, |terminal, _| {
+ terminal.focus_out();
+ });
+ cx.notify();
+ });
+
Self {
terminal,
has_new_content: true,
@@ -274,6 +291,7 @@ impl TerminalView {
blink_epoch: 0,
can_navigate_to_selected_word: false,
workspace_id,
+ _subscriptions: vec![focus_in, focus_out],
}
}
@@ -303,7 +321,7 @@ impl TerminalView {
menu.action("Clear", Box::new(Clear))
.action("Close", Box::new(CloseActiveItem { save_intent: None }))
}));
- // todo!()
+ // todo!(context menus)
// self.context_menu
// .show(position, AnchorCorner::TopLeft, menu_entries, cx);
// cx.notify();
@@ -448,6 +466,81 @@ impl TerminalView {
});
}
}
+
+ fn dispatch_context(&self, cx: &AppContext) -> KeyContext {
+ let mut dispatch_context = KeyContext::default();
+ dispatch_context.add("Terminal");
+
+ let mode = self.terminal.read(cx).last_content.mode;
+ dispatch_context.set(
+ "screen",
+ if mode.contains(TermMode::ALT_SCREEN) {
+ "alt"
+ } else {
+ "normal"
+ },
+ );
+
+ if mode.contains(TermMode::APP_CURSOR) {
+ dispatch_context.add("DECCKM");
+ }
+ if mode.contains(TermMode::APP_KEYPAD) {
+ dispatch_context.add("DECPAM");
+ } else {
+ dispatch_context.add("DECPNM");
+ }
+ if mode.contains(TermMode::SHOW_CURSOR) {
+ dispatch_context.add("DECTCEM");
+ }
+ if mode.contains(TermMode::LINE_WRAP) {
+ dispatch_context.add("DECAWM");
+ }
+ if mode.contains(TermMode::ORIGIN) {
+ dispatch_context.add("DECOM");
+ }
+ if mode.contains(TermMode::INSERT) {
+ dispatch_context.add("IRM");
+ }
+ //LNM is apparently the name for this. https://vt100.net/docs/vt510-rm/LNM.html
+ if mode.contains(TermMode::LINE_FEED_NEW_LINE) {
+ dispatch_context.add("LNM");
+ }
+ if mode.contains(TermMode::FOCUS_IN_OUT) {
+ dispatch_context.add("report_focus");
+ }
+ if mode.contains(TermMode::ALTERNATE_SCROLL) {
+ dispatch_context.add("alternate_scroll");
+ }
+ if mode.contains(TermMode::BRACKETED_PASTE) {
+ dispatch_context.add("bracketed_paste");
+ }
+ if mode.intersects(TermMode::MOUSE_MODE) {
+ dispatch_context.add("any_mouse_reporting");
+ }
+ {
+ let mouse_reporting = if mode.contains(TermMode::MOUSE_REPORT_CLICK) {
+ "click"
+ } else if mode.contains(TermMode::MOUSE_DRAG) {
+ "drag"
+ } else if mode.contains(TermMode::MOUSE_MOTION) {
+ "motion"
+ } else {
+ "off"
+ };
+ dispatch_context.set("mouse_reporting", mouse_reporting);
+ }
+ {
+ let format = if mode.contains(TermMode::SGR_MOUSE) {
+ "sgr"
+ } else if mode.contains(TermMode::UTF8_MOUSE) {
+ "utf8"
+ } else {
+ "normal"
+ };
+ dispatch_context.set("mouse_format", format);
+ };
+ dispatch_context
+ }
}
fn possible_open_targets(
@@ -533,6 +626,7 @@ impl Render for TerminalView {
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let terminal_handle = self.terminal.clone().downgrade();
+ let this_view = cx.view().clone();
let self_id = cx.entity_id();
let focused = self.focus_handle.is_focused(cx);
@@ -555,6 +649,7 @@ impl Render for TerminalView {
.on_action(cx.listener(TerminalView::select_all))
.child(TerminalElement::new(
terminal_handle,
+ this_view,
self.focus_handle.clone(),
focused,
self.should_show_cursor(focused, cx),
@@ -579,104 +674,14 @@ impl Render for TerminalView {
}
}
-// impl View for TerminalView {
-//todo!()
-// fn modifiers_changed(
-// &mut self,
-// event: &ModifiersChangedEvent,
-// cx: &mut ViewContext<Self>,
-// ) -> bool {
-// let handled = self
-// .terminal()
-// .update(cx, |term, _| term.try_modifiers_change(&event.modifiers));
-// if handled {
-// cx.notify();
-// }
-// handled
-// }
-// }
-
-// todo!()
-// fn update_keymap_context(&self, keymap: &mut KeymapContext, cx: &gpui::AppContext) {
-// Self::reset_to_default_keymap_context(keymap);
-
-// let mode = self.terminal.read(cx).last_content.mode;
-// keymap.add_key(
-// "screen",
-// if mode.contains(TermMode::ALT_SCREEN) {
-// "alt"
-// } else {
-// "normal"
-// },
-// );
-
-// if mode.contains(TermMode::APP_CURSOR) {
-// keymap.add_identifier("DECCKM");
-// }
-// if mode.contains(TermMode::APP_KEYPAD) {
-// keymap.add_identifier("DECPAM");
-// } else {
-// keymap.add_identifier("DECPNM");
-// }
-// if mode.contains(TermMode::SHOW_CURSOR) {
-// keymap.add_identifier("DECTCEM");
-// }
-// if mode.contains(TermMode::LINE_WRAP) {
-// keymap.add_identifier("DECAWM");
-// }
-// if mode.contains(TermMode::ORIGIN) {
-// keymap.add_identifier("DECOM");
-// }
-// if mode.contains(TermMode::INSERT) {
-// keymap.add_identifier("IRM");
-// }
-// //LNM is apparently the name for this. https://vt100.net/docs/vt510-rm/LNM.html
-// if mode.contains(TermMode::LINE_FEED_NEW_LINE) {
-// keymap.add_identifier("LNM");
-// }
-// if mode.contains(TermMode::FOCUS_IN_OUT) {
-// keymap.add_identifier("report_focus");
-// }
-// if mode.contains(TermMode::ALTERNATE_SCROLL) {
-// keymap.add_identifier("alternate_scroll");
-// }
-// if mode.contains(TermMode::BRACKETED_PASTE) {
-// keymap.add_identifier("bracketed_paste");
-// }
-// if mode.intersects(TermMode::MOUSE_MODE) {
-// keymap.add_identifier("any_mouse_reporting");
-// }
-// {
-// let mouse_reporting = if mode.contains(TermMode::MOUSE_REPORT_CLICK) {
-// "click"
-// } else if mode.contains(TermMode::MOUSE_DRAG) {
-// "drag"
-// } else if mode.contains(TermMode::MOUSE_MOTION) {
-// "motion"
-// } else {
-// "off"
-// };
-// keymap.add_key("mouse_reporting", mouse_reporting);
-// }
-// {
-// let format = if mode.contains(TermMode::SGR_MOUSE) {
-// "sgr"
-// } else if mode.contains(TermMode::UTF8_MOUSE) {
-// "utf8"
-// } else {
-// "normal"
-// };
-// keymap.add_key("mouse_format", format);
-// }
-// }
-
+//todo!(Implement IME)
impl InputHandler for TerminalView {
fn text_for_range(
&mut self,
range: std::ops::Range<usize>,
cx: &mut ViewContext<Self>,
) -> Option<String> {
- todo!()
+ None
}
fn selected_text_range(
@@ -696,13 +701,11 @@ impl InputHandler for TerminalView {
}
}
- fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<std::ops::Range<usize>> {
- todo!()
+ fn marked_text_range(&self, _cx: &mut ViewContext<Self>) -> Option<std::ops::Range<usize>> {
+ None
}
- fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
- todo!()
- }
+ fn unmark_text(&mut self, _cx: &mut ViewContext<Self>) {}
fn replace_text_in_range(
&mut self,
@@ -717,21 +720,75 @@ impl InputHandler for TerminalView {
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>,
+ _range: Option<std::ops::Range<usize>>,
+ _new_text: &str,
+ _new_selected_range: Option<std::ops::Range<usize>>,
+ _cx: &mut ViewContext<Self>,
) {
- todo!()
}
+ // 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>,
- element_bounds: gpui::Bounds<Pixels>,
+ _range_utf16: std::ops::Range<usize>,
+ bounds: gpui::Bounds<Pixels>,
cx: &mut ViewContext<Self>,
) -> Option<gpui::Bounds<Pixels>> {
- todo!()
+ 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)
}
}
@@ -776,7 +833,7 @@ impl Item for TerminalView {
false
}
- // todo!()
+ // todo!(search)
// fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
// Some(Box::new(handle.clone()))
// }
@@ -806,22 +863,23 @@ impl Item for TerminalView {
let window = cx.window_handle();
cx.spawn(|pane, mut cx| async move {
let cwd = None;
- // todo!()
- // TERMINAL_DB
- // .get_working_directory(item_id, workspace_id)
- // .log_err()
- // .flatten()
- // .or_else(|| {
- // cx.read(|cx| {
- // let strategy = TerminalSettings::get_global(cx).working_directory.clone();
- // workspace
- // .upgrade()
- // .map(|workspace| {
- // get_working_directory(workspace.read(cx), cx, strategy)
- // })
- // .flatten()
- // })
- // });
+ TERMINAL_DB
+ .get_working_directory(item_id, workspace_id)
+ .log_err()
+ .flatten()
+ .or_else(|| {
+ cx.update(|_, cx| {
+ let strategy = TerminalSettings::get_global(cx).working_directory.clone();
+ workspace
+ .upgrade()
+ .map(|workspace| {
+ get_working_directory(workspace.read(cx), cx, strategy)
+ })
+ .flatten()
+ })
+ .ok()
+ .flatten()
+ });
let terminal = project.update(&mut cx, |project, cx| {
project.create_terminal(cwd, window, cx)
@@ -833,14 +891,13 @@ impl Item for TerminalView {
}
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
- // todo!()
- // cx.background()
- // .spawn(TERMINAL_DB.update_workspace_id(
- // workspace.database_id(),
- // self.workspace_id,
- // cx.view_id(),
- // ))
- // .detach();
+ cx.background_executor()
+ .spawn(TERMINAL_DB.update_workspace_id(
+ workspace.database_id(),
+ self.workspace_id,
+ cx.entity_id().as_u64(),
+ ))
+ .detach();
self.workspace_id = workspace.database_id();
}
}