More compilation fixes

This commit is contained in:
Kirill Bulatov 2023-11-14 17:40:29 +02:00
parent 61d6cb880c
commit a238368296
6 changed files with 244 additions and 205 deletions

View File

@ -1,4 +1,4 @@
use gpui::{AppContext, FontFeatures}; use gpui::{AppContext, FontFeatures, Pixels};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
@ -15,7 +15,7 @@ pub enum TerminalDockPosition {
pub struct TerminalSettings { pub struct TerminalSettings {
pub shell: Shell, pub shell: Shell,
pub working_directory: WorkingDirectory, pub working_directory: WorkingDirectory,
font_size: Option<f32>, pub font_size: Option<Pixels>,
pub font_family: Option<String>, pub font_family: Option<String>,
pub line_height: TerminalLineHeight, pub line_height: TerminalLineHeight,
pub font_features: Option<FontFeatures>, pub font_features: Option<FontFeatures>,
@ -90,14 +90,6 @@ pub struct TerminalSettingsContent {
pub detect_venv: Option<VenvSettings>, pub detect_venv: Option<VenvSettings>,
} }
impl TerminalSettings {
// todo!("move to terminal element")
// pub fn font_size(&self, cx: &AppContext) -> Option<f32> {
// self.font_size
// .map(|size| theme2::adjusted_font_size(size, cx))
// }
}
impl settings::Settings for TerminalSettings { impl settings::Settings for TerminalSettings {
const KEY: Option<&'static str> = Some("terminal"); const KEY: Option<&'static str> = Some("terminal");

View File

@ -1,11 +1,13 @@
use editor::{Cursor, HighlightedRange, HighlightedRangeLine}; use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{ use gpui::{
serde_json::json, AnyElement, Bounds, HighlightStyle, Hsla, Line, ModelContext, MouseButton, AnyElement, AppContext, Bounds, Component, Element, HighlightStyle, Hsla, LayoutId, Line,
Pixels, Point, TextStyle, ViewContext, WeakModel, WindowContext, ModelContext, MouseButton, Pixels, Point, TextStyle, Underline, ViewContext, WeakModel,
WindowContext,
}; };
use itertools::Itertools; use itertools::Itertools;
use language::CursorShape; use language::CursorShape;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use settings::Settings;
use terminal::{ use terminal::{
alacritty_terminal::{ alacritty_terminal::{
ansi::{Color as AnsiColor, Color::Named, CursorShape as AlacCursorShape, NamedColor}, ansi::{Color as AnsiColor, Color::Named, CursorShape as AlacCursorShape, NamedColor},
@ -21,10 +23,9 @@ use terminal::{
TerminalSize, TerminalSize,
}; };
use theme::ThemeSettings; use theme::ThemeSettings;
use util::ResultExt;
use std::mem;
use std::{fmt::Debug, ops::RangeInclusive}; use std::{fmt::Debug, ops::RangeInclusive};
use std::{mem, ops::Range};
use crate::TerminalView; use crate::TerminalView;
@ -143,7 +144,7 @@ impl LayoutRect {
cx.paint_quad( cx.paint_quad(
Bounds::new(position, size), Bounds::new(position, size),
Default::default(), Default::default(),
Some(self.color), self.color,
Default::default(), Default::default(),
Default::default(), Default::default(),
); );
@ -282,10 +283,10 @@ impl TerminalElement {
text_fragment: &Line, text_fragment: &Line,
) -> Option<(Vector2F, f32)> { ) -> Option<(Vector2F, f32)> {
if cursor_point.line() < size.total_lines() as i32 { if cursor_point.line() < size.total_lines() as i32 {
let cursor_width = if text_fragment.width() == 0. { let cursor_width = if text_fragment.width == 0. {
size.cell_width() size.cell_width()
} else { } else {
text_fragment.width() text_fragment.width
}; };
//Cursor should always surround as much of the text as possible, //Cursor should always surround as much of the text as possible,
@ -339,7 +340,7 @@ impl TerminalElement {
let font_id = font_cache let font_id = font_cache
.select_font(text_style.font_family_id, &properties) .select_font(text_style.font_family_id, &properties)
.unwrap_or(text_style.font_id); .unwrap_or(8text_style.font_id);
let mut result = RunStyle { let mut result = RunStyle {
color: fg, color: fg,
@ -369,7 +370,7 @@ impl TerminalElement {
) -> impl Fn(E, &mut TerminalView, &mut EventContext<TerminalView>) { ) -> impl Fn(E, &mut TerminalView, &mut EventContext<TerminalView>) {
move |event, _: &mut TerminalView, cx| { move |event, _: &mut TerminalView, cx| {
cx.focus_parent(); cx.focus_parent();
if let Some(conn_handle) = connection.upgrade(cx) { if let Some(conn_handle) = connection.upgrade() {
conn_handle.update(cx, |terminal, cx| { conn_handle.update(cx, |terminal, cx| {
f(terminal, origin, event, cx); f(terminal, origin, event, cx);
@ -382,7 +383,7 @@ impl TerminalElement {
fn attach_mouse_handlers( fn attach_mouse_handlers(
&self, &self,
origin: Point<Pixels>, origin: Point<Pixels>,
visible_bounds: Bounds, visible_bounds: Bounds<Pixels>,
mode: TermMode, mode: TermMode,
cx: &mut ViewContext<TerminalView>, cx: &mut ViewContext<TerminalView>,
) { ) {
@ -397,7 +398,7 @@ impl TerminalElement {
let terminal_view = cx.handle(); let terminal_view = cx.handle();
cx.focus(&terminal_view); cx.focus(&terminal_view);
v.context_menu.update(cx, |menu, _cx| menu.delay_cancel()); v.context_menu.update(cx, |menu, _cx| menu.delay_cancel());
if let Some(conn_handle) = connection.upgrade(cx) { if let Some(conn_handle) = connection.upgrade() {
conn_handle.update(cx, |terminal, cx| { conn_handle.update(cx, |terminal, cx| {
terminal.mouse_down(&event, origin); terminal.mouse_down(&event, origin);
@ -412,7 +413,7 @@ impl TerminalElement {
} }
if cx.is_self_focused() { if cx.is_self_focused() {
if let Some(conn_handle) = connection.upgrade(cx) { if let Some(conn_handle) = connection.upgrade() {
conn_handle.update(cx, |terminal, cx| { conn_handle.update(cx, |terminal, cx| {
terminal.mouse_drag(event, origin); terminal.mouse_drag(event, origin);
cx.notify(); cx.notify();
@ -435,7 +436,7 @@ impl TerminalElement {
.on_click( .on_click(
MouseButton::Right, MouseButton::Right,
move |event, view: &mut TerminalView, cx| { move |event, view: &mut TerminalView, cx| {
let mouse_mode = if let Some(conn_handle) = connection.upgrade(cx) { let mouse_mode = if let Some(conn_handle) = connection.upgrade() {
conn_handle.update(cx, |terminal, _cx| terminal.mouse_mode(event.shift)) conn_handle.update(cx, |terminal, _cx| terminal.mouse_mode(event.shift))
} else { } else {
// If we can't get the model handle, probably can't deploy the context menu // If we can't get the model handle, probably can't deploy the context menu
@ -448,7 +449,7 @@ impl TerminalElement {
) )
.on_move(move |event, _: &mut TerminalView, cx| { .on_move(move |event, _: &mut TerminalView, cx| {
if cx.is_self_focused() { if cx.is_self_focused() {
if let Some(conn_handle) = connection.upgrade(cx) { if let Some(conn_handle) = connection.upgrade() {
conn_handle.update(cx, |terminal, cx| { conn_handle.update(cx, |terminal, cx| {
terminal.mouse_move(&event, origin); terminal.mouse_move(&event, origin);
cx.notify(); cx.notify();
@ -457,7 +458,7 @@ impl TerminalElement {
} }
}) })
.on_scroll(move |event, _: &mut TerminalView, cx| { .on_scroll(move |event, _: &mut TerminalView, cx| {
if let Some(conn_handle) = connection.upgrade(cx) { if let Some(conn_handle) = connection.upgrade() {
conn_handle.update(cx, |terminal, cx| { conn_handle.update(cx, |terminal, cx| {
terminal.scroll_wheel(event, origin); terminal.scroll_wheel(event, origin);
cx.notify(); cx.notify();
@ -516,17 +517,16 @@ impl TerminalElement {
} }
impl Element<TerminalView> for TerminalElement { impl Element<TerminalView> for TerminalElement {
type LayoutState = LayoutState; type ElementState = LayoutState;
type PaintState = ();
fn layout( fn layout(
&mut self, &mut self,
constraint: gpui::SizeConstraint, view_state: &mut TerminalView,
view: &mut TerminalView, element_state: &mut Self::ElementState,
cx: &mut ViewContext<TerminalView>, cx: &mut ViewContext<TerminalView>,
) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { ) -> LayoutId {
let settings = settings::get::<ThemeSettings>(cx); let settings = ThemeSettings::get_global(cx);
let terminal_settings = settings::get::<TerminalSettings>(cx); let terminal_settings = TerminalSettings::get_global(cx);
//Setup layout information //Setup layout information
let terminal_theme = settings.theme.terminal.clone(); //TODO: Try to minimize this clone. let terminal_theme = settings.theme.terminal.clone(); //TODO: Try to minimize this clone.
@ -534,9 +534,7 @@ impl Element<TerminalView> for TerminalElement {
let tooltip_style = settings.theme.tooltip.clone(); let tooltip_style = settings.theme.tooltip.clone();
let font_cache = cx.font_cache(); let font_cache = cx.font_cache();
let font_size = terminal_settings let font_size = font_size(&terminal_settings, cx).unwrap_or(settings.buffer_font_size(cx));
.font_size(cx)
.unwrap_or(settings.buffer_font_size(cx));
let font_family_name = terminal_settings let font_family_name = terminal_settings
.font_family .font_family
.as_ref() .as_ref()
@ -575,14 +573,14 @@ impl Element<TerminalView> for TerminalElement {
TerminalSize::new(line_height, cell_width, size) TerminalSize::new(line_height, cell_width, size)
}; };
let search_matches = if let Some(terminal_model) = self.terminal.upgrade(cx) { let search_matches = if let Some(terminal_model) = self.terminal.upgrade() {
terminal_model.read(cx).matches.clone() terminal_model.read(cx).matches.clone()
} else { } else {
Default::default() Default::default()
}; };
let background_color = terminal_theme.background; let background_color = terminal_theme.background;
let terminal_handle = self.terminal.upgrade(cx).unwrap(); let terminal_handle = self.terminal.upgrade().unwrap();
let last_hovered_word = terminal_handle.update(cx, |terminal, cx| { let last_hovered_word = terminal_handle.update(cx, |terminal, cx| {
terminal.set_size(dimensions); terminal.set_size(dimensions);
@ -614,7 +612,7 @@ impl Element<TerminalView> for TerminalElement {
tooltip.layout( tooltip.layout(
SizeConstraint::new(Vector2F::zero(), cx.window_size()), SizeConstraint::new(Vector2F::zero(), cx.window_size()),
view, view_state,
cx, cx,
); );
tooltip tooltip
@ -709,7 +707,7 @@ impl Element<TerminalView> for TerminalElement {
//Done! //Done!
( (
constraint.max, constraint.max,
LayoutState { Self::ElementState {
cells, cells,
cursor, cursor,
background_color, background_color,
@ -726,26 +724,25 @@ impl Element<TerminalView> for TerminalElement {
fn paint( fn paint(
&mut self, &mut self,
bounds: Bounds, bounds: Bounds<Pixels>,
visible_bounds: Bounds, view_state: &mut TerminalView,
layout: &mut Self::LayoutState, element_state: &mut Self::ElementState,
view: &mut TerminalView,
cx: &mut ViewContext<TerminalView>, cx: &mut ViewContext<TerminalView>,
) -> Self::PaintState { ) {
let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
//Setup element stuff //Setup element stuff
let clip_bounds = Some(visible_bounds); let clip_bounds = Some(visible_bounds);
cx.paint_layer(clip_bounds, |cx| { cx.paint_layer(clip_bounds, |cx| {
let origin = bounds.origin() + vec2f(layout.gutter, 0.); let origin = bounds.origin() + vec2f(element_state.gutter, 0.);
// Elements are ephemeral, only at paint time do we know what could be clicked by a mouse // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse
self.attach_mouse_handlers(origin, visible_bounds, layout.mode, cx); self.attach_mouse_handlers(origin, visible_bounds, element_state.mode, cx);
cx.scene().push_cursor_region(gpui::CursorRegion { cx.scene().push_cursor_region(gpui::CursorRegion {
bounds, bounds,
style: if layout.hyperlink_tooltip.is_some() { style: if element_state.hyperlink_tooltip.is_some() {
CursorStyle::AlacPointingHand CursorStyle::AlacPointingHand
} else { } else {
CursorStyle::IBeam CursorStyle::IBeam
@ -755,31 +752,34 @@ impl Element<TerminalView> for TerminalElement {
cx.paint_layer(clip_bounds, |cx| { cx.paint_layer(clip_bounds, |cx| {
//Start with a background color //Start with a background color
cx.scene().push_quad(Quad { cx.scene().push_quad(Quad {
bounds: RectF::new(bounds.origin(), bounds.size()), bounds,
background: Some(layout.background_color), background: Some(element_state.background_color),
border: Default::default(), border: Default::default(),
corner_radii: Default::default(), corner_radii: Default::default(),
}); });
for rect in &layout.rects { for rect in &element_state.rects {
rect.paint(origin, layout, view, cx); rect.paint(origin, element_state, view_state, cx);
} }
}); });
//Draw Highlighted Backgrounds //Draw Highlighted Backgrounds
cx.paint_layer(clip_bounds, |cx| { cx.paint_layer(clip_bounds, |cx| {
for (relative_highlighted_range, color) in layout.relative_highlighted_ranges.iter() for (relative_highlighted_range, color) in
element_state.relative_highlighted_ranges.iter()
{ {
if let Some((start_y, highlighted_range_lines)) = if let Some((start_y, highlighted_range_lines)) = to_highlighted_range_lines(
to_highlighted_range_lines(relative_highlighted_range, layout, origin) relative_highlighted_range,
{ element_state,
origin,
) {
let hr = HighlightedRange { let hr = HighlightedRange {
start_y, //Need to change this start_y, //Need to change this
line_height: layout.size.line_height, line_height: element_state.size.line_height,
lines: highlighted_range_lines, lines: highlighted_range_lines,
color: color.clone(), color: color.clone(),
//Copied from editor. TODO: move to theme or something //Copied from editor. TODO: move to theme or something
corner_radius: 0.15 * layout.size.line_height, corner_radius: 0.15 * element_state.size.line_height,
}; };
hr.paint(bounds, cx); hr.paint(bounds, cx);
} }
@ -788,63 +788,83 @@ impl Element<TerminalView> for TerminalElement {
//Draw the text cells //Draw the text cells
cx.paint_layer(clip_bounds, |cx| { cx.paint_layer(clip_bounds, |cx| {
for cell in &layout.cells { for cell in &element_state.cells {
cell.paint(origin, layout, visible_bounds, view, cx); cell.paint(origin, element_state, visible_bounds, view_state, cx);
} }
}); });
//Draw cursor //Draw cursor
if self.cursor_visible { if self.cursor_visible {
if let Some(cursor) = &layout.cursor { if let Some(cursor) = &element_state.cursor {
cx.paint_layer(clip_bounds, |cx| { cx.paint_layer(clip_bounds, |cx| {
cursor.paint(origin, cx); cursor.paint(origin, cx);
}) })
} }
} }
if let Some(element) = &mut layout.hyperlink_tooltip { if let Some(element) = &mut element_state.hyperlink_tooltip {
element.paint(origin, visible_bounds, view, cx) element.paint(origin, visible_bounds, view_state, cx)
} }
}); });
} }
fn metadata(&self) -> Option<&dyn std::any::Any> { fn id(&self) -> Option<gpui::ElementId> {
None todo!()
} }
fn debug( fn initialize(
&self, &mut self,
_: Bounds, view_state: &mut TerminalView,
_: &Self::LayoutState, element_state: Option<Self::ElementState>,
_: &Self::PaintState, cx: &mut ViewContext<TerminalView>,
_: &TerminalView, ) -> Self::ElementState {
_: &gpui::ViewContext<TerminalView>, todo!()
) -> gpui::serde_json::Value {
json!({
"type": "TerminalElement",
})
} }
fn rect_for_text_range( // todo!() remove?
&self, // fn metadata(&self) -> Option<&dyn std::any::Any> {
_: Range<usize>, // None
bounds: Bounds, // }
_: Bounds,
layout: &Self::LayoutState,
_: &Self::PaintState,
_: &TerminalView,
_: &gpui::ViewContext<TerminalView>,
) -> Option<RectF> {
// Use the same origin that's passed to `Cursor::paint` in the paint
// method bove.
let mut origin = bounds.origin() + vec2f(layout.size.cell_width, 0.);
// TODO - Why is it necessary to move downward one line to get correct // fn debug(
// positioning? I would think that we'd want the same rect that is // &self,
// painted for the cursor. // _: Bounds<Pixels>,
origin += vec2f(0., layout.size.line_height); // _: &Self::ElementState,
// _: &Self::PaintState,
// _: &TerminalView,
// _: &gpui::ViewContext<TerminalView>,
// ) -> gpui::serde_json::Value {
// json!({
// "type": "TerminalElement",
// })
// }
Some(layout.cursor.as_ref()?.bounding_rect(origin)) // fn rect_for_text_range(
// &self,
// _: Range<usize>,
// bounds: Bounds<Pixels>,
// _: Bounds<Pixels>,
// layout: &Self::ElementState,
// _: &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() + vec2f(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 += vec2f(0., layout.size.line_height);
// Some(layout.cursor.as_ref()?.bounding_rect(origin))
// }
}
impl Component<TerminalView> for TerminalElement {
fn render(self) -> AnyElement<TerminalView> {
todo!()
} }
} }
@ -933,3 +953,9 @@ fn to_highlighted_range_lines(
Some((start_y, highlighted_range_lines)) Some((start_y, highlighted_range_lines))
} }
fn font_size(terminal_settings: &TerminalSettings, cx: &mut AppContext) -> Option<Pixels> {
terminal_settings
.font_size
.map(|size| theme::adjusted_font_size(size, cx))
}

View File

@ -3,27 +3,34 @@ use std::{path::PathBuf, sync::Arc};
use crate::TerminalView; use crate::TerminalView;
use db::kvp::KEY_VALUE_STORE; use db::kvp::KEY_VALUE_STORE;
use gpui::{ use gpui::{
actions, anyhow::Result, elements::*, serde_json, Action, AppContext, AsyncAppContext, Entity, actions, serde_json, Action, AppContext, AsyncAppContext, Entity, EventEmitter, Render,
Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, WindowContext, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
}; };
use project::Fs; use project::Fs;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use settings::SettingsStore; use settings::{Settings, SettingsStore};
use terminal::terminal_settings::{TerminalDockPosition, TerminalSettings}; use terminal::terminal_settings::{TerminalDockPosition, TerminalSettings};
use util::{ResultExt, TryFutureExt}; use util::{ResultExt, TryFutureExt};
use workspace::{ use workspace::{
dock::{DockPosition, Panel}, dock::{DockPosition, Panel, PanelEvent},
item::Item, item::Item,
pane, DraggedItem, Pane, Workspace, pane, Pane, Workspace,
}; };
use anyhow::Result;
const TERMINAL_PANEL_KEY: &'static str = "TerminalPanel"; const TERMINAL_PANEL_KEY: &'static str = "TerminalPanel";
actions!(terminal_panel, [ToggleFocus]); actions!(ToggleFocus);
pub fn init(cx: &mut AppContext) { pub fn init(cx: &mut AppContext) {
cx.add_action(TerminalPanel::new_terminal); cx.observe_new_views(
cx.add_action(TerminalPanel::open_terminal); |workspace: &mut Workspace, _: &mut ViewContext<Workspace>| {
workspace.register_action(TerminalPanel::new_terminal);
workspace.register_action(TerminalPanel::open_terminal);
},
)
.detach();
} }
#[derive(Debug)] #[derive(Debug)]
@ -36,9 +43,9 @@ pub enum Event {
} }
pub struct TerminalPanel { pub struct TerminalPanel {
pane: ViewHandle<Pane>, pane: View<Pane>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
workspace: WeakViewHandle<Workspace>, workspace: WeakView<Workspace>,
width: Option<f32>, width: Option<f32>,
height: Option<f32>, height: Option<f32>,
pending_serialization: Task<Option<()>>, pending_serialization: Task<Option<()>>,
@ -48,12 +55,11 @@ pub struct TerminalPanel {
impl TerminalPanel { impl TerminalPanel {
fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self { fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self {
let weak_self = cx.weak_handle(); let weak_self = cx.weak_handle();
let pane = cx.add_view(|cx| { let pane = cx.build_view(|cx| {
let window = cx.window(); let window = cx.window_handle();
let mut pane = Pane::new( let mut pane = Pane::new(
workspace.weak_handle(), workspace.weak_handle(),
workspace.project().clone(), workspace.project().clone(),
workspace.app_state().background_actions,
Default::default(), Default::default(),
cx, cx,
); );
@ -78,7 +84,7 @@ impl TerminalPanel {
move |_, cx| { move |_, cx| {
let this = this.clone(); let this = this.clone();
cx.window_context().defer(move |cx| { cx.window_context().defer(move |cx| {
if let Some(this) = this.upgrade(cx) { if let Some(this) = this.upgrade() {
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
this.add_terminal(None, cx); this.add_terminal(None, cx);
}); });
@ -104,7 +110,7 @@ impl TerminalPanel {
)) ))
.into_any() .into_any()
}); });
let buffer_search_bar = cx.add_view(search::BufferSearchBar::new); let buffer_search_bar = cx.build_view(search::BufferSearchBar::new);
pane.toolbar() pane.toolbar()
.update(cx, |toolbar, cx| toolbar.add_item(buffer_search_bar, cx)); .update(cx, |toolbar, cx| toolbar.add_item(buffer_search_bar, cx));
pane pane
@ -123,7 +129,7 @@ impl TerminalPanel {
_subscriptions: subscriptions, _subscriptions: subscriptions,
}; };
let mut old_dock_position = this.position(cx); let mut old_dock_position = this.position(cx);
cx.observe_global::<SettingsStore, _>(move |this, cx| { cx.observe_global::<SettingsStore>(move |this, cx| {
let new_dock_position = this.position(cx); let new_dock_position = this.position(cx);
if new_dock_position != old_dock_position { if new_dock_position != old_dock_position {
old_dock_position = new_dock_position; old_dock_position = new_dock_position;
@ -134,13 +140,10 @@ impl TerminalPanel {
this this
} }
pub fn load( pub fn load(workspace: WeakView<Workspace>, cx: AsyncAppContext) -> Task<Result<View<Self>>> {
workspace: WeakViewHandle<Workspace>,
cx: AsyncAppContext,
) -> Task<Result<ViewHandle<Self>>> {
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
let serialized_panel = if let Some(panel) = cx let serialized_panel = if let Some(panel) = cx
.background() .background_executor()
.spawn(async move { KEY_VALUE_STORE.read_kvp(TERMINAL_PANEL_KEY) }) .spawn(async move { KEY_VALUE_STORE.read_kvp(TERMINAL_PANEL_KEY) })
.await .await
.log_err() .log_err()
@ -151,7 +154,7 @@ impl TerminalPanel {
None None
}; };
let (panel, pane, items) = workspace.update(&mut cx, |workspace, cx| { let (panel, pane, items) = workspace.update(&mut cx, |workspace, cx| {
let panel = cx.add_view(|cx| TerminalPanel::new(workspace, cx)); let panel = cx.build_view(|cx| TerminalPanel::new(workspace, cx));
let items = if let Some(serialized_panel) = serialized_panel.as_ref() { let items = if let Some(serialized_panel) = serialized_panel.as_ref() {
panel.update(cx, |panel, cx| { panel.update(cx, |panel, cx| {
cx.notify(); cx.notify();
@ -189,7 +192,7 @@ impl TerminalPanel {
let mut active_ix = None; let mut active_ix = None;
for item in items { for item in items {
if let Some(item) = item.log_err() { if let Some(item) = item.log_err() {
let item_id = item.id(); let item_id = item.entity_id().as_u64();
pane.add_item(Box::new(item), false, false, None, cx); pane.add_item(Box::new(item), false, false, None, cx);
if Some(item_id) == active_item_id { if Some(item_id) == active_item_id {
active_ix = Some(pane.items_len() - 1); active_ix = Some(pane.items_len() - 1);
@ -208,7 +211,7 @@ impl TerminalPanel {
fn handle_pane_event( fn handle_pane_event(
&mut self, &mut self,
_pane: ViewHandle<Pane>, _pane: View<Pane>,
event: &pane::Event, event: &pane::Event,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
@ -221,7 +224,7 @@ impl TerminalPanel {
pane::Event::Focus => cx.emit(Event::Focus), pane::Event::Focus => cx.emit(Event::Focus),
pane::Event::AddItem { item } => { pane::Event::AddItem { item } => {
if let Some(workspace) = self.workspace.upgrade(cx) { if let Some(workspace) = self.workspace.upgrade() {
let pane = self.pane.clone(); let pane = self.pane.clone();
workspace.update(cx, |workspace, cx| item.added_to_pane(workspace, pane, cx)) workspace.update(cx, |workspace, cx| item.added_to_pane(workspace, pane, cx))
} }
@ -261,24 +264,23 @@ impl TerminalPanel {
fn add_terminal(&mut self, working_directory: Option<PathBuf>, cx: &mut ViewContext<Self>) { fn add_terminal(&mut self, working_directory: Option<PathBuf>, cx: &mut ViewContext<Self>) {
let workspace = self.workspace.clone(); let workspace = self.workspace.clone();
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
let pane = this.read_with(&cx, |this, _| this.pane.clone())?; let pane = this.update(&mut cx, |this, _| this.pane.clone())?;
workspace.update(&mut cx, |workspace, cx| { workspace.update(&mut cx, |workspace, cx| {
let working_directory = if let Some(working_directory) = working_directory { let working_directory = if let Some(working_directory) = working_directory {
Some(working_directory) Some(working_directory)
} else { } else {
let working_directory_strategy = settings::get::<TerminalSettings>(cx) let working_directory_strategy =
.working_directory TerminalSettings::get_global(cx).working_directory.clone();
.clone();
crate::get_working_directory(workspace, cx, working_directory_strategy) crate::get_working_directory(workspace, cx, working_directory_strategy)
}; };
let window = cx.window(); let window = cx.window_handle();
if let Some(terminal) = workspace.project().update(cx, |project, cx| { if let Some(terminal) = workspace.project().update(cx, |project, cx| {
project project
.create_terminal(working_directory, window, cx) .create_terminal(working_directory, window, cx)
.log_err() .log_err()
}) { }) {
let terminal = Box::new(cx.add_view(|cx| { let terminal = Box::new(cx.build_view(|cx| {
TerminalView::new( TerminalView::new(
terminal, terminal,
workspace.weak_handle(), workspace.weak_handle(),
@ -287,7 +289,7 @@ impl TerminalPanel {
) )
})); }));
pane.update(cx, |pane, cx| { pane.update(cx, |pane, cx| {
let focus = pane.has_focus(); let focus = pane.has_focus(cx);
pane.add_item(terminal, true, focus, None, cx); pane.add_item(terminal, true, focus, None, cx);
}); });
} }
@ -303,12 +305,16 @@ impl TerminalPanel {
.pane .pane
.read(cx) .read(cx)
.items() .items()
.map(|item| item.id()) .map(|item| item.id().as_u64())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let active_item_id = self.pane.read(cx).active_item().map(|item| item.id()); let active_item_id = self
.pane
.read(cx)
.active_item()
.map(|item| item.id().as_u64());
let height = self.height; let height = self.height;
let width = self.width; let width = self.width;
self.pending_serialization = cx.background().spawn( self.pending_serialization = cx.background_executor().spawn(
async move { async move {
KEY_VALUE_STORE KEY_VALUE_STORE
.write_kvp( .write_kvp(
@ -328,29 +334,25 @@ impl TerminalPanel {
} }
} }
impl Entity for TerminalPanel { impl EventEmitter<Event> for TerminalPanel {}
type Event = Event; impl EventEmitter<PanelEvent> for TerminalPanel {}
}
impl View for TerminalPanel {
fn ui_name() -> &'static str {
"TerminalPanel"
}
impl Render for TerminalPanel {
fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::AnyElement<Self> { fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::AnyElement<Self> {
ChildView::new(&self.pane, cx).into_any() ChildView::new(&self.pane, cx).into_any()
} }
fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext<Self>) { // todo!()
if cx.is_self_focused() { // fn focus_in(&mut self, _: gpui::AnyView, cx: &mut ViewContext<Self>) {
cx.focus(&self.pane); // if cx.is_self_focused() {
} // cx.focus(&self.pane);
} // }
// }
} }
impl Panel for TerminalPanel { impl Panel for TerminalPanel {
fn position(&self, cx: &WindowContext) -> DockPosition { fn position(&self, cx: &WindowContext) -> DockPosition {
match settings::get::<TerminalSettings>(cx).dock { match TerminalSettings::get_global(cx).dock {
TerminalDockPosition::Left => DockPosition::Left, TerminalDockPosition::Left => DockPosition::Left,
TerminalDockPosition::Bottom => DockPosition::Bottom, TerminalDockPosition::Bottom => DockPosition::Bottom,
TerminalDockPosition::Right => DockPosition::Right, TerminalDockPosition::Right => DockPosition::Right,
@ -373,7 +375,7 @@ impl Panel for TerminalPanel {
} }
fn size(&self, cx: &WindowContext) -> f32 { fn size(&self, cx: &WindowContext) -> f32 {
let settings = settings::get::<TerminalSettings>(cx); let settings = TerminalSettings::get_global(cx);
match self.position(cx) { match self.position(cx) {
DockPosition::Left | DockPosition::Right => { DockPosition::Left | DockPosition::Right => {
self.width.unwrap_or_else(|| settings.default_width) self.width.unwrap_or_else(|| settings.default_width)
@ -391,14 +393,6 @@ impl Panel for TerminalPanel {
cx.notify(); cx.notify();
} }
fn should_zoom_in_on_event(event: &Event) -> bool {
matches!(event, Event::ZoomIn)
}
fn should_zoom_out_on_event(event: &Event) -> bool {
matches!(event, Event::ZoomOut)
}
fn is_zoomed(&self, cx: &WindowContext) -> bool { fn is_zoomed(&self, cx: &WindowContext) -> bool {
self.pane.read(cx).is_zoomed() self.pane.read(cx).is_zoomed()
} }
@ -430,31 +424,44 @@ impl Panel for TerminalPanel {
} }
} }
fn should_change_position_on_event(event: &Self::Event) -> bool {
matches!(event, Event::DockPositionChanged)
}
fn should_activate_on_event(_: &Self::Event) -> bool {
false
}
fn should_close_on_event(event: &Event) -> bool {
matches!(event, Event::Close)
}
fn has_focus(&self, cx: &WindowContext) -> bool { fn has_focus(&self, cx: &WindowContext) -> bool {
self.pane.read(cx).has_focus() self.pane.read(cx).has_focus(cx)
} }
fn is_focus_event(event: &Self::Event) -> bool { fn persistent_name(&self) -> &'static str {
matches!(event, Event::Focus) todo!()
} }
// todo!() is it needed?
// fn should_change_position_on_event(event: &Self::Event) -> bool {
// matches!(event, Event::DockPositionChanged)
// }
// fn should_activate_on_event(_: &Self::Event) -> bool {
// false
// }
// fn should_close_on_event(event: &Event) -> bool {
// matches!(event, Event::Close)
// }
// fn is_focus_event(event: &Self::Event) -> bool {
// matches!(event, Event::Focus)
// }
// fn should_zoom_in_on_event(event: &Event) -> bool {
// matches!(event, Event::ZoomIn)
// }
// fn should_zoom_out_on_event(event: &Event) -> bool {
// matches!(event, Event::ZoomOut)
// }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct SerializedTerminalPanel { struct SerializedTerminalPanel {
items: Vec<usize>, items: Vec<u64>,
active_item_id: Option<usize>, active_item_id: Option<u64>,
width: Option<f32>, width: Option<f32>,
height: Option<f32>, height: Option<f32>,
} }

View File

@ -10,10 +10,11 @@ use anyhow::Context;
use dirs::home_dir; use dirs::home_dir;
use editor::{scroll::autoscroll::Autoscroll, Editor}; use editor::{scroll::autoscroll::Autoscroll, Editor};
use gpui::{ use gpui::{
actions, div, img, red, register_action, AnyElement, AppContext, Component, Div, EventEmitter, actions, div, img, red, register_action, AnyElement, AppContext, Component, DispatchPhase, Div,
FocusEvent, FocusHandle, Focusable, FocusableKeyDispatch, InputHandler, KeyDownEvent, EventEmitter, FocusEvent, FocusHandle, Focusable, FocusableKeyDispatch, InputHandler,
Keystroke, Model, ParentElement, Pixels, Render, StatefulInteractivity, StatelessInteractive, KeyDownEvent, Keystroke, Model, ParentElement, Pixels, Render, SharedString,
Styled, Task, View, ViewContext, VisualContext, WeakView, StatefulInteractivity, StatelessInteractive, Styled, Task, View, ViewContext, VisualContext,
WeakView,
}; };
use language::Bias; use language::Bias;
use project::{search::SearchQuery, LocalWorktree, Project}; use project::{search::SearchQuery, LocalWorktree, Project};
@ -21,7 +22,6 @@ use serde::Deserialize;
use settings::Settings; use settings::Settings;
use smol::Timer; use smol::Timer;
use std::{ use std::{
borrow::Cow,
ops::RangeInclusive, ops::RangeInclusive,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
@ -40,7 +40,7 @@ use workspace::{
item::{BreadcrumbText, Item, ItemEvent}, item::{BreadcrumbText, Item, ItemEvent},
notifications::NotifyResultExt, notifications::NotifyResultExt,
register_deserializable_item, register_deserializable_item,
searchable::{SearchEvent, SearchOptions, SearchableItem, SearchableItemHandle}, searchable::{SearchEvent, SearchOptions, SearchableItem},
NewCenterTerminal, Pane, ToolbarItemLocation, Workspace, WorkspaceId, NewCenterTerminal, Pane, ToolbarItemLocation, Workspace, WorkspaceId,
}; };
@ -51,11 +51,11 @@ const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
pub struct ScrollTerminal(pub i32); pub struct ScrollTerminal(pub i32);
#[register_action] #[register_action]
#[derive(Clone, Default, Deserialize, PartialEq)] #[derive(Clone, Debug, Default, Deserialize, PartialEq)]
pub struct SendText(String); pub struct SendText(String);
#[register_action] #[register_action]
#[derive(Clone, Default, Deserialize, PartialEq)] #[derive(Clone, Debug, Default, Deserialize, PartialEq)]
pub struct SendKeystroke(String); pub struct SendKeystroke(String);
actions!(Clear, Copy, Paste, ShowCharacterPalette, SearchTest); actions!(Clear, Copy, Paste, ShowCharacterPalette, SearchTest);
@ -260,7 +260,7 @@ impl TerminalView {
has_bell: false, has_bell: false,
focus_handle: cx.focus_handle(), focus_handle: cx.focus_handle(),
// todo!() // todo!()
// context_menu: cx.add_view(|cx| ContextMenu::new(view_id, cx)), // context_menu: cx.build_view(|cx| ContextMenu::new(view_id, cx)),
blink_state: true, blink_state: true,
blinking_on: false, blinking_on: false,
blinking_paused: false, blinking_paused: false,
@ -493,7 +493,12 @@ pub fn regex_search_for_query(query: &project::search::SearchQuery) -> Option<Re
} }
impl TerminalView { impl TerminalView {
fn key_down(&mut self, event: &KeyDownEvent, cx: &mut ViewContext<Self>) -> bool { fn key_down(
&mut self,
event: &KeyDownEvent,
_dispatch_phase: DispatchPhase,
cx: &mut ViewContext<Self>,
) {
self.clear_bel(cx); self.clear_bel(cx);
self.pause_cursor_blinking(cx); self.pause_cursor_blinking(cx);
@ -502,7 +507,7 @@ impl TerminalView {
&event.keystroke, &event.keystroke,
TerminalSettings::get_global(cx).option_as_meta, TerminalSettings::get_global(cx).option_as_meta,
) )
}) });
} }
fn focus_in(&mut self, event: &FocusEvent, cx: &mut ViewContext<Self>) { fn focus_in(&mut self, event: &FocusEvent, cx: &mut ViewContext<Self>) {
@ -652,7 +657,10 @@ impl InputHandler for TerminalView {
todo!() todo!()
} }
fn selected_text_range(&self, cx: &AppContext) -> Option<std::ops::Range<usize>> { fn selected_text_range(
&mut self,
cx: &mut ViewContext<Self>,
) -> Option<std::ops::Range<usize>> {
if self if self
.terminal .terminal
.read(cx) .read(cx)
@ -706,7 +714,7 @@ impl InputHandler for TerminalView {
} }
impl Item for TerminalView { impl Item for TerminalView {
fn tab_tooltip_text(&self, cx: &AppContext) -> Option<Cow<str>> { fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString> {
Some(self.terminal().read(cx).title().into()) Some(self.terminal().read(cx).title().into())
} }
@ -727,7 +735,7 @@ impl Item for TerminalView {
&self, &self,
_workspace_id: WorkspaceId, _workspace_id: WorkspaceId,
_cx: &mut ViewContext<Self>, _cx: &mut ViewContext<Self>,
) -> Option<Self> { ) -> Option<View<Self>> {
//From what I can tell, there's no way to tell the current working //From what I can tell, there's no way to tell the current working
//Directory of the terminal from outside the shell. There might be //Directory of the terminal from outside the shell. There might be
//solutions to this, but they are non-trivial and require more IPC //solutions to this, but they are non-trivial and require more IPC
@ -789,7 +797,7 @@ impl Item for TerminalView {
// cx.read(|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(cx) // .upgrade()
// .map(|workspace| { // .map(|workspace| {
// get_working_directory(workspace.read(cx), cx, strategy) // get_working_directory(workspace.read(cx), cx, strategy)
// }) // })
@ -817,6 +825,10 @@ impl Item for TerminalView {
// .detach(); // .detach();
self.workspace_id = workspace.database_id(); self.workspace_id = workspace.database_id();
} }
fn focus_handle(&self) -> FocusHandle {
self.focus_handle.clone()
}
} }
impl SearchableItem for TerminalView { impl SearchableItem for TerminalView {
@ -1098,7 +1110,8 @@ mod tests {
let project = Project::test(params.fs.clone(), [], cx).await; let project = Project::test(params.fs.clone(), [], cx).await;
let workspace = cx let workspace = cx
.add_window(|cx| Workspace::test_new(project.clone(), cx)) .add_window(|cx| Workspace::test_new(project.clone(), cx))
.root_view(cx); .root_view(cx)
.unwrap();
(project, workspace) (project, workspace)
} }

View File

@ -179,7 +179,7 @@ pub struct Pane {
workspace: WeakView<Workspace>, workspace: WeakView<Workspace>,
project: Model<Project>, project: Model<Project>,
// can_drop: Rc<dyn Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool>, // can_drop: Rc<dyn Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool>,
// can_split: bool, can_split: bool,
// render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement<Pane>>, // render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement<Pane>>,
} }
@ -347,7 +347,7 @@ impl Pane {
workspace, workspace,
project, project,
// can_drop: Rc::new(|_, _| true), // can_drop: Rc::new(|_, _| true),
// can_split: true, can_split: true,
// render_tab_bar_buttons: Rc::new(move |pane, cx| { // render_tab_bar_buttons: Rc::new(move |pane, cx| {
// Flex::row() // Flex::row()
// // New menu // // New menu
@ -427,17 +427,17 @@ impl Pane {
// self.can_drop = Rc::new(can_drop); // self.can_drop = Rc::new(can_drop);
// } // }
// pub fn set_can_split(&mut self, can_split: bool, cx: &mut ViewContext<Self>) { pub fn set_can_split(&mut self, can_split: bool, cx: &mut ViewContext<Self>) {
// self.can_split = can_split; self.can_split = can_split;
// cx.notify(); cx.notify();
// } }
// pub fn set_can_navigate(&mut self, can_navigate: bool, cx: &mut ViewContext<Self>) { pub fn set_can_navigate(&mut self, can_navigate: bool, cx: &mut ViewContext<Self>) {
// self.toolbar.update(cx, |toolbar, cx| { self.toolbar.update(cx, |toolbar, cx| {
// toolbar.set_can_navigate(can_navigate, cx); toolbar.set_can_navigate(can_navigate, cx);
// }); });
// cx.notify(); cx.notify();
// } }
// pub fn set_render_tab_bar_buttons<F>(&mut self, cx: &mut ViewContext<Self>, render: F) // pub fn set_render_tab_bar_buttons<F>(&mut self, cx: &mut ViewContext<Self>, render: F)
// where // where

View File

@ -36,11 +36,12 @@ use futures::{
Future, FutureExt, StreamExt, Future, FutureExt, StreamExt,
}; };
use gpui::{ use gpui::{
actions, div, point, prelude::*, size, Action, AnyModel, AnyView, AnyWeakView, AppContext, actions, div, point, register_action, size, Action, AnyModel, AnyView, AnyWeakView, AppContext,
AsyncAppContext, AsyncWindowContext, Bounds, Div, Entity, EntityId, EventEmitter, FocusHandle, AsyncAppContext, AsyncWindowContext, Bounds, Div, Entity, EntityId, EventEmitter, FocusHandle,
FocusableView, GlobalPixels, KeyContext, Model, ModelContext, ParentComponent, Point, Render, FocusableView, GlobalPixels, KeyContext, Model, ModelContext, ParentElement, Point, Render,
Size, Styled, Subscription, Task, View, ViewContext, WeakView, WindowBounds, WindowContext, Size, StatefulInteractive, StatelessInteractive, StatelessInteractivity, Styled, Subscription,
WindowHandle, WindowOptions, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle,
WindowOptions,
}; };
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem}; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools; use itertools::Itertools;
@ -193,10 +194,11 @@ impl Clone for Toast {
} }
} }
// #[derive(Clone, Deserialize, PartialEq)] #[register_action]
// pub struct OpenTerminal { #[derive(Debug, Default, Clone, Deserialize, PartialEq)]
// pub working_directory: PathBuf, pub struct OpenTerminal {
// } pub working_directory: PathBuf,
}
// impl_actions!( // impl_actions!(
// workspace, // workspace,
@ -206,7 +208,6 @@ impl Clone for Toast {
// SwapPaneInDirection, // SwapPaneInDirection,
// NewFileInDirection, // NewFileInDirection,
// Toast, // Toast,
// OpenTerminal,
// SaveAll, // SaveAll,
// Save, // Save,
// CloseAllItemsAndPanes, // CloseAllItemsAndPanes,