Detailed changes
@@ -8986,6 +8986,7 @@ dependencies = [
"itertools 0.13.0",
"language",
"log",
+ "markdown",
"menu",
"ordered-float 2.10.1",
"paths",
@@ -9001,6 +9002,7 @@ dependencies = [
"smol",
"task",
"terminal_view",
+ "theme",
"ui",
"util",
"workspace",
@@ -76,9 +76,9 @@ use gpui::{
ClipboardItem, Context, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusOutEvent,
FocusableView, FontId, FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext,
ListSizingBehavior, Model, MouseButton, PaintQuad, ParentElement, Pixels, Render, SharedString,
- Size, StrikethroughStyle, Styled, StyledText, Subscription, Task, TextStyle, UTF16Selection,
- UnderlineStyle, UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext,
- WeakFocusHandle, WeakView, WindowContext,
+ Size, StrikethroughStyle, Styled, StyledText, Subscription, Task, TextStyle,
+ TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, View,
+ ViewContext, ViewInputHandler, VisualContext, WeakFocusHandle, WeakView, WindowContext,
};
use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState};
@@ -546,6 +546,7 @@ pub struct Editor {
ime_transaction: Option<TransactionId>,
active_diagnostics: Option<ActiveDiagnosticGroup>,
soft_wrap_mode_override: Option<language_settings::SoftWrap>,
+
project: Option<Model<Project>>,
semantics_provider: Option<Rc<dyn SemanticsProvider>>,
completion_provider: Option<Box<dyn CompletionProvider>>,
@@ -615,6 +616,7 @@ pub struct Editor {
pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
gutter_dimensions: GutterDimensions,
style: Option<EditorStyle>,
+ text_style_refinement: Option<TextStyleRefinement>,
next_editor_action_id: EditorActionId,
editor_actions: Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut ViewContext<Self>)>>>>,
use_autoclose: bool,
@@ -2062,6 +2064,7 @@ impl Editor {
next_scroll_position: NextScrollCursorCenterTopBottom::default(),
addons: HashMap::default(),
_scroll_cursor_center_top_bottom_task: Task::ready(()),
+ text_style_refinement: None,
};
this.tasks_update_task = Some(this.refresh_runnables(cx));
this._subscriptions.extend(project_subscriptions);
@@ -11180,7 +11183,12 @@ impl Editor {
cx.notify();
}
- pub fn set_style(&mut self, style: EditorStyle, cx: &mut ViewContext<Self>) {
+ pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
+ self.text_style_refinement = Some(style);
+ }
+
+ /// called by the Element so we know what style we were most recently rendered with.
+ pub(crate) fn set_style(&mut self, style: EditorStyle, cx: &mut ViewContext<Self>) {
let rem_size = cx.rem_size();
self.display_map.update(cx, |map, cx| {
map.set_font(
@@ -13676,7 +13684,7 @@ impl Render for Editor {
fn render<'a>(&mut self, cx: &mut ViewContext<'a, Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
- let text_style = match self.mode {
+ let mut text_style = match self.mode {
EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
color: cx.theme().colors().editor_foreground,
font_family: settings.ui_font.family.clone(),
@@ -13698,6 +13706,9 @@ impl Render for Editor {
..Default::default()
},
};
+ if let Some(text_style_refinement) = &self.text_style_refinement {
+ text_style.refine(text_style_refinement)
+ }
let background = match self.mode {
EditorMode::SingleLine { .. } => cx.theme().system().transparent,
@@ -119,6 +119,10 @@ impl Markdown {
this
}
+ pub fn source(&self) -> &str {
+ &self.source
+ }
+
pub fn append(&mut self, text: &str, cx: &ViewContext<Self>) {
self.source.push_str(text);
self.parse(cx);
@@ -137,10 +141,6 @@ impl Markdown {
self.parse(cx);
}
- pub fn source(&self) -> &str {
- &self.source
- }
-
pub fn parsed_markdown(&self) -> &ParsedMarkdown {
&self.parsed_markdown
}
@@ -24,6 +24,8 @@ fuzzy.workspace = true
gpui.workspace = true
itertools.workspace = true
log.workspace = true
+language.workspace = true
+markdown.workspace = true
menu.workspace = true
ordered-float.workspace = true
picker.workspace = true
@@ -37,6 +39,7 @@ settings.workspace = true
smol.workspace = true
task.workspace = true
terminal_view.workspace = true
+theme.workspace = true
ui.workspace = true
util.workspace = true
workspace.workspace = true
@@ -7,15 +7,18 @@ use futures::channel::oneshot;
use gpui::{
percentage, px, Animation, AnimationExt, AnyWindowHandle, AsyncAppContext, DismissEvent,
EventEmitter, FocusableView, ParentElement as _, Render, SemanticVersion, SharedString, Task,
- Transformation, View,
+ TextStyleRefinement, Transformation, View,
};
use gpui::{AppContext, Model};
+use language::CursorShape;
+use markdown::{Markdown, MarkdownStyle};
use release_channel::{AppVersion, ReleaseChannel};
use remote::{SshConnectionOptions, SshPlatform, SshRemoteClient};
use schemars::JsonSchema;
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,
@@ -102,7 +105,7 @@ pub struct SshPrompt {
connection_string: SharedString,
status_message: Option<SharedString>,
error_message: Option<SharedString>,
- prompt: Option<(SharedString, oneshot::Sender<Result<String>>)>,
+ prompt: Option<(View<Markdown>, oneshot::Sender<Result<String>>)>,
editor: View<Editor>,
}
@@ -132,14 +135,34 @@ impl SshPrompt {
tx: oneshot::Sender<Result<String>>,
cx: &mut ViewContext<Self>,
) {
+ let theme = ThemeSettings::get_global(cx);
+
+ let mut text_style = cx.text_style();
+ let refinement = TextStyleRefinement {
+ font_family: Some(theme.buffer_font.family.clone()),
+ font_size: Some(theme.buffer_font_size.into()),
+ color: Some(cx.theme().colors().editor_foreground),
+ background_color: Some(gpui::transparent_black()),
+ ..Default::default()
+ };
+
+ text_style.refine(&refinement);
self.editor.update(cx, |editor, cx| {
if prompt.contains("yes/no") {
editor.set_masked(false, cx);
} else {
editor.set_masked(true, cx);
}
+ editor.set_text_style_refinement(refinement);
+ editor.set_cursor_shape(CursorShape::Block, cx);
});
- self.prompt = Some((prompt.into(), tx));
+ let markdown_style = MarkdownStyle {
+ base_text_style: text_style,
+ selection_background_color: cx.theme().players().local().selection,
+ ..Default::default()
+ };
+ let markdown = cx.new_view(|cx| Markdown::new_text(prompt, markdown_style, None, cx, None));
+ self.prompt = Some((markdown, tx));
self.status_message.take();
cx.focus_view(&self.editor);
cx.notify();
@@ -157,6 +180,7 @@ impl SshPrompt {
pub fn confirm(&mut self, cx: &mut ViewContext<Self>) {
if let Some((_, tx)) = self.prompt.take() {
+ self.status_message = Some("Connecting".into());
self.editor.update(cx, |editor, cx| {
tx.send(Ok(editor.text(cx))).ok();
editor.clear(cx);
@@ -172,60 +196,73 @@ impl Render for SshPrompt {
v_flex()
.key_context("PasswordPrompt")
.size_full()
- .child(
- h_flex()
- .p_2()
- .flex()
- .child(if self.error_message.is_some() {
- Icon::new(IconName::XCircle)
- .size(IconSize::Medium)
- .color(Color::Error)
- .into_any_element()
- } else {
- Icon::new(IconName::ArrowCircle)
- .size(IconSize::Medium)
- .with_animation(
- "arrow-circle",
- Animation::new(Duration::from_secs(2)).repeat(),
- |icon, delta| {
- icon.transform(Transformation::rotate(percentage(delta)))
- },
- )
- .into_any_element()
- })
- .child(
- div()
- .ml_1()
- .text_ellipsis()
- .overflow_x_hidden()
- .when_some(self.error_message.as_ref(), |el, error| {
- el.child(Label::new(format!("{}", error)).size(LabelSize::Small))
- })
- .when(
- self.error_message.is_none() && self.status_message.is_some(),
- |el| {
- el.child(
- Label::new(format!(
- "{}…",
- self.status_message.clone().unwrap()
- ))
- .size(LabelSize::Small),
+ .when(
+ self.error_message.is_some() || self.status_message.is_some(),
+ |el| {
+ el.child(
+ h_flex()
+ .p_2()
+ .flex()
+ .child(if self.error_message.is_some() {
+ Icon::new(IconName::XCircle)
+ .size(IconSize::Medium)
+ .color(Color::Error)
+ .into_any_element()
+ } else {
+ Icon::new(IconName::ArrowCircle)
+ .size(IconSize::Medium)
+ .with_animation(
+ "arrow-circle",
+ Animation::new(Duration::from_secs(2)).repeat(),
+ |icon, delta| {
+ icon.transform(Transformation::rotate(percentage(
+ delta,
+ )))
+ },
)
- },
+ .into_any_element()
+ })
+ .child(
+ div()
+ .ml_1()
+ .text_ellipsis()
+ .overflow_x_hidden()
+ .when_some(self.error_message.as_ref(), |el, error| {
+ el.child(
+ Label::new(format!("{}", error)).size(LabelSize::Small),
+ )
+ })
+ .when(
+ self.error_message.is_none()
+ && self.status_message.is_some(),
+ |el| {
+ el.child(
+ Label::new(format!(
+ "{}…",
+ self.status_message.clone().unwrap()
+ ))
+ .size(LabelSize::Small),
+ )
+ },
+ ),
),
- ),
+ )
+ },
)
- .child(div().when_some(self.prompt.as_ref(), |el, prompt| {
+ .when_some(self.prompt.as_ref(), |el, prompt| {
el.child(
- h_flex()
+ div()
+ .size_full()
+ .overflow_hidden()
.p_4()
.border_t_1()
.border_color(theme.colors().border_variant)
.font_buffer(cx)
- .child(Label::new(prompt.0.clone()))
+ .text_buffer(cx)
+ .child(prompt.0.clone())
.child(self.editor.clone()),
)
- }))
+ })
}
}
@@ -1202,7 +1202,7 @@ impl SshRemoteConnection {
use smol::{fs::unix::PermissionsExt as _, net::unix::UnixListener};
use util::ResultExt as _;
- delegate.set_status(Some("connecting"), cx);
+ delegate.set_status(Some("Connecting"), cx);
let url = connection_options.ssh_url();
let temp_dir = tempfile::Builder::new()
@@ -79,7 +79,7 @@ pub trait StyledTypography: Styled + Sized {
///
/// This should only be used for text that is displayed in a buffer,
/// or other places that text needs to match the user's buffer font size.
- fn text_buffer(self, cx: &mut WindowContext) -> Self {
+ fn text_buffer(self, cx: &WindowContext) -> Self {
let settings = ThemeSettings::get_global(cx);
self.text_size(settings.buffer_font_size(cx))
}