diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index e653710c0f..aa6a5e32ec 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -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 { - element: E, + pub element: E, } impl FocusableElement for Focusable {} diff --git a/crates/terminal2/src/terminal2.rs b/crates/terminal2/src/terminal2.rs index 197b912b1b..6036d65d6e 100644 --- a/crates/terminal2/src/terminal2.rs +++ b/crates/terminal2/src/terminal2.rs @@ -976,7 +976,6 @@ impl Terminal { } pub fn try_sync(&mut self, cx: &mut ModelContext) { - println!("trying to sync"); let term = self.term.clone(); let mut terminal = if let Some(term) = term.try_lock_unfair() { @@ -1235,7 +1234,7 @@ impl Terminal { } ///Scroll the terminal - pub fn scroll_wheel(&mut self, e: ScrollWheelEvent, origin: Point) { + pub fn scroll_wheel(&mut self, e: &ScrollWheelEvent, origin: Point) { let mouse_mode = self.mouse_mode(e.shift); if let Some(scroll_lines) = self.determine_scroll_lines(&e, mouse_mode) { diff --git a/crates/terminal_view2/src/terminal_element.rs b/crates/terminal_view2/src/terminal_element.rs index 96ffbb1ffb..03e98e831d 100644 --- a/crates/terminal_view2/src/terminal_element.rs +++ b/crates/terminal_view2/src/terminal_element.rs @@ -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, @@ -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_view: View, focus: FocusHandle, focused: bool, cursor_visible: bool, @@ -164,6 +168,7 @@ impl StatefulInteractiveElement for TerminalElement {} impl TerminalElement { pub fn new( terminal: WeakModel, + terminal_view: View, 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> -> 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, 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) - }) - } 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_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"); - // .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(); - // }) - // } - // }); + 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"); - // // 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); - // }, - // ), - // ) - // } + 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"); - // cx.scene().push_mouse_region(region); + if let Some(conn_handle) = connection.upgrade() { + conn_handle.update(cx, |terminal, cx| { + terminal.scroll_wheel(e, origin); + cx.notify(); + }) + } + } + }); + + // 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, state: &mut Self::State, cx: &mut WindowContext<'_>) { + fn paint( + mut self, + bounds: Bounds, + 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, - // _: &Self::State, - // _: &Self::PaintState, - // _: &TerminalView, - // _: &gpui::ViewContext, - // ) -> gpui::serde_json::Value { - // json!({ - // "type": "TerminalElement", - // }) - // } - - // fn rect_for_text_range( - // &self, - // _: Range, - // bounds: Bounds, - // _: Bounds, - // layout: &Self::State, - // _: &Self::PaintState, - // _: &TerminalView, - // _: &gpui::ViewContext, - // ) -> Option> { - // // 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 { diff --git a/crates/terminal_view2/src/terminal_view.rs b/crates/terminal_view2/src/terminal_view.rs index 5b864f4a5e..e9e4cd5167 100644 --- a/crates/terminal_view2/src/terminal_view.rs +++ b/crates/terminal_view2/src/terminal_view.rs @@ -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, } impl EventEmitter 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::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, -// ) -> 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, cx: &mut ViewContext, ) -> Option { - todo!() + None } fn selected_text_range( @@ -696,13 +701,11 @@ impl InputHandler for TerminalView { } } - fn marked_text_range(&self, cx: &mut ViewContext) -> Option> { - todo!() + fn marked_text_range(&self, _cx: &mut ViewContext) -> Option> { + None } - fn unmark_text(&mut self, cx: &mut ViewContext) { - todo!() - } + fn unmark_text(&mut self, _cx: &mut ViewContext) {} 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>, - new_text: &str, - new_selected_range: Option>, - cx: &mut ViewContext, + _range: Option>, + _new_text: &str, + _new_selected_range: Option>, + _cx: &mut ViewContext, ) { - 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, - element_bounds: gpui::Bounds, + _range_utf16: std::ops::Range, + bounds: gpui::Bounds, cx: &mut ViewContext, ) -> Option> { - 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) -> Option> { // 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) { - // 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(); } }