Merge branch 'main' into fix/windows-ctrl-slash
This commit is contained in:
4 files changed
+148
-2
No files matched your search
@@ -136,6 +136,7 @@ impl ThemeAdvancedEditor {
|
||||
let ansi_pickers = (0..ANSI_COUNT)
|
||||
.map(|index| {
|
||||
new_color_picker(
|
||||
ThemeAdvancedField::Ansi(index),
|
||||
Some(definition.terminal.palette.get(index).unwrap_or([0, 0, 0])),
|
||||
ansi_inputs[index].clone(),
|
||||
window,
|
||||
@@ -145,6 +146,7 @@ impl ThemeAdvancedEditor {
|
||||
})
|
||||
.collect();
|
||||
let selection_background_picker = new_color_picker(
|
||||
ThemeAdvancedField::SelectionBackground,
|
||||
definition.terminal.selection_background,
|
||||
selection_background_input.clone(),
|
||||
window,
|
||||
@@ -152,6 +154,7 @@ impl ThemeAdvancedEditor {
|
||||
&mut picker_subscriptions,
|
||||
);
|
||||
let selection_foreground_picker = new_color_picker(
|
||||
ThemeAdvancedField::SelectionForeground,
|
||||
definition.terminal.selection_foreground,
|
||||
selection_foreground_input.clone(),
|
||||
window,
|
||||
@@ -159,6 +162,7 @@ impl ThemeAdvancedEditor {
|
||||
&mut picker_subscriptions,
|
||||
);
|
||||
let cursor_text_picker = new_color_picker(
|
||||
ThemeAdvancedField::CursorText,
|
||||
definition.terminal.cursor_text,
|
||||
cursor_text_input.clone(),
|
||||
window,
|
||||
@@ -211,6 +215,17 @@ impl ThemeAdvancedEditor {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(super) fn picker(&self, field: ThemeAdvancedField) -> Option<&Entity<ColorPickerState>> {
|
||||
match field {
|
||||
ThemeAdvancedField::Ansi(index) => self.ansi_pickers.get(index),
|
||||
ThemeAdvancedField::SelectionBackground => Some(&self.selection_background_picker),
|
||||
ThemeAdvancedField::SelectionForeground => Some(&self.selection_foreground_picker),
|
||||
ThemeAdvancedField::CursorText => Some(&self.cursor_text_picker),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace all control values after a template/reset/import operation.
|
||||
/// Invalid input errors belong to the old draft and therefore disappear.
|
||||
pub(super) fn sync_from_definition(
|
||||
@@ -557,6 +572,7 @@ impl ThemeAdvancedEditor {
|
||||
}
|
||||
|
||||
fn new_color_picker(
|
||||
field: ThemeAdvancedField,
|
||||
color: Option<Rgb8>,
|
||||
input: Entity<InputState>,
|
||||
window: &mut Window,
|
||||
@@ -590,6 +606,7 @@ fn new_color_picker(
|
||||
input.update(cx, |state, cx| {
|
||||
state.set_value(format_hex_rgb(rgb), window, cx);
|
||||
});
|
||||
this.on_theme_advanced_input(field, window, cx);
|
||||
},
|
||||
);
|
||||
subscriptions.push(subscription);
|
||||
|
||||
@@ -938,7 +938,7 @@ impl SettingsPane {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn on_theme_advanced_input(
|
||||
pub(super) fn on_theme_advanced_input(
|
||||
&mut self,
|
||||
field: ThemeAdvancedField,
|
||||
window: &mut Window,
|
||||
@@ -964,6 +964,14 @@ impl SettingsPane {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(super) fn theme_advanced_picker(
|
||||
&self,
|
||||
field: ThemeAdvancedField,
|
||||
) -> Option<Entity<gpui_component::color_picker::ColorPickerState>> {
|
||||
self.theme_editor.as_ref()?.advanced_editor.as_ref()?.picker(field).cloned()
|
||||
}
|
||||
|
||||
fn request_close_theme_editor(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if self.theme_editor.as_ref().is_some_and(|editor| editor.save_busy) {
|
||||
return;
|
||||
|
||||
@@ -21,6 +21,8 @@ impl SettingsPane {
|
||||
let foreground = theme_color(draft.terminal.foreground, 1.0);
|
||||
let accent = theme_color(resolved_ui.accent, 1.0);
|
||||
let cursor = theme_color(draft.terminal.cursor.unwrap_or(draft.terminal.foreground), 1.0);
|
||||
let cursor_text =
|
||||
theme_color(draft.terminal.cursor_text.unwrap_or(draft.terminal.background), 1.0);
|
||||
let selection_background = theme_color(
|
||||
draft
|
||||
.terminal
|
||||
@@ -233,7 +235,18 @@ impl SettingsPane {
|
||||
.gap(px(7.0))
|
||||
.items_center()
|
||||
.child(div().text_color(accent).child("❯"))
|
||||
.child(div().w(px(8.0)).h(px(font_size * line_height)).bg(cursor)),
|
||||
.child(
|
||||
div()
|
||||
.debug_selector(|| "theme-editor-preview-cursor".to_owned())
|
||||
.w(px(font_size * 0.78))
|
||||
.h(px(font_size * line_height))
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.bg(cursor)
|
||||
.text_color(cursor_text)
|
||||
.child("A"),
|
||||
),
|
||||
)
|
||||
.into_any_element(),
|
||||
};
|
||||
|
||||
@@ -483,6 +483,28 @@ fn editor_template(pane: &Entity<SettingsPane>, cx: &mut VisualTestContext) -> T
|
||||
pane.read_with(cx, |pane, _| pane.theme_editor.as_ref().expect("theme editor state").template)
|
||||
}
|
||||
|
||||
fn emit_advanced_picker_color(
|
||||
pane: &Entity<SettingsPane>,
|
||||
field: super::theme_advanced::ThemeAdvancedField,
|
||||
color: [u8; 3],
|
||||
cx: &mut VisualTestContext,
|
||||
) {
|
||||
let picker = pane
|
||||
.read_with(cx, |pane, _| pane.theme_advanced_picker(field).expect("advanced color picker"));
|
||||
picker.update(cx, |_, cx| {
|
||||
let [r, g, b] = color;
|
||||
let hsla: gpui::Hsla = gpui::Rgba {
|
||||
r: f32::from(r) / 255.0,
|
||||
g: f32::from(g) / 255.0,
|
||||
b: f32::from(b) / 255.0,
|
||||
a: 1.0,
|
||||
}
|
||||
.into();
|
||||
cx.emit(gpui_component::color_picker::ColorPickerEvent::Change(Some(hsla)));
|
||||
});
|
||||
draw(cx);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn theme_editor_opens_from_the_picker_with_common_fields_and_collapsed_advanced(
|
||||
cx: &mut TestAppContext,
|
||||
@@ -728,6 +750,92 @@ fn theme_editor_save_and_apply_persists_copy_and_reloads_its_foreground(cx: &mut
|
||||
assert_eq!(palette_foreground(&mut window), applied.color("terminal", "foreground").unwrap());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn advanced_selection_and_cursor_text_picker_colors_preview_persist_apply_and_reopen(
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
use super::theme_advanced::ThemeAdvancedField;
|
||||
|
||||
let _fixture_guard = lock_theme_studio();
|
||||
let _settings_guard = SettingsBytesGuard::capture();
|
||||
std::fs::write(nebula_settings::settings_path(), TEST_SETTINGS)
|
||||
.expect("write isolated advanced color settings");
|
||||
let mut theme_cleanup = CustomThemeCleanup::default();
|
||||
let (pane, mut window) = open_settings(cx);
|
||||
let before_library_ids = custom_theme_ids();
|
||||
let saved_name = format!("Advanced colors native test {}", std::process::id());
|
||||
let selection_background = [0x1b, 0x2c, 0x3d];
|
||||
let selection_foreground = [0xe1, 0xd2, 0xc3];
|
||||
let cursor_text = [0x12, 0xeb, 0x77];
|
||||
|
||||
open_theme_editor(&mut window);
|
||||
edit_input("theme-editor-name", &saved_name, &mut window);
|
||||
click("theme-editor-advanced-toggle", &mut window);
|
||||
assert!(window.debug_bounds("theme-editor-preview-cursor").is_some());
|
||||
|
||||
emit_advanced_picker_color(
|
||||
&pane,
|
||||
ThemeAdvancedField::SelectionBackground,
|
||||
selection_background,
|
||||
&mut window,
|
||||
);
|
||||
emit_advanced_picker_color(
|
||||
&pane,
|
||||
ThemeAdvancedField::SelectionForeground,
|
||||
selection_foreground,
|
||||
&mut window,
|
||||
);
|
||||
emit_advanced_picker_color(&pane, ThemeAdvancedField::CursorText, cursor_text, &mut window);
|
||||
|
||||
let draft = editor_draft(&pane, &mut window);
|
||||
assert_eq!(draft.terminal.selection_background, Some(selection_background));
|
||||
assert_eq!(draft.terminal.selection_foreground, Some(selection_foreground));
|
||||
assert_eq!(draft.terminal.cursor_text, Some(cursor_text));
|
||||
|
||||
click("theme-editor-save-apply", &mut window);
|
||||
assert!(window.debug_bounds("theme-editor-dialog").is_none());
|
||||
|
||||
let after_documents = custom_theme_documents();
|
||||
for document in &after_documents {
|
||||
if document.id().is_some_and(|id| !before_library_ids.iter().any(|before| before == id))
|
||||
&& document.name().starts_with(&saved_name)
|
||||
{
|
||||
theme_cleanup.track(document);
|
||||
}
|
||||
}
|
||||
let applied_id = RuntimeSettings::load().custom_theme.expect("advanced color theme is active");
|
||||
let applied = after_documents
|
||||
.iter()
|
||||
.find(|document| document.id() == Some(applied_id.as_str()))
|
||||
.expect("advanced color theme remains in the library");
|
||||
let applied_definition = applied.definition().expect("saved advanced color definition");
|
||||
assert_eq!(applied_definition.terminal.selection_background, Some(selection_background));
|
||||
assert_eq!(applied_definition.terminal.selection_foreground, Some(selection_foreground));
|
||||
assert_eq!(applied_definition.terminal.cursor_text, Some(cursor_text));
|
||||
|
||||
window.read(|cx| {
|
||||
let palette = &cx.global::<crate::gpui_shell::config::Settings>().palette;
|
||||
let bytes = |color: gpui::Rgba| {
|
||||
[
|
||||
(color.r * 255.0).round() as u8,
|
||||
(color.g * 255.0).round() as u8,
|
||||
(color.b * 255.0).round() as u8,
|
||||
]
|
||||
};
|
||||
assert_eq!(bytes(palette.selection), selection_background);
|
||||
assert_eq!(palette.selection_foreground.map(bytes), Some(selection_foreground));
|
||||
assert_eq!(palette.cursor_text.map(bytes), Some(cursor_text));
|
||||
});
|
||||
|
||||
click("open-theme-picker", &mut window);
|
||||
assert!(window.debug_bounds("appearance-picker-dialog").is_some());
|
||||
click("customize-theme", &mut window);
|
||||
let reopened = editor_draft(&pane, &mut window);
|
||||
assert_eq!(reopened.terminal.selection_background, Some(selection_background));
|
||||
assert_eq!(reopened.terminal.selection_foreground, Some(selection_foreground));
|
||||
assert_eq!(reopened.terminal.cursor_text, Some(cursor_text));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn invalid_color_stays_dirty_and_save_rejects_after_a_later_valid_edit(cx: &mut TestAppContext) {
|
||||
let _fixture_guard = lock_theme_studio();
|
||||
|
||||
Reference in new issue
Block a user