@@ -18,8 +18,8 @@ use gpui::ClipboardItem;
use gpui::Task;
use gpui::WeakView;
use gpui::{
- AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, FontWeight,
- Model, PromptLevel, ScrollHandle, View, ViewContext,
+ AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, Model,
+ PromptLevel, ScrollHandle, View, ViewContext,
};
use picker::Picker;
use project::terminals::wrap_for_ssh;
@@ -33,10 +33,10 @@ use task::HideStrategy;
use task::RevealStrategy;
use task::SpawnInTerminal;
use terminal_view::terminal_panel::TerminalPanel;
-use ui::Scrollbar;
-use ui::ScrollbarState;
-use ui::Section;
-use ui::{prelude::*, IconButtonShape, List, ListItem, ListSeparator, Modal, ModalHeader, Tooltip};
+use ui::{
+ prelude::*, IconButtonShape, List, ListItem, ListSeparator, Modal, ModalHeader, Scrollbar,
+ ScrollbarState, Section, Tooltip,
+};
use util::ResultExt;
use workspace::notifications::NotificationId;
use workspace::OpenOptions;
@@ -316,7 +316,12 @@ impl gpui::Render for ProjectPicker {
}
.render(cx),
)
- .child(self.picker.clone())
+ .child(
+ div()
+ .border_t_1()
+ .border_color(cx.theme().colors().border_variant)
+ .child(self.picker.clone()),
+ )
}
}
enum Mode {
@@ -366,18 +371,34 @@ impl RemoteServerProjects {
}
}
+ fn scroll_to_selected(&self, _: &mut ViewContext<Self>) {
+ if let Mode::Default(scroll_state) = &self.mode {
+ if let ui::ScrollableHandle::NonUniform(scroll_handle) = scroll_state.scroll_handle() {
+ if let Some(active_item) = self.selectable_items.active_item {
+ scroll_handle.scroll_to_item(active_item);
+ }
+ }
+ }
+ }
+
fn next_item(&mut self, _: &menu::SelectNext, cx: &mut ViewContext<Self>) {
if !matches!(self.mode, Mode::Default(_) | Mode::ViewServerOptions(_, _)) {
return;
}
self.selectable_items.next(cx);
+ cx.notify();
+ self.scroll_to_selected(cx);
}
+
fn prev_item(&mut self, _: &menu::SelectPrev, cx: &mut ViewContext<Self>) {
if !matches!(self.mode, Mode::Default(_) | Mode::ViewServerOptions(_, _)) {
return;
}
self.selectable_items.prev(cx);
+ cx.notify();
+ self.scroll_to_selected(cx);
}
+
pub fn project_picker(
ix: usize,
connection_options: remote::SshConnectionOptions,
@@ -654,7 +675,6 @@ impl RemoteServerProjects {
.child(
Label::new(main_label)
.size(LabelSize::Small)
- .weight(FontWeight::SEMIBOLD)
.color(Color::Muted),
)
.children(
@@ -951,7 +971,8 @@ impl RemoteServerProjects {
)
.child(
v_flex()
- .py_1()
+ .pb_1()
+ .child(ListSeparator)
.child({
self.selectable_items.add_item(Box::new({
move |this, cx| {
@@ -1135,7 +1156,13 @@ impl RemoteServerProjects {
}
.render(cx),
)
- .child(h_flex().p_2().child(state.editor.clone()))
+ .child(
+ h_flex()
+ .p_2()
+ .border_t_1()
+ .border_color(cx.theme().colors().border_variant)
+ .child(state.editor.clone()),
+ )
}
fn render_default(
@@ -1178,26 +1205,21 @@ impl RemoteServerProjects {
.size_full()
.child(connect_button)
.child(
- h_flex().child(
- List::new()
- .empty_message(
- v_flex()
- .child(ListSeparator)
- .child(
- div().px_3().child(
- Label::new("No remote servers registered yet.")
- .color(Color::Muted),
- ),
- )
- .into_any_element(),
- )
- .children(ssh_connections.iter().cloned().enumerate().map(
- |(ix, connection)| {
- self.render_ssh_connection(ix, connection, cx)
- .into_any_element()
- },
- )),
- ),
+ List::new()
+ .empty_message(
+ v_flex()
+ // .child(ListSeparator)
+ .child(div().px_3().child(
+ Label::new("No remote servers registered yet.").color(Color::Muted),
+ ))
+ .into_any_element(),
+ )
+ .children(ssh_connections.iter().cloned().enumerate().map(
+ |(ix, connection)| {
+ self.render_ssh_connection(ix, connection, cx)
+ .into_any_element()
+ },
+ )),
)
.into_any_element();
@@ -1208,36 +1230,38 @@ impl RemoteServerProjects {
)
.section(
Section::new().padded(false).child(
- h_flex()
+ v_flex()
.min_h(rems(20.))
+ .group("remote-projects-section")
.size_full()
+ .relative()
+ .child(ListSeparator)
.child(
- v_flex().size_full().child(ListSeparator).child(
- canvas(
- |bounds, cx| {
- modal_section.prepaint_as_root(
- bounds.origin,
- bounds.size.into(),
- cx,
- );
- modal_section
- },
- |_, mut modal_section, cx| {
- modal_section.paint(cx);
- },
- )
- .size_full(),
- ),
+ canvas(
+ |bounds, cx| {
+ modal_section.prepaint_as_root(
+ bounds.origin,
+ bounds.size.into(),
+ cx,
+ );
+ modal_section
+ },
+ |_, mut modal_section, cx| {
+ modal_section.paint(cx);
+ },
+ )
+ .size_full(),
)
.child(
div()
+ .visible_on_hover("remote-projects-section")
.occlude()
.h_full()
.absolute()
- .right_1()
.top_1()
.bottom_1()
- .w(px(12.))
+ .right_1()
+ .w(px(8.))
.children(Scrollbar::vertical(scroll_state)),
),
),
@@ -1268,6 +1292,7 @@ impl Render for RemoteServerProjects {
div()
.track_focus(&self.focus_handle)
.elevation_3(cx)
+ .w(rems(34.))
.key_context("RemoteServerModal")
.on_action(cx.listener(Self::cancel))
.on_action(cx.listener(Self::confirm))
@@ -1281,7 +1306,6 @@ impl Render for RemoteServerProjects {
cx.emit(DismissEvent)
}
}))
- .w(rems(34.))
.child(match &self.mode {
Mode::Default(state) => self.render_default(state.clone(), cx).into_any_element(),
Mode::ViewServerOptions(index, connection) => self
@@ -5,7 +5,7 @@ use auto_update::AutoUpdater;
use editor::Editor;
use futures::channel::oneshot;
use gpui::{
- percentage, px, Animation, AnimationExt, AnyWindowHandle, AsyncAppContext, DismissEvent,
+ percentage, Animation, AnimationExt, AnyWindowHandle, AsyncAppContext, DismissEvent,
EventEmitter, FocusableView, ParentElement as _, PromptLevel, Render, SemanticVersion,
SharedString, Task, TextStyleRefinement, Transformation, View,
};
@@ -20,9 +20,8 @@ use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
use theme::ThemeSettings;
use ui::{
- div, h_flex, prelude::*, v_flex, ActiveTheme, Color, Icon, IconName, IconSize,
- InteractiveElement, IntoElement, Label, LabelCommon, Styled, ViewContext, VisualContext,
- WindowContext,
+ prelude::*, ActiveTheme, Color, Icon, IconName, IconSize, InteractiveElement, IntoElement,
+ Label, LabelCommon, Styled, ViewContext, VisualContext, WindowContext,
};
use workspace::{AppState, ModalView, Workspace};
@@ -52,6 +51,7 @@ impl SshSettings {
})
.next()
}
+
pub fn nickname_for(
&self,
host: &str,
@@ -86,6 +86,7 @@ pub struct SshConnection {
#[serde(default)]
pub args: Vec<String>,
}
+
impl From<SshConnection> for SshConnectionOptions {
fn from(val: SshConnection) -> Self {
SshConnectionOptions {
@@ -205,15 +206,17 @@ impl SshPrompt {
impl Render for SshPrompt {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let cx = cx.window_context();
- let theme = cx.theme();
+
v_flex()
.key_context("PasswordPrompt")
+ .py_2()
+ .px_3()
.size_full()
+ .text_buffer(cx)
.when_some(self.status_message.clone(), |el, status_message| {
el.child(
h_flex()
- .p_2()
- .flex()
+ .gap_1()
.child(
Icon::new(IconName::ArrowCircle)
.size(IconSize::Medium)
@@ -225,9 +228,12 @@ impl Render for SshPrompt {
},
),
)
- .child(div().ml_1().text_ellipsis().overflow_x_hidden().child(
- Label::new(format!("{}…", status_message)).size(LabelSize::Small),
- )),
+ .child(
+ div()
+ .text_ellipsis()
+ .overflow_x_hidden()
+ .child(format!("{}…", status_message)),
+ ),
)
})
.when_some(self.prompt.as_ref(), |el, prompt| {
@@ -235,11 +241,6 @@ impl Render for SshPrompt {
div()
.size_full()
.overflow_hidden()
- .p_4()
- .border_t_1()
- .border_color(theme.colors().border_variant)
- .font_buffer(cx)
- .text_buffer(cx)
.child(prompt.0.clone())
.child(self.editor.clone()),
)
@@ -292,29 +293,18 @@ impl RenderOnce for SshConnectionHeader {
};
h_flex()
- .p_1()
+ .px(Spacing::XLarge.rems(cx))
+ .pt(Spacing::Large.rems(cx))
+ .pb(Spacing::Small.rems(cx))
.rounded_t_md()
.w_full()
- .gap_2()
- .justify_center()
- .border_b_1()
- .border_color(theme.colors().border_variant)
- .bg(header_color)
+ .gap_1p5()
.child(Icon::new(IconName::Server).size(IconSize::XSmall))
.child(
h_flex()
.gap_1()
- .child(
- Label::new(main_label)
- .size(ui::LabelSize::Small)
- .single_line(),
- )
- .children(meta_label.map(|label| {
- Label::new(label)
- .size(ui::LabelSize::Small)
- .single_line()
- .color(Color::Muted)
- })),
+ .child(Headline::new(main_label).size(HeadlineSize::XSmall))
+ .children(meta_label.map(|label| Label::new(label).color(Color::Muted))),
)
}
}
@@ -323,18 +313,18 @@ impl Render for SshConnectionModal {
fn render(&mut self, cx: &mut ui::ViewContext<Self>) -> impl ui::IntoElement {
let nickname = self.prompt.read(cx).nickname.clone();
let connection_string = self.prompt.read(cx).connection_string.clone();
- let theme = cx.theme();
+ let theme = cx.theme().clone();
let body_color = theme.colors().editor_background;
v_flex()
.elevation_3(cx)
+ .w(rems(34.))
+ .border_1()
+ .border_color(theme.colors().border)
.track_focus(&self.focus_handle(cx))
.on_action(cx.listener(Self::dismiss))
.on_action(cx.listener(Self::confirm))
- .w(px(500.))
- .border_1()
- .border_color(theme.colors().border)
.child(
SshConnectionHeader {
connection_string,
@@ -343,10 +333,12 @@ impl Render for SshConnectionModal {
.render(cx),
)
.child(
- h_flex()
- .rounded_b_md()
- .bg(body_color)
+ div()
.w_full()
+ .rounded_b_lg()
+ .bg(body_color)
+ .border_t_1()
+ .border_color(theme.colors().border_variant)
.child(self.prompt.clone()),
)
}