Add back the main structure

Mikayla created

Change summary

crates/gpui2/src/elements/div.rs              |  14 
crates/terminal2/src/terminal2.rs             |   3 
crates/terminal_view2/src/terminal_element.rs | 353 +++++++++++---------
crates/terminal_view2/src/terminal_view.rs    | 327 +++++++++++--------
4 files changed, 385 insertions(+), 312 deletions(-)

Detailed changes

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<E> {
-    element: E,
+    pub element: E,
 }
 
 impl<E: InteractiveElement> FocusableElement for Focusable<E> {}

crates/terminal2/src/terminal2.rs 🔗

@@ -976,7 +976,6 @@ impl Terminal {
     }
 
     pub fn try_sync(&mut self, cx: &mut ModelContext<Self>) {
-        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<Pixels>) {
+    pub fn scroll_wheel(&mut self, e: &ScrollWheelEvent, origin: Point<Pixels>) {
         let mouse_mode = self.mouse_mode(e.shift);
 
         if let Some(scroll_lines) = self.determine_scroll_lines(&e, mouse_mode) {

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<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 {

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<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();
     }
 }