Add back the main structure
This commit is contained in:
parent
ab140ee4c2
commit
2ee0ecb677
4 changed files with 383 additions and 310 deletions
|
@ -1,10 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, Action, AnyDrag, AnyDragState, AnyElement, AnyTooltip, AnyView, AppContext,
|
green, point, px, red, Action, AnyDrag, AnyDragState, AnyElement, AnyTooltip, AnyView,
|
||||||
BorrowAppContext, BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId,
|
AppContext, BorrowAppContext, BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element,
|
||||||
FocusEvent, FocusHandle, IntoElement, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
|
ElementId, FocusEvent, FocusHandle, IntoElement, KeyContext, KeyDownEvent, KeyUpEvent,
|
||||||
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point,
|
LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels,
|
||||||
Render, ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement, Styled,
|
Point, Render, ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement,
|
||||||
Task, View, Visibility, WindowContext,
|
Styled, Task, View, Visibility, WindowContext,
|
||||||
};
|
};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
|
@ -1363,7 +1363,7 @@ impl GroupBounds {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Focusable<E> {
|
pub struct Focusable<E> {
|
||||||
element: E,
|
pub element: E,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
|
impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
|
||||||
|
|
|
@ -976,7 +976,6 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_sync(&mut self, cx: &mut ModelContext<Self>) {
|
pub fn try_sync(&mut self, cx: &mut ModelContext<Self>) {
|
||||||
println!("trying to sync");
|
|
||||||
let term = self.term.clone();
|
let term = self.term.clone();
|
||||||
|
|
||||||
let mut terminal = if let Some(term) = term.try_lock_unfair() {
|
let mut terminal = if let Some(term) = term.try_lock_unfair() {
|
||||||
|
@ -1235,7 +1234,7 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
|
|
||||||
///Scroll the 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);
|
let mouse_mode = self.mouse_mode(e.shift);
|
||||||
|
|
||||||
if let Some(scroll_lines) = self.determine_scroll_lines(&e, mouse_mode) {
|
if let Some(scroll_lines) = self.determine_scroll_lines(&e, mouse_mode) {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
|
use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
black, div, point, px, red, relative, transparent_black, AnyElement, AvailableSpace, Bounds,
|
black, div, point, px, red, relative, transparent_black, AnyElement, AvailableSpace, Bounds,
|
||||||
Element, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle, Hsla,
|
DispatchPhase, Element, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle,
|
||||||
InteractiveElement, InteractiveElementState, IntoElement, LayoutId, ModelContext, Pixels,
|
Hsla, InteractiveElement, InteractiveElementState, IntoElement, LayoutId, ModelContext,
|
||||||
Point, Rgba, ShapedLine, Size, StatefulInteractiveElement, Styled, TextRun, TextStyle,
|
ModifiersChangedEvent, MouseButton, Pixels, Point, Rgba, ShapedLine, Size,
|
||||||
TextSystem, UnderlineStyle, WeakModel, WhiteSpace, WindowContext,
|
StatefulInteractiveElement, Styled, TextRun, TextStyle, TextSystem, UnderlineStyle, View,
|
||||||
|
WeakModel, WhiteSpace, WindowContext,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use language::CursorShape;
|
use language::CursorShape;
|
||||||
|
@ -26,6 +27,8 @@ use ui::Tooltip;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::{fmt::Debug, ops::RangeInclusive};
|
use std::{fmt::Debug, ops::RangeInclusive};
|
||||||
|
|
||||||
|
use crate::TerminalView;
|
||||||
|
|
||||||
///The information generated during layout that is necessary for painting
|
///The information generated during layout that is necessary for painting
|
||||||
pub struct LayoutState {
|
pub struct LayoutState {
|
||||||
cells: Vec<LayoutCell>,
|
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?
|
///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 {
|
pub struct TerminalElement {
|
||||||
terminal: WeakModel<Terminal>,
|
terminal: WeakModel<Terminal>,
|
||||||
|
terminal_view: View<TerminalView>,
|
||||||
focus: FocusHandle,
|
focus: FocusHandle,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
cursor_visible: bool,
|
cursor_visible: bool,
|
||||||
|
@ -164,6 +168,7 @@ impl StatefulInteractiveElement for TerminalElement {}
|
||||||
impl TerminalElement {
|
impl TerminalElement {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
terminal: WeakModel<Terminal>,
|
terminal: WeakModel<Terminal>,
|
||||||
|
terminal_view: View<TerminalView>,
|
||||||
focus: FocusHandle,
|
focus: FocusHandle,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
cursor_visible: bool,
|
cursor_visible: bool,
|
||||||
|
@ -171,12 +176,15 @@ impl TerminalElement {
|
||||||
) -> TerminalElement {
|
) -> TerminalElement {
|
||||||
TerminalElement {
|
TerminalElement {
|
||||||
terminal,
|
terminal,
|
||||||
|
terminal_view,
|
||||||
focused,
|
focused,
|
||||||
focus,
|
focus: focus.clone(),
|
||||||
cursor_visible,
|
cursor_visible,
|
||||||
can_navigate_to_selected_word,
|
can_navigate_to_selected_word,
|
||||||
interactivity: Default::default(),
|
interactivity: Default::default(),
|
||||||
}
|
}
|
||||||
|
.track_focus(&focus)
|
||||||
|
.element
|
||||||
}
|
}
|
||||||
|
|
||||||
//Vec<Range<AlacPoint>> -> Clip out the parts of the ranges
|
//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,
|
self,
|
||||||
origin: Point<Pixels>,
|
origin: Point<Pixels>,
|
||||||
mode: TermMode,
|
mode: TermMode,
|
||||||
|
@ -611,133 +637,153 @@ impl TerminalElement {
|
||||||
let focus = self.focus.clone();
|
let focus = self.focus.clone();
|
||||||
let connection = self.terminal.clone();
|
let connection = self.terminal.clone();
|
||||||
|
|
||||||
self.on_mouse_down(gpui::MouseButton::Left, {
|
let mut this = self
|
||||||
let connection = connection.clone();
|
.on_mouse_down(MouseButton::Left, {
|
||||||
let focus = focus.clone();
|
let connection = connection.clone();
|
||||||
move |e, cx| {
|
let focus = focus.clone();
|
||||||
cx.focus(&focus);
|
move |e, cx| {
|
||||||
//todo!(context menu)
|
dbg!("here");
|
||||||
// v.context_menu.update(cx, |menu, _cx| menu.delay_cancel());
|
cx.focus(&focus);
|
||||||
if let Some(conn_handle) = connection.upgrade() {
|
//todo!(context menu)
|
||||||
conn_handle.update(cx, |terminal, cx| {
|
// v.context_menu.update(cx, |menu, _cx| menu.delay_cancel());
|
||||||
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) {
|
|
||||||
if let Some(conn_handle) = connection.upgrade() {
|
if let Some(conn_handle) = connection.upgrade() {
|
||||||
conn_handle.update(cx, |terminal, cx| {
|
conn_handle.update(cx, |terminal, cx| {
|
||||||
terminal.mouse_drag(e, origin, bounds);
|
terminal.mouse_down(&e, origin);
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
.on_drag_event({
|
||||||
.on_mouse_up(
|
let connection = connection.clone();
|
||||||
gpui::MouseButton::Left,
|
let focus = focus.clone();
|
||||||
TerminalElement::generic_button_handler(
|
move |e, cx| {
|
||||||
connection.clone(),
|
dbg!("here");
|
||||||
origin,
|
|
||||||
focus.clone(),
|
if focus.is_focused(cx) {
|
||||||
move |terminal, origin, e, cx| {
|
if let Some(conn_handle) = connection.upgrade() {
|
||||||
terminal.mouse_up(&e, origin, cx);
|
conn_handle.update(cx, |terminal, cx| {
|
||||||
},
|
terminal.mouse_drag(e, origin, bounds);
|
||||||
),
|
cx.notify();
|
||||||
)
|
})
|
||||||
.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_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 e.down.button == MouseButton::Right {
|
||||||
// if cx.is_self_focused() {
|
let mouse_mode = if let Some(conn_handle) = connection.upgrade() {
|
||||||
// if let Some(conn_handle) = connection.upgrade() {
|
conn_handle.update(cx, |terminal, _cx| {
|
||||||
// conn_handle.update(cx, |terminal, cx| {
|
terminal.mouse_mode(e.down.modifiers.shift)
|
||||||
// terminal.mouse_move(&event, origin);
|
})
|
||||||
// cx.notify();
|
} else {
|
||||||
// })
|
// If we can't get the model handle, probably can't deploy the context menu
|
||||||
// }
|
true
|
||||||
// }
|
};
|
||||||
// })
|
if !mouse_mode {
|
||||||
// .on_scroll(move |event, _: &mut TerminalView, cx| {
|
//todo!(context menu)
|
||||||
// if let Some(conn_handle) = connection.upgrade() {
|
// view.deploy_context_menu(e.position, cx);
|
||||||
// conn_handle.update(cx, |terminal, cx| {
|
}
|
||||||
// terminal.scroll_wheel(event, origin);
|
}
|
||||||
// cx.notify();
|
}
|
||||||
// })
|
})
|
||||||
// }
|
.on_mouse_move({
|
||||||
// });
|
let connection = connection.clone();
|
||||||
|
let focus = focus.clone();
|
||||||
|
move |e, cx| {
|
||||||
|
dbg!("here");
|
||||||
|
|
||||||
// // Mouse mode handlers:
|
if focus.is_focused(cx) {
|
||||||
// // All mouse modes need the extra click handlers
|
if let Some(conn_handle) = connection.upgrade() {
|
||||||
// if mode.intersects(TermMode::MOUSE_MODE) {
|
conn_handle.update(cx, |terminal, cx| {
|
||||||
// region = region
|
terminal.mouse_move(&e, origin);
|
||||||
// .on_down(
|
cx.notify();
|
||||||
// MouseButton::Right,
|
})
|
||||||
// TerminalElement::generic_button_handler(
|
}
|
||||||
// connection,
|
}
|
||||||
// origin,
|
}
|
||||||
// move |terminal, origin, e, _cx| {
|
})
|
||||||
// terminal.mouse_down(&e, origin);
|
.on_scroll_wheel({
|
||||||
// },
|
let connection = connection.clone();
|
||||||
// ),
|
move |e, cx| {
|
||||||
// )
|
dbg!("here");
|
||||||
// .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);
|
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)
|
(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 mut layout = self.compute_layout(bounds, cx);
|
||||||
|
|
||||||
let theme = cx.theme();
|
let theme = cx.theme();
|
||||||
|
|
||||||
|
let dispatch_context = self.terminal_view.read(cx).dispatch_context(cx);
|
||||||
|
self.interactivity().key_context = dispatch_context;
|
||||||
cx.paint_quad(
|
cx.paint_quad(
|
||||||
bounds,
|
bounds,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
@ -776,10 +829,13 @@ impl Element for TerminalElement {
|
||||||
);
|
);
|
||||||
let origin = bounds.origin + Point::new(layout.gutter, px(0.));
|
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 {
|
for rect in &layout.rects {
|
||||||
rect.paint(origin, &layout, cx);
|
rect.paint(origin, &layout, cx);
|
||||||
}
|
}
|
||||||
|
@ -824,47 +880,8 @@ impl Element for TerminalElement {
|
||||||
element.draw(origin, Size { width, height }, cx)
|
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 {
|
impl IntoElement for TerminalElement {
|
||||||
|
|
|
@ -9,10 +9,11 @@ pub mod terminal_panel;
|
||||||
// use crate::terminal_element::TerminalElement;
|
// use crate::terminal_element::TerminalElement;
|
||||||
use editor::{scroll::autoscroll::Autoscroll, Editor};
|
use editor::{scroll::autoscroll::Autoscroll, Editor};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, Action, AnyElement, AppContext, Div, Element, EventEmitter, FocusEvent,
|
actions, div, point, px, size, Action, AnyElement, AppContext, Bounds, Div, Element,
|
||||||
FocusHandle, Focusable, FocusableElement, FocusableView, InputHandler, InteractiveElement,
|
EventEmitter, FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView, Font,
|
||||||
KeyDownEvent, Keystroke, Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Render,
|
FontStyle, FontWeight, InputHandler, InteractiveElement, KeyContext, KeyDownEvent, Keystroke,
|
||||||
SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
|
Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Render, SharedString, Styled,
|
||||||
|
Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use language::Bias;
|
use language::Bias;
|
||||||
use persistence::TERMINAL_DB;
|
use persistence::TERMINAL_DB;
|
||||||
|
@ -26,6 +27,7 @@ use terminal::{
|
||||||
Event, MaybeNavigationTarget, Terminal,
|
Event, MaybeNavigationTarget, Terminal,
|
||||||
};
|
};
|
||||||
use terminal_element::TerminalElement;
|
use terminal_element::TerminalElement;
|
||||||
|
use theme::ThemeSettings;
|
||||||
use util::{paths::PathLikeWithPosition, ResultExt};
|
use util::{paths::PathLikeWithPosition, ResultExt};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
item::{BreadcrumbText, Item, ItemEvent},
|
item::{BreadcrumbText, Item, ItemEvent},
|
||||||
|
@ -91,6 +93,7 @@ pub struct TerminalView {
|
||||||
blink_epoch: usize,
|
blink_epoch: usize,
|
||||||
can_navigate_to_selected_word: bool,
|
can_navigate_to_selected_word: bool,
|
||||||
workspace_id: WorkspaceId,
|
workspace_id: WorkspaceId,
|
||||||
|
_subscriptions: Vec<Subscription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<Event> for TerminalView {}
|
impl EventEmitter<Event> for TerminalView {}
|
||||||
|
@ -262,6 +265,20 @@ impl TerminalView {
|
||||||
})
|
})
|
||||||
.detach();
|
.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 {
|
Self {
|
||||||
terminal,
|
terminal,
|
||||||
has_new_content: true,
|
has_new_content: true,
|
||||||
|
@ -274,6 +291,7 @@ impl TerminalView {
|
||||||
blink_epoch: 0,
|
blink_epoch: 0,
|
||||||
can_navigate_to_selected_word: false,
|
can_navigate_to_selected_word: false,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
|
_subscriptions: vec![focus_in, focus_out],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +321,7 @@ impl TerminalView {
|
||||||
menu.action("Clear", Box::new(Clear))
|
menu.action("Clear", Box::new(Clear))
|
||||||
.action("Close", Box::new(CloseActiveItem { save_intent: None }))
|
.action("Close", Box::new(CloseActiveItem { save_intent: None }))
|
||||||
}));
|
}));
|
||||||
// todo!()
|
// todo!(context menus)
|
||||||
// self.context_menu
|
// self.context_menu
|
||||||
// .show(position, AnchorCorner::TopLeft, menu_entries, cx);
|
// .show(position, AnchorCorner::TopLeft, menu_entries, cx);
|
||||||
// cx.notify();
|
// 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(
|
fn possible_open_targets(
|
||||||
|
@ -533,6 +626,7 @@ impl Render for TerminalView {
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||||
let terminal_handle = self.terminal.clone().downgrade();
|
let terminal_handle = self.terminal.clone().downgrade();
|
||||||
|
let this_view = cx.view().clone();
|
||||||
|
|
||||||
let self_id = cx.entity_id();
|
let self_id = cx.entity_id();
|
||||||
let focused = self.focus_handle.is_focused(cx);
|
let focused = self.focus_handle.is_focused(cx);
|
||||||
|
@ -555,6 +649,7 @@ impl Render for TerminalView {
|
||||||
.on_action(cx.listener(TerminalView::select_all))
|
.on_action(cx.listener(TerminalView::select_all))
|
||||||
.child(TerminalElement::new(
|
.child(TerminalElement::new(
|
||||||
terminal_handle,
|
terminal_handle,
|
||||||
|
this_view,
|
||||||
self.focus_handle.clone(),
|
self.focus_handle.clone(),
|
||||||
focused,
|
focused,
|
||||||
self.should_show_cursor(focused, cx),
|
self.should_show_cursor(focused, cx),
|
||||||
|
@ -579,104 +674,14 @@ impl Render for TerminalView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl View for TerminalView {
|
//todo!(Implement IME)
|
||||||
//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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl InputHandler for TerminalView {
|
impl InputHandler for TerminalView {
|
||||||
fn text_for_range(
|
fn text_for_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
range: std::ops::Range<usize>,
|
range: std::ops::Range<usize>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
todo!()
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn selected_text_range(
|
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>> {
|
fn marked_text_range(&self, _cx: &mut ViewContext<Self>) -> Option<std::ops::Range<usize>> {
|
||||||
todo!()
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
|
fn unmark_text(&mut self, _cx: &mut ViewContext<Self>) {}
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn replace_text_in_range(
|
fn replace_text_in_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -717,21 +720,75 @@ impl InputHandler for TerminalView {
|
||||||
|
|
||||||
fn replace_and_mark_text_in_range(
|
fn replace_and_mark_text_in_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
range: Option<std::ops::Range<usize>>,
|
_range: Option<std::ops::Range<usize>>,
|
||||||
new_text: &str,
|
_new_text: &str,
|
||||||
new_selected_range: Option<std::ops::Range<usize>>,
|
_new_selected_range: Option<std::ops::Range<usize>>,
|
||||||
cx: &mut ViewContext<Self>,
|
_cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo!(Check that this works correctly, why aren't we reading the range?)
|
||||||
fn bounds_for_range(
|
fn bounds_for_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
range_utf16: std::ops::Range<usize>,
|
_range_utf16: std::ops::Range<usize>,
|
||||||
element_bounds: gpui::Bounds<Pixels>,
|
bounds: gpui::Bounds<Pixels>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<gpui::Bounds<Pixels>> {
|
) -> 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
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo!()
|
// todo!(search)
|
||||||
// fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
|
// fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
|
||||||
// Some(Box::new(handle.clone()))
|
// Some(Box::new(handle.clone()))
|
||||||
// }
|
// }
|
||||||
|
@ -806,22 +863,23 @@ impl Item for TerminalView {
|
||||||
let window = cx.window_handle();
|
let window = cx.window_handle();
|
||||||
cx.spawn(|pane, mut cx| async move {
|
cx.spawn(|pane, mut cx| async move {
|
||||||
let cwd = None;
|
let cwd = None;
|
||||||
// todo!()
|
TERMINAL_DB
|
||||||
// TERMINAL_DB
|
.get_working_directory(item_id, workspace_id)
|
||||||
// .get_working_directory(item_id, workspace_id)
|
.log_err()
|
||||||
// .log_err()
|
.flatten()
|
||||||
// .flatten()
|
.or_else(|| {
|
||||||
// .or_else(|| {
|
cx.update(|_, cx| {
|
||||||
// cx.read(|cx| {
|
let strategy = TerminalSettings::get_global(cx).working_directory.clone();
|
||||||
// let strategy = TerminalSettings::get_global(cx).working_directory.clone();
|
workspace
|
||||||
// workspace
|
.upgrade()
|
||||||
// .upgrade()
|
.map(|workspace| {
|
||||||
// .map(|workspace| {
|
get_working_directory(workspace.read(cx), cx, strategy)
|
||||||
// get_working_directory(workspace.read(cx), cx, strategy)
|
})
|
||||||
// })
|
.flatten()
|
||||||
// .flatten()
|
})
|
||||||
// })
|
.ok()
|
||||||
// });
|
.flatten()
|
||||||
|
});
|
||||||
|
|
||||||
let terminal = project.update(&mut cx, |project, cx| {
|
let terminal = project.update(&mut cx, |project, cx| {
|
||||||
project.create_terminal(cwd, window, 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>) {
|
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
|
||||||
// todo!()
|
cx.background_executor()
|
||||||
// cx.background()
|
.spawn(TERMINAL_DB.update_workspace_id(
|
||||||
// .spawn(TERMINAL_DB.update_workspace_id(
|
workspace.database_id(),
|
||||||
// workspace.database_id(),
|
self.workspace_id,
|
||||||
// self.workspace_id,
|
cx.entity_id().as_u64(),
|
||||||
// cx.view_id(),
|
))
|
||||||
// ))
|
.detach();
|
||||||
// .detach();
|
|
||||||
self.workspace_id = workspace.database_id();
|
self.workspace_id = workspace.database_id();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue