Merge branch 'main' into add-collab-tests
This commit is contained in:
commit
9b30f490c7
171 changed files with 50671 additions and 7748 deletions
|
@ -15,8 +15,8 @@ use futures::{
|
|||
TryStreamExt,
|
||||
};
|
||||
use gpui::{
|
||||
serde_json, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Model, SemanticVersion, Task,
|
||||
WeakModel,
|
||||
actions, serde_json, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Model,
|
||||
SemanticVersion, Task, WeakModel,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::RwLock;
|
||||
|
@ -70,14 +70,7 @@ pub const ZED_SECRET_CLIENT_TOKEN: &str = "618033988749894";
|
|||
pub const INITIAL_RECONNECTION_DELAY: Duration = Duration::from_millis(100);
|
||||
pub const CONNECTION_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
#[derive(Clone, Default, PartialEq, Deserialize)]
|
||||
pub struct SignIn;
|
||||
|
||||
#[derive(Clone, Default, PartialEq, Deserialize)]
|
||||
pub struct SignOut;
|
||||
|
||||
#[derive(Clone, Default, PartialEq, Deserialize)]
|
||||
pub struct Reconnect;
|
||||
actions!(SignIn, SignOut, Reconnect);
|
||||
|
||||
pub fn init_settings(cx: &mut AppContext) {
|
||||
TelemetrySettings::register(cx);
|
||||
|
@ -87,7 +80,6 @@ pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
|
|||
init_settings(cx);
|
||||
|
||||
let client = Arc::downgrade(client);
|
||||
cx.register_action_type::<SignIn>();
|
||||
cx.on_action({
|
||||
let client = client.clone();
|
||||
move |_: &SignIn, cx| {
|
||||
|
@ -100,7 +92,6 @@ pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
|
|||
}
|
||||
});
|
||||
|
||||
cx.register_action_type::<SignOut>();
|
||||
cx.on_action({
|
||||
let client = client.clone();
|
||||
move |_: &SignOut, cx| {
|
||||
|
@ -113,7 +104,6 @@ pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
|
|||
}
|
||||
});
|
||||
|
||||
cx.register_action_type::<Reconnect>();
|
||||
cx.on_action({
|
||||
let client = client.clone();
|
||||
move |_: &Reconnect, cx| {
|
||||
|
|
|
@ -7,8 +7,8 @@ use async_tar::Archive;
|
|||
use collections::{HashMap, HashSet};
|
||||
use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt};
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Model, ModelContext,
|
||||
Task, WeakModel,
|
||||
actions, AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Model,
|
||||
ModelContext, Task, WeakModel,
|
||||
};
|
||||
use language::{
|
||||
language_settings::{all_language_settings, language_settings},
|
||||
|
@ -34,19 +34,11 @@ use util::{
|
|||
|
||||
// todo!()
|
||||
// const COPILOT_AUTH_NAMESPACE: &'static str = "copilot_auth";
|
||||
// actions!(copilot_auth, [SignIn, SignOut]);
|
||||
actions!(SignIn, SignOut);
|
||||
|
||||
// todo!()
|
||||
// const COPILOT_NAMESPACE: &'static str = "copilot";
|
||||
// actions!(
|
||||
// copilot,
|
||||
// [Suggest, NextSuggestion, PreviousSuggestion, Reinstall]
|
||||
// );
|
||||
//
|
||||
pub struct Suggest;
|
||||
pub struct NextSuggestion;
|
||||
pub struct PreviousSuggestion;
|
||||
pub struct Reinstall;
|
||||
actions!(Suggest, NextSuggestion, PreviousSuggestion, Reinstall);
|
||||
|
||||
pub fn init(
|
||||
new_server_id: LanguageServerId,
|
||||
|
|
|
@ -31,7 +31,7 @@ drag_and_drop = { path = "../drag_and_drop" }
|
|||
collections = { path = "../collections" }
|
||||
# context_menu = { path = "../context_menu" }
|
||||
fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
|
||||
git = { path = "../git" }
|
||||
git = { package = "git3", path = "../git3" }
|
||||
gpui = { package = "gpui2", path = "../gpui2" }
|
||||
language = { package = "language2", path = "../language2" }
|
||||
lsp = { package = "lsp2", path = "../lsp2" }
|
||||
|
|
|
@ -4,6 +4,7 @@ mod inlay_map;
|
|||
mod tab_map;
|
||||
mod wrap_map;
|
||||
|
||||
use crate::EditorStyle;
|
||||
use crate::{
|
||||
link_go_to_definition::InlayHighlight, movement::TextLayoutDetails, Anchor, AnchorRangeExt,
|
||||
InlayId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
|
||||
|
@ -11,14 +12,18 @@ use crate::{
|
|||
pub use block_map::{BlockMap, BlockPoint};
|
||||
use collections::{BTreeMap, HashMap, HashSet};
|
||||
use fold_map::FoldMap;
|
||||
use gpui::{Font, FontId, HighlightStyle, Hsla, Line, Model, ModelContext, Pixels};
|
||||
use gpui::{
|
||||
Font, FontId, HighlightStyle, Hsla, Line, Model, ModelContext, Pixels, TextRun, UnderlineStyle,
|
||||
};
|
||||
use inlay_map::InlayMap;
|
||||
use language::{
|
||||
language_settings::language_settings, OffsetUtf16, Point, Subscription as BufferSubscription,
|
||||
};
|
||||
use lsp::DiagnosticSeverity;
|
||||
use std::{any::TypeId, borrow::Cow, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc};
|
||||
use sum_tree::{Bias, TreeMap};
|
||||
use tab_map::TabMap;
|
||||
use theme::{SyntaxTheme, Theme};
|
||||
use wrap_map::WrapMap;
|
||||
|
||||
pub use block_map::{
|
||||
|
@ -35,6 +40,8 @@ pub enum FoldStatus {
|
|||
Foldable,
|
||||
}
|
||||
|
||||
const UNNECESSARY_CODE_FADE: f32 = 0.3;
|
||||
|
||||
pub trait ToDisplayPoint {
|
||||
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint;
|
||||
}
|
||||
|
@ -496,63 +503,63 @@ impl DisplaySnapshot {
|
|||
)
|
||||
}
|
||||
|
||||
// pub fn highlighted_chunks<'a>(
|
||||
// &'a self,
|
||||
// display_rows: Range<u32>,
|
||||
// language_aware: bool,
|
||||
// style: &'a EditorStyle,
|
||||
// ) -> impl Iterator<Item = HighlightedChunk<'a>> {
|
||||
// self.chunks(
|
||||
// display_rows,
|
||||
// language_aware,
|
||||
// Some(style.theme.hint),
|
||||
// Some(style.theme.suggestion),
|
||||
// )
|
||||
// .map(|chunk| {
|
||||
// let mut highlight_style = chunk
|
||||
// .syntax_highlight_id
|
||||
// .and_then(|id| id.style(&style.syntax));
|
||||
pub fn highlighted_chunks<'a>(
|
||||
&'a self,
|
||||
display_rows: Range<u32>,
|
||||
language_aware: bool,
|
||||
editor_style: &'a EditorStyle,
|
||||
) -> impl Iterator<Item = HighlightedChunk<'a>> {
|
||||
self.chunks(
|
||||
display_rows,
|
||||
language_aware,
|
||||
Some(editor_style.syntax.inlay_style),
|
||||
Some(editor_style.syntax.suggestion_style),
|
||||
)
|
||||
.map(|chunk| {
|
||||
let mut highlight_style = chunk
|
||||
.syntax_highlight_id
|
||||
.and_then(|id| id.style(&editor_style.syntax));
|
||||
|
||||
// if let Some(chunk_highlight) = chunk.highlight_style {
|
||||
// if let Some(highlight_style) = highlight_style.as_mut() {
|
||||
// highlight_style.highlight(chunk_highlight);
|
||||
// } else {
|
||||
// highlight_style = Some(chunk_highlight);
|
||||
// }
|
||||
// }
|
||||
if let Some(chunk_highlight) = chunk.highlight_style {
|
||||
if let Some(highlight_style) = highlight_style.as_mut() {
|
||||
highlight_style.highlight(chunk_highlight);
|
||||
} else {
|
||||
highlight_style = Some(chunk_highlight);
|
||||
}
|
||||
}
|
||||
|
||||
// let mut diagnostic_highlight = HighlightStyle::default();
|
||||
let mut diagnostic_highlight = HighlightStyle::default();
|
||||
|
||||
// if chunk.is_unnecessary {
|
||||
// diagnostic_highlight.fade_out = Some(style.unnecessary_code_fade);
|
||||
// }
|
||||
if chunk.is_unnecessary {
|
||||
diagnostic_highlight.fade_out = Some(UNNECESSARY_CODE_FADE);
|
||||
}
|
||||
|
||||
// if let Some(severity) = chunk.diagnostic_severity {
|
||||
// // Omit underlines for HINT/INFO diagnostics on 'unnecessary' code.
|
||||
// if severity <= DiagnosticSeverity::WARNING || !chunk.is_unnecessary {
|
||||
// todo!()
|
||||
// // let diagnostic_style = super::diagnostic_style(severity, true, style);
|
||||
// // diagnostic_highlight.underline = Some(UnderlineStyle {
|
||||
// // color: Some(diagnostic_style.message.text.color),
|
||||
// // thickness: 1.0.into(),
|
||||
// // wavy: true,
|
||||
// // });
|
||||
// }
|
||||
// }
|
||||
if let Some(severity) = chunk.diagnostic_severity {
|
||||
// Omit underlines for HINT/INFO diagnostics on 'unnecessary' code.
|
||||
if severity <= DiagnosticSeverity::WARNING || !chunk.is_unnecessary {
|
||||
let diagnostic_color =
|
||||
super::diagnostic_style(severity, true, &editor_style.diagnostic_style);
|
||||
diagnostic_highlight.underline = Some(UnderlineStyle {
|
||||
color: Some(diagnostic_color),
|
||||
thickness: 1.0.into(),
|
||||
wavy: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// if let Some(highlight_style) = highlight_style.as_mut() {
|
||||
// highlight_style.highlight(diagnostic_highlight);
|
||||
// } else {
|
||||
// highlight_style = Some(diagnostic_highlight);
|
||||
// }
|
||||
if let Some(highlight_style) = highlight_style.as_mut() {
|
||||
highlight_style.highlight(diagnostic_highlight);
|
||||
} else {
|
||||
highlight_style = Some(diagnostic_highlight);
|
||||
}
|
||||
|
||||
// HighlightedChunk {
|
||||
// chunk: chunk.text,
|
||||
// style: highlight_style,
|
||||
// is_tab: chunk.is_tab,
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
HighlightedChunk {
|
||||
chunk: chunk.text,
|
||||
style: highlight_style,
|
||||
is_tab: chunk.is_tab,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lay_out_line_for_row(
|
||||
&self,
|
||||
|
@ -560,53 +567,46 @@ impl DisplaySnapshot {
|
|||
TextLayoutDetails {
|
||||
text_system,
|
||||
editor_style,
|
||||
rem_size,
|
||||
}: &TextLayoutDetails,
|
||||
) -> Line {
|
||||
todo!()
|
||||
// let mut styles = Vec::new();
|
||||
// let mut line = String::new();
|
||||
// let mut ended_in_newline = false;
|
||||
let mut runs = Vec::new();
|
||||
let mut line = String::new();
|
||||
let mut ended_in_newline = false;
|
||||
|
||||
// let range = display_row..display_row + 1;
|
||||
// for chunk in self.highlighted_chunks(range, false, editor_style) {
|
||||
// line.push_str(chunk.chunk);
|
||||
let range = display_row..display_row + 1;
|
||||
for chunk in self.highlighted_chunks(range, false, &editor_style) {
|
||||
line.push_str(chunk.chunk);
|
||||
|
||||
// let text_style = if let Some(style) = chunk.style {
|
||||
// editor_style
|
||||
// .text
|
||||
// .clone()
|
||||
// .highlight(style, text_system)
|
||||
// .map(Cow::Owned)
|
||||
// .unwrap_or_else(|_| Cow::Borrowed(&editor_style.text))
|
||||
// } else {
|
||||
// Cow::Borrowed(&editor_style.text)
|
||||
// };
|
||||
// ended_in_newline = chunk.chunk.ends_with("\n");
|
||||
let text_style = if let Some(style) = chunk.style {
|
||||
editor_style
|
||||
.text
|
||||
.clone()
|
||||
.highlight(style)
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or_else(|_| Cow::Borrowed(&editor_style.text))
|
||||
} else {
|
||||
Cow::Borrowed(&editor_style.text)
|
||||
};
|
||||
ended_in_newline = chunk.chunk.ends_with("\n");
|
||||
|
||||
// styles.push(
|
||||
// todo!(), // len: chunk.chunk.len(),
|
||||
// // font_id: text_style.font_id,
|
||||
// // color: text_style.color,
|
||||
// // underline: text_style.underline,
|
||||
// );
|
||||
// }
|
||||
runs.push(text_style.to_run(chunk.chunk.len()))
|
||||
}
|
||||
|
||||
// // our pixel positioning logic assumes each line ends in \n,
|
||||
// // this is almost always true except for the last line which
|
||||
// // may have no trailing newline.
|
||||
// if !ended_in_newline && display_row == self.max_point().row() {
|
||||
// line.push_str("\n");
|
||||
// our pixel positioning logic assumes each line ends in \n,
|
||||
// this is almost always true except for the last line which
|
||||
// may have no trailing newline.
|
||||
if !ended_in_newline && display_row == self.max_point().row() {
|
||||
line.push_str("\n");
|
||||
runs.push(editor_style.text.to_run("\n".len()));
|
||||
}
|
||||
|
||||
// todo!();
|
||||
// // styles.push(RunStyle {
|
||||
// // len: "\n".len(),
|
||||
// // font_id: editor_style.text.font_id,
|
||||
// // color: editor_style.text_color,
|
||||
// // underline: editor_style.text.underline,
|
||||
// // });
|
||||
// }
|
||||
|
||||
// text_system.layout_text(&line, editor_style.text.font_size, &styles, None)
|
||||
let font_size = editor_style.text.font_size.to_pixels(*rem_size);
|
||||
text_system
|
||||
.layout_text(&line, font_size, &runs, None)
|
||||
.unwrap()
|
||||
.pop()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn x_for_point(
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -24,7 +24,7 @@ pub fn refresh_matching_bracket_highlights(editor: &mut Editor, cx: &mut ViewCon
|
|||
opening_range.to_anchors(&snapshot.buffer_snapshot),
|
||||
closing_range.to_anchors(&snapshot.buffer_snapshot),
|
||||
],
|
||||
|theme| todo!("theme.editor.document_highlight_read_background"),
|
||||
|theme| theme.editor_document_highlight_read_background,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -144,8 +144,7 @@ pub fn hide_hover(editor: &mut Editor, cx: &mut ViewContext<Editor>) -> bool {
|
|||
editor.hover_state.info_task = None;
|
||||
editor.hover_state.triggered_from = None;
|
||||
|
||||
// todo!()
|
||||
// editor.clear_background_highlights::<HoverState>(cx);
|
||||
editor.clear_background_highlights::<HoverState>(cx);
|
||||
|
||||
if did_hide {
|
||||
cx.notify();
|
||||
|
@ -325,23 +324,22 @@ fn show_hover(
|
|||
};
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
todo!();
|
||||
// if let Some(symbol_range) = hover_popover
|
||||
// .as_ref()
|
||||
// .and_then(|hover_popover| hover_popover.symbol_range.as_text_range())
|
||||
// {
|
||||
// // Highlight the selected symbol using a background highlight
|
||||
// this.highlight_background::<HoverState>(
|
||||
// vec![symbol_range],
|
||||
// |theme| theme.editor.hover_popover.highlight,
|
||||
// cx,
|
||||
// );
|
||||
// } else {
|
||||
// this.clear_background_highlights::<HoverState>(cx);
|
||||
// }
|
||||
//
|
||||
// this.hover_state.info_popover = hover_popover;
|
||||
// cx.notify();
|
||||
if let Some(symbol_range) = hover_popover
|
||||
.as_ref()
|
||||
.and_then(|hover_popover| hover_popover.symbol_range.as_text_range())
|
||||
{
|
||||
// Highlight the selected symbol using a background highlight
|
||||
this.highlight_background::<HoverState>(
|
||||
vec![symbol_range],
|
||||
|theme| theme.element_hover, // todo! update theme
|
||||
cx,
|
||||
);
|
||||
} else {
|
||||
this.clear_background_highlights::<HoverState>(cx);
|
||||
}
|
||||
|
||||
this.hover_state.info_popover = hover_popover;
|
||||
cx.notify();
|
||||
})?;
|
||||
|
||||
Ok::<_, anyhow::Error>(())
|
||||
|
|
|
@ -27,7 +27,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
use text::Selection;
|
||||
use theme::{ActiveTheme, ThemeVariant};
|
||||
use theme::{ActiveTheme, Theme};
|
||||
use util::{paths::PathExt, ResultExt, TryFutureExt};
|
||||
use workspace::item::{BreadcrumbText, FollowableItemHandle};
|
||||
use workspace::{
|
||||
|
@ -159,16 +159,14 @@ impl FollowableItem for Editor {
|
|||
self.buffer.update(cx, |buffer, cx| {
|
||||
buffer.remove_active_selections(cx);
|
||||
});
|
||||
} else {
|
||||
} else if self.focus_handle.is_focused(cx) {
|
||||
self.buffer.update(cx, |buffer, cx| {
|
||||
if self.focused {
|
||||
buffer.set_active_selections(
|
||||
&self.selections.disjoint_anchors(),
|
||||
self.selections.line_mode,
|
||||
self.cursor_shape,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
buffer.set_active_selections(
|
||||
&self.selections.disjoint_anchors(),
|
||||
self.selections.line_mode,
|
||||
self.cursor_shape,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
cx.notify();
|
||||
|
@ -779,7 +777,7 @@ impl Item for Editor {
|
|||
ToolbarItemLocation::PrimaryLeft { flex: None }
|
||||
}
|
||||
|
||||
fn breadcrumbs(&self, variant: &ThemeVariant, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
|
||||
fn breadcrumbs(&self, variant: &Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
|
||||
todo!();
|
||||
// let cursor = self.selections.newest_anchor().head();
|
||||
// let multibuffer = &self.buffer().read(cx);
|
||||
|
|
|
@ -171,173 +171,170 @@ pub fn update_inlay_link_and_hover_points(
|
|||
shift_held: bool,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) {
|
||||
todo!("old implementation below")
|
||||
}
|
||||
// ) {
|
||||
// let hovered_offset = if point_for_position.column_overshoot_after_line_end == 0 {
|
||||
// Some(snapshot.display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left))
|
||||
// } else {
|
||||
// None
|
||||
// };
|
||||
// let mut go_to_definition_updated = false;
|
||||
// let mut hover_updated = false;
|
||||
// if let Some(hovered_offset) = hovered_offset {
|
||||
// let buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
// let previous_valid_anchor = buffer_snapshot.anchor_at(
|
||||
// point_for_position.previous_valid.to_point(snapshot),
|
||||
// Bias::Left,
|
||||
// );
|
||||
// let next_valid_anchor = buffer_snapshot.anchor_at(
|
||||
// point_for_position.next_valid.to_point(snapshot),
|
||||
// Bias::Right,
|
||||
// );
|
||||
// if let Some(hovered_hint) = editor
|
||||
// .visible_inlay_hints(cx)
|
||||
// .into_iter()
|
||||
// .skip_while(|hint| {
|
||||
// hint.position
|
||||
// .cmp(&previous_valid_anchor, &buffer_snapshot)
|
||||
// .is_lt()
|
||||
// })
|
||||
// .take_while(|hint| {
|
||||
// hint.position
|
||||
// .cmp(&next_valid_anchor, &buffer_snapshot)
|
||||
// .is_le()
|
||||
// })
|
||||
// .max_by_key(|hint| hint.id)
|
||||
// {
|
||||
// let inlay_hint_cache = editor.inlay_hint_cache();
|
||||
// let excerpt_id = previous_valid_anchor.excerpt_id;
|
||||
// if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
|
||||
// match cached_hint.resolve_state {
|
||||
// ResolveState::CanResolve(_, _) => {
|
||||
// if let Some(buffer_id) = previous_valid_anchor.buffer_id {
|
||||
// inlay_hint_cache.spawn_hint_resolve(
|
||||
// buffer_id,
|
||||
// excerpt_id,
|
||||
// hovered_hint.id,
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// ResolveState::Resolved => {
|
||||
// let mut extra_shift_left = 0;
|
||||
// let mut extra_shift_right = 0;
|
||||
// if cached_hint.padding_left {
|
||||
// extra_shift_left += 1;
|
||||
// extra_shift_right += 1;
|
||||
// }
|
||||
// if cached_hint.padding_right {
|
||||
// extra_shift_right += 1;
|
||||
// }
|
||||
// match cached_hint.label {
|
||||
// project::InlayHintLabel::String(_) => {
|
||||
// if let Some(tooltip) = cached_hint.tooltip {
|
||||
// hover_popover::hover_at_inlay(
|
||||
// editor,
|
||||
// InlayHover {
|
||||
// excerpt: excerpt_id,
|
||||
// tooltip: match tooltip {
|
||||
// InlayHintTooltip::String(text) => HoverBlock {
|
||||
// text,
|
||||
// kind: HoverBlockKind::PlainText,
|
||||
// },
|
||||
// InlayHintTooltip::MarkupContent(content) => {
|
||||
// HoverBlock {
|
||||
// text: content.value,
|
||||
// kind: content.kind,
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// range: InlayHighlight {
|
||||
// inlay: hovered_hint.id,
|
||||
// inlay_position: hovered_hint.position,
|
||||
// range: extra_shift_left
|
||||
// ..hovered_hint.text.len() + extra_shift_right,
|
||||
// },
|
||||
// },
|
||||
// cx,
|
||||
// );
|
||||
// hover_updated = true;
|
||||
// }
|
||||
// }
|
||||
// project::InlayHintLabel::LabelParts(label_parts) => {
|
||||
// let hint_start =
|
||||
// snapshot.anchor_to_inlay_offset(hovered_hint.position);
|
||||
// if let Some((hovered_hint_part, part_range)) =
|
||||
// hover_popover::find_hovered_hint_part(
|
||||
// label_parts,
|
||||
// hint_start,
|
||||
// hovered_offset,
|
||||
// )
|
||||
// {
|
||||
// let highlight_start =
|
||||
// (part_range.start - hint_start).0 + extra_shift_left;
|
||||
// let highlight_end =
|
||||
// (part_range.end - hint_start).0 + extra_shift_right;
|
||||
// let highlight = InlayHighlight {
|
||||
// inlay: hovered_hint.id,
|
||||
// inlay_position: hovered_hint.position,
|
||||
// range: highlight_start..highlight_end,
|
||||
// };
|
||||
// if let Some(tooltip) = hovered_hint_part.tooltip {
|
||||
// hover_popover::hover_at_inlay(
|
||||
// editor,
|
||||
// InlayHover {
|
||||
// excerpt: excerpt_id,
|
||||
// tooltip: match tooltip {
|
||||
// InlayHintLabelPartTooltip::String(text) => {
|
||||
// HoverBlock {
|
||||
// text,
|
||||
// kind: HoverBlockKind::PlainText,
|
||||
// }
|
||||
// }
|
||||
// InlayHintLabelPartTooltip::MarkupContent(
|
||||
// content,
|
||||
// ) => HoverBlock {
|
||||
// text: content.value,
|
||||
// kind: content.kind,
|
||||
// },
|
||||
// },
|
||||
// range: highlight.clone(),
|
||||
// },
|
||||
// cx,
|
||||
// );
|
||||
// hover_updated = true;
|
||||
// }
|
||||
// if let Some((language_server_id, location)) =
|
||||
// hovered_hint_part.location
|
||||
// {
|
||||
// go_to_definition_updated = true;
|
||||
// update_go_to_definition_link(
|
||||
// editor,
|
||||
// Some(GoToDefinitionTrigger::InlayHint(
|
||||
// highlight,
|
||||
// location,
|
||||
// language_server_id,
|
||||
// )),
|
||||
// cmd_held,
|
||||
// shift_held,
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// ResolveState::Resolving => {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
let hovered_offset = if point_for_position.column_overshoot_after_line_end == 0 {
|
||||
Some(snapshot.display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut go_to_definition_updated = false;
|
||||
let mut hover_updated = false;
|
||||
if let Some(hovered_offset) = hovered_offset {
|
||||
let buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
let previous_valid_anchor = buffer_snapshot.anchor_at(
|
||||
point_for_position.previous_valid.to_point(snapshot),
|
||||
Bias::Left,
|
||||
);
|
||||
let next_valid_anchor = buffer_snapshot.anchor_at(
|
||||
point_for_position.next_valid.to_point(snapshot),
|
||||
Bias::Right,
|
||||
);
|
||||
if let Some(hovered_hint) = editor
|
||||
.visible_inlay_hints(cx)
|
||||
.into_iter()
|
||||
.skip_while(|hint| {
|
||||
hint.position
|
||||
.cmp(&previous_valid_anchor, &buffer_snapshot)
|
||||
.is_lt()
|
||||
})
|
||||
.take_while(|hint| {
|
||||
hint.position
|
||||
.cmp(&next_valid_anchor, &buffer_snapshot)
|
||||
.is_le()
|
||||
})
|
||||
.max_by_key(|hint| hint.id)
|
||||
{
|
||||
let inlay_hint_cache = editor.inlay_hint_cache();
|
||||
let excerpt_id = previous_valid_anchor.excerpt_id;
|
||||
if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
|
||||
match cached_hint.resolve_state {
|
||||
ResolveState::CanResolve(_, _) => {
|
||||
if let Some(buffer_id) = previous_valid_anchor.buffer_id {
|
||||
inlay_hint_cache.spawn_hint_resolve(
|
||||
buffer_id,
|
||||
excerpt_id,
|
||||
hovered_hint.id,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
ResolveState::Resolved => {
|
||||
let mut extra_shift_left = 0;
|
||||
let mut extra_shift_right = 0;
|
||||
if cached_hint.padding_left {
|
||||
extra_shift_left += 1;
|
||||
extra_shift_right += 1;
|
||||
}
|
||||
if cached_hint.padding_right {
|
||||
extra_shift_right += 1;
|
||||
}
|
||||
match cached_hint.label {
|
||||
project::InlayHintLabel::String(_) => {
|
||||
if let Some(tooltip) = cached_hint.tooltip {
|
||||
hover_popover::hover_at_inlay(
|
||||
editor,
|
||||
InlayHover {
|
||||
excerpt: excerpt_id,
|
||||
tooltip: match tooltip {
|
||||
InlayHintTooltip::String(text) => HoverBlock {
|
||||
text,
|
||||
kind: HoverBlockKind::PlainText,
|
||||
},
|
||||
InlayHintTooltip::MarkupContent(content) => {
|
||||
HoverBlock {
|
||||
text: content.value,
|
||||
kind: content.kind,
|
||||
}
|
||||
}
|
||||
},
|
||||
range: InlayHighlight {
|
||||
inlay: hovered_hint.id,
|
||||
inlay_position: hovered_hint.position,
|
||||
range: extra_shift_left
|
||||
..hovered_hint.text.len() + extra_shift_right,
|
||||
},
|
||||
},
|
||||
cx,
|
||||
);
|
||||
hover_updated = true;
|
||||
}
|
||||
}
|
||||
project::InlayHintLabel::LabelParts(label_parts) => {
|
||||
let hint_start =
|
||||
snapshot.anchor_to_inlay_offset(hovered_hint.position);
|
||||
if let Some((hovered_hint_part, part_range)) =
|
||||
hover_popover::find_hovered_hint_part(
|
||||
label_parts,
|
||||
hint_start,
|
||||
hovered_offset,
|
||||
)
|
||||
{
|
||||
let highlight_start =
|
||||
(part_range.start - hint_start).0 + extra_shift_left;
|
||||
let highlight_end =
|
||||
(part_range.end - hint_start).0 + extra_shift_right;
|
||||
let highlight = InlayHighlight {
|
||||
inlay: hovered_hint.id,
|
||||
inlay_position: hovered_hint.position,
|
||||
range: highlight_start..highlight_end,
|
||||
};
|
||||
if let Some(tooltip) = hovered_hint_part.tooltip {
|
||||
hover_popover::hover_at_inlay(
|
||||
editor,
|
||||
InlayHover {
|
||||
excerpt: excerpt_id,
|
||||
tooltip: match tooltip {
|
||||
InlayHintLabelPartTooltip::String(text) => {
|
||||
HoverBlock {
|
||||
text,
|
||||
kind: HoverBlockKind::PlainText,
|
||||
}
|
||||
}
|
||||
InlayHintLabelPartTooltip::MarkupContent(
|
||||
content,
|
||||
) => HoverBlock {
|
||||
text: content.value,
|
||||
kind: content.kind,
|
||||
},
|
||||
},
|
||||
range: highlight.clone(),
|
||||
},
|
||||
cx,
|
||||
);
|
||||
hover_updated = true;
|
||||
}
|
||||
if let Some((language_server_id, location)) =
|
||||
hovered_hint_part.location
|
||||
{
|
||||
go_to_definition_updated = true;
|
||||
update_go_to_definition_link(
|
||||
editor,
|
||||
Some(GoToDefinitionTrigger::InlayHint(
|
||||
highlight,
|
||||
location,
|
||||
language_server_id,
|
||||
)),
|
||||
cmd_held,
|
||||
shift_held,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
ResolveState::Resolving => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if !go_to_definition_updated {
|
||||
// update_go_to_definition_link(editor, None, cmd_held, shift_held, cx);
|
||||
// }
|
||||
// if !hover_updated {
|
||||
// hover_popover::hover_at(editor, None, cx);
|
||||
// }
|
||||
// }
|
||||
if !go_to_definition_updated {
|
||||
update_go_to_definition_link(editor, None, cmd_held, shift_held, cx);
|
||||
}
|
||||
if !hover_updated {
|
||||
hover_popover::hover_at(editor, None, cx);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum LinkDefinitionKind {
|
||||
|
@ -581,7 +578,7 @@ fn go_to_fetched_definition_of_kind(
|
|||
|
||||
let is_correct_kind = cached_definitions_kind == Some(kind);
|
||||
if !cached_definitions.is_empty() && is_correct_kind {
|
||||
if !editor.focused {
|
||||
if !editor.focus_handle.is_focused(cx) {
|
||||
cx.focus(&editor.focus_handle);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
|
||||
use crate::{char_kind, CharKind, EditorStyle, ToOffset, ToPoint};
|
||||
use gpui::{px, TextSystem};
|
||||
use gpui::{px, Pixels, TextSystem};
|
||||
use language::Point;
|
||||
use serde::de::IntoDeserializer;
|
||||
use std::ops::Range;
|
||||
use std::{ops::Range, sync::Arc};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum FindRange {
|
||||
|
@ -14,8 +14,9 @@ pub enum FindRange {
|
|||
/// TextLayoutDetails encompasses everything we need to move vertically
|
||||
/// taking into account variable width characters.
|
||||
pub struct TextLayoutDetails {
|
||||
pub text_system: TextSystem,
|
||||
pub text_system: Arc<TextSystem>,
|
||||
pub editor_style: EditorStyle,
|
||||
pub rem_size: Pixels,
|
||||
}
|
||||
|
||||
pub fn left(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint {
|
||||
|
|
|
@ -288,16 +288,15 @@ impl ScrollManager {
|
|||
}
|
||||
}
|
||||
|
||||
// todo!()
|
||||
impl Editor {
|
||||
// pub fn vertical_scroll_margin(&mut self) -> usize {
|
||||
// self.scroll_manager.vertical_scroll_margin as usize
|
||||
// }
|
||||
pub fn vertical_scroll_margin(&mut self) -> usize {
|
||||
self.scroll_manager.vertical_scroll_margin as usize
|
||||
}
|
||||
|
||||
// pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
|
||||
// self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
|
||||
// cx.notify();
|
||||
// }
|
||||
pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
|
||||
self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn visible_line_count(&self) -> Option<f32> {
|
||||
self.scroll_manager.visible_line_count
|
||||
|
@ -349,10 +348,10 @@ impl Editor {
|
|||
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||
}
|
||||
|
||||
// pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<Pixels> {
|
||||
// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// self.scroll_manager.anchor.scroll_position(&display_map)
|
||||
// }
|
||||
pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<f32> {
|
||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
self.scroll_manager.anchor.scroll_position(&display_map)
|
||||
}
|
||||
|
||||
pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
|
||||
hide_hover(self, cx);
|
||||
|
@ -380,50 +379,50 @@ impl Editor {
|
|||
.set_anchor(scroll_anchor, top_row, false, false, workspace_id, cx);
|
||||
}
|
||||
|
||||
// pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) {
|
||||
// if matches!(self.mode, EditorMode::SingleLine) {
|
||||
// cx.propagate_action();
|
||||
// return;
|
||||
// }
|
||||
pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) {
|
||||
if matches!(self.mode, EditorMode::SingleLine) {
|
||||
cx.propagate();
|
||||
return;
|
||||
}
|
||||
|
||||
// if self.take_rename(true, cx).is_some() {
|
||||
// return;
|
||||
// }
|
||||
if self.take_rename(true, cx).is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
// let cur_position = self.scroll_position(cx);
|
||||
// let new_pos = cur_position + point(0., amount.lines(self));
|
||||
// self.set_scroll_position(new_pos, cx);
|
||||
// }
|
||||
let cur_position = self.scroll_position(cx);
|
||||
let new_pos = cur_position + point(0., amount.lines(self));
|
||||
self.set_scroll_position(new_pos, cx);
|
||||
}
|
||||
|
||||
// /// Returns an ordering. The newest selection is:
|
||||
// /// Ordering::Equal => on screen
|
||||
// /// Ordering::Less => above the screen
|
||||
// /// Ordering::Greater => below the screen
|
||||
// pub fn newest_selection_on_screen(&self, cx: &mut AppContext) -> Ordering {
|
||||
// let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
// let newest_head = self
|
||||
// .selections
|
||||
// .newest_anchor()
|
||||
// .head()
|
||||
// .to_display_point(&snapshot);
|
||||
// let screen_top = self
|
||||
// .scroll_manager
|
||||
// .anchor
|
||||
// .anchor
|
||||
// .to_display_point(&snapshot);
|
||||
/// Returns an ordering. The newest selection is:
|
||||
/// Ordering::Equal => on screen
|
||||
/// Ordering::Less => above the screen
|
||||
/// Ordering::Greater => below the screen
|
||||
pub fn newest_selection_on_screen(&self, cx: &mut AppContext) -> Ordering {
|
||||
let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
let newest_head = self
|
||||
.selections
|
||||
.newest_anchor()
|
||||
.head()
|
||||
.to_display_point(&snapshot);
|
||||
let screen_top = self
|
||||
.scroll_manager
|
||||
.anchor
|
||||
.anchor
|
||||
.to_display_point(&snapshot);
|
||||
|
||||
// if screen_top > newest_head {
|
||||
// return Ordering::Less;
|
||||
// }
|
||||
if screen_top > newest_head {
|
||||
return Ordering::Less;
|
||||
}
|
||||
|
||||
// if let Some(visible_lines) = self.visible_line_count() {
|
||||
// if newest_head.row() < screen_top.row() + visible_lines as u32 {
|
||||
// return Ordering::Equal;
|
||||
// }
|
||||
// }
|
||||
if let Some(visible_lines) = self.visible_line_count() {
|
||||
if newest_head.row() < screen_top.row() + visible_lines as u32 {
|
||||
return Ordering::Equal;
|
||||
}
|
||||
}
|
||||
|
||||
// Ordering::Greater
|
||||
// }
|
||||
Ordering::Greater
|
||||
}
|
||||
|
||||
pub fn read_scroll_position_from_db(
|
||||
&mut self,
|
||||
|
|
|
@ -1,148 +1,103 @@
|
|||
use gpui::AppContext;
|
||||
use super::Axis;
|
||||
use crate::{
|
||||
Autoscroll, Bias, Editor, EditorMode, NextScreen, ScrollAnchor, ScrollCursorBottom,
|
||||
ScrollCursorCenter, ScrollCursorTop,
|
||||
};
|
||||
use gpui::{actions, AppContext, Point, ViewContext};
|
||||
|
||||
// actions!(
|
||||
// editor,
|
||||
// [
|
||||
// LineDown,
|
||||
// LineUp,
|
||||
// HalfPageDown,
|
||||
// HalfPageUp,
|
||||
// PageDown,
|
||||
// PageUp,
|
||||
// NextScreen,
|
||||
// ScrollCursorTop,
|
||||
// ScrollCursorCenter,
|
||||
// ScrollCursorBottom,
|
||||
// ]
|
||||
// );
|
||||
impl Editor {
|
||||
pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) {
|
||||
if self.take_rename(true, cx).is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
// todo!()
|
||||
// cx.add_action(Editor::next_screen);
|
||||
// cx.add_action(Editor::scroll_cursor_top);
|
||||
// cx.add_action(Editor::scroll_cursor_center);
|
||||
// cx.add_action(Editor::scroll_cursor_bottom);
|
||||
// cx.add_action(|this: &mut Editor, _: &LineDown, cx| {
|
||||
// this.scroll_screen(&ScrollAmount::Line(1.), cx)
|
||||
// });
|
||||
// cx.add_action(|this: &mut Editor, _: &LineUp, cx| {
|
||||
// this.scroll_screen(&ScrollAmount::Line(-1.), cx)
|
||||
// });
|
||||
// cx.add_action(|this: &mut Editor, _: &HalfPageDown, cx| {
|
||||
// this.scroll_screen(&ScrollAmount::Page(0.5), cx)
|
||||
// });
|
||||
// cx.add_action(|this: &mut Editor, _: &HalfPageUp, cx| {
|
||||
// this.scroll_screen(&ScrollAmount::Page(-0.5), cx)
|
||||
// });
|
||||
// cx.add_action(|this: &mut Editor, _: &PageDown, cx| {
|
||||
// this.scroll_screen(&ScrollAmount::Page(1.), cx)
|
||||
// });
|
||||
// cx.add_action(|this: &mut Editor, _: &PageUp, cx| {
|
||||
// this.scroll_screen(&ScrollAmount::Page(-1.), cx)
|
||||
// });
|
||||
// todo!()
|
||||
// if self.mouse_context_menu.read(cx).visible() {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
if matches!(self.mode, EditorMode::SingleLine) {
|
||||
cx.propagate();
|
||||
return;
|
||||
}
|
||||
self.request_autoscroll(Autoscroll::Next, cx);
|
||||
}
|
||||
|
||||
pub fn scroll(
|
||||
&mut self,
|
||||
scroll_position: Point<f32>,
|
||||
axis: Option<Axis>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.scroll_manager.update_ongoing_scroll(axis);
|
||||
self.set_scroll_position(scroll_position, cx);
|
||||
}
|
||||
|
||||
pub fn scroll_cursor_top(&mut self, _: &ScrollCursorTop, cx: &mut ViewContext<Editor>) {
|
||||
let snapshot = self.snapshot(cx).display_snapshot;
|
||||
let scroll_margin_rows = self.vertical_scroll_margin() as u32;
|
||||
|
||||
let mut new_screen_top = self.selections.newest_display(cx).head();
|
||||
*new_screen_top.row_mut() = new_screen_top.row().saturating_sub(scroll_margin_rows);
|
||||
*new_screen_top.column_mut() = 0;
|
||||
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||
|
||||
self.set_scroll_anchor(
|
||||
ScrollAnchor {
|
||||
anchor: new_anchor,
|
||||
offset: Default::default(),
|
||||
},
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn scroll_cursor_center(&mut self, _: &ScrollCursorCenter, cx: &mut ViewContext<Editor>) {
|
||||
let snapshot = self.snapshot(cx).display_snapshot;
|
||||
let visible_rows = if let Some(visible_rows) = self.visible_line_count() {
|
||||
visible_rows as u32
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut new_screen_top = self.selections.newest_display(cx).head();
|
||||
*new_screen_top.row_mut() = new_screen_top.row().saturating_sub(visible_rows / 2);
|
||||
*new_screen_top.column_mut() = 0;
|
||||
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||
|
||||
self.set_scroll_anchor(
|
||||
ScrollAnchor {
|
||||
anchor: new_anchor,
|
||||
offset: Default::default(),
|
||||
},
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn scroll_cursor_bottom(&mut self, _: &ScrollCursorBottom, cx: &mut ViewContext<Editor>) {
|
||||
let snapshot = self.snapshot(cx).display_snapshot;
|
||||
let scroll_margin_rows = self.vertical_scroll_margin() as u32;
|
||||
let visible_rows = if let Some(visible_rows) = self.visible_line_count() {
|
||||
visible_rows as u32
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut new_screen_top = self.selections.newest_display(cx).head();
|
||||
*new_screen_top.row_mut() = new_screen_top
|
||||
.row()
|
||||
.saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
|
||||
*new_screen_top.column_mut() = 0;
|
||||
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||
|
||||
self.set_scroll_anchor(
|
||||
ScrollAnchor {
|
||||
anchor: new_anchor,
|
||||
offset: Default::default(),
|
||||
},
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// impl Editor {
|
||||
// pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) -> Option<()> {
|
||||
// if self.take_rename(true, cx).is_some() {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// if self.mouse_context_menu.read(cx).visible() {
|
||||
// return None;
|
||||
// }
|
||||
|
||||
// if matches!(self.mode, EditorMode::SingleLine) {
|
||||
// cx.propagate_action();
|
||||
// return None;
|
||||
// }
|
||||
// self.request_autoscroll(Autoscroll::Next, cx);
|
||||
// Some(())
|
||||
// }
|
||||
|
||||
// pub fn scroll(
|
||||
// &mut self,
|
||||
// scroll_position: Vector2F,
|
||||
// axis: Option<Axis>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// self.scroll_manager.update_ongoing_scroll(axis);
|
||||
// self.set_scroll_position(scroll_position, cx);
|
||||
// }
|
||||
|
||||
// fn scroll_cursor_top(editor: &mut Editor, _: &ScrollCursorTop, cx: &mut ViewContext<Editor>) {
|
||||
// let snapshot = editor.snapshot(cx).display_snapshot;
|
||||
// let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
|
||||
|
||||
// let mut new_screen_top = editor.selections.newest_display(cx).head();
|
||||
// *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(scroll_margin_rows);
|
||||
// *new_screen_top.column_mut() = 0;
|
||||
// let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||
// let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||
|
||||
// editor.set_scroll_anchor(
|
||||
// ScrollAnchor {
|
||||
// anchor: new_anchor,
|
||||
// offset: Default::default(),
|
||||
// },
|
||||
// cx,
|
||||
// )
|
||||
// }
|
||||
|
||||
// fn scroll_cursor_center(
|
||||
// editor: &mut Editor,
|
||||
// _: &ScrollCursorCenter,
|
||||
// cx: &mut ViewContext<Editor>,
|
||||
// ) {
|
||||
// let snapshot = editor.snapshot(cx).display_snapshot;
|
||||
// let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
|
||||
// visible_rows as u32
|
||||
// } else {
|
||||
// return;
|
||||
// };
|
||||
|
||||
// let mut new_screen_top = editor.selections.newest_display(cx).head();
|
||||
// *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(visible_rows / 2);
|
||||
// *new_screen_top.column_mut() = 0;
|
||||
// let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||
// let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||
|
||||
// editor.set_scroll_anchor(
|
||||
// ScrollAnchor {
|
||||
// anchor: new_anchor,
|
||||
// offset: Default::default(),
|
||||
// },
|
||||
// cx,
|
||||
// )
|
||||
// }
|
||||
|
||||
// fn scroll_cursor_bottom(
|
||||
// editor: &mut Editor,
|
||||
// _: &ScrollCursorBottom,
|
||||
// cx: &mut ViewContext<Editor>,
|
||||
// ) {
|
||||
// let snapshot = editor.snapshot(cx).display_snapshot;
|
||||
// let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
|
||||
// let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
|
||||
// visible_rows as u32
|
||||
// } else {
|
||||
// return;
|
||||
// };
|
||||
|
||||
// let mut new_screen_top = editor.selections.newest_display(cx).head();
|
||||
// *new_screen_top.row_mut() = new_screen_top
|
||||
// .row()
|
||||
// .saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
|
||||
// *new_screen_top.column_mut() = 0;
|
||||
// let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||
// let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||
|
||||
// editor.set_scroll_anchor(
|
||||
// ScrollAnchor {
|
||||
// anchor: new_anchor,
|
||||
// offset: Default::default(),
|
||||
// },
|
||||
// cx,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -302,39 +302,39 @@ impl SelectionsCollection {
|
|||
.collect()
|
||||
}
|
||||
|
||||
// pub fn build_columnar_selection(
|
||||
// &mut self,
|
||||
// display_map: &DisplaySnapshot,
|
||||
// row: u32,
|
||||
// positions: &Range<Pixels>,
|
||||
// reversed: bool,
|
||||
// text_layout_details: &TextLayoutDetails,
|
||||
// ) -> Option<Selection<Point>> {
|
||||
// let is_empty = positions.start == positions.end;
|
||||
// let line_len = display_map.line_len(row);
|
||||
pub fn build_columnar_selection(
|
||||
&mut self,
|
||||
display_map: &DisplaySnapshot,
|
||||
row: u32,
|
||||
positions: &Range<Pixels>,
|
||||
reversed: bool,
|
||||
text_layout_details: &TextLayoutDetails,
|
||||
) -> Option<Selection<Point>> {
|
||||
let is_empty = positions.start == positions.end;
|
||||
let line_len = display_map.line_len(row);
|
||||
|
||||
// let layed_out_line = display_map.lay_out_line_for_row(row, &text_layout_details);
|
||||
let layed_out_line = display_map.lay_out_line_for_row(row, &text_layout_details);
|
||||
|
||||
// let start_col = layed_out_line.closest_index_for_x(positions.start) as u32;
|
||||
// if start_col < line_len || (is_empty && positions.start == layed_out_line.width()) {
|
||||
// let start = DisplayPoint::new(row, start_col);
|
||||
// let end_col = layed_out_line.closest_index_for_x(positions.end) as u32;
|
||||
// let end = DisplayPoint::new(row, end_col);
|
||||
let start_col = layed_out_line.closest_index_for_x(positions.start) as u32;
|
||||
if start_col < line_len || (is_empty && positions.start == layed_out_line.width) {
|
||||
let start = DisplayPoint::new(row, start_col);
|
||||
let end_col = layed_out_line.closest_index_for_x(positions.end) as u32;
|
||||
let end = DisplayPoint::new(row, end_col);
|
||||
|
||||
// Some(Selection {
|
||||
// id: post_inc(&mut self.next_selection_id),
|
||||
// start: start.to_point(display_map),
|
||||
// end: end.to_point(display_map),
|
||||
// reversed,
|
||||
// goal: SelectionGoal::HorizontalRange {
|
||||
// start: positions.start,
|
||||
// end: positions.end,
|
||||
// },
|
||||
// })
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
Some(Selection {
|
||||
id: post_inc(&mut self.next_selection_id),
|
||||
start: start.to_point(display_map),
|
||||
end: end.to_point(display_map),
|
||||
reversed,
|
||||
goal: SelectionGoal::HorizontalRange {
|
||||
start: positions.start.into(),
|
||||
end: positions.end.into(),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn change_with<R>(
|
||||
&mut self,
|
||||
|
|
25
crates/go_to_line2/Cargo.toml
Normal file
25
crates/go_to_line2/Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
|||
[package]
|
||||
name = "go_to_line2"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
path = "src/go_to_line.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
editor = { package = "editor2", path = "../editor2" }
|
||||
gpui = { package = "gpui2", path = "../gpui2" }
|
||||
menu = { package = "menu2", path = "../menu2" }
|
||||
serde.workspace = true
|
||||
settings = { package = "settings2", path = "../settings2" }
|
||||
text = { package = "text2", path = "../text2" }
|
||||
workspace = { package = "workspace2", path = "../workspace2" }
|
||||
postage.workspace = true
|
||||
theme = { package = "theme2", path = "../theme2" }
|
||||
ui = { package = "ui2", path = "../ui2" }
|
||||
util = { path = "../util" }
|
||||
|
||||
[dev-dependencies]
|
||||
editor = { package = "editor2", path = "../editor2", features = ["test-support"] }
|
221
crates/go_to_line2/src/go_to_line.rs
Normal file
221
crates/go_to_line2/src/go_to_line.rs
Normal file
|
@ -0,0 +1,221 @@
|
|||
use gpui::{actions, div, px, red, AppContext, Div, Render, Styled, ViewContext, VisualContext};
|
||||
use workspace::ModalRegistry;
|
||||
|
||||
actions!(Toggle);
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
cx.global_mut::<ModalRegistry>()
|
||||
.register_modal(Toggle, |_, cx| {
|
||||
// if let Some(editor) = workspace
|
||||
// .active_item(cx)
|
||||
// .and_then(|active_item| active_item.downcast::<Editor>())
|
||||
// {
|
||||
// cx.build_view(|cx| GoToLine::new(editor, cx))
|
||||
// }
|
||||
let view = cx.build_view(|_| GoToLine);
|
||||
view
|
||||
});
|
||||
|
||||
// cx.add_action(GoToLine::toggle);
|
||||
// cx.add_action(GoToLine::confirm);
|
||||
// cx.add_action(GoToLine::cancel);
|
||||
}
|
||||
|
||||
pub struct GoToLine;
|
||||
|
||||
impl Render for GoToLine {
|
||||
type Element = Div<Self>;
|
||||
|
||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
dbg!("rendering GoToLine");
|
||||
div().bg(red()).w(px(100.0)).h(px(100.0))
|
||||
}
|
||||
}
|
||||
|
||||
// pub struct GoToLine {
|
||||
// //line_editor: View<Editor>,
|
||||
// active_editor: View<Editor>,
|
||||
// prev_scroll_position: Option<gpui::Point<Pixels>>,
|
||||
// cursor_point: Point,
|
||||
// max_point: Point,
|
||||
// has_focus: bool,
|
||||
// }
|
||||
|
||||
// pub enum Event {
|
||||
// Dismissed,
|
||||
// }
|
||||
|
||||
// impl GoToLine {
|
||||
// pub fn new(active_editor: View<Editor>, cx: &mut ViewContext<Self>) -> Self {
|
||||
// // let line_editor = cx.build_view(|cx| {
|
||||
// // Editor::single_line(
|
||||
// // Some(Arc::new(|theme| theme.picker.input_editor.clone())),
|
||||
// // cx,
|
||||
// // )
|
||||
// // });
|
||||
// // cx.subscribe(&line_editor, Self::on_line_editor_event)
|
||||
// // .detach();
|
||||
|
||||
// let (scroll_position, cursor_point, max_point) = active_editor.update(cx, |editor, cx| {
|
||||
// let scroll_position = editor.scroll_position(cx);
|
||||
// let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||
// (
|
||||
// Some(scroll_position),
|
||||
// editor.selections.newest(cx).head(),
|
||||
// buffer.max_point(),
|
||||
// )
|
||||
// });
|
||||
|
||||
// cx.on_release(|_, on_release| {}).detach();
|
||||
|
||||
// Self {
|
||||
// //line_editor,
|
||||
// active_editor,
|
||||
// prev_scroll_position: scroll_position,
|
||||
// cursor_point,
|
||||
// max_point,
|
||||
// has_focus: false,
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
||||
// cx.emit(Event::Dismissed);
|
||||
// }
|
||||
|
||||
// fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
||||
// self.prev_scroll_position.take();
|
||||
// if let Some(point) = self.point_from_query(cx) {
|
||||
// self.active_editor.update(cx, |active_editor, cx| {
|
||||
// let snapshot = active_editor.snapshot(cx).display_snapshot;
|
||||
// let point = snapshot.buffer_snapshot.clip_point(point, Bias::Left);
|
||||
// active_editor.change_selections(Some(Autoscroll::center()), cx, |s| {
|
||||
// s.select_ranges([point..point])
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
// cx.emit(Event::Dismissed);
|
||||
// }
|
||||
|
||||
// fn on_line_editor_event(
|
||||
// &mut self,
|
||||
// _: View<Editor>,
|
||||
// event: &editor::Event,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// match event {
|
||||
// editor::Event::Blurred => cx.emit(Event::Dismissed),
|
||||
// editor::Event::BufferEdited { .. } => {
|
||||
// if let Some(point) = self.point_from_query(cx) {
|
||||
// // todo!()
|
||||
// // self.active_editor.update(cx, |active_editor, cx| {
|
||||
// // let snapshot = active_editor.snapshot(cx).display_snapshot;
|
||||
// // let point = snapshot.buffer_snapshot.clip_point(point, Bias::Left);
|
||||
// // let display_point = point.to_display_point(&snapshot);
|
||||
// // let row = display_point.row();
|
||||
// // active_editor.highlight_rows(Some(row..row + 1));
|
||||
// // active_editor.request_autoscroll(Autoscroll::center(), cx);
|
||||
// // });
|
||||
// cx.notify();
|
||||
// }
|
||||
// }
|
||||
// _ => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn point_from_query(&self, cx: &ViewContext<Self>) -> Option<Point> {
|
||||
// return None;
|
||||
// // todo!()
|
||||
// // let line_editor = self.line_editor.read(cx).text(cx);
|
||||
// // let mut components = line_editor
|
||||
// // .splitn(2, FILE_ROW_COLUMN_DELIMITER)
|
||||
// // .map(str::trim)
|
||||
// // .fuse();
|
||||
// // let row = components.next().and_then(|row| row.parse::<u32>().ok())?;
|
||||
// // let column = components.next().and_then(|col| col.parse::<u32>().ok());
|
||||
// // Some(Point::new(
|
||||
// // row.saturating_sub(1),
|
||||
// // column.unwrap_or(0).saturating_sub(1),
|
||||
// // ))
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl EventEmitter for GoToLine {
|
||||
// type Event = Event;
|
||||
// }
|
||||
|
||||
// impl Entity for GoToLine {
|
||||
// fn release(&mut self, cx: &mut AppContext) {
|
||||
// let scroll_position = self.prev_scroll_position.take();
|
||||
// self.active_editor.window().update(cx, |cx| {
|
||||
// self.active_editor.update(cx, |editor, cx| {
|
||||
// editor.highlight_rows(None);
|
||||
// if let Some(scroll_position) = scroll_position {
|
||||
// editor.set_scroll_position(scroll_position, cx);
|
||||
// }
|
||||
// })
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl Render for GoToLine {
|
||||
// type Element = Div<Self>;
|
||||
|
||||
// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
// // todo!()
|
||||
// div()
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl View for GoToLine {
|
||||
// fn ui_name() -> &'static str {
|
||||
// "GoToLine"
|
||||
// }
|
||||
|
||||
// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||
// let theme = &theme::current(cx).picker;
|
||||
|
||||
// let label = format!(
|
||||
// "{}{FILE_ROW_COLUMN_DELIMITER}{} of {} lines",
|
||||
// self.cursor_point.row + 1,
|
||||
// self.cursor_point.column + 1,
|
||||
// self.max_point.row + 1
|
||||
// );
|
||||
|
||||
// Flex::new(Axis::Vertical)
|
||||
// .with_child(
|
||||
// ChildView::new(&self.line_editor, cx)
|
||||
// .contained()
|
||||
// .with_style(theme.input_editor.container),
|
||||
// )
|
||||
// .with_child(
|
||||
// Label::new(label, theme.no_matches.label.clone())
|
||||
// .contained()
|
||||
// .with_style(theme.no_matches.container),
|
||||
// )
|
||||
// .contained()
|
||||
// .with_style(theme.container)
|
||||
// .constrained()
|
||||
// .with_max_width(500.0)
|
||||
// .into_any_named("go to line")
|
||||
// }
|
||||
|
||||
// fn focus_in(&mut self, _: AnyView, cx: &mut ViewContext<Self>) {
|
||||
// self.has_focus = true;
|
||||
// cx.focus(&self.line_editor);
|
||||
// }
|
||||
|
||||
// fn focus_out(&mut self, _: AnyView, _: &mut ViewContext<Self>) {
|
||||
// self.has_focus = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl Modal for GoToLine {
|
||||
// fn has_focus(&self) -> bool {
|
||||
// self.has_focus
|
||||
// }
|
||||
|
||||
// fn dismiss_on_event(event: &Self::Event) -> bool {
|
||||
// matches!(event, Event::Dismissed)
|
||||
// }
|
||||
// }
|
|
@ -1,10 +1,55 @@
|
|||
use crate::SharedString;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use collections::{HashMap, HashSet};
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
|
||||
use serde::Deserialize;
|
||||
use std::any::{type_name, Any};
|
||||
|
||||
pub trait Action: 'static {
|
||||
/// Actions are used to implement keyboard-driven UI.
|
||||
/// When you declare an action, you can bind keys to the action in the keymap and
|
||||
/// listeners for that action in the element tree.
|
||||
///
|
||||
/// To declare a list of simple actions, you can use the actions! macro, which defines a simple unit struct
|
||||
/// action for each listed action name.
|
||||
/// ```rust
|
||||
/// actions!(MoveUp, MoveDown, MoveLeft, MoveRight, Newline);
|
||||
/// ```
|
||||
/// More complex data types can also be actions. If you annotate your type with the `#[action]` proc macro,
|
||||
/// it will automatically
|
||||
/// ```
|
||||
/// #[action]
|
||||
/// pub struct SelectNext {
|
||||
/// pub replace_newest: bool,
|
||||
/// }
|
||||
///
|
||||
/// Any type A that satisfies the following bounds is automatically an action:
|
||||
///
|
||||
/// ```
|
||||
/// A: for<'a> Deserialize<'a> + PartialEq + Clone + Default + std::fmt::Debug + 'static,
|
||||
/// ```
|
||||
///
|
||||
/// The `#[action]` annotation will derive these implementations for your struct automatically. If you
|
||||
/// want to control them manually, you can use the lower-level `#[register_action]` macro, which only
|
||||
/// generates the code needed to register your action before `main`. Then you'll need to implement all
|
||||
/// the traits manually.
|
||||
///
|
||||
/// ```
|
||||
/// #[gpui::register_action]
|
||||
/// #[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::fmt::Debug)]
|
||||
/// pub struct Paste {
|
||||
/// pub content: SharedString,
|
||||
/// }
|
||||
///
|
||||
/// impl std::default::Default for Paste {
|
||||
/// fn default() -> Self {
|
||||
/// Self {
|
||||
/// content: SharedString::from("🍝"),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Action: std::fmt::Debug + 'static {
|
||||
fn qualified_name() -> SharedString
|
||||
where
|
||||
Self: Sized;
|
||||
|
@ -17,12 +62,14 @@ pub trait Action: 'static {
|
|||
fn as_any(&self) -> &dyn Any;
|
||||
}
|
||||
|
||||
// Types become actions by satisfying a list of trait bounds.
|
||||
impl<A> Action for A
|
||||
where
|
||||
A: for<'a> Deserialize<'a> + PartialEq + Clone + Default + 'static,
|
||||
A: for<'a> Deserialize<'a> + PartialEq + Clone + Default + std::fmt::Debug + 'static,
|
||||
{
|
||||
fn qualified_name() -> SharedString {
|
||||
type_name::<A>().into()
|
||||
// todo!() remove the 2 replacement when migration is done
|
||||
type_name::<A>().replace("2::", "::").into()
|
||||
}
|
||||
|
||||
fn build(params: Option<serde_json::Value>) -> Result<Box<dyn Action>>
|
||||
|
@ -53,6 +100,61 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
|
||||
|
||||
lazy_static! {
|
||||
static ref ACTION_REGISTRY: RwLock<ActionRegistry> = RwLock::default();
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ActionRegistry {
|
||||
builders_by_name: HashMap<SharedString, ActionBuilder>,
|
||||
all_names: Vec<SharedString>, // So we can return a static slice.
|
||||
}
|
||||
|
||||
/// Register an action type to allow it to be referenced in keymaps.
|
||||
pub fn register_action<A: Action>() {
|
||||
let name = A::qualified_name();
|
||||
let mut lock = ACTION_REGISTRY.write();
|
||||
lock.builders_by_name.insert(name.clone(), A::build);
|
||||
lock.all_names.push(name);
|
||||
}
|
||||
|
||||
/// Construct an action based on its name and optional JSON parameters sourced from the keymap.
|
||||
pub fn build_action(name: &str, params: Option<serde_json::Value>) -> Result<Box<dyn Action>> {
|
||||
let lock = ACTION_REGISTRY.read();
|
||||
let build_action = lock
|
||||
.builders_by_name
|
||||
.get(name)
|
||||
.ok_or_else(|| anyhow!("no action type registered for {}", name))?;
|
||||
(build_action)(params)
|
||||
}
|
||||
|
||||
pub fn all_action_names() -> MappedRwLockReadGuard<'static, [SharedString]> {
|
||||
let lock = ACTION_REGISTRY.read();
|
||||
RwLockReadGuard::map(lock, |registry: &ActionRegistry| {
|
||||
registry.all_names.as_slice()
|
||||
})
|
||||
}
|
||||
|
||||
/// Defines unit structs that can be used as actions.
|
||||
/// To use more complex data types as actions, annotate your type with the #[action] macro.
|
||||
#[macro_export]
|
||||
macro_rules! actions {
|
||||
() => {};
|
||||
|
||||
( $name:ident ) => {
|
||||
#[gpui::register_action]
|
||||
#[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
|
||||
pub struct $name;
|
||||
};
|
||||
|
||||
( $name:ident, $($rest:tt)* ) => {
|
||||
actions!($name);
|
||||
actions!($($rest)*);
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct DispatchContext {
|
||||
set: HashSet<SharedString>,
|
||||
|
@ -290,8 +392,28 @@ fn skip_whitespace(source: &str) -> &str {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate as gpui;
|
||||
use DispatchContextPredicate::*;
|
||||
|
||||
#[test]
|
||||
fn test_actions_definition() {
|
||||
{
|
||||
actions!(A, B, C, D, E, F, G);
|
||||
}
|
||||
|
||||
{
|
||||
actions!(
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
F,
|
||||
G, // Don't wrap, test the trailing comma
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_context() {
|
||||
let mut expected = DispatchContext::default();
|
||||
|
|
|
@ -17,9 +17,9 @@ use crate::{
|
|||
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle,
|
||||
AppMetadata, AssetSource, BackgroundExecutor, ClipboardItem, Context, DispatchPhase, DisplayId,
|
||||
Entity, EventEmitter, FocusEvent, FocusHandle, FocusId, ForegroundExecutor, KeyBinding, Keymap,
|
||||
LayoutId, PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, Render, SharedString,
|
||||
SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem,
|
||||
View, Window, WindowContext, WindowHandle, WindowId,
|
||||
LayoutId, PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, Render, SubscriberSet,
|
||||
Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window,
|
||||
WindowContext, WindowHandle, WindowId,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::{HashMap, HashSet, VecDeque};
|
||||
|
@ -144,7 +144,6 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
|
||||
pub(crate) type FrameCallback = Box<dyn FnOnce(&mut AppContext)>;
|
||||
type Handler = Box<dyn FnMut(&mut AppContext) -> bool + 'static>;
|
||||
type Listener = Box<dyn FnMut(&dyn Any, &mut AppContext) -> bool + 'static>;
|
||||
|
@ -158,7 +157,7 @@ type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut AppContext) + 'static>;
|
|||
// }
|
||||
|
||||
pub struct AppContext {
|
||||
this: Weak<AppCell>,
|
||||
pub(crate) this: Weak<AppCell>,
|
||||
pub(crate) platform: Rc<dyn Platform>,
|
||||
app_metadata: AppMetadata,
|
||||
text_system: Arc<TextSystem>,
|
||||
|
@ -180,7 +179,6 @@ pub struct AppContext {
|
|||
pub(crate) keymap: Arc<Mutex<Keymap>>,
|
||||
pub(crate) global_action_listeners:
|
||||
HashMap<TypeId, Vec<Box<dyn Fn(&dyn Action, DispatchPhase, &mut Self)>>>,
|
||||
action_builders: HashMap<SharedString, ActionBuilder>,
|
||||
pending_effects: VecDeque<Effect>,
|
||||
pub(crate) pending_notifications: HashSet<EntityId>,
|
||||
pub(crate) pending_global_notifications: HashSet<TypeId>,
|
||||
|
@ -238,7 +236,6 @@ impl AppContext {
|
|||
windows: SlotMap::with_key(),
|
||||
keymap: Arc::new(Mutex::new(Keymap::default())),
|
||||
global_action_listeners: HashMap::default(),
|
||||
action_builders: HashMap::default(),
|
||||
pending_effects: VecDeque::new(),
|
||||
pending_notifications: HashSet::default(),
|
||||
pending_global_notifications: HashSet::default(),
|
||||
|
@ -755,13 +752,17 @@ impl AppContext {
|
|||
self.globals_by_type.insert(global_type, Box::new(global));
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn clear_globals(&mut self) {
|
||||
dbg!(core::panic::Location::caller());
|
||||
//todo!(notify globals?)
|
||||
self.globals_by_type.drain();
|
||||
}
|
||||
|
||||
/// Set the value of the global of the given type.
|
||||
#[track_caller]
|
||||
pub fn remove_global<G: Any>(&mut self) -> G {
|
||||
dbg!(core::panic::Location::caller());
|
||||
let global_type = TypeId::of::<G>();
|
||||
//todo!(notify globals?)
|
||||
*self
|
||||
|
@ -795,10 +796,6 @@ impl AppContext {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn all_action_names<'a>(&'a self) -> impl Iterator<Item = SharedString> + 'a {
|
||||
self.action_builders.keys().cloned()
|
||||
}
|
||||
|
||||
/// Move the global of the given type to the stack.
|
||||
pub(crate) fn lease_global<G: 'static>(&mut self) -> GlobalLease<G> {
|
||||
GlobalLease::new(
|
||||
|
@ -861,29 +858,21 @@ impl AppContext {
|
|||
}));
|
||||
}
|
||||
|
||||
/// Register an action type to allow it to be referenced in keymaps.
|
||||
pub fn register_action_type<A: Action>(&mut self) {
|
||||
self.action_builders.insert(A::qualified_name(), A::build);
|
||||
}
|
||||
|
||||
/// Construct an action based on its name and parameters.
|
||||
pub fn build_action(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<Box<dyn Action>> {
|
||||
let build = self
|
||||
.action_builders
|
||||
.get(name)
|
||||
.ok_or_else(|| anyhow!("no action type registered for {}", name))?;
|
||||
(build)(params)
|
||||
}
|
||||
|
||||
/// Halt propagation of a mouse event, keyboard event, or action. This prevents listeners
|
||||
/// that have not yet been invoked from receiving the event.
|
||||
/// Event handlers propagate events by default. Call this method to stop dispatching to
|
||||
/// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is
|
||||
/// the opposite of [propagate]. It's also possible to cancel a call to [propagate] by
|
||||
/// calling this method before effects are flushed.
|
||||
pub fn stop_propagation(&mut self) {
|
||||
self.propagate_event = false;
|
||||
}
|
||||
|
||||
/// Action handlers stop propagation by default during the bubble phase of action dispatch
|
||||
/// dispatching to action handlers higher in the element tree. This is the opposite of
|
||||
/// [stop_propagation]. It's also possible to cancel a call to [stop_propagate] by calling
|
||||
/// this method before effects are flushed.
|
||||
pub fn propagate(&mut self) {
|
||||
self.propagate_event = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for AppContext {
|
||||
|
|
|
@ -13,6 +13,7 @@ use std::{
|
|||
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||
Arc, Weak,
|
||||
},
|
||||
thread::panicking,
|
||||
};
|
||||
|
||||
slotmap::new_key_type! { pub struct EntityId; }
|
||||
|
@ -140,9 +141,8 @@ impl<'a, T: 'static> core::ops::DerefMut for Lease<'a, T> {
|
|||
|
||||
impl<'a, T> Drop for Lease<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
if self.entity.is_some() {
|
||||
// We don't panic here, because other panics can cause us to drop the lease without ending it cleanly.
|
||||
log::error!("Leases must be ended with EntityMap::end_lease")
|
||||
if self.entity.is_some() && !panicking() {
|
||||
panic!("Leases must be ended with EntityMap::end_lease")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{
|
||||
AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext, BackgroundExecutor, Context,
|
||||
EventEmitter, ForegroundExecutor, Model, ModelContext, Render, Result, Task, TestDispatcher,
|
||||
TestPlatform, ViewContext, VisualContext, WindowContext, WindowHandle, WindowOptions,
|
||||
EventEmitter, ForegroundExecutor, InputEvent, KeyDownEvent, Keystroke, Model, ModelContext,
|
||||
Render, Result, Task, TestDispatcher, TestPlatform, ViewContext, VisualContext, WindowContext,
|
||||
WindowHandle, WindowOptions,
|
||||
};
|
||||
use anyhow::{anyhow, bail};
|
||||
use futures::{Stream, StreamExt};
|
||||
|
@ -161,6 +162,23 @@ impl TestAppContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn dispatch_keystroke(
|
||||
&mut self,
|
||||
window: AnyWindowHandle,
|
||||
keystroke: Keystroke,
|
||||
is_held: bool,
|
||||
) {
|
||||
let handled = window
|
||||
.update(self, |_, cx| {
|
||||
cx.dispatch_event(InputEvent::KeyDown(KeyDownEvent { keystroke, is_held }))
|
||||
})
|
||||
.is_ok_and(|handled| handled);
|
||||
|
||||
if !handled {
|
||||
// todo!() simluate input here
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notifications<T: 'static>(&mut self, entity: &Model<T>) -> impl Stream<Item = ()> {
|
||||
let (tx, rx) = futures::channel::mpsc::unbounded();
|
||||
|
||||
|
|
|
@ -176,6 +176,15 @@ pub fn black() -> Hsla {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn transparent_black() -> Hsla {
|
||||
Hsla {
|
||||
h: 0.,
|
||||
s: 0.,
|
||||
l: 0.,
|
||||
a: 0.,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn white() -> Hsla {
|
||||
Hsla {
|
||||
h: 0.,
|
||||
|
@ -194,6 +203,15 @@ pub fn red() -> Hsla {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn blue() -> Hsla {
|
||||
Hsla {
|
||||
h: 0.6,
|
||||
s: 1.,
|
||||
l: 0.5,
|
||||
a: 1.,
|
||||
}
|
||||
}
|
||||
|
||||
impl Hsla {
|
||||
/// Returns true if the HSLA color is fully transparent, false otherwise.
|
||||
pub fn is_transparent(&self) -> bool {
|
||||
|
|
|
@ -134,7 +134,10 @@ where
|
|||
.layout(state, frame_state.as_mut().unwrap(), cx);
|
||||
}
|
||||
}
|
||||
_ => panic!("must call initialize before layout"),
|
||||
ElementRenderPhase::Start => panic!("must call initialize before layout"),
|
||||
ElementRenderPhase::LayoutRequested { .. } | ElementRenderPhase::Painted => {
|
||||
panic!("element rendered twice")
|
||||
}
|
||||
};
|
||||
|
||||
self.phase = ElementRenderPhase::LayoutRequested {
|
||||
|
|
|
@ -2,8 +2,10 @@ mod div;
|
|||
mod img;
|
||||
mod svg;
|
||||
mod text;
|
||||
mod uniform_list;
|
||||
|
||||
pub use div::*;
|
||||
pub use img::*;
|
||||
pub use svg::*;
|
||||
pub use text::*;
|
||||
pub use uniform_list::*;
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
use crate::{
|
||||
point, AnyElement, BorrowWindow, Bounds, Component, Element, ElementFocus, ElementId,
|
||||
ElementInteraction, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable,
|
||||
ElementInteractivity, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable,
|
||||
GlobalElementId, GroupBounds, InteractiveElementState, LayoutId, Overflow, ParentElement,
|
||||
Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
|
||||
StatelessInteractive, Style, StyleRefinement, Styled, ViewContext, Visibility,
|
||||
Pixels, Point, SharedString, StatefulInteractive, StatefulInteractivity, StatelessInteractive,
|
||||
StatelessInteractivity, Style, StyleRefinement, Styled, ViewContext, Visibility,
|
||||
};
|
||||
use refineable::Refineable;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
pub struct Div<
|
||||
V: 'static,
|
||||
I: ElementInteraction<V> = StatelessInteraction<V>,
|
||||
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
||||
F: ElementFocus<V> = FocusDisabled,
|
||||
> {
|
||||
interaction: I,
|
||||
interactivity: I,
|
||||
focus: F,
|
||||
children: SmallVec<[AnyElement<V>; 2]>,
|
||||
group: Option<SharedString>,
|
||||
base_style: StyleRefinement,
|
||||
}
|
||||
|
||||
pub fn div<V: 'static>() -> Div<V, StatelessInteraction<V>, FocusDisabled> {
|
||||
pub fn div<V: 'static>() -> Div<V, StatelessInteractivity<V>, FocusDisabled> {
|
||||
Div {
|
||||
interaction: StatelessInteraction::default(),
|
||||
interactivity: StatelessInteractivity::default(),
|
||||
focus: FocusDisabled,
|
||||
children: SmallVec::new(),
|
||||
group: None,
|
||||
|
@ -30,14 +30,14 @@ pub fn div<V: 'static>() -> Div<V, StatelessInteraction<V>, FocusDisabled> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, F> Div<V, StatelessInteraction<V>, F>
|
||||
impl<V, F> Div<V, StatelessInteractivity<V>, F>
|
||||
where
|
||||
V: 'static,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteraction<V>, F> {
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> {
|
||||
Div {
|
||||
interaction: id.into().into(),
|
||||
interactivity: id.into().into(),
|
||||
focus: self.focus,
|
||||
children: self.children,
|
||||
group: self.group,
|
||||
|
@ -48,7 +48,7 @@ where
|
|||
|
||||
impl<V, I, F> Div<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
|
||||
|
@ -98,16 +98,20 @@ where
|
|||
let mut computed_style = Style::default();
|
||||
computed_style.refine(&self.base_style);
|
||||
self.focus.refine_style(&mut computed_style, cx);
|
||||
self.interaction
|
||||
.refine_style(&mut computed_style, bounds, &element_state.interactive, cx);
|
||||
self.interactivity.refine_style(
|
||||
&mut computed_style,
|
||||
bounds,
|
||||
&element_state.interactive,
|
||||
cx,
|
||||
);
|
||||
computed_style
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Div<V, StatefulInteraction<V>, FocusDisabled> {
|
||||
pub fn focusable(self) -> Div<V, StatefulInteraction<V>, FocusEnabled<V>> {
|
||||
impl<V: 'static> Div<V, StatefulInteractivity<V>, FocusDisabled> {
|
||||
pub fn focusable(self) -> Div<V, StatefulInteractivity<V>, FocusEnabled<V>> {
|
||||
Div {
|
||||
interaction: self.interaction,
|
||||
interactivity: self.interactivity,
|
||||
focus: FocusEnabled::new(),
|
||||
children: self.children,
|
||||
group: self.group,
|
||||
|
@ -118,9 +122,9 @@ impl<V: 'static> Div<V, StatefulInteraction<V>, FocusDisabled> {
|
|||
pub fn track_focus(
|
||||
self,
|
||||
handle: &FocusHandle,
|
||||
) -> Div<V, StatefulInteraction<V>, FocusEnabled<V>> {
|
||||
) -> Div<V, StatefulInteractivity<V>, FocusEnabled<V>> {
|
||||
Div {
|
||||
interaction: self.interaction,
|
||||
interactivity: self.interactivity,
|
||||
focus: FocusEnabled::tracked(handle),
|
||||
children: self.children,
|
||||
group: self.group,
|
||||
|
@ -145,13 +149,13 @@ impl<V: 'static> Div<V, StatefulInteraction<V>, FocusDisabled> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Div<V, StatelessInteraction<V>, FocusDisabled> {
|
||||
impl<V: 'static> Div<V, StatelessInteractivity<V>, FocusDisabled> {
|
||||
pub fn track_focus(
|
||||
self,
|
||||
handle: &FocusHandle,
|
||||
) -> Div<V, StatefulInteraction<V>, FocusEnabled<V>> {
|
||||
) -> Div<V, StatefulInteractivity<V>, FocusEnabled<V>> {
|
||||
Div {
|
||||
interaction: self.interaction.into_stateful(handle),
|
||||
interactivity: self.interactivity.into_stateful(handle),
|
||||
focus: handle.clone().into(),
|
||||
children: self.children,
|
||||
group: self.group,
|
||||
|
@ -163,7 +167,7 @@ impl<V: 'static> Div<V, StatelessInteraction<V>, FocusDisabled> {
|
|||
impl<V, I> Focusable<V> for Div<V, I, FocusEnabled<V>>
|
||||
where
|
||||
V: 'static,
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
{
|
||||
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
||||
&mut self.focus.focus_listeners
|
||||
|
@ -191,13 +195,13 @@ pub struct DivState {
|
|||
|
||||
impl<V, I, F> Element<V> for Div<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
type ElementState = DivState;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
self.interaction
|
||||
self.interactivity
|
||||
.as_stateful()
|
||||
.map(|identified| identified.id.clone())
|
||||
}
|
||||
|
@ -209,15 +213,15 @@ where
|
|||
cx: &mut ViewContext<V>,
|
||||
) -> Self::ElementState {
|
||||
let mut element_state = element_state.unwrap_or_default();
|
||||
self.focus
|
||||
.initialize(element_state.focus_handle.take(), cx, |focus_handle, cx| {
|
||||
element_state.focus_handle = focus_handle;
|
||||
self.interaction.initialize(cx, |cx| {
|
||||
self.interactivity.initialize(cx, |cx| {
|
||||
self.focus
|
||||
.initialize(element_state.focus_handle.take(), cx, |focus_handle, cx| {
|
||||
element_state.focus_handle = focus_handle;
|
||||
for child in &mut self.children {
|
||||
child.initialize(view_state, cx);
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
element_state
|
||||
}
|
||||
|
||||
|
@ -281,11 +285,11 @@ where
|
|||
(child_max - child_min).into()
|
||||
};
|
||||
|
||||
cx.stack(z_index, |cx| {
|
||||
cx.stack(0, |cx| {
|
||||
cx.with_z_index(z_index, |cx| {
|
||||
cx.with_z_index(0, |cx| {
|
||||
style.paint(bounds, cx);
|
||||
this.focus.paint(bounds, cx);
|
||||
this.interaction.paint(
|
||||
this.interactivity.paint(
|
||||
bounds,
|
||||
content_size,
|
||||
style.overflow,
|
||||
|
@ -293,7 +297,7 @@ where
|
|||
cx,
|
||||
);
|
||||
});
|
||||
cx.stack(1, |cx| {
|
||||
cx.with_z_index(1, |cx| {
|
||||
style.apply_text_style(cx, |cx| {
|
||||
style.apply_overflow(bounds, cx, |cx| {
|
||||
let scroll_offset = element_state.interactive.scroll_offset();
|
||||
|
@ -316,7 +320,7 @@ where
|
|||
|
||||
impl<V, I, F> Component<V> for Div<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn render(self) -> AnyElement<V> {
|
||||
|
@ -326,7 +330,7 @@ where
|
|||
|
||||
impl<V, I, F> ParentElement<V> for Div<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
|
@ -336,7 +340,7 @@ where
|
|||
|
||||
impl<V, I, F> Styled for Div<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
|
@ -346,19 +350,19 @@ where
|
|||
|
||||
impl<V, I, F> StatelessInteractive<V> for Div<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V> {
|
||||
self.interaction.as_stateless_mut()
|
||||
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
self.interactivity.as_stateless_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, F> StatefulInteractive<V> for Div<V, StatefulInteraction<V>, F>
|
||||
impl<V, F> StatefulInteractive<V> for Div<V, StatefulInteractivity<V>, F>
|
||||
where
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V> {
|
||||
&mut self.interaction
|
||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||
&mut self.interactivity
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
use crate::{
|
||||
div, AnyElement, BorrowWindow, Bounds, Component, Div, DivState, Element, ElementFocus,
|
||||
ElementId, ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable,
|
||||
LayoutId, Pixels, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
|
||||
StatelessInteractive, StyleRefinement, Styled, ViewContext,
|
||||
ElementId, ElementInteractivity, FocusDisabled, FocusEnabled, FocusListeners, Focusable,
|
||||
LayoutId, Pixels, SharedString, StatefulInteractive, StatefulInteractivity,
|
||||
StatelessInteractive, StatelessInteractivity, StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use futures::FutureExt;
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct Img<
|
||||
V: 'static,
|
||||
I: ElementInteraction<V> = StatelessInteraction<V>,
|
||||
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
||||
F: ElementFocus<V> = FocusDisabled,
|
||||
> {
|
||||
base: Div<V, I, F>,
|
||||
|
@ -17,7 +17,7 @@ pub struct Img<
|
|||
grayscale: bool,
|
||||
}
|
||||
|
||||
pub fn img<V: 'static>() -> Img<V, StatelessInteraction<V>, FocusDisabled> {
|
||||
pub fn img<V: 'static>() -> Img<V, StatelessInteractivity<V>, FocusDisabled> {
|
||||
Img {
|
||||
base: div(),
|
||||
uri: None,
|
||||
|
@ -28,7 +28,7 @@ pub fn img<V: 'static>() -> Img<V, StatelessInteraction<V>, FocusDisabled> {
|
|||
impl<V, I, F> Img<V, I, F>
|
||||
where
|
||||
V: 'static,
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
|
||||
|
@ -42,11 +42,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, F> Img<V, StatelessInteraction<V>, F>
|
||||
impl<V, F> Img<V, StatelessInteractivity<V>, F>
|
||||
where
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Img<V, StatefulInteraction<V>, F> {
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Img<V, StatefulInteractivity<V>, F> {
|
||||
Img {
|
||||
base: self.base.id(id),
|
||||
uri: self.uri,
|
||||
|
@ -57,7 +57,7 @@ where
|
|||
|
||||
impl<V, I, F> Component<V> for Img<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn render(self) -> AnyElement<V> {
|
||||
|
@ -67,7 +67,7 @@ where
|
|||
|
||||
impl<V, I, F> Element<V> for Img<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
type ElementState = DivState;
|
||||
|
@ -101,7 +101,7 @@ where
|
|||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
cx.stack(0, |cx| {
|
||||
cx.with_z_index(0, |cx| {
|
||||
self.base.paint(bounds, view, element_state, cx);
|
||||
});
|
||||
|
||||
|
@ -118,7 +118,7 @@ where
|
|||
.and_then(ResultExt::log_err)
|
||||
{
|
||||
let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
|
||||
cx.stack(1, |cx| {
|
||||
cx.with_z_index(1, |cx| {
|
||||
cx.paint_image(bounds, corner_radii, data, self.grayscale)
|
||||
.log_err()
|
||||
});
|
||||
|
@ -136,7 +136,7 @@ where
|
|||
|
||||
impl<V, I, F> Styled for Img<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
|
@ -146,27 +146,27 @@ where
|
|||
|
||||
impl<V, I, F> StatelessInteractive<V> for Img<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V> {
|
||||
self.base.stateless_interaction()
|
||||
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
self.base.stateless_interactivity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, F> StatefulInteractive<V> for Img<V, StatefulInteraction<V>, F>
|
||||
impl<V, F> StatefulInteractive<V> for Img<V, StatefulInteractivity<V>, F>
|
||||
where
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V> {
|
||||
self.base.stateful_interaction()
|
||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||
self.base.stateful_interactivity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I> Focusable<V> for Img<V, I, FocusEnabled<V>>
|
||||
where
|
||||
V: 'static,
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
{
|
||||
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
||||
self.base.focus_listeners()
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
use crate::{
|
||||
div, AnyElement, Bounds, Component, Div, DivState, Element, ElementFocus, ElementId,
|
||||
ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, LayoutId, Pixels,
|
||||
SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
|
||||
StatelessInteractive, StyleRefinement, Styled, ViewContext,
|
||||
ElementInteractivity, FocusDisabled, FocusEnabled, FocusListeners, Focusable, LayoutId, Pixels,
|
||||
SharedString, StatefulInteractive, StatefulInteractivity, StatelessInteractive,
|
||||
StatelessInteractivity, StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct Svg<
|
||||
V: 'static,
|
||||
I: ElementInteraction<V> = StatelessInteraction<V>,
|
||||
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
||||
F: ElementFocus<V> = FocusDisabled,
|
||||
> {
|
||||
base: Div<V, I, F>,
|
||||
path: Option<SharedString>,
|
||||
}
|
||||
|
||||
pub fn svg<V: 'static>() -> Svg<V, StatelessInteraction<V>, FocusDisabled> {
|
||||
pub fn svg<V: 'static>() -> Svg<V, StatelessInteractivity<V>, FocusDisabled> {
|
||||
Svg {
|
||||
base: div(),
|
||||
path: None,
|
||||
|
@ -24,7 +24,7 @@ pub fn svg<V: 'static>() -> Svg<V, StatelessInteraction<V>, FocusDisabled> {
|
|||
|
||||
impl<V, I, F> Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
|
||||
|
@ -33,11 +33,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, F> Svg<V, StatelessInteraction<V>, F>
|
||||
impl<V, F> Svg<V, StatelessInteractivity<V>, F>
|
||||
where
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, StatefulInteraction<V>, F> {
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, StatefulInteractivity<V>, F> {
|
||||
Svg {
|
||||
base: self.base.id(id),
|
||||
path: self.path,
|
||||
|
@ -47,7 +47,7 @@ where
|
|||
|
||||
impl<V, I, F> Component<V> for Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn render(self) -> AnyElement<V> {
|
||||
|
@ -57,7 +57,7 @@ where
|
|||
|
||||
impl<V, I, F> Element<V> for Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
type ElementState = DivState;
|
||||
|
@ -107,7 +107,7 @@ where
|
|||
|
||||
impl<V, I, F> Styled for Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
|
@ -117,27 +117,27 @@ where
|
|||
|
||||
impl<V, I, F> StatelessInteractive<V> for Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V> {
|
||||
self.base.stateless_interaction()
|
||||
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
self.base.stateless_interactivity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, F> StatefulInteractive<V> for Svg<V, StatefulInteraction<V>, F>
|
||||
impl<V, F> StatefulInteractive<V> for Svg<V, StatefulInteractivity<V>, F>
|
||||
where
|
||||
V: 'static,
|
||||
F: ElementFocus<V>,
|
||||
{
|
||||
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V> {
|
||||
self.base.stateful_interaction()
|
||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||
self.base.stateful_interactivity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static, I> Focusable<V> for Svg<V, I, FocusEnabled<V>>
|
||||
where
|
||||
I: ElementInteraction<V>,
|
||||
I: ElementInteractivity<V>,
|
||||
{
|
||||
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
||||
self.base.focus_listeners()
|
||||
|
|
|
@ -74,7 +74,7 @@ impl<V: 'static> Element<V> for Text<V> {
|
|||
) -> LayoutId {
|
||||
let text_system = cx.text_system().clone();
|
||||
let text_style = cx.text_style();
|
||||
let font_size = text_style.font_size * cx.rem_size();
|
||||
let font_size = text_style.font_size.to_pixels(cx.rem_size());
|
||||
let line_height = text_style
|
||||
.line_height
|
||||
.to_pixels(font_size.into(), cx.rem_size());
|
||||
|
@ -127,6 +127,7 @@ impl<V: 'static> Element<V> for Text<V> {
|
|||
let element_state = element_state
|
||||
.as_ref()
|
||||
.expect("measurement has not been performed");
|
||||
|
||||
let line_height = element_state.line_height;
|
||||
let mut line_origin = bounds.origin;
|
||||
for line in &element_state.lines {
|
||||
|
|
244
crates/gpui2/src/elements/uniform_list.rs
Normal file
244
crates/gpui2/src/elements/uniform_list.rs
Normal file
|
@ -0,0 +1,244 @@
|
|||
use crate::{
|
||||
point, px, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
|
||||
ElementInteractivity, InteractiveElementState, LayoutId, Pixels, Point, Size,
|
||||
StatefulInteractive, StatefulInteractivity, StatelessInteractive, StatelessInteractivity,
|
||||
StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use smallvec::SmallVec;
|
||||
use std::{cmp, ops::Range, sync::Arc};
|
||||
use taffy::style::Overflow;
|
||||
|
||||
pub fn uniform_list<Id, V, C>(
|
||||
id: Id,
|
||||
item_count: usize,
|
||||
f: impl 'static + Fn(&mut V, Range<usize>, &mut ViewContext<V>) -> SmallVec<[C; 64]>,
|
||||
) -> UniformList<V>
|
||||
where
|
||||
Id: Into<ElementId>,
|
||||
V: 'static,
|
||||
C: Component<V>,
|
||||
{
|
||||
let id = id.into();
|
||||
UniformList {
|
||||
id: id.clone(),
|
||||
style: Default::default(),
|
||||
item_count,
|
||||
render_items: Box::new(move |view, visible_range, cx| {
|
||||
f(view, visible_range, cx)
|
||||
.into_iter()
|
||||
.map(|component| component.render())
|
||||
.collect()
|
||||
}),
|
||||
interactivity: id.into(),
|
||||
scroll_handle: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UniformList<V: 'static> {
|
||||
id: ElementId,
|
||||
style: StyleRefinement,
|
||||
item_count: usize,
|
||||
render_items: Box<
|
||||
dyn for<'a> Fn(
|
||||
&'a mut V,
|
||||
Range<usize>,
|
||||
&'a mut ViewContext<V>,
|
||||
) -> SmallVec<[AnyElement<V>; 64]>,
|
||||
>,
|
||||
interactivity: StatefulInteractivity<V>,
|
||||
scroll_handle: Option<UniformListScrollHandle>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UniformListScrollHandle(Arc<Mutex<Option<ScrollHandleState>>>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ScrollHandleState {
|
||||
item_height: Pixels,
|
||||
list_height: Pixels,
|
||||
scroll_offset: Arc<Mutex<Point<Pixels>>>,
|
||||
}
|
||||
|
||||
impl UniformListScrollHandle {
|
||||
pub fn new() -> Self {
|
||||
Self(Arc::new(Mutex::new(None)))
|
||||
}
|
||||
|
||||
pub fn scroll_to_item(&self, ix: usize) {
|
||||
if let Some(state) = &*self.0.lock() {
|
||||
let mut scroll_offset = state.scroll_offset.lock();
|
||||
let item_top = state.item_height * ix;
|
||||
let item_bottom = item_top + state.item_height;
|
||||
let scroll_top = -scroll_offset.y;
|
||||
if item_top < scroll_top {
|
||||
scroll_offset.y = -item_top;
|
||||
} else if item_bottom > scroll_top + state.list_height {
|
||||
scroll_offset.y = -(item_bottom - state.list_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Styled for UniformList<V> {
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
&mut self.style
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Element<V> for UniformList<V> {
|
||||
type ElementState = InteractiveElementState;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
Some(self.id.clone())
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
_: &mut V,
|
||||
element_state: Option<Self::ElementState>,
|
||||
_: &mut ViewContext<V>,
|
||||
) -> Self::ElementState {
|
||||
element_state.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
_view_state: &mut V,
|
||||
_element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> LayoutId {
|
||||
cx.request_layout(&self.computed_style(), None)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: crate::Bounds<crate::Pixels>,
|
||||
view_state: &mut V,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let style = self.computed_style();
|
||||
style.paint(bounds, cx);
|
||||
|
||||
let border = style.border_widths.to_pixels(cx.rem_size());
|
||||
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
||||
|
||||
let padded_bounds = Bounds::from_corners(
|
||||
bounds.origin + point(border.left + padding.left, border.top + padding.top),
|
||||
bounds.lower_right()
|
||||
- point(border.right + padding.right, border.bottom + padding.bottom),
|
||||
);
|
||||
|
||||
cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
|
||||
let content_size;
|
||||
if self.item_count > 0 {
|
||||
let item_height = self.measure_item_height(view_state, padded_bounds, cx);
|
||||
if let Some(scroll_handle) = self.scroll_handle.clone() {
|
||||
scroll_handle.0.lock().replace(ScrollHandleState {
|
||||
item_height,
|
||||
list_height: padded_bounds.size.height,
|
||||
scroll_offset: element_state.track_scroll_offset(),
|
||||
});
|
||||
}
|
||||
let visible_item_count = if item_height > px(0.) {
|
||||
(padded_bounds.size.height / item_height).ceil() as usize + 1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let scroll_offset = element_state
|
||||
.scroll_offset()
|
||||
.map_or((0.0).into(), |offset| offset.y);
|
||||
let first_visible_element_ix = (-scroll_offset / item_height).floor() as usize;
|
||||
let visible_range = first_visible_element_ix
|
||||
..cmp::min(
|
||||
first_visible_element_ix + visible_item_count,
|
||||
self.item_count,
|
||||
);
|
||||
|
||||
let mut items = (self.render_items)(view_state, visible_range.clone(), cx);
|
||||
|
||||
content_size = Size {
|
||||
width: padded_bounds.size.width,
|
||||
height: item_height * self.item_count,
|
||||
};
|
||||
|
||||
cx.with_z_index(1, |cx| {
|
||||
for (item, ix) in items.iter_mut().zip(visible_range) {
|
||||
item.initialize(view_state, cx);
|
||||
|
||||
let layout_id = item.layout(view_state, cx);
|
||||
cx.compute_layout(
|
||||
layout_id,
|
||||
Size {
|
||||
width: AvailableSpace::Definite(bounds.size.width),
|
||||
height: AvailableSpace::Definite(item_height),
|
||||
},
|
||||
);
|
||||
let offset =
|
||||
padded_bounds.origin + point(px(0.), item_height * ix + scroll_offset);
|
||||
cx.with_element_offset(Some(offset), |cx| item.paint(view_state, cx))
|
||||
}
|
||||
});
|
||||
} else {
|
||||
content_size = Size {
|
||||
width: bounds.size.width,
|
||||
height: px(0.),
|
||||
};
|
||||
}
|
||||
|
||||
let overflow = point(style.overflow.x, Overflow::Scroll);
|
||||
|
||||
cx.with_z_index(0, |cx| {
|
||||
self.interactivity
|
||||
.paint(bounds, content_size, overflow, element_state, cx);
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> UniformList<V> {
|
||||
fn measure_item_height(
|
||||
&self,
|
||||
view_state: &mut V,
|
||||
list_bounds: Bounds<Pixels>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Pixels {
|
||||
let mut items = (self.render_items)(view_state, 0..1, cx);
|
||||
debug_assert!(items.len() == 1);
|
||||
let mut item_to_measure = items.pop().unwrap();
|
||||
item_to_measure.initialize(view_state, cx);
|
||||
let layout_id = item_to_measure.layout(view_state, cx);
|
||||
cx.compute_layout(
|
||||
layout_id,
|
||||
Size {
|
||||
width: AvailableSpace::Definite(list_bounds.size.width),
|
||||
height: AvailableSpace::MinContent,
|
||||
},
|
||||
);
|
||||
cx.layout_bounds(layout_id).size.height
|
||||
}
|
||||
|
||||
pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self {
|
||||
self.scroll_handle = Some(handle);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> StatelessInteractive<V> for UniformList<V> {
|
||||
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
self.interactivity.as_stateless_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> StatefulInteractive<V> for UniformList<V> {
|
||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||
&mut self.interactivity
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Component<V> for UniformList<V> {
|
||||
fn render(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
|
@ -71,7 +71,8 @@ impl<T> Future for Task<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
type AnyLocalFuture<R> = Pin<Box<dyn 'static + Future<Output = R>>>;
|
||||
type AnyFuture<R> = Pin<Box<dyn 'static + Send + Future<Output = R>>>;
|
||||
impl BackgroundExecutor {
|
||||
pub fn new(dispatcher: Arc<dyn PlatformDispatcher>) -> Self {
|
||||
Self { dispatcher }
|
||||
|
@ -84,10 +85,16 @@ impl BackgroundExecutor {
|
|||
R: Send + 'static,
|
||||
{
|
||||
let dispatcher = self.dispatcher.clone();
|
||||
let (runnable, task) =
|
||||
async_task::spawn(future, move |runnable| dispatcher.dispatch(runnable));
|
||||
runnable.schedule();
|
||||
Task::Spawned(task)
|
||||
fn inner<R: Send + 'static>(
|
||||
dispatcher: Arc<dyn PlatformDispatcher>,
|
||||
future: AnyFuture<R>,
|
||||
) -> Task<R> {
|
||||
let (runnable, task) =
|
||||
async_task::spawn(future, move |runnable| dispatcher.dispatch(runnable));
|
||||
runnable.schedule();
|
||||
Task::Spawned(task)
|
||||
}
|
||||
inner::<R>(dispatcher, Box::pin(future))
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
|
@ -251,11 +258,17 @@ impl ForegroundExecutor {
|
|||
R: 'static,
|
||||
{
|
||||
let dispatcher = self.dispatcher.clone();
|
||||
let (runnable, task) = async_task::spawn_local(future, move |runnable| {
|
||||
dispatcher.dispatch_on_main_thread(runnable)
|
||||
});
|
||||
runnable.schedule();
|
||||
Task::Spawned(task)
|
||||
fn inner<R: 'static>(
|
||||
dispatcher: Arc<dyn PlatformDispatcher>,
|
||||
future: AnyLocalFuture<R>,
|
||||
) -> Task<R> {
|
||||
let (runnable, task) = async_task::spawn_local(future, move |runnable| {
|
||||
dispatcher.dispatch_on_main_thread(runnable)
|
||||
});
|
||||
runnable.schedule();
|
||||
Task::Spawned(task)
|
||||
}
|
||||
inner::<R>(dispatcher, Box::pin(future))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@ impl<T: Clone + Debug + Default> Point<T> {
|
|||
Self { x, y }
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Self::new(T::default(), T::default())
|
||||
}
|
||||
|
||||
pub fn map<U: Clone + Default + Debug>(&self, f: impl Fn(T) -> U) -> Point<U> {
|
||||
Point {
|
||||
x: f(self.x.clone()),
|
||||
|
@ -120,6 +124,10 @@ where
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clamp(&self, min: &Self, max: &Self) -> Self {
|
||||
self.max(min).min(max)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Default + Debug> Clone for Point<T> {
|
||||
|
@ -259,6 +267,24 @@ impl From<Size<Pixels>> for Size<GlobalPixels> {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Size<Pixels>> for Size<DefiniteLength> {
|
||||
fn from(size: Size<Pixels>) -> Self {
|
||||
Size {
|
||||
width: size.width.into(),
|
||||
height: size.height.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Size<Pixels>> for Size<AbsoluteLength> {
|
||||
fn from(size: Size<Pixels>) -> Self {
|
||||
Size {
|
||||
width: size.width.into(),
|
||||
height: size.height.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Size<Length> {
|
||||
pub fn full() -> Self {
|
||||
Self {
|
||||
|
@ -492,6 +518,15 @@ where
|
|||
impl<T: Clone + Default + Debug + Copy> Copy for Edges<T> {}
|
||||
|
||||
impl<T: Clone + Default + Debug> Edges<T> {
|
||||
pub fn all(value: T) -> Self {
|
||||
Self {
|
||||
top: value.clone(),
|
||||
right: value.clone(),
|
||||
bottom: value.clone(),
|
||||
left: value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map<U>(&self, f: impl Fn(&T) -> U) -> Edges<U>
|
||||
where
|
||||
U: Clone + Default + Debug,
|
||||
|
@ -541,6 +576,15 @@ impl Edges<DefiniteLength> {
|
|||
left: px(0.).into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_pixels(&self, parent_size: Size<AbsoluteLength>, rem_size: Pixels) -> Edges<Pixels> {
|
||||
Edges {
|
||||
top: self.top.to_pixels(parent_size.height, rem_size),
|
||||
right: self.right.to_pixels(parent_size.width, rem_size),
|
||||
bottom: self.bottom.to_pixels(parent_size.height, rem_size),
|
||||
left: self.left.to_pixels(parent_size.width, rem_size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Edges<AbsoluteLength> {
|
||||
|
@ -672,16 +716,16 @@ impl<T> Copy for Corners<T> where T: Copy + Clone + Default + Debug {}
|
|||
pub struct Pixels(pub(crate) f32);
|
||||
|
||||
impl std::ops::Div for Pixels {
|
||||
type Output = Self;
|
||||
type Output = f32;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 / rhs.0)
|
||||
self.0 / rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DivAssign for Pixels {
|
||||
fn div_assign(&mut self, rhs: Self) {
|
||||
self.0 /= rhs.0;
|
||||
*self = Self(self.0 / rhs.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -730,16 +774,9 @@ impl MulAssign<f32> for Pixels {
|
|||
}
|
||||
|
||||
impl Pixels {
|
||||
pub const ZERO: Pixels = Pixels(0.0);
|
||||
pub const MAX: Pixels = Pixels(f32::MAX);
|
||||
|
||||
pub fn as_usize(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
|
||||
pub fn as_isize(&self) -> isize {
|
||||
self.0 as isize
|
||||
}
|
||||
|
||||
pub fn floor(&self) -> Self {
|
||||
Self(self.0.floor())
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#[macro_use]
|
||||
mod action;
|
||||
mod app;
|
||||
mod assets;
|
||||
|
@ -23,6 +24,7 @@ mod text_system;
|
|||
mod util;
|
||||
mod view;
|
||||
mod window;
|
||||
mod window_input_handler;
|
||||
|
||||
mod private {
|
||||
/// A mechanism for restricting implementations of a trait to only those in GPUI.
|
||||
|
@ -35,6 +37,7 @@ pub use anyhow::Result;
|
|||
pub use app::*;
|
||||
pub use assets::*;
|
||||
pub use color::*;
|
||||
pub use ctor::ctor;
|
||||
pub use element::*;
|
||||
pub use elements::*;
|
||||
pub use executor::*;
|
||||
|
@ -63,6 +66,7 @@ pub use text_system::*;
|
|||
pub use util::arc_cow::ArcCow;
|
||||
pub use view::*;
|
||||
pub use window::*;
|
||||
pub use window_input_handler::*;
|
||||
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use std::{
|
||||
|
|
|
@ -25,13 +25,13 @@ const TOOLTIP_DELAY: Duration = Duration::from_millis(500);
|
|||
const TOOLTIP_OFFSET: Point<Pixels> = Point::new(px(10.0), px(8.0));
|
||||
|
||||
pub trait StatelessInteractive<V: 'static>: Element<V> {
|
||||
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V>;
|
||||
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V>;
|
||||
|
||||
fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction().hover_style = f(StyleRefinement::default());
|
||||
self.stateless_interactivity().hover_style = f(StyleRefinement::default());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction().group_hover_style = Some(GroupStyle {
|
||||
self.stateless_interactivity().group_hover_style = Some(GroupStyle {
|
||||
group: group_name.into(),
|
||||
style: f(StyleRefinement::default()),
|
||||
});
|
||||
|
@ -58,7 +58,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction()
|
||||
self.stateless_interactivity()
|
||||
.mouse_down_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
|
@ -79,7 +79,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction()
|
||||
self.stateless_interactivity()
|
||||
.mouse_up_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
|
@ -100,7 +100,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction()
|
||||
self.stateless_interactivity()
|
||||
.mouse_down_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
|
@ -121,7 +121,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction()
|
||||
self.stateless_interactivity()
|
||||
.mouse_up_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
|
@ -141,7 +141,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction()
|
||||
self.stateless_interactivity()
|
||||
.mouse_move_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
|
@ -158,7 +158,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction()
|
||||
self.stateless_interactivity()
|
||||
.scroll_wheel_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
|
@ -174,23 +174,48 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
C: TryInto<DispatchContext>,
|
||||
C::Error: Debug,
|
||||
{
|
||||
self.stateless_interaction().dispatch_context =
|
||||
self.stateless_interactivity().dispatch_context =
|
||||
context.try_into().expect("invalid dispatch context");
|
||||
self
|
||||
}
|
||||
|
||||
fn on_action<A: 'static>(
|
||||
/// Capture the given action, fires during the capture phase
|
||||
fn capture_action<A: 'static>(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &A, DispatchPhase, &mut ViewContext<V>) + 'static,
|
||||
listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction().key_listeners.push((
|
||||
self.stateless_interactivity().key_listeners.push((
|
||||
TypeId::of::<A>(),
|
||||
Box::new(move |view, event, _, phase, cx| {
|
||||
let event = event.downcast_ref().unwrap();
|
||||
listener(view, event, phase, cx);
|
||||
if phase == DispatchPhase::Capture {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
None
|
||||
}),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a listener for the given action, fires during the bubble event phase
|
||||
fn on_action<A: 'static>(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity().key_listeners.push((
|
||||
TypeId::of::<A>(),
|
||||
Box::new(move |view, event, _, phase, cx| {
|
||||
let event = event.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Bubble {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
|
||||
None
|
||||
}),
|
||||
));
|
||||
|
@ -204,7 +229,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction().key_listeners.push((
|
||||
self.stateless_interactivity().key_listeners.push((
|
||||
TypeId::of::<KeyDownEvent>(),
|
||||
Box::new(move |view, event, _, phase, cx| {
|
||||
let event = event.downcast_ref().unwrap();
|
||||
|
@ -222,7 +247,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction().key_listeners.push((
|
||||
self.stateless_interactivity().key_listeners.push((
|
||||
TypeId::of::<KeyUpEvent>(),
|
||||
Box::new(move |view, event, _, phase, cx| {
|
||||
let event = event.downcast_ref().unwrap();
|
||||
|
@ -237,7 +262,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction()
|
||||
self.stateless_interactivity()
|
||||
.drag_over_styles
|
||||
.push((TypeId::of::<S>(), f(StyleRefinement::default())));
|
||||
self
|
||||
|
@ -251,7 +276,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction().group_drag_over_styles.push((
|
||||
self.stateless_interactivity().group_drag_over_styles.push((
|
||||
TypeId::of::<S>(),
|
||||
GroupStyle {
|
||||
group: group_name.into(),
|
||||
|
@ -268,7 +293,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interaction().drop_listeners.push((
|
||||
self.stateless_interactivity().drop_listeners.push((
|
||||
TypeId::of::<W>(),
|
||||
Box::new(move |view, dragged_view, cx| {
|
||||
listener(view, dragged_view.downcast().unwrap(), cx);
|
||||
|
@ -279,13 +304,13 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
|
|||
}
|
||||
|
||||
pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
||||
fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V>;
|
||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V>;
|
||||
|
||||
fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateful_interaction().active_style = f(StyleRefinement::default());
|
||||
self.stateful_interactivity().active_style = f(StyleRefinement::default());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -297,7 +322,7 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateful_interaction().group_active_style = Some(GroupStyle {
|
||||
self.stateful_interactivity().group_active_style = Some(GroupStyle {
|
||||
group: group_name.into(),
|
||||
style: f(StyleRefinement::default()),
|
||||
});
|
||||
|
@ -311,7 +336,7 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateful_interaction()
|
||||
self.stateful_interactivity()
|
||||
.click_listeners
|
||||
.push(Box::new(move |view, event, cx| listener(view, event, cx)));
|
||||
self
|
||||
|
@ -326,10 +351,10 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||
W: 'static + Render,
|
||||
{
|
||||
debug_assert!(
|
||||
self.stateful_interaction().drag_listener.is_none(),
|
||||
self.stateful_interactivity().drag_listener.is_none(),
|
||||
"calling on_drag more than once on the same element is not supported"
|
||||
);
|
||||
self.stateful_interaction().drag_listener =
|
||||
self.stateful_interactivity().drag_listener =
|
||||
Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
|
||||
view: listener(view_state, cx).into(),
|
||||
cursor_offset,
|
||||
|
@ -342,10 +367,10 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||
Self: Sized,
|
||||
{
|
||||
debug_assert!(
|
||||
self.stateful_interaction().hover_listener.is_none(),
|
||||
self.stateful_interactivity().hover_listener.is_none(),
|
||||
"calling on_hover more than once on the same element is not supported"
|
||||
);
|
||||
self.stateful_interaction().hover_listener = Some(Box::new(listener));
|
||||
self.stateful_interactivity().hover_listener = Some(Box::new(listener));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -358,10 +383,10 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||
W: 'static + Render,
|
||||
{
|
||||
debug_assert!(
|
||||
self.stateful_interaction().tooltip_builder.is_none(),
|
||||
self.stateful_interactivity().tooltip_builder.is_none(),
|
||||
"calling tooltip more than once on the same element is not supported"
|
||||
);
|
||||
self.stateful_interaction().tooltip_builder = Some(Arc::new(move |view_state, cx| {
|
||||
self.stateful_interactivity().tooltip_builder = Some(Arc::new(move |view_state, cx| {
|
||||
build_tooltip(view_state, cx).into()
|
||||
}));
|
||||
|
||||
|
@ -369,11 +394,11 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ElementInteraction<V: 'static>: 'static {
|
||||
fn as_stateless(&self) -> &StatelessInteraction<V>;
|
||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V>;
|
||||
fn as_stateful(&self) -> Option<&StatefulInteraction<V>>;
|
||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>>;
|
||||
pub trait ElementInteractivity<V: 'static>: 'static {
|
||||
fn as_stateless(&self) -> &StatelessInteractivity<V>;
|
||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V>;
|
||||
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;
|
||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>>;
|
||||
|
||||
fn initialize<R>(
|
||||
&mut self,
|
||||
|
@ -397,9 +422,10 @@ pub trait ElementInteraction<V: 'static>: 'static {
|
|||
None
|
||||
}),
|
||||
));
|
||||
let result = stateful.stateless.initialize(cx, f);
|
||||
stateful.key_listeners.pop();
|
||||
result
|
||||
|
||||
cx.with_key_dispatch_context(stateful.dispatch_context.clone(), |cx| {
|
||||
cx.with_key_listeners(mem::take(&mut stateful.key_listeners), f)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
let stateless = self.as_stateless_mut();
|
||||
|
@ -735,11 +761,11 @@ pub trait ElementInteraction<V: 'static>: 'static {
|
|||
}
|
||||
|
||||
#[derive(Deref, DerefMut)]
|
||||
pub struct StatefulInteraction<V> {
|
||||
pub struct StatefulInteractivity<V> {
|
||||
pub id: ElementId,
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
stateless: StatelessInteraction<V>,
|
||||
stateless: StatelessInteractivity<V>,
|
||||
click_listeners: SmallVec<[ClickListener<V>; 2]>,
|
||||
active_style: StyleRefinement,
|
||||
group_active_style: Option<GroupStyle>,
|
||||
|
@ -748,29 +774,29 @@ pub struct StatefulInteraction<V> {
|
|||
tooltip_builder: Option<TooltipBuilder<V>>,
|
||||
}
|
||||
|
||||
impl<V: 'static> ElementInteraction<V> for StatefulInteraction<V> {
|
||||
fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
|
||||
impl<V: 'static> ElementInteractivity<V> for StatefulInteractivity<V> {
|
||||
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
|
||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn as_stateless(&self) -> &StatelessInteraction<V> {
|
||||
fn as_stateless(&self) -> &StatelessInteractivity<V> {
|
||||
&self.stateless
|
||||
}
|
||||
|
||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
|
||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
&mut self.stateless
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> From<ElementId> for StatefulInteraction<V> {
|
||||
impl<V> From<ElementId> for StatefulInteractivity<V> {
|
||||
fn from(id: ElementId) -> Self {
|
||||
Self {
|
||||
id,
|
||||
stateless: StatelessInteraction::default(),
|
||||
stateless: StatelessInteractivity::default(),
|
||||
click_listeners: SmallVec::new(),
|
||||
drag_listener: None,
|
||||
hover_listener: None,
|
||||
|
@ -783,7 +809,7 @@ impl<V> From<ElementId> for StatefulInteraction<V> {
|
|||
|
||||
type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
|
||||
|
||||
pub struct StatelessInteraction<V> {
|
||||
pub struct StatelessInteractivity<V> {
|
||||
pub dispatch_context: DispatchContext,
|
||||
pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
|
||||
pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
|
||||
|
@ -797,9 +823,9 @@ pub struct StatelessInteraction<V> {
|
|||
drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
|
||||
}
|
||||
|
||||
impl<V> StatelessInteraction<V> {
|
||||
pub fn into_stateful(self, id: impl Into<ElementId>) -> StatefulInteraction<V> {
|
||||
StatefulInteraction {
|
||||
impl<V> StatelessInteractivity<V> {
|
||||
pub fn into_stateful(self, id: impl Into<ElementId>) -> StatefulInteractivity<V> {
|
||||
StatefulInteractivity {
|
||||
id: id.into(),
|
||||
stateless: self,
|
||||
click_listeners: SmallVec::new(),
|
||||
|
@ -875,9 +901,15 @@ impl InteractiveElementState {
|
|||
.as_ref()
|
||||
.map(|offset| offset.lock().clone())
|
||||
}
|
||||
|
||||
pub fn track_scroll_offset(&mut self) -> Arc<Mutex<Point<Pixels>>> {
|
||||
self.scroll_offset
|
||||
.get_or_insert_with(|| Arc::new(Mutex::new(Default::default())))
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Default for StatelessInteraction<V> {
|
||||
impl<V> Default for StatelessInteractivity<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dispatch_context: DispatchContext::default(),
|
||||
|
@ -895,20 +927,20 @@ impl<V> Default for StatelessInteraction<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ElementInteraction<V> for StatelessInteraction<V> {
|
||||
fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
|
||||
impl<V: 'static> ElementInteractivity<V> for StatelessInteractivity<V> {
|
||||
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
|
||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_stateless(&self) -> &StatelessInteraction<V> {
|
||||
fn as_stateless(&self) -> &StatelessInteractivity<V> {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
|
||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1230,3 +1262,70 @@ pub type KeyListener<V> = Box<
|
|||
) -> Option<Box<dyn Action>>
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{
|
||||
self as gpui, div, Div, FocusHandle, KeyBinding, Keystroke, ParentElement, Render,
|
||||
StatefulInteractivity, StatelessInteractive, TestAppContext, VisualContext,
|
||||
};
|
||||
|
||||
struct TestView {
|
||||
saw_key_down: bool,
|
||||
saw_action: bool,
|
||||
focus_handle: FocusHandle,
|
||||
}
|
||||
|
||||
actions!(TestAction);
|
||||
|
||||
impl Render for TestView {
|
||||
type Element = Div<Self, StatefulInteractivity<Self>>;
|
||||
|
||||
fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
div().id("testview").child(
|
||||
div()
|
||||
.on_key_down(|this: &mut TestView, _, _, _| {
|
||||
dbg!("ola!");
|
||||
this.saw_key_down = true
|
||||
})
|
||||
.on_action(|this: &mut TestView, _: &TestAction, _| {
|
||||
dbg!("ola!");
|
||||
this.saw_action = true
|
||||
})
|
||||
.track_focus(&self.focus_handle),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_on_events(cx: &mut TestAppContext) {
|
||||
let window = cx.update(|cx| {
|
||||
cx.open_window(Default::default(), |cx| {
|
||||
cx.build_view(|cx| TestView {
|
||||
saw_key_down: false,
|
||||
saw_action: false,
|
||||
focus_handle: cx.focus_handle(),
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
cx.update(|cx| {
|
||||
cx.bind_keys(vec![KeyBinding::new("ctrl-g", TestAction, None)]);
|
||||
});
|
||||
|
||||
window
|
||||
.update(cx, |test_view, cx| cx.focus(&test_view.focus_handle))
|
||||
.unwrap();
|
||||
|
||||
cx.dispatch_keystroke(*window, Keystroke::parse("space").unwrap(), false);
|
||||
cx.dispatch_keystroke(*window, Keystroke::parse("ctrl-g").unwrap(), false);
|
||||
|
||||
window
|
||||
.update(cx, |test_view, _| {
|
||||
assert!(test_view.saw_key_down || test_view.saw_action);
|
||||
assert!(test_view.saw_key_down);
|
||||
assert!(test_view.saw_action);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ impl MetalRenderer {
|
|||
MTLResourceOptions::StorageModeManaged,
|
||||
);
|
||||
|
||||
let paths_rasterization_pipeline_state = build_pipeline_state(
|
||||
let paths_rasterization_pipeline_state = build_path_rasterization_pipeline_state(
|
||||
&device,
|
||||
&library,
|
||||
"paths_rasterization",
|
||||
|
@ -823,7 +823,40 @@ fn build_pipeline_state(
|
|||
color_attachment.set_source_alpha_blend_factor(metal::MTLBlendFactor::One);
|
||||
color_attachment.set_destination_rgb_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha);
|
||||
color_attachment.set_destination_alpha_blend_factor(metal::MTLBlendFactor::One);
|
||||
descriptor.set_depth_attachment_pixel_format(MTLPixelFormat::Invalid);
|
||||
|
||||
device
|
||||
.new_render_pipeline_state(&descriptor)
|
||||
.expect("could not create render pipeline state")
|
||||
}
|
||||
|
||||
fn build_path_rasterization_pipeline_state(
|
||||
device: &metal::DeviceRef,
|
||||
library: &metal::LibraryRef,
|
||||
label: &str,
|
||||
vertex_fn_name: &str,
|
||||
fragment_fn_name: &str,
|
||||
pixel_format: metal::MTLPixelFormat,
|
||||
) -> metal::RenderPipelineState {
|
||||
let vertex_fn = library
|
||||
.get_function(vertex_fn_name, None)
|
||||
.expect("error locating vertex function");
|
||||
let fragment_fn = library
|
||||
.get_function(fragment_fn_name, None)
|
||||
.expect("error locating fragment function");
|
||||
|
||||
let descriptor = metal::RenderPipelineDescriptor::new();
|
||||
descriptor.set_label(label);
|
||||
descriptor.set_vertex_function(Some(vertex_fn.as_ref()));
|
||||
descriptor.set_fragment_function(Some(fragment_fn.as_ref()));
|
||||
let color_attachment = descriptor.color_attachments().object_at(0).unwrap();
|
||||
color_attachment.set_pixel_format(pixel_format);
|
||||
color_attachment.set_blending_enabled(true);
|
||||
color_attachment.set_rgb_blend_operation(metal::MTLBlendOperation::Add);
|
||||
color_attachment.set_alpha_blend_operation(metal::MTLBlendOperation::Add);
|
||||
color_attachment.set_source_rgb_blend_factor(metal::MTLBlendFactor::One);
|
||||
color_attachment.set_source_alpha_blend_factor(metal::MTLBlendFactor::One);
|
||||
color_attachment.set_destination_rgb_blend_factor(metal::MTLBlendFactor::One);
|
||||
color_attachment.set_destination_alpha_blend_factor(metal::MTLBlendFactor::One);
|
||||
|
||||
device
|
||||
.new_render_pipeline_state(&descriptor)
|
||||
|
|
|
@ -5,10 +5,11 @@ using namespace metal;
|
|||
|
||||
float4 hsla_to_rgba(Hsla hsla);
|
||||
float4 to_device_position(float2 unit_vertex, Bounds_ScaledPixels bounds,
|
||||
Bounds_ScaledPixels clip_bounds,
|
||||
constant Size_DevicePixels *viewport_size);
|
||||
float2 to_tile_position(float2 unit_vertex, AtlasTile tile,
|
||||
constant Size_DevicePixels *atlas_size);
|
||||
float4 distance_from_clip_rect(float2 unit_vertex, Bounds_ScaledPixels bounds,
|
||||
Bounds_ScaledPixels clip_bounds);
|
||||
float quad_sdf(float2 point, Bounds_ScaledPixels bounds,
|
||||
Corners_ScaledPixels corner_radii);
|
||||
float gaussian(float x, float sigma);
|
||||
|
@ -21,6 +22,14 @@ struct QuadVertexOutput {
|
|||
float4 background_color [[flat]];
|
||||
float4 border_color [[flat]];
|
||||
uint quad_id [[flat]];
|
||||
float clip_distance [[clip_distance]][4];
|
||||
};
|
||||
|
||||
struct QuadFragmentInput {
|
||||
float4 position [[position]];
|
||||
float4 background_color [[flat]];
|
||||
float4 border_color [[flat]];
|
||||
uint quad_id [[flat]];
|
||||
};
|
||||
|
||||
vertex QuadVertexOutput quad_vertex(uint unit_vertex_id [[vertex_id]],
|
||||
|
@ -33,15 +42,21 @@ vertex QuadVertexOutput quad_vertex(uint unit_vertex_id [[vertex_id]],
|
|||
[[buffer(QuadInputIndex_ViewportSize)]]) {
|
||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||
Quad quad = quads[quad_id];
|
||||
float4 device_position = to_device_position(
|
||||
unit_vertex, quad.bounds, quad.content_mask.bounds, viewport_size);
|
||||
float4 device_position =
|
||||
to_device_position(unit_vertex, quad.bounds, viewport_size);
|
||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds,
|
||||
quad.content_mask.bounds);
|
||||
float4 background_color = hsla_to_rgba(quad.background);
|
||||
float4 border_color = hsla_to_rgba(quad.border_color);
|
||||
return QuadVertexOutput{device_position, background_color, border_color,
|
||||
quad_id};
|
||||
return QuadVertexOutput{
|
||||
device_position,
|
||||
background_color,
|
||||
border_color,
|
||||
quad_id,
|
||||
{clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};
|
||||
}
|
||||
|
||||
fragment float4 quad_fragment(QuadVertexOutput input [[stage_in]],
|
||||
fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]],
|
||||
constant Quad *quads
|
||||
[[buffer(QuadInputIndex_Quads)]]) {
|
||||
Quad quad = quads[input.quad_id];
|
||||
|
@ -117,6 +132,13 @@ struct ShadowVertexOutput {
|
|||
float4 position [[position]];
|
||||
float4 color [[flat]];
|
||||
uint shadow_id [[flat]];
|
||||
float clip_distance [[clip_distance]][4];
|
||||
};
|
||||
|
||||
struct ShadowFragmentInput {
|
||||
float4 position [[position]];
|
||||
float4 color [[flat]];
|
||||
uint shadow_id [[flat]];
|
||||
};
|
||||
|
||||
vertex ShadowVertexOutput shadow_vertex(
|
||||
|
@ -137,18 +159,20 @@ vertex ShadowVertexOutput shadow_vertex(
|
|||
bounds.size.width += 2. * margin;
|
||||
bounds.size.height += 2. * margin;
|
||||
|
||||
float4 device_position = to_device_position(
|
||||
unit_vertex, bounds, shadow.content_mask.bounds, viewport_size);
|
||||
float4 device_position =
|
||||
to_device_position(unit_vertex, bounds, viewport_size);
|
||||
float4 clip_distance =
|
||||
distance_from_clip_rect(unit_vertex, bounds, shadow.content_mask.bounds);
|
||||
float4 color = hsla_to_rgba(shadow.color);
|
||||
|
||||
return ShadowVertexOutput{
|
||||
device_position,
|
||||
color,
|
||||
shadow_id,
|
||||
};
|
||||
{clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};
|
||||
}
|
||||
|
||||
fragment float4 shadow_fragment(ShadowVertexOutput input [[stage_in]],
|
||||
fragment float4 shadow_fragment(ShadowFragmentInput input [[stage_in]],
|
||||
constant Shadow *shadows
|
||||
[[buffer(ShadowInputIndex_Shadows)]]) {
|
||||
Shadow shadow = shadows[input.shadow_id];
|
||||
|
@ -197,6 +221,13 @@ struct UnderlineVertexOutput {
|
|||
float4 position [[position]];
|
||||
float4 color [[flat]];
|
||||
uint underline_id [[flat]];
|
||||
float clip_distance [[clip_distance]][4];
|
||||
};
|
||||
|
||||
struct UnderlineFragmentInput {
|
||||
float4 position [[position]];
|
||||
float4 color [[flat]];
|
||||
uint underline_id [[flat]];
|
||||
};
|
||||
|
||||
vertex UnderlineVertexOutput underline_vertex(
|
||||
|
@ -208,13 +239,18 @@ vertex UnderlineVertexOutput underline_vertex(
|
|||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||
Underline underline = underlines[underline_id];
|
||||
float4 device_position =
|
||||
to_device_position(unit_vertex, underline.bounds,
|
||||
underline.content_mask.bounds, viewport_size);
|
||||
to_device_position(unit_vertex, underline.bounds, viewport_size);
|
||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, underline.bounds,
|
||||
underline.content_mask.bounds);
|
||||
float4 color = hsla_to_rgba(underline.color);
|
||||
return UnderlineVertexOutput{device_position, color, underline_id};
|
||||
return UnderlineVertexOutput{
|
||||
device_position,
|
||||
color,
|
||||
underline_id,
|
||||
{clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};
|
||||
}
|
||||
|
||||
fragment float4 underline_fragment(UnderlineVertexOutput input [[stage_in]],
|
||||
fragment float4 underline_fragment(UnderlineFragmentInput input [[stage_in]],
|
||||
constant Underline *underlines
|
||||
[[buffer(UnderlineInputIndex_Underlines)]]) {
|
||||
Underline underline = underlines[input.underline_id];
|
||||
|
@ -244,7 +280,13 @@ struct MonochromeSpriteVertexOutput {
|
|||
float4 position [[position]];
|
||||
float2 tile_position;
|
||||
float4 color [[flat]];
|
||||
uint sprite_id [[flat]];
|
||||
float clip_distance [[clip_distance]][4];
|
||||
};
|
||||
|
||||
struct MonochromeSpriteFragmentInput {
|
||||
float4 position [[position]];
|
||||
float2 tile_position;
|
||||
float4 color [[flat]];
|
||||
};
|
||||
|
||||
vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex(
|
||||
|
@ -255,32 +297,31 @@ vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex(
|
|||
[[buffer(SpriteInputIndex_ViewportSize)]],
|
||||
constant Size_DevicePixels *atlas_size
|
||||
[[buffer(SpriteInputIndex_AtlasTextureSize)]]) {
|
||||
|
||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||
MonochromeSprite sprite = sprites[sprite_id];
|
||||
// Don't apply content mask at the vertex level because we don't have time
|
||||
// to make sampling from the texture match the mask.
|
||||
float4 device_position = to_device_position(unit_vertex, sprite.bounds,
|
||||
sprite.bounds, viewport_size);
|
||||
float4 device_position =
|
||||
to_device_position(unit_vertex, sprite.bounds, viewport_size);
|
||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds,
|
||||
sprite.content_mask.bounds);
|
||||
float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size);
|
||||
float4 color = hsla_to_rgba(sprite.color);
|
||||
return MonochromeSpriteVertexOutput{device_position, tile_position, color,
|
||||
sprite_id};
|
||||
return MonochromeSpriteVertexOutput{
|
||||
device_position,
|
||||
tile_position,
|
||||
color,
|
||||
{clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};
|
||||
}
|
||||
|
||||
fragment float4 monochrome_sprite_fragment(
|
||||
MonochromeSpriteVertexOutput input [[stage_in]],
|
||||
MonochromeSpriteFragmentInput input [[stage_in]],
|
||||
constant MonochromeSprite *sprites [[buffer(SpriteInputIndex_Sprites)]],
|
||||
texture2d<float> atlas_texture [[texture(SpriteInputIndex_AtlasTexture)]]) {
|
||||
MonochromeSprite sprite = sprites[input.sprite_id];
|
||||
constexpr sampler atlas_texture_sampler(mag_filter::linear,
|
||||
min_filter::linear);
|
||||
float4 sample =
|
||||
atlas_texture.sample(atlas_texture_sampler, input.tile_position);
|
||||
float clip_distance = quad_sdf(input.position.xy, sprite.content_mask.bounds,
|
||||
Corners_ScaledPixels{0., 0., 0., 0.});
|
||||
float4 color = input.color;
|
||||
color.a *= sample.a * saturate(0.5 - clip_distance);
|
||||
color.a *= sample.a;
|
||||
return color;
|
||||
}
|
||||
|
||||
|
@ -288,6 +329,13 @@ struct PolychromeSpriteVertexOutput {
|
|||
float4 position [[position]];
|
||||
float2 tile_position;
|
||||
uint sprite_id [[flat]];
|
||||
float clip_distance [[clip_distance]][4];
|
||||
};
|
||||
|
||||
struct PolychromeSpriteFragmentInput {
|
||||
float4 position [[position]];
|
||||
float2 tile_position;
|
||||
uint sprite_id [[flat]];
|
||||
};
|
||||
|
||||
vertex PolychromeSpriteVertexOutput polychrome_sprite_vertex(
|
||||
|
@ -301,17 +349,20 @@ vertex PolychromeSpriteVertexOutput polychrome_sprite_vertex(
|
|||
|
||||
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||
PolychromeSprite sprite = sprites[sprite_id];
|
||||
// Don't apply content mask at the vertex level because we don't have time
|
||||
// to make sampling from the texture match the mask.
|
||||
float4 device_position = to_device_position(unit_vertex, sprite.bounds,
|
||||
sprite.bounds, viewport_size);
|
||||
float4 device_position =
|
||||
to_device_position(unit_vertex, sprite.bounds, viewport_size);
|
||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds,
|
||||
sprite.content_mask.bounds);
|
||||
float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size);
|
||||
return PolychromeSpriteVertexOutput{device_position, tile_position,
|
||||
sprite_id};
|
||||
return PolychromeSpriteVertexOutput{
|
||||
device_position,
|
||||
tile_position,
|
||||
sprite_id,
|
||||
{clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};
|
||||
}
|
||||
|
||||
fragment float4 polychrome_sprite_fragment(
|
||||
PolychromeSpriteVertexOutput input [[stage_in]],
|
||||
PolychromeSpriteFragmentInput input [[stage_in]],
|
||||
constant PolychromeSprite *sprites [[buffer(SpriteInputIndex_Sprites)]],
|
||||
texture2d<float> atlas_texture [[texture(SpriteInputIndex_AtlasTexture)]]) {
|
||||
PolychromeSprite sprite = sprites[input.sprite_id];
|
||||
|
@ -319,11 +370,8 @@ fragment float4 polychrome_sprite_fragment(
|
|||
min_filter::linear);
|
||||
float4 sample =
|
||||
atlas_texture.sample(atlas_texture_sampler, input.tile_position);
|
||||
float quad_distance =
|
||||
float distance =
|
||||
quad_sdf(input.position.xy, sprite.bounds, sprite.corner_radii);
|
||||
float clip_distance = quad_sdf(input.position.xy, sprite.content_mask.bounds,
|
||||
Corners_ScaledPixels{0., 0., 0., 0.});
|
||||
float distance = max(quad_distance, clip_distance);
|
||||
|
||||
float4 color = sample;
|
||||
if (sprite.grayscale) {
|
||||
|
@ -385,7 +433,6 @@ struct PathSpriteVertexOutput {
|
|||
float4 position [[position]];
|
||||
float2 tile_position;
|
||||
float4 color [[flat]];
|
||||
uint sprite_id [[flat]];
|
||||
};
|
||||
|
||||
vertex PathSpriteVertexOutput path_sprite_vertex(
|
||||
|
@ -401,19 +448,17 @@ vertex PathSpriteVertexOutput path_sprite_vertex(
|
|||
PathSprite sprite = sprites[sprite_id];
|
||||
// Don't apply content mask because it was already accounted for when
|
||||
// rasterizing the path.
|
||||
float4 device_position = to_device_position(unit_vertex, sprite.bounds,
|
||||
sprite.bounds, viewport_size);
|
||||
float4 device_position =
|
||||
to_device_position(unit_vertex, sprite.bounds, viewport_size);
|
||||
float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size);
|
||||
float4 color = hsla_to_rgba(sprite.color);
|
||||
return PathSpriteVertexOutput{device_position, tile_position, color,
|
||||
sprite_id};
|
||||
return PathSpriteVertexOutput{device_position, tile_position, color};
|
||||
}
|
||||
|
||||
fragment float4 path_sprite_fragment(
|
||||
PathSpriteVertexOutput input [[stage_in]],
|
||||
constant PathSprite *sprites [[buffer(SpriteInputIndex_Sprites)]],
|
||||
texture2d<float> atlas_texture [[texture(SpriteInputIndex_AtlasTexture)]]) {
|
||||
PathSprite sprite = sprites[input.sprite_id];
|
||||
constexpr sampler atlas_texture_sampler(mag_filter::linear,
|
||||
min_filter::linear);
|
||||
float4 sample =
|
||||
|
@ -473,16 +518,10 @@ float4 hsla_to_rgba(Hsla hsla) {
|
|||
}
|
||||
|
||||
float4 to_device_position(float2 unit_vertex, Bounds_ScaledPixels bounds,
|
||||
Bounds_ScaledPixels clip_bounds,
|
||||
constant Size_DevicePixels *input_viewport_size) {
|
||||
float2 position =
|
||||
unit_vertex * float2(bounds.size.width, bounds.size.height) +
|
||||
float2(bounds.origin.x, bounds.origin.y);
|
||||
position.x = max(clip_bounds.origin.x, position.x);
|
||||
position.x = min(clip_bounds.origin.x + clip_bounds.size.width, position.x);
|
||||
position.y = max(clip_bounds.origin.y, position.y);
|
||||
position.y = min(clip_bounds.origin.y + clip_bounds.size.height, position.y);
|
||||
|
||||
float2 viewport_size = float2((float)input_viewport_size->width,
|
||||
(float)input_viewport_size->height);
|
||||
float2 device_position =
|
||||
|
@ -551,3 +590,14 @@ float blur_along_x(float x, float y, float sigma, float corner,
|
|||
0.5 + 0.5 * erf((x + float2(-curved, curved)) * (sqrt(0.5) / sigma));
|
||||
return integral.y - integral.x;
|
||||
}
|
||||
|
||||
float4 distance_from_clip_rect(float2 unit_vertex, Bounds_ScaledPixels bounds,
|
||||
Bounds_ScaledPixels clip_bounds) {
|
||||
float2 position =
|
||||
unit_vertex * float2(bounds.size.width, bounds.size.height) +
|
||||
float2(bounds.origin.x, bounds.origin.y);
|
||||
return float4(position.x - clip_bounds.origin.x,
|
||||
clip_bounds.origin.x + clip_bounds.size.width - position.x,
|
||||
position.y - clip_bounds.origin.y,
|
||||
clip_bounds.origin.y + clip_bounds.size.height - position.y);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
mod dispatcher;
|
||||
mod display;
|
||||
mod platform;
|
||||
mod window;
|
||||
|
||||
pub use dispatcher::*;
|
||||
pub use display::*;
|
||||
pub use platform::*;
|
||||
pub use window::*;
|
||||
|
|
41
crates/gpui2/src/platform/test/display.rs
Normal file
41
crates/gpui2/src/platform/test/display.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use anyhow::{Ok, Result};
|
||||
|
||||
use crate::{Bounds, DisplayId, GlobalPixels, PlatformDisplay, Point};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TestDisplay {
|
||||
id: DisplayId,
|
||||
uuid: uuid::Uuid,
|
||||
bounds: Bounds<GlobalPixels>,
|
||||
}
|
||||
|
||||
impl TestDisplay {
|
||||
pub fn new() -> Self {
|
||||
TestDisplay {
|
||||
id: DisplayId(1),
|
||||
uuid: uuid::Uuid::new_v4(),
|
||||
bounds: Bounds::from_corners(
|
||||
Point::zero(),
|
||||
Point::new(GlobalPixels(1920.), GlobalPixels(1080.)),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformDisplay for TestDisplay {
|
||||
fn id(&self) -> crate::DisplayId {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn uuid(&self) -> Result<uuid::Uuid> {
|
||||
Ok(self.uuid)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn bounds(&self) -> crate::Bounds<crate::GlobalPixels> {
|
||||
self.bounds
|
||||
}
|
||||
}
|
|
@ -1,10 +1,18 @@
|
|||
use crate::{BackgroundExecutor, DisplayId, ForegroundExecutor, Platform, PlatformTextSystem};
|
||||
use crate::{
|
||||
AnyWindowHandle, BackgroundExecutor, CursorStyle, DisplayId, ForegroundExecutor, Platform,
|
||||
PlatformDisplay, PlatformTextSystem, TestDisplay, TestWindow, WindowOptions,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::sync::Arc;
|
||||
use parking_lot::Mutex;
|
||||
use std::{rc::Rc, sync::Arc};
|
||||
|
||||
pub struct TestPlatform {
|
||||
background_executor: BackgroundExecutor,
|
||||
foreground_executor: ForegroundExecutor,
|
||||
|
||||
active_window: Arc<Mutex<Option<AnyWindowHandle>>>,
|
||||
active_display: Rc<dyn PlatformDisplay>,
|
||||
active_cursor: Mutex<CursorStyle>,
|
||||
}
|
||||
|
||||
impl TestPlatform {
|
||||
|
@ -12,6 +20,10 @@ impl TestPlatform {
|
|||
TestPlatform {
|
||||
background_executor: executor,
|
||||
foreground_executor,
|
||||
|
||||
active_cursor: Default::default(),
|
||||
active_display: Rc::new(TestDisplay::new()),
|
||||
active_window: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,11 +71,11 @@ impl Platform for TestPlatform {
|
|||
}
|
||||
|
||||
fn displays(&self) -> Vec<std::rc::Rc<dyn crate::PlatformDisplay>> {
|
||||
unimplemented!()
|
||||
vec![self.active_display.clone()]
|
||||
}
|
||||
|
||||
fn display(&self, _id: DisplayId) -> Option<std::rc::Rc<dyn crate::PlatformDisplay>> {
|
||||
unimplemented!()
|
||||
fn display(&self, id: DisplayId) -> Option<std::rc::Rc<dyn crate::PlatformDisplay>> {
|
||||
self.displays().iter().find(|d| d.id() == id).cloned()
|
||||
}
|
||||
|
||||
fn main_window(&self) -> Option<crate::AnyWindowHandle> {
|
||||
|
@ -72,10 +84,11 @@ impl Platform for TestPlatform {
|
|||
|
||||
fn open_window(
|
||||
&self,
|
||||
_handle: crate::AnyWindowHandle,
|
||||
_options: crate::WindowOptions,
|
||||
handle: AnyWindowHandle,
|
||||
options: WindowOptions,
|
||||
) -> Box<dyn crate::PlatformWindow> {
|
||||
unimplemented!()
|
||||
*self.active_window.lock() = Some(handle);
|
||||
Box::new(TestWindow::new(options, self.active_display.clone()))
|
||||
}
|
||||
|
||||
fn set_display_link_output_callback(
|
||||
|
@ -164,8 +177,8 @@ impl Platform for TestPlatform {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_cursor_style(&self, _style: crate::CursorStyle) {
|
||||
unimplemented!()
|
||||
fn set_cursor_style(&self, style: crate::CursorStyle) {
|
||||
*self.active_cursor.lock() = style;
|
||||
}
|
||||
|
||||
fn should_auto_hide_scrollbars(&self) -> bool {
|
||||
|
|
179
crates/gpui2/src/platform/test/window.rs
Normal file
179
crates/gpui2/src/platform/test/window.rs
Normal file
|
@ -0,0 +1,179 @@
|
|||
use std::{rc::Rc, sync::Arc};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::{
|
||||
px, Pixels, PlatformAtlas, PlatformDisplay, PlatformWindow, Point, Scene, Size,
|
||||
WindowAppearance, WindowBounds, WindowOptions,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
struct Handlers {
|
||||
active_status_change: Vec<Box<dyn FnMut(bool)>>,
|
||||
input: Vec<Box<dyn FnMut(crate::InputEvent) -> bool>>,
|
||||
moved: Vec<Box<dyn FnMut()>>,
|
||||
resize: Vec<Box<dyn FnMut(Size<Pixels>, f32)>>,
|
||||
}
|
||||
|
||||
pub struct TestWindow {
|
||||
bounds: WindowBounds,
|
||||
current_scene: Mutex<Option<Scene>>,
|
||||
display: Rc<dyn PlatformDisplay>,
|
||||
|
||||
handlers: Mutex<Handlers>,
|
||||
sprite_atlas: Arc<dyn PlatformAtlas>,
|
||||
}
|
||||
impl TestWindow {
|
||||
pub fn new(options: WindowOptions, display: Rc<dyn PlatformDisplay>) -> Self {
|
||||
Self {
|
||||
bounds: options.bounds,
|
||||
current_scene: Default::default(),
|
||||
display,
|
||||
|
||||
sprite_atlas: Arc::new(TestAtlas),
|
||||
handlers: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformWindow for TestWindow {
|
||||
fn bounds(&self) -> WindowBounds {
|
||||
self.bounds
|
||||
}
|
||||
|
||||
fn content_size(&self) -> Size<Pixels> {
|
||||
let bounds = match self.bounds {
|
||||
WindowBounds::Fixed(bounds) => bounds,
|
||||
WindowBounds::Maximized | WindowBounds::Fullscreen => self.display().bounds(),
|
||||
};
|
||||
bounds.size.map(|p| px(p.0))
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f32 {
|
||||
2.0
|
||||
}
|
||||
|
||||
fn titlebar_height(&self) -> Pixels {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn appearance(&self) -> WindowAppearance {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn display(&self) -> std::rc::Rc<dyn crate::PlatformDisplay> {
|
||||
self.display.clone()
|
||||
}
|
||||
|
||||
fn mouse_position(&self) -> Point<Pixels> {
|
||||
Point::zero()
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_input_handler(&mut self, _input_handler: Box<dyn crate::PlatformInputHandler>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn prompt(
|
||||
&self,
|
||||
_level: crate::PromptLevel,
|
||||
_msg: &str,
|
||||
_answers: &[&str],
|
||||
) -> futures::channel::oneshot::Receiver<usize> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn activate(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_title(&mut self, _title: &str) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_edited(&mut self, _edited: bool) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn show_character_palette(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn minimize(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn zoom(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn toggle_full_screen(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn on_input(&self, callback: Box<dyn FnMut(crate::InputEvent) -> bool>) {
|
||||
self.handlers.lock().input.push(callback)
|
||||
}
|
||||
|
||||
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
|
||||
self.handlers.lock().active_status_change.push(callback)
|
||||
}
|
||||
|
||||
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
|
||||
self.handlers.lock().resize.push(callback)
|
||||
}
|
||||
|
||||
fn on_fullscreen(&self, _callback: Box<dyn FnMut(bool)>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn on_moved(&self, callback: Box<dyn FnMut()>) {
|
||||
self.handlers.lock().moved.push(callback)
|
||||
}
|
||||
|
||||
fn on_should_close(&self, _callback: Box<dyn FnMut() -> bool>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn on_close(&self, _callback: Box<dyn FnOnce()>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn on_appearance_changed(&self, _callback: Box<dyn FnMut()>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_topmost_for_position(&self, _position: crate::Point<Pixels>) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn draw(&self, scene: crate::Scene) {
|
||||
self.current_scene.lock().replace(scene);
|
||||
}
|
||||
|
||||
fn sprite_atlas(&self) -> std::sync::Arc<dyn crate::PlatformAtlas> {
|
||||
self.sprite_atlas.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestAtlas;
|
||||
|
||||
impl PlatformAtlas for TestAtlas {
|
||||
fn get_or_insert_with<'a>(
|
||||
&self,
|
||||
_key: &crate::AtlasKey,
|
||||
_build: &mut dyn FnMut() -> anyhow::Result<(
|
||||
Size<crate::DevicePixels>,
|
||||
std::borrow::Cow<'a, [u8]>,
|
||||
)>,
|
||||
) -> anyhow::Result<crate::AtlasTile> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn clear(&self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
use crate::{
|
||||
black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask,
|
||||
Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font,
|
||||
FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems,
|
||||
Result, Rgba, SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext, WindowContext,
|
||||
FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Result,
|
||||
Rgba, SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext, WindowContext,
|
||||
};
|
||||
use refineable::{Cascade, Refineable};
|
||||
use smallvec::SmallVec;
|
||||
|
@ -134,7 +134,7 @@ pub struct TextStyle {
|
|||
pub color: Hsla,
|
||||
pub font_family: SharedString,
|
||||
pub font_features: FontFeatures,
|
||||
pub font_size: Rems,
|
||||
pub font_size: AbsoluteLength,
|
||||
pub line_height: DefiniteLength,
|
||||
pub font_weight: FontWeight,
|
||||
pub font_style: FontStyle,
|
||||
|
@ -147,7 +147,7 @@ impl Default for TextStyle {
|
|||
color: black(),
|
||||
font_family: "Helvetica".into(), // todo!("Get a font we know exists on the system")
|
||||
font_features: FontFeatures::default(),
|
||||
font_size: rems(1.),
|
||||
font_size: rems(1.).into(),
|
||||
line_height: phi(),
|
||||
font_weight: FontWeight::default(),
|
||||
font_style: FontStyle::default(),
|
||||
|
@ -189,6 +189,10 @@ impl TextStyle {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn line_height_in_pixels(&self, rem_size: Pixels) -> Pixels {
|
||||
self.line_height.to_pixels(self.font_size, rem_size)
|
||||
}
|
||||
|
||||
pub fn to_run(&self, len: usize) -> TextRun {
|
||||
TextRun {
|
||||
len,
|
||||
|
@ -277,7 +281,7 @@ impl Style {
|
|||
pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
|
||||
let rem_size = cx.rem_size();
|
||||
|
||||
cx.stack(0, |cx| {
|
||||
cx.with_z_index(0, |cx| {
|
||||
cx.paint_shadows(
|
||||
bounds,
|
||||
self.corner_radii.to_pixels(bounds.size, rem_size),
|
||||
|
@ -287,7 +291,7 @@ impl Style {
|
|||
|
||||
let background_color = self.background.as_ref().and_then(Fill::color);
|
||||
if background_color.is_some() || self.is_border_visible() {
|
||||
cx.stack(1, |cx| {
|
||||
cx.with_z_index(1, |cx| {
|
||||
cx.paint_quad(
|
||||
bounds,
|
||||
self.corner_radii.to_pixels(bounds.size, rem_size),
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
use crate::{
|
||||
self as gpui, hsla, point, px, relative, rems, AlignItems, CursorStyle, DefiniteLength,
|
||||
Display, Fill, FlexDirection, Hsla, JustifyContent, Length, Position, Rems, SharedString,
|
||||
StyleRefinement, Visibility,
|
||||
self as gpui, hsla, point, px, relative, rems, AbsoluteLength, AlignItems, CursorStyle,
|
||||
DefiniteLength, Display, Fill, FlexDirection, Hsla, JustifyContent, Length, Position,
|
||||
SharedString, Style, StyleRefinement, Visibility,
|
||||
};
|
||||
use crate::{BoxShadow, TextStyleRefinement};
|
||||
use refineable::Refineable;
|
||||
use smallvec::smallvec;
|
||||
|
||||
pub trait Styled {
|
||||
fn style(&mut self) -> &mut StyleRefinement;
|
||||
|
||||
fn computed_style(&mut self) -> Style {
|
||||
Style::default().refined(self.style().clone())
|
||||
}
|
||||
|
||||
gpui2_macros::style_helpers!();
|
||||
|
||||
/// Sets the size of the element to the full width and height.
|
||||
|
@ -433,7 +438,7 @@ pub trait Styled {
|
|||
self
|
||||
}
|
||||
|
||||
fn text_size(mut self, size: impl Into<Rems>) -> Self
|
||||
fn text_size(mut self, size: impl Into<AbsoluteLength>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
@ -449,7 +454,7 @@ pub trait Styled {
|
|||
{
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(0.75));
|
||||
.font_size = Some(rems(0.75).into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -459,7 +464,7 @@ pub trait Styled {
|
|||
{
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(0.875));
|
||||
.font_size = Some(rems(0.875).into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -469,7 +474,7 @@ pub trait Styled {
|
|||
{
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.0));
|
||||
.font_size = Some(rems(1.0).into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -479,7 +484,7 @@ pub trait Styled {
|
|||
{
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.125));
|
||||
.font_size = Some(rems(1.125).into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -489,7 +494,7 @@ pub trait Styled {
|
|||
{
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.25));
|
||||
.font_size = Some(rems(1.25).into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -499,7 +504,7 @@ pub trait Styled {
|
|||
{
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.5));
|
||||
.font_size = Some(rems(1.5).into());
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -509,7 +514,7 @@ pub trait Styled {
|
|||
{
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.875));
|
||||
.font_size = Some(rems(1.875).into());
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,6 @@ impl Line {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn width(&self) -> Pixels {
|
||||
self.layout.width
|
||||
}
|
||||
|
||||
pub fn wrap_count(&self) -> usize {
|
||||
self.layout.wrap_boundaries.len()
|
||||
}
|
||||
|
@ -78,7 +74,6 @@ impl Line {
|
|||
glyph_origin.y += line_height;
|
||||
}
|
||||
prev_glyph_position = glyph.position;
|
||||
let glyph_origin = glyph_origin + baseline_offset;
|
||||
|
||||
let mut finished_underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
|
||||
if glyph.index >= run_end {
|
||||
|
@ -129,14 +124,14 @@ impl Line {
|
|||
if max_glyph_bounds.intersects(&content_mask.bounds) {
|
||||
if glyph.is_emoji {
|
||||
cx.paint_emoji(
|
||||
glyph_origin,
|
||||
glyph_origin + baseline_offset,
|
||||
run.font_id,
|
||||
glyph.id,
|
||||
self.layout.layout.font_size,
|
||||
)?;
|
||||
} else {
|
||||
cx.paint_glyph(
|
||||
glyph_origin,
|
||||
glyph_origin + baseline_offset,
|
||||
run.font_id,
|
||||
glyph.id,
|
||||
self.layout.layout.font_size,
|
||||
|
|
|
@ -82,18 +82,6 @@ impl LineLayout {
|
|||
self.width
|
||||
}
|
||||
|
||||
pub fn font_for_index(&self, index: usize) -> Option<FontId> {
|
||||
for run in &self.runs {
|
||||
for glyph in &run.glyphs {
|
||||
if glyph.index >= index {
|
||||
return Some(run.font_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn compute_wrap_boundaries(
|
||||
&self,
|
||||
text: &str,
|
||||
|
|
|
@ -2,13 +2,14 @@ use crate::{
|
|||
px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
|
||||
Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, DispatchContext, DisplayId,
|
||||
Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId,
|
||||
GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch,
|
||||
KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton,
|
||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay,
|
||||
PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams,
|
||||
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
|
||||
Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View,
|
||||
VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, InputHandler, IsZero, KeyListener,
|
||||
KeyMatch, KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite,
|
||||
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
|
||||
PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel,
|
||||
Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
|
||||
SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet, Subscription,
|
||||
TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView,
|
||||
WindowBounds, WindowInputHandler, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::HashMap;
|
||||
|
@ -191,6 +192,7 @@ pub struct Window {
|
|||
default_prevented: bool,
|
||||
mouse_position: Point<Pixels>,
|
||||
requested_cursor_style: Option<CursorStyle>,
|
||||
requested_input_handler: Option<Box<dyn PlatformInputHandler>>,
|
||||
scale_factor: f32,
|
||||
bounds: WindowBounds,
|
||||
bounds_observers: SubscriberSet<(), AnyObserver>,
|
||||
|
@ -253,7 +255,7 @@ impl Window {
|
|||
handle
|
||||
.update(&mut cx, |_, cx| cx.dispatch_event(event))
|
||||
.log_err()
|
||||
.unwrap_or(true)
|
||||
.unwrap_or(false)
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -285,6 +287,7 @@ impl Window {
|
|||
default_prevented: true,
|
||||
mouse_position,
|
||||
requested_cursor_style: None,
|
||||
requested_input_handler: None,
|
||||
scale_factor,
|
||||
bounds,
|
||||
bounds_observers: SubscriberSet::new(),
|
||||
|
@ -300,7 +303,8 @@ impl Window {
|
|||
|
||||
/// When constructing the element tree, we maintain a stack of key dispatch frames until we
|
||||
/// find the focused element. We interleave key listeners with dispatch contexts so we can use the
|
||||
/// contexts when matching key events against the keymap.
|
||||
/// contexts when matching key events against the keymap. A key listener can be either an action
|
||||
/// handler or a [KeyDown] / [KeyUp] event listener.
|
||||
enum KeyDispatchStackFrame {
|
||||
Listener {
|
||||
event_type: TypeId,
|
||||
|
@ -559,6 +563,12 @@ impl<'a> WindowContext<'a> {
|
|||
.request_measured_layout(style, rem_size, measure)
|
||||
}
|
||||
|
||||
pub fn compute_layout(&mut self, layout_id: LayoutId, available_space: Size<AvailableSpace>) {
|
||||
self.window
|
||||
.layout_engine
|
||||
.compute_layout(layout_id, available_space)
|
||||
}
|
||||
|
||||
/// Obtain the bounds computed for the given LayoutId relative to the window. This method should not
|
||||
/// be invoked until the paint phase begins, and will usually be invoked by GPUI itself automatically
|
||||
/// in order to pass your element its `Bounds` automatically.
|
||||
|
@ -604,6 +614,10 @@ impl<'a> WindowContext<'a> {
|
|||
.find(|display| display.id() == self.window.display_id)
|
||||
}
|
||||
|
||||
pub fn show_character_palette(&self) {
|
||||
self.window.platform_window.show_character_palette();
|
||||
}
|
||||
|
||||
/// The scale factor of the display associated with the window. For example, it could
|
||||
/// return 2.0 for a "retina" display, indicating that each logical pixel should actually
|
||||
/// be rendered as two pixels on screen.
|
||||
|
@ -786,6 +800,7 @@ impl<'a> WindowContext<'a> {
|
|||
}
|
||||
|
||||
/// Paint a monochrome (non-emoji) glyph into the scene for the current frame at the current z-index.
|
||||
/// The y component of the origin is the baseline of the glyph.
|
||||
pub fn paint_glyph(
|
||||
&mut self,
|
||||
origin: Point<Pixels>,
|
||||
|
@ -839,6 +854,7 @@ impl<'a> WindowContext<'a> {
|
|||
}
|
||||
|
||||
/// Paint an emoji glyph into the scene for the current frame at the current z-index.
|
||||
/// The y component of the origin is the baseline of the glyph.
|
||||
pub fn paint_emoji(
|
||||
&mut self,
|
||||
origin: Point<Pixels>,
|
||||
|
@ -1007,6 +1023,9 @@ impl<'a> WindowContext<'a> {
|
|||
.take()
|
||||
.unwrap_or(CursorStyle::Arrow);
|
||||
self.platform.set_cursor_style(cursor_style);
|
||||
if let Some(handler) = self.window.requested_input_handler.take() {
|
||||
self.window.platform_window.set_input_handler(handler);
|
||||
}
|
||||
|
||||
self.window.dirty = false;
|
||||
}
|
||||
|
@ -1047,7 +1066,11 @@ impl<'a> WindowContext<'a> {
|
|||
}
|
||||
|
||||
/// Dispatch a mouse or keyboard event on the window.
|
||||
fn dispatch_event(&mut self, event: InputEvent) -> bool {
|
||||
pub fn dispatch_event(&mut self, event: InputEvent) -> bool {
|
||||
// Handlers may set this to false by calling `stop_propagation`
|
||||
self.app.propagate_event = true;
|
||||
self.window.default_prevented = false;
|
||||
|
||||
let event = match event {
|
||||
// Track the mouse position with our own state, since accessing the platform
|
||||
// API for the mouse position can only occur on the main thread.
|
||||
|
@ -1101,10 +1124,6 @@ impl<'a> WindowContext<'a> {
|
|||
};
|
||||
|
||||
if let Some(any_mouse_event) = event.mouse_event() {
|
||||
// Handlers may set this to false by calling `stop_propagation`
|
||||
self.app.propagate_event = true;
|
||||
self.window.default_prevented = false;
|
||||
|
||||
if let Some(mut handlers) = self
|
||||
.window
|
||||
.mouse_listeners
|
||||
|
@ -1151,6 +1170,7 @@ impl<'a> WindowContext<'a> {
|
|||
.insert(any_mouse_event.type_id(), handlers);
|
||||
}
|
||||
} else if let Some(any_key_event) = event.keyboard_event() {
|
||||
let mut did_handle_action = false;
|
||||
let key_dispatch_stack = mem::take(&mut self.window.key_dispatch_stack);
|
||||
let key_event_type = any_key_event.type_id();
|
||||
let mut context_stack = SmallVec::<[&DispatchContext; 16]>::new();
|
||||
|
@ -1171,6 +1191,7 @@ impl<'a> WindowContext<'a> {
|
|||
self.dispatch_action(action, &key_dispatch_stack[..ix]);
|
||||
}
|
||||
if !self.app.propagate_event {
|
||||
did_handle_action = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1199,6 +1220,7 @@ impl<'a> WindowContext<'a> {
|
|||
}
|
||||
|
||||
if !self.app.propagate_event {
|
||||
did_handle_action = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1212,6 +1234,7 @@ impl<'a> WindowContext<'a> {
|
|||
|
||||
drop(context_stack);
|
||||
self.window.key_dispatch_stack = key_dispatch_stack;
|
||||
return did_handle_action;
|
||||
}
|
||||
|
||||
true
|
||||
|
@ -1314,6 +1337,7 @@ impl<'a> WindowContext<'a> {
|
|||
} = stack_frame
|
||||
{
|
||||
if action_type == *event_type {
|
||||
self.app.propagate_event = false;
|
||||
listener(action.as_any(), &[], DispatchPhase::Bubble, self);
|
||||
if !self.app.propagate_event {
|
||||
break;
|
||||
|
@ -1328,6 +1352,7 @@ impl<'a> WindowContext<'a> {
|
|||
self.app.global_action_listeners.remove(&action_type)
|
||||
{
|
||||
for listener in global_listeners.iter().rev() {
|
||||
self.app.propagate_event = false;
|
||||
listener(action.as_ref(), DispatchPhase::Bubble, self);
|
||||
if !self.app.propagate_event {
|
||||
break;
|
||||
|
@ -1702,8 +1727,8 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
|||
&mut self.window_cx
|
||||
}
|
||||
|
||||
pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
self.window.z_index_stack.push(order);
|
||||
pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
self.window.z_index_stack.push(z_index);
|
||||
let result = f(self);
|
||||
self.window.z_index_stack.pop();
|
||||
result
|
||||
|
@ -2004,6 +2029,19 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V> ViewContext<'_, V>
|
||||
where
|
||||
V: InputHandler + 'static,
|
||||
{
|
||||
pub fn handle_text_input(&mut self) {
|
||||
self.window.requested_input_handler = Some(Box::new(WindowInputHandler {
|
||||
cx: self.app.this.clone(),
|
||||
window: self.window_handle(),
|
||||
handler: self.view().downgrade(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> ViewContext<'_, V>
|
||||
where
|
||||
V: EventEmitter,
|
||||
|
@ -2058,9 +2096,9 @@ impl<V> Context for ViewContext<'_, V> {
|
|||
impl<V: 'static> VisualContext for ViewContext<'_, V> {
|
||||
fn build_view<W: 'static>(
|
||||
&mut self,
|
||||
build_view: impl FnOnce(&mut ViewContext<'_, W>) -> W,
|
||||
build_view_state: impl FnOnce(&mut ViewContext<'_, W>) -> W,
|
||||
) -> Self::Result<View<W>> {
|
||||
self.window_cx.build_view(build_view)
|
||||
self.window_cx.build_view(build_view_state)
|
||||
}
|
||||
|
||||
fn update_view<V2: 'static, R>(
|
||||
|
|
89
crates/gpui2/src/window_input_handler.rs
Normal file
89
crates/gpui2/src/window_input_handler.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
use crate::{AnyWindowHandle, AppCell, Context, PlatformInputHandler, ViewContext, WeakView};
|
||||
use std::{ops::Range, rc::Weak};
|
||||
|
||||
pub struct WindowInputHandler<V>
|
||||
where
|
||||
V: InputHandler,
|
||||
{
|
||||
pub cx: Weak<AppCell>,
|
||||
pub window: AnyWindowHandle,
|
||||
pub handler: WeakView<V>,
|
||||
}
|
||||
|
||||
impl<V: InputHandler + 'static> PlatformInputHandler for WindowInputHandler<V> {
|
||||
fn selected_text_range(&self) -> Option<std::ops::Range<usize>> {
|
||||
self.update(|view, cx| view.selected_text_range(cx))
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fn marked_text_range(&self) -> Option<std::ops::Range<usize>> {
|
||||
self.update(|view, cx| view.marked_text_range(cx)).flatten()
|
||||
}
|
||||
|
||||
fn text_for_range(&self, range_utf16: std::ops::Range<usize>) -> Option<String> {
|
||||
self.update(|view, cx| view.text_for_range(range_utf16, cx))
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fn replace_text_in_range(
|
||||
&mut self,
|
||||
replacement_range: Option<std::ops::Range<usize>>,
|
||||
text: &str,
|
||||
) {
|
||||
self.update(|view, cx| view.replace_text_in_range(replacement_range, text, cx));
|
||||
}
|
||||
|
||||
fn replace_and_mark_text_in_range(
|
||||
&mut self,
|
||||
range_utf16: Option<std::ops::Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<std::ops::Range<usize>>,
|
||||
) {
|
||||
self.update(|view, cx| {
|
||||
view.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx)
|
||||
});
|
||||
}
|
||||
|
||||
fn unmark_text(&mut self) {
|
||||
self.update(|view, cx| view.unmark_text(cx));
|
||||
}
|
||||
|
||||
fn bounds_for_range(&self, range_utf16: std::ops::Range<usize>) -> Option<crate::Bounds<f32>> {
|
||||
self.update(|view, cx| view.bounds_for_range(range_utf16, cx))
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: InputHandler + 'static> WindowInputHandler<V> {
|
||||
fn update<T>(&self, f: impl FnOnce(&mut V, &mut ViewContext<V>) -> T) -> Option<T> {
|
||||
let cx = self.cx.upgrade()?;
|
||||
let mut cx = cx.borrow_mut();
|
||||
cx.update_window(self.window, |_, cx| self.handler.update(cx, f).ok())
|
||||
.ok()?
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InputHandler: Sized {
|
||||
fn text_for_range(&self, range: Range<usize>, cx: &mut ViewContext<Self>) -> Option<String>;
|
||||
fn selected_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>>;
|
||||
fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>>;
|
||||
fn unmark_text(&mut self, cx: &mut ViewContext<Self>);
|
||||
fn replace_text_in_range(
|
||||
&mut self,
|
||||
range: Option<Range<usize>>,
|
||||
text: &str,
|
||||
cx: &mut ViewContext<Self>,
|
||||
);
|
||||
fn replace_and_mark_text_in_range(
|
||||
&mut self,
|
||||
range: Option<Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<Range<usize>>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
);
|
||||
fn bounds_for_range(
|
||||
&self,
|
||||
range_utf16: std::ops::Range<usize>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<crate::Bounds<f32>>;
|
||||
}
|
55
crates/gpui2_macros/src/action.rs
Normal file
55
crates/gpui2_macros/src/action.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Input:
|
||||
//
|
||||
// #[action]
|
||||
// struct Foo {
|
||||
// bar: String,
|
||||
// }
|
||||
|
||||
// Output:
|
||||
//
|
||||
// #[gpui::register_action]
|
||||
// #[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::default::Default, std::fmt::Debug)]
|
||||
// struct Foo {
|
||||
// bar: String,
|
||||
// }
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
pub fn action(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as DeriveInput);
|
||||
let name = &input.ident;
|
||||
let attrs = input
|
||||
.attrs
|
||||
.into_iter()
|
||||
.filter(|attr| !attr.path.is_ident("action"))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let attributes = quote! {
|
||||
#[gpui::register_action]
|
||||
#[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::default::Default, std::fmt::Debug)]
|
||||
#(#attrs)*
|
||||
};
|
||||
let visibility = input.vis;
|
||||
|
||||
let output = match input.data {
|
||||
syn::Data::Struct(ref struct_data) => {
|
||||
let fields = &struct_data.fields;
|
||||
quote! {
|
||||
#attributes
|
||||
#visibility struct #name #fields
|
||||
}
|
||||
}
|
||||
syn::Data::Enum(ref enum_data) => {
|
||||
let variants = &enum_data.variants;
|
||||
quote! {
|
||||
#attributes
|
||||
#visibility enum #name { #variants }
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected a struct or an enum."),
|
||||
};
|
||||
|
||||
TokenStream::from(output)
|
||||
}
|
|
@ -1,14 +1,26 @@
|
|||
use proc_macro::TokenStream;
|
||||
|
||||
mod action;
|
||||
mod derive_component;
|
||||
mod register_action;
|
||||
mod style_helpers;
|
||||
mod test;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn style_helpers(args: TokenStream) -> TokenStream {
|
||||
style_helpers::style_helpers(args)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn action(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
action::action(attr, item)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn register_action(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
register_action::register_action(attr, item)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Component, attributes(component))]
|
||||
pub fn derive_component(input: TokenStream) -> TokenStream {
|
||||
derive_component::derive_component(input)
|
||||
|
|
33
crates/gpui2_macros/src/register_action.rs
Normal file
33
crates/gpui2_macros/src/register_action.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Input:
|
||||
//
|
||||
// struct FooBar {}
|
||||
|
||||
// Output:
|
||||
//
|
||||
// struct FooBar {}
|
||||
//
|
||||
// #[allow(non_snake_case)]
|
||||
// #[gpui2::ctor]
|
||||
// fn register_foobar_builder() {
|
||||
// gpui2::register_action_builder::<Foo>()
|
||||
// }
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
pub fn register_action(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as DeriveInput);
|
||||
let type_name = &input.ident;
|
||||
let ctor_fn_name = format_ident!("register_{}_builder", type_name.to_string().to_lowercase());
|
||||
|
||||
let expanded = quote! {
|
||||
#input
|
||||
#[allow(non_snake_case)]
|
||||
#[gpui::ctor]
|
||||
fn #ctor_fn_name() {
|
||||
gpui::register_action::<#type_name>()
|
||||
}
|
||||
};
|
||||
|
||||
TokenStream::from(expanded)
|
||||
}
|
|
@ -95,6 +95,8 @@ mod tests {
|
|||
.iter()
|
||||
.map(|(name, color)| (name.to_string(), (*color).into()))
|
||||
.collect(),
|
||||
inlay_style: HighlightStyle::default(),
|
||||
suggestion_style: HighlightStyle::default(),
|
||||
};
|
||||
|
||||
let capture_names = &[
|
||||
|
|
|
@ -43,7 +43,7 @@ use std::{
|
|||
},
|
||||
};
|
||||
use syntax_map::SyntaxSnapshot;
|
||||
use theme::{SyntaxTheme, ThemeVariant};
|
||||
use theme::{SyntaxTheme, Theme};
|
||||
use tree_sitter::{self, Query};
|
||||
use unicase::UniCase;
|
||||
use util::{http::HttpClient, paths::PathExt};
|
||||
|
@ -643,7 +643,7 @@ struct LanguageRegistryState {
|
|||
next_available_language_id: AvailableLanguageId,
|
||||
loading_languages: HashMap<AvailableLanguageId, Vec<oneshot::Sender<Result<Arc<Language>>>>>,
|
||||
subscription: (watch::Sender<()>, watch::Receiver<()>),
|
||||
theme: Option<Arc<ThemeVariant>>,
|
||||
theme: Option<Arc<Theme>>,
|
||||
version: usize,
|
||||
reload_count: usize,
|
||||
}
|
||||
|
@ -744,7 +744,7 @@ impl LanguageRegistry {
|
|||
self.state.read().reload_count
|
||||
}
|
||||
|
||||
pub fn set_theme(&self, theme: Arc<ThemeVariant>) {
|
||||
pub fn set_theme(&self, theme: Arc<Theme>) {
|
||||
let mut state = self.state.write();
|
||||
state.theme = Some(theme.clone());
|
||||
for language in &state.languages {
|
||||
|
|
|
@ -9,4 +9,5 @@ path = "src/menu2.rs"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
gpui = { package = "gpui2", path = "../gpui2" }
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
// todo!(use actions! macro)
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct Cancel;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct Confirm;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct SecondaryConfirm;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct SelectPrev;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct SelectNext;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct SelectFirst;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct SelectLast;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
|
||||
pub struct ShowContextMenu;
|
||||
|
|
28
crates/picker2/Cargo.toml
Normal file
28
crates/picker2/Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
|||
[package]
|
||||
name = "picker2"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
path = "src/picker2.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
editor = { package = "editor2", path = "../editor2" }
|
||||
gpui = { package = "gpui2", path = "../gpui2" }
|
||||
menu = { package = "menu2", path = "../menu2" }
|
||||
settings = { package = "settings2", path = "../settings2" }
|
||||
util = { path = "../util" }
|
||||
theme = { package = "theme2", path = "../theme2" }
|
||||
workspace = { package = "workspace2", path = "../workspace2" }
|
||||
|
||||
parking_lot.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
editor = { package = "editor2", path = "../editor2", features = ["test-support"] }
|
||||
gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
|
||||
serde_json.workspace = true
|
||||
workspace = { package = "workspace2", path = "../workspace2", features = ["test-support"] }
|
||||
ctor.workspace = true
|
||||
env_logger.workspace = true
|
163
crates/picker2/src/picker2.rs
Normal file
163
crates/picker2/src/picker2.rs
Normal file
|
@ -0,0 +1,163 @@
|
|||
use editor::Editor;
|
||||
use gpui::{
|
||||
div, uniform_list, Component, Div, FocusEnabled, ParentElement, Render, StatefulInteractivity,
|
||||
StatelessInteractive, Styled, Task, UniformListScrollHandle, View, ViewContext, VisualContext,
|
||||
WindowContext,
|
||||
};
|
||||
use std::cmp;
|
||||
|
||||
pub struct Picker<D: PickerDelegate> {
|
||||
pub delegate: D,
|
||||
scroll_handle: UniformListScrollHandle,
|
||||
editor: View<Editor>,
|
||||
pending_update_matches: Option<Task<Option<()>>>,
|
||||
}
|
||||
|
||||
pub trait PickerDelegate: Sized + 'static {
|
||||
type ListItem: Component<Picker<Self>>;
|
||||
|
||||
fn match_count(&self) -> usize;
|
||||
fn selected_index(&self) -> usize;
|
||||
fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext<Picker<Self>>);
|
||||
|
||||
// fn placeholder_text(&self) -> Arc<str>;
|
||||
fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()>;
|
||||
|
||||
fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<Picker<Self>>);
|
||||
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>);
|
||||
|
||||
fn render_match(
|
||||
&self,
|
||||
ix: usize,
|
||||
selected: bool,
|
||||
cx: &mut ViewContext<Picker<Self>>,
|
||||
) -> Self::ListItem;
|
||||
}
|
||||
|
||||
impl<D: PickerDelegate> Picker<D> {
|
||||
pub fn new(delegate: D, cx: &mut ViewContext<Self>) -> Self {
|
||||
let editor = cx.build_view(|cx| Editor::single_line(cx));
|
||||
cx.subscribe(&editor, Self::on_input_editor_event).detach();
|
||||
Self {
|
||||
delegate,
|
||||
scroll_handle: UniformListScrollHandle::new(),
|
||||
pending_update_matches: None,
|
||||
editor,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn focus(&self, cx: &mut WindowContext) {
|
||||
self.editor.update(cx, |editor, cx| editor.focus(cx));
|
||||
}
|
||||
|
||||
fn select_next(&mut self, _: &menu::SelectNext, cx: &mut ViewContext<Self>) {
|
||||
let count = self.delegate.match_count();
|
||||
if count > 0 {
|
||||
let index = self.delegate.selected_index();
|
||||
let ix = cmp::min(index + 1, count - 1);
|
||||
self.delegate.set_selected_index(ix, cx);
|
||||
self.scroll_handle.scroll_to_item(ix);
|
||||
}
|
||||
}
|
||||
|
||||
fn select_prev(&mut self, _: &menu::SelectPrev, cx: &mut ViewContext<Self>) {
|
||||
let count = self.delegate.match_count();
|
||||
if count > 0 {
|
||||
let index = self.delegate.selected_index();
|
||||
let ix = index.saturating_sub(1);
|
||||
self.delegate.set_selected_index(ix, cx);
|
||||
self.scroll_handle.scroll_to_item(ix);
|
||||
}
|
||||
}
|
||||
|
||||
fn select_first(&mut self, _: &menu::SelectFirst, cx: &mut ViewContext<Self>) {
|
||||
let count = self.delegate.match_count();
|
||||
if count > 0 {
|
||||
self.delegate.set_selected_index(0, cx);
|
||||
self.scroll_handle.scroll_to_item(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn select_last(&mut self, _: &menu::SelectLast, cx: &mut ViewContext<Self>) {
|
||||
let count = self.delegate.match_count();
|
||||
if count > 0 {
|
||||
self.delegate.set_selected_index(count - 1, cx);
|
||||
self.scroll_handle.scroll_to_item(count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
|
||||
self.delegate.dismissed(cx);
|
||||
}
|
||||
|
||||
fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
|
||||
self.delegate.confirm(false, cx);
|
||||
}
|
||||
|
||||
fn secondary_confirm(&mut self, _: &menu::SecondaryConfirm, cx: &mut ViewContext<Self>) {
|
||||
self.delegate.confirm(true, cx);
|
||||
}
|
||||
|
||||
fn on_input_editor_event(
|
||||
&mut self,
|
||||
_: View<Editor>,
|
||||
event: &editor::Event,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
if let editor::Event::BufferEdited = event {
|
||||
let query = self.editor.read(cx).text(cx);
|
||||
self.update_matches(query, cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_matches(&mut self, query: String, cx: &mut ViewContext<Self>) {
|
||||
let update = self.delegate.update_matches(query, cx);
|
||||
self.matches_updated(cx);
|
||||
self.pending_update_matches = Some(cx.spawn(|this, mut cx| async move {
|
||||
update.await;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.matches_updated(cx);
|
||||
})
|
||||
.ok()
|
||||
}));
|
||||
}
|
||||
|
||||
fn matches_updated(&mut self, cx: &mut ViewContext<Self>) {
|
||||
let index = self.delegate.selected_index();
|
||||
self.scroll_handle.scroll_to_item(index);
|
||||
self.pending_update_matches = None;
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: PickerDelegate> Render for Picker<D> {
|
||||
type Element = Div<Self, StatefulInteractivity<Self>, FocusEnabled<Self>>;
|
||||
|
||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
div()
|
||||
.context("picker")
|
||||
.id("picker-container")
|
||||
.focusable()
|
||||
.size_full()
|
||||
.on_action(Self::select_next)
|
||||
.on_action(Self::select_prev)
|
||||
.on_action(Self::select_first)
|
||||
.on_action(Self::select_last)
|
||||
.on_action(Self::cancel)
|
||||
.on_action(Self::confirm)
|
||||
.on_action(Self::secondary_confirm)
|
||||
.child(self.editor.clone())
|
||||
.child(
|
||||
uniform_list("candidates", self.delegate.match_count(), {
|
||||
move |this: &mut Self, visible_range, cx| {
|
||||
let selected_ix = this.delegate.selected_index();
|
||||
visible_range
|
||||
.map(|ix| this.delegate.render_match(ix, ix == selected_ix, cx))
|
||||
.collect()
|
||||
}
|
||||
})
|
||||
.track_scroll(self.scroll_handle.clone())
|
||||
.size_full(),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{settings_store::parse_json_with_comments, SettingsAssets};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use collections::BTreeMap;
|
||||
use gpui::{AppContext, KeyBinding, SharedString};
|
||||
use gpui::{actions, Action, AppContext, KeyBinding, SharedString};
|
||||
use schemars::{
|
||||
gen::{SchemaGenerator, SchemaSettings},
|
||||
schema::{InstanceType, Schema, SchemaObject, SingleOrVec, SubschemaValidation},
|
||||
|
@ -73,9 +73,9 @@ impl KeymapFile {
|
|||
"Expected first item in array to be a string."
|
||||
)));
|
||||
};
|
||||
cx.build_action(&name, Some(data))
|
||||
gpui::build_action(&name, Some(data))
|
||||
}
|
||||
Value::String(name) => cx.build_action(&name, None),
|
||||
Value::String(name) => gpui::build_action(&name, None),
|
||||
Value::Null => Ok(no_action()),
|
||||
_ => {
|
||||
return Some(Err(anyhow!("Expected two-element array, got {action:?}")))
|
||||
|
@ -137,8 +137,10 @@ impl KeymapFile {
|
|||
}
|
||||
}
|
||||
|
||||
actions!(NoAction);
|
||||
|
||||
fn no_action() -> Box<dyn gpui::Action> {
|
||||
todo!()
|
||||
NoAction.boxed_clone()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{settings_store::SettingsStore, Settings};
|
||||
use crate::{settings_store::SettingsStore, KeymapFile, Settings};
|
||||
use anyhow::Result;
|
||||
use fs::Fs;
|
||||
use futures::{channel::mpsc, StreamExt};
|
||||
|
@ -117,3 +117,50 @@ pub fn update_settings_file<T: Settings>(
|
|||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
pub fn load_default_keymap(cx: &mut AppContext) {
|
||||
for path in ["keymaps/default.json", "keymaps/vim.json"] {
|
||||
KeymapFile::load_asset(path, cx).unwrap();
|
||||
}
|
||||
|
||||
// todo!()
|
||||
// if let Some(asset_path) = settings::get::<BaseKeymap>(cx).asset_path() {
|
||||
// KeymapFile::load_asset(asset_path, cx).unwrap();
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn handle_keymap_file_changes(
|
||||
mut user_keymap_file_rx: mpsc::UnboundedReceiver<String>,
|
||||
cx: &mut AppContext,
|
||||
) {
|
||||
cx.spawn(move |cx| async move {
|
||||
// let mut settings_subscription = None;
|
||||
while let Some(user_keymap_content) = user_keymap_file_rx.next().await {
|
||||
if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() {
|
||||
cx.update(|cx| reload_keymaps(cx, &keymap_content)).ok();
|
||||
|
||||
// todo!()
|
||||
// let mut old_base_keymap = cx.read(|cx| *settings::get::<BaseKeymap>(cx));
|
||||
// drop(settings_subscription);
|
||||
// settings_subscription = Some(cx.update(|cx| {
|
||||
// cx.observe_global::<SettingsStore, _>(move |cx| {
|
||||
// let new_base_keymap = *settings::get::<BaseKeymap>(cx);
|
||||
// if new_base_keymap != old_base_keymap {
|
||||
// old_base_keymap = new_base_keymap.clone();
|
||||
// reload_keymaps(cx, &keymap_content);
|
||||
// }
|
||||
// })
|
||||
// }));
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn reload_keymaps(cx: &mut AppContext, keymap_content: &KeymapFile) {
|
||||
// todo!()
|
||||
// cx.clear_bindings();
|
||||
load_default_keymap(cx);
|
||||
keymap_content.clone().add_to_cx(cx).log_err();
|
||||
// cx.set_menus(menus::menus());
|
||||
}
|
||||
|
|
|
@ -13,9 +13,12 @@ anyhow.workspace = true
|
|||
# TODO: Remove after diagnosing stack overflow.
|
||||
backtrace-on-stack-overflow = "0.3.0"
|
||||
clap = { version = "4.4", features = ["derive", "string"] }
|
||||
editor = { package = "editor2", path = "../editor2" }
|
||||
chrono = "0.4"
|
||||
fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
|
||||
gpui = { package = "gpui2", path = "../gpui2" }
|
||||
itertools = "0.11.0"
|
||||
language = { package = "language2", path = "../language2" }
|
||||
log.workspace = true
|
||||
rust-embed.workspace = true
|
||||
serde.workspace = true
|
||||
|
@ -25,8 +28,10 @@ smallvec.workspace = true
|
|||
strum = { version = "0.25.0", features = ["derive"] }
|
||||
theme = { path = "../theme" }
|
||||
theme2 = { path = "../theme2" }
|
||||
menu = { package = "menu2", path = "../menu2" }
|
||||
ui = { package = "ui2", path = "../ui2", features = ["stories"] }
|
||||
util = { path = "../util" }
|
||||
picker = { package = "picker2", path = "../picker2" }
|
||||
|
||||
[dev-dependencies]
|
||||
gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
mod colors;
|
||||
mod focus;
|
||||
mod kitchen_sink;
|
||||
mod picker;
|
||||
mod scroll;
|
||||
mod text;
|
||||
mod z_index;
|
||||
|
@ -8,6 +9,7 @@ mod z_index;
|
|||
pub use colors::*;
|
||||
pub use focus::*;
|
||||
pub use kitchen_sink::*;
|
||||
pub use picker::*;
|
||||
pub use scroll::*;
|
||||
pub use text::*;
|
||||
pub use z_index::*;
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
use gpui::{
|
||||
div, Div, FocusEnabled, Focusable, KeyBinding, ParentElement, Render, StatefulInteraction,
|
||||
StatelessInteractive, Styled, View, VisualContext, WindowContext,
|
||||
actions, div, Div, FocusEnabled, Focusable, KeyBinding, ParentElement, Render,
|
||||
StatefulInteractivity, StatelessInteractive, Styled, View, VisualContext, WindowContext,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use theme2::ActiveTheme;
|
||||
|
||||
#[derive(Clone, Default, PartialEq, Deserialize)]
|
||||
struct ActionA;
|
||||
|
||||
#[derive(Clone, Default, PartialEq, Deserialize)]
|
||||
struct ActionB;
|
||||
|
||||
#[derive(Clone, Default, PartialEq, Deserialize)]
|
||||
struct ActionC;
|
||||
actions!(ActionA, ActionB, ActionC);
|
||||
|
||||
pub struct FocusStory {}
|
||||
|
||||
|
@ -23,24 +15,22 @@ impl FocusStory {
|
|||
KeyBinding::new("cmd-a", ActionB, Some("child-1")),
|
||||
KeyBinding::new("cmd-c", ActionC, None),
|
||||
]);
|
||||
cx.register_action_type::<ActionA>();
|
||||
cx.register_action_type::<ActionB>();
|
||||
|
||||
cx.build_view(move |cx| Self {})
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for FocusStory {
|
||||
type Element = Div<Self, StatefulInteraction<Self>, FocusEnabled<Self>>;
|
||||
type Element = Div<Self, StatefulInteractivity<Self>, FocusEnabled<Self>>;
|
||||
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
let theme = cx.theme();
|
||||
let color_1 = theme.styles.git.created;
|
||||
let color_2 = theme.styles.git.modified;
|
||||
let color_3 = theme.styles.git.deleted;
|
||||
let color_4 = theme.styles.git.conflict;
|
||||
let color_5 = theme.styles.git.ignored;
|
||||
let color_6 = theme.styles.git.renamed;
|
||||
let color_1 = theme.status().created;
|
||||
let color_2 = theme.status().modified;
|
||||
let color_3 = theme.status().deleted;
|
||||
let color_4 = theme.status().conflict;
|
||||
let color_5 = theme.status().ignored;
|
||||
let color_6 = theme.status().renamed;
|
||||
let child_1 = cx.focus_handle();
|
||||
let child_2 = cx.focus_handle();
|
||||
|
||||
|
@ -48,20 +38,18 @@ impl Render for FocusStory {
|
|||
.id("parent")
|
||||
.focusable()
|
||||
.context("parent")
|
||||
.on_action(|_, action: &ActionA, phase, cx| {
|
||||
println!("Action A dispatched on parent during {:?}", phase);
|
||||
.on_action(|_, action: &ActionA, cx| {
|
||||
println!("Action A dispatched on parent during");
|
||||
})
|
||||
.on_action(|_, action: &ActionB, phase, cx| {
|
||||
println!("Action B dispatched on parent during {:?}", phase);
|
||||
.on_action(|_, action: &ActionB, cx| {
|
||||
println!("Action B dispatched on parent during");
|
||||
})
|
||||
.on_focus(|_, _, _| println!("Parent focused"))
|
||||
.on_blur(|_, _, _| println!("Parent blurred"))
|
||||
.on_focus_in(|_, _, _| println!("Parent focus_in"))
|
||||
.on_focus_out(|_, _, _| println!("Parent focus_out"))
|
||||
.on_key_down(|_, event, phase, _| {
|
||||
println!("Key down on parent {:?} {:?}", phase, event)
|
||||
})
|
||||
.on_key_up(|_, event, phase, _| println!("Key up on parent {:?} {:?}", phase, event))
|
||||
.on_key_down(|_, event, phase, _| println!("Key down on parent {:?}", event))
|
||||
.on_key_up(|_, event, phase, _| println!("Key up on parent {:?}", event))
|
||||
.size_full()
|
||||
.bg(color_1)
|
||||
.focus(|style| style.bg(color_2))
|
||||
|
@ -70,8 +58,8 @@ impl Render for FocusStory {
|
|||
div()
|
||||
.track_focus(&child_1)
|
||||
.context("child-1")
|
||||
.on_action(|_, action: &ActionB, phase, cx| {
|
||||
println!("Action B dispatched on child 1 during {:?}", phase);
|
||||
.on_action(|_, action: &ActionB, cx| {
|
||||
println!("Action B dispatched on child 1 during");
|
||||
})
|
||||
.w_full()
|
||||
.h_6()
|
||||
|
@ -82,20 +70,16 @@ impl Render for FocusStory {
|
|||
.on_blur(|_, _, _| println!("Child 1 blurred"))
|
||||
.on_focus_in(|_, _, _| println!("Child 1 focus_in"))
|
||||
.on_focus_out(|_, _, _| println!("Child 1 focus_out"))
|
||||
.on_key_down(|_, event, phase, _| {
|
||||
println!("Key down on child 1 {:?} {:?}", phase, event)
|
||||
})
|
||||
.on_key_up(|_, event, phase, _| {
|
||||
println!("Key up on child 1 {:?} {:?}", phase, event)
|
||||
})
|
||||
.on_key_down(|_, event, phase, _| println!("Key down on child 1 {:?}", event))
|
||||
.on_key_up(|_, event, phase, _| println!("Key up on child 1 {:?}", event))
|
||||
.child("Child 1"),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.track_focus(&child_2)
|
||||
.context("child-2")
|
||||
.on_action(|_, action: &ActionC, phase, cx| {
|
||||
println!("Action C dispatched on child 2 during {:?}", phase);
|
||||
.on_action(|_, action: &ActionC, cx| {
|
||||
println!("Action C dispatched on child 2 during");
|
||||
})
|
||||
.w_full()
|
||||
.h_6()
|
||||
|
@ -104,12 +88,8 @@ impl Render for FocusStory {
|
|||
.on_blur(|_, _, _| println!("Child 2 blurred"))
|
||||
.on_focus_in(|_, _, _| println!("Child 2 focus_in"))
|
||||
.on_focus_out(|_, _, _| println!("Child 2 focus_out"))
|
||||
.on_key_down(|_, event, phase, _| {
|
||||
println!("Key down on child 2 {:?} {:?}", phase, event)
|
||||
})
|
||||
.on_key_up(|_, event, phase, _| {
|
||||
println!("Key up on child 2 {:?} {:?}", phase, event)
|
||||
})
|
||||
.on_key_down(|_, event, phase, _| println!("Key down on child 2 {:?}", event))
|
||||
.on_key_up(|_, event, phase, _| println!("Key up on child 2 {:?}", event))
|
||||
.child("Child 2"),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{story::Story, story_selector::ComponentStory};
|
||||
use gpui::{Div, Render, StatefulInteraction, View, VisualContext};
|
||||
use gpui::{Div, Render, StatefulInteractivity, View, VisualContext};
|
||||
use strum::IntoEnumIterator;
|
||||
use ui::prelude::*;
|
||||
|
||||
|
@ -12,7 +12,7 @@ impl KitchenSinkStory {
|
|||
}
|
||||
|
||||
impl Render for KitchenSinkStory {
|
||||
type Element = Div<Self, StatefulInteraction<Self>>;
|
||||
type Element = Div<Self, StatefulInteractivity<Self>>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let component_stories = ComponentStory::iter()
|
||||
|
|
214
crates/storybook2/src/stories/picker.rs
Normal file
214
crates/storybook2/src/stories/picker.rs
Normal file
|
@ -0,0 +1,214 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use fuzzy::StringMatchCandidate;
|
||||
use gpui::{
|
||||
div, Component, Div, KeyBinding, ParentElement, Render, StatelessInteractive, Styled, Task,
|
||||
View, VisualContext, WindowContext,
|
||||
};
|
||||
use picker::{Picker, PickerDelegate};
|
||||
use theme2::ActiveTheme;
|
||||
|
||||
pub struct PickerStory {
|
||||
picker: View<Picker<Delegate>>,
|
||||
}
|
||||
|
||||
struct Delegate {
|
||||
candidates: Arc<[StringMatchCandidate]>,
|
||||
matches: Vec<usize>,
|
||||
selected_ix: usize,
|
||||
}
|
||||
|
||||
impl Delegate {
|
||||
fn new(strings: &[&str]) -> Self {
|
||||
Self {
|
||||
candidates: strings
|
||||
.iter()
|
||||
.copied()
|
||||
.enumerate()
|
||||
.map(|(id, string)| StringMatchCandidate {
|
||||
id,
|
||||
char_bag: string.into(),
|
||||
string: string.into(),
|
||||
})
|
||||
.collect(),
|
||||
matches: vec![],
|
||||
selected_ix: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PickerDelegate for Delegate {
|
||||
type ListItem = Div<Picker<Self>>;
|
||||
|
||||
fn match_count(&self) -> usize {
|
||||
self.candidates.len()
|
||||
}
|
||||
|
||||
fn render_match(
|
||||
&self,
|
||||
ix: usize,
|
||||
selected: bool,
|
||||
cx: &mut gpui::ViewContext<Picker<Self>>,
|
||||
) -> Self::ListItem {
|
||||
let colors = cx.theme().colors();
|
||||
let Some(candidate_ix) = self.matches.get(ix) else {
|
||||
return div();
|
||||
};
|
||||
let candidate = self.candidates[*candidate_ix].string.clone();
|
||||
|
||||
div()
|
||||
.text_color(colors.text)
|
||||
.when(selected, |s| {
|
||||
s.border_l_10().border_color(colors.terminal_ansi_yellow)
|
||||
})
|
||||
.hover(|style| {
|
||||
style
|
||||
.bg(colors.element_active)
|
||||
.text_color(colors.text_accent)
|
||||
})
|
||||
.child(candidate)
|
||||
}
|
||||
|
||||
fn selected_index(&self) -> usize {
|
||||
self.selected_ix
|
||||
}
|
||||
|
||||
fn set_selected_index(&mut self, ix: usize, cx: &mut gpui::ViewContext<Picker<Self>>) {
|
||||
self.selected_ix = ix;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn confirm(&mut self, secondary: bool, cx: &mut gpui::ViewContext<Picker<Self>>) {
|
||||
let candidate_ix = self.matches[self.selected_ix];
|
||||
let candidate = self.candidates[candidate_ix].string.clone();
|
||||
|
||||
if secondary {
|
||||
eprintln!("Secondary confirmed {}", candidate)
|
||||
} else {
|
||||
eprintln!("Confirmed {}", candidate)
|
||||
}
|
||||
}
|
||||
|
||||
fn dismissed(&mut self, cx: &mut gpui::ViewContext<Picker<Self>>) {
|
||||
cx.quit();
|
||||
}
|
||||
|
||||
fn update_matches(
|
||||
&mut self,
|
||||
query: String,
|
||||
cx: &mut gpui::ViewContext<Picker<Self>>,
|
||||
) -> Task<()> {
|
||||
let candidates = self.candidates.clone();
|
||||
self.matches = cx
|
||||
.background_executor()
|
||||
.block(fuzzy::match_strings(
|
||||
&candidates,
|
||||
&query,
|
||||
true,
|
||||
100,
|
||||
&Default::default(),
|
||||
cx.background_executor().clone(),
|
||||
))
|
||||
.into_iter()
|
||||
.map(|r| r.candidate_id)
|
||||
.collect();
|
||||
self.selected_ix = 0;
|
||||
Task::ready(())
|
||||
}
|
||||
}
|
||||
|
||||
impl PickerStory {
|
||||
pub fn new(cx: &mut WindowContext) -> View<Self> {
|
||||
cx.build_view(|cx| {
|
||||
cx.bind_keys([
|
||||
KeyBinding::new("up", menu::SelectPrev, Some("picker")),
|
||||
KeyBinding::new("pageup", menu::SelectFirst, Some("picker")),
|
||||
KeyBinding::new("shift-pageup", menu::SelectFirst, Some("picker")),
|
||||
KeyBinding::new("ctrl-p", menu::SelectPrev, Some("picker")),
|
||||
KeyBinding::new("down", menu::SelectNext, Some("picker")),
|
||||
KeyBinding::new("pagedown", menu::SelectLast, Some("picker")),
|
||||
KeyBinding::new("shift-pagedown", menu::SelectFirst, Some("picker")),
|
||||
KeyBinding::new("ctrl-n", menu::SelectNext, Some("picker")),
|
||||
KeyBinding::new("cmd-up", menu::SelectFirst, Some("picker")),
|
||||
KeyBinding::new("cmd-down", menu::SelectLast, Some("picker")),
|
||||
KeyBinding::new("enter", menu::Confirm, Some("picker")),
|
||||
KeyBinding::new("ctrl-enter", menu::ShowContextMenu, Some("picker")),
|
||||
KeyBinding::new("cmd-enter", menu::SecondaryConfirm, Some("picker")),
|
||||
KeyBinding::new("escape", menu::Cancel, Some("picker")),
|
||||
KeyBinding::new("ctrl-c", menu::Cancel, Some("picker")),
|
||||
]);
|
||||
|
||||
PickerStory {
|
||||
picker: cx.build_view(|cx| {
|
||||
let mut delegate = Delegate::new(&[
|
||||
"Baguette (France)",
|
||||
"Baklava (Turkey)",
|
||||
"Beef Wellington (UK)",
|
||||
"Biryani (India)",
|
||||
"Borscht (Ukraine)",
|
||||
"Bratwurst (Germany)",
|
||||
"Bulgogi (Korea)",
|
||||
"Burrito (USA)",
|
||||
"Ceviche (Peru)",
|
||||
"Chicken Tikka Masala (India)",
|
||||
"Churrasco (Brazil)",
|
||||
"Couscous (North Africa)",
|
||||
"Croissant (France)",
|
||||
"Dim Sum (China)",
|
||||
"Empanada (Argentina)",
|
||||
"Fajitas (Mexico)",
|
||||
"Falafel (Middle East)",
|
||||
"Feijoada (Brazil)",
|
||||
"Fish and Chips (UK)",
|
||||
"Fondue (Switzerland)",
|
||||
"Goulash (Hungary)",
|
||||
"Haggis (Scotland)",
|
||||
"Kebab (Middle East)",
|
||||
"Kimchi (Korea)",
|
||||
"Lasagna (Italy)",
|
||||
"Maple Syrup Pancakes (Canada)",
|
||||
"Moussaka (Greece)",
|
||||
"Pad Thai (Thailand)",
|
||||
"Paella (Spain)",
|
||||
"Pancakes (USA)",
|
||||
"Pasta Carbonara (Italy)",
|
||||
"Pavlova (Australia)",
|
||||
"Peking Duck (China)",
|
||||
"Pho (Vietnam)",
|
||||
"Pierogi (Poland)",
|
||||
"Pizza (Italy)",
|
||||
"Poutine (Canada)",
|
||||
"Pretzel (Germany)",
|
||||
"Ramen (Japan)",
|
||||
"Rendang (Indonesia)",
|
||||
"Sashimi (Japan)",
|
||||
"Satay (Indonesia)",
|
||||
"Shepherd's Pie (Ireland)",
|
||||
"Sushi (Japan)",
|
||||
"Tacos (Mexico)",
|
||||
"Tandoori Chicken (India)",
|
||||
"Tortilla (Spain)",
|
||||
"Tzatziki (Greece)",
|
||||
"Wiener Schnitzel (Austria)",
|
||||
]);
|
||||
delegate.update_matches("".into(), cx).detach();
|
||||
|
||||
let picker = Picker::new(delegate, cx);
|
||||
picker.focus(cx);
|
||||
picker
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for PickerStory {
|
||||
type Element = Div<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
div()
|
||||
.bg(cx.theme().styles.colors.background)
|
||||
.size_full()
|
||||
.child(self.picker.clone())
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
use gpui::{
|
||||
div, px, Component, Div, ParentElement, Render, SharedString, StatefulInteraction, Styled,
|
||||
div, px, Component, Div, ParentElement, Render, SharedString, StatefulInteractivity, Styled,
|
||||
View, VisualContext, WindowContext,
|
||||
};
|
||||
use theme2::ActiveTheme;
|
||||
|
@ -13,12 +13,12 @@ impl ScrollStory {
|
|||
}
|
||||
|
||||
impl Render for ScrollStory {
|
||||
type Element = Div<Self, StatefulInteraction<Self>>;
|
||||
type Element = Div<Self, StatefulInteractivity<Self>>;
|
||||
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
let theme = cx.theme();
|
||||
let color_1 = theme.styles.git.created;
|
||||
let color_2 = theme.styles.git.modified;
|
||||
let color_1 = theme.status().created;
|
||||
let color_2 = theme.status().modified;
|
||||
|
||||
div()
|
||||
.id("parent")
|
||||
|
|
|
@ -38,6 +38,7 @@ pub enum ComponentStory {
|
|||
Palette,
|
||||
Panel,
|
||||
ProjectPanel,
|
||||
Players,
|
||||
RecentProjects,
|
||||
Scroll,
|
||||
Tab,
|
||||
|
@ -51,6 +52,7 @@ pub enum ComponentStory {
|
|||
TrafficLights,
|
||||
Workspace,
|
||||
ZIndex,
|
||||
Picker,
|
||||
}
|
||||
|
||||
impl ComponentStory {
|
||||
|
@ -79,6 +81,7 @@ impl ComponentStory {
|
|||
Self::MultiBuffer => cx.build_view(|_| ui::MultiBufferStory).into(),
|
||||
Self::NotificationsPanel => cx.build_view(|cx| ui::NotificationsPanelStory).into(),
|
||||
Self::Palette => cx.build_view(|cx| ui::PaletteStory).into(),
|
||||
Self::Players => cx.build_view(|_| theme2::PlayerStory).into(),
|
||||
Self::Panel => cx.build_view(|cx| ui::PanelStory).into(),
|
||||
Self::ProjectPanel => cx.build_view(|_| ui::ProjectPanelStory).into(),
|
||||
Self::RecentProjects => cx.build_view(|_| ui::RecentProjectsStory).into(),
|
||||
|
@ -94,6 +97,7 @@ impl ComponentStory {
|
|||
Self::TrafficLights => cx.build_view(|_| ui::TrafficLightsStory).into(),
|
||||
Self::Workspace => ui::WorkspaceStory::view(cx).into(),
|
||||
Self::ZIndex => cx.build_view(|_| ZIndexStory).into(),
|
||||
Self::Picker => PickerStory::new(cx).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,8 @@ fn main() {
|
|||
ThemeSettings::override_global(theme_settings, cx);
|
||||
|
||||
ui::settings::init(cx);
|
||||
language::init(cx);
|
||||
editor::init(cx);
|
||||
|
||||
let window = cx.open_window(
|
||||
WindowOptions {
|
||||
|
|
|
@ -186,9 +186,9 @@ pub fn mouse_side(
|
|||
}
|
||||
|
||||
pub fn grid_point(pos: Point<Pixels>, cur_size: TerminalSize, display_offset: usize) -> AlacPoint {
|
||||
let col = GridCol((pos.x / cur_size.cell_width).as_usize());
|
||||
let col = GridCol((cur_size.cell_width / pos.x) as usize);
|
||||
let col = min(col, cur_size.last_column());
|
||||
let line = (pos.y / cur_size.line_height).as_isize() as i32;
|
||||
let line = (cur_size.line_height / pos.y) as i32;
|
||||
let line = min(line, cur_size.bottommost_line().0);
|
||||
AlacPoint::new(GridLine(line - display_offset as i32), col)
|
||||
}
|
||||
|
|
|
@ -1121,8 +1121,7 @@ impl Terminal {
|
|||
None => return,
|
||||
};
|
||||
|
||||
let scroll_lines =
|
||||
(scroll_delta / self.last_content.size.line_height).as_isize() as i32;
|
||||
let scroll_lines = (scroll_delta / self.last_content.size.line_height) as i32;
|
||||
|
||||
self.events
|
||||
.push_back(InternalEvent::Scroll(AlacScroll::Delta(scroll_lines)));
|
||||
|
@ -1280,11 +1279,11 @@ impl Terminal {
|
|||
}
|
||||
/* Calculate the appropriate scroll lines */
|
||||
TouchPhase::Moved => {
|
||||
let old_offset = (self.scroll_px / line_height).as_isize() as i32;
|
||||
let old_offset = (self.scroll_px / line_height) as i32;
|
||||
|
||||
self.scroll_px += e.delta.pixel_delta(line_height).y * scroll_multiplier;
|
||||
|
||||
let new_offset = (self.scroll_px / line_height).as_isize() as i32;
|
||||
let new_offset = (self.scroll_px / line_height) as i32;
|
||||
|
||||
// Whenever we hit the edges, reset our stored scroll to 0
|
||||
// so we can respond to changes in direction quickly
|
||||
|
@ -1396,9 +1395,9 @@ fn all_search_matches<'a, T>(
|
|||
}
|
||||
|
||||
fn content_index_for_mouse(pos: Point<Pixels>, size: &TerminalSize) -> usize {
|
||||
let col = (pos.x / size.cell_width()).round().as_usize();
|
||||
let col = (pos.x / size.cell_width()).round() as usize;
|
||||
let clamped_col = min(col, size.columns() - 1);
|
||||
let row = (pos.y / size.line_height()).round().as_usize();
|
||||
let row = (pos.y / size.line_height()).round() as usize;
|
||||
let clamped_row = min(row, size.screen_lines() - 1);
|
||||
clamped_row * size.columns() + clamped_col
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ edition = "2021"
|
|||
publish = false
|
||||
|
||||
[features]
|
||||
default = ["stories"]
|
||||
stories = ["dep:itertools"]
|
||||
test-support = [
|
||||
"gpui/test-support",
|
||||
"fs/test-support",
|
||||
|
@ -28,7 +30,9 @@ serde_derive.workspace = true
|
|||
serde_json.workspace = true
|
||||
settings = { package = "settings2", path = "../settings2" }
|
||||
toml.workspace = true
|
||||
uuid.workspace = true
|
||||
util = { path = "../util" }
|
||||
itertools = { version = "0.11.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use gpui::Hsla;
|
||||
use refineable::Refineable;
|
||||
|
||||
use crate::SyntaxTheme;
|
||||
use crate::{PlayerColors, SyntaxTheme};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SystemColors {
|
||||
|
@ -11,16 +13,6 @@ pub struct SystemColors {
|
|||
pub mac_os_traffic_light_green: Hsla,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PlayerColor {
|
||||
pub cursor: Hsla,
|
||||
pub background: Hsla,
|
||||
pub selection: Hsla,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PlayerColors(pub Vec<PlayerColor>);
|
||||
|
||||
#[derive(Refineable, Clone, Debug)]
|
||||
#[refineable(debug)]
|
||||
pub struct StatusColors {
|
||||
|
@ -37,77 +29,217 @@ pub struct StatusColors {
|
|||
pub warning: Hsla,
|
||||
}
|
||||
|
||||
#[derive(Refineable, Clone, Debug)]
|
||||
#[refineable(debug)]
|
||||
pub struct GitStatusColors {
|
||||
pub conflict: Hsla,
|
||||
pub created: Hsla,
|
||||
pub deleted: Hsla,
|
||||
pub ignored: Hsla,
|
||||
pub modified: Hsla,
|
||||
pub renamed: Hsla,
|
||||
}
|
||||
|
||||
#[derive(Refineable, Clone, Debug)]
|
||||
#[refineable(debug, deserialize)]
|
||||
pub struct ThemeColors {
|
||||
pub border: Hsla,
|
||||
/// Border color. Used for deemphasized borders, like a visual divider between two sections
|
||||
pub border_variant: Hsla,
|
||||
/// Border color. Used for focused elements, like keyboard focused list item.
|
||||
pub border_focused: Hsla,
|
||||
/// Border color. Used for selected elements, like an active search filter or selected checkbox.
|
||||
pub border_selected: Hsla,
|
||||
/// Border color. Used for transparent borders. Used for placeholder borders when an element gains a border on state change.
|
||||
pub border_transparent: Hsla,
|
||||
/// Border color. Used for disabled elements, like a disabled input or button.
|
||||
pub border_disabled: Hsla,
|
||||
/// Border color. Used for elevated surfaces, like a context menu, popup, or dialog.
|
||||
pub elevated_surface_background: Hsla,
|
||||
/// Background Color. Used for grounded surfaces like a panel or tab.
|
||||
pub surface_background: Hsla,
|
||||
/// Background Color. Used for the app background and blank panels or windows.
|
||||
pub background: Hsla,
|
||||
/// Background Color. Used for the background of an element that should have a different background than the surface it's on.
|
||||
///
|
||||
/// Elements might include: Buttons, Inputs, Checkboxes, Radio Buttons...
|
||||
///
|
||||
/// For an element that should have the same background as the surface it's on, use `ghost_element_background`.
|
||||
pub element_background: Hsla,
|
||||
/// Background Color. Used for the hover state of an element that should have a different background than the surface it's on.
|
||||
///
|
||||
/// Hover states are triggered by the mouse entering an element, or a finger touching an element on a touch screen.
|
||||
pub element_hover: Hsla,
|
||||
/// Background Color. Used for the active state of an element that should have a different background than the surface it's on.
|
||||
///
|
||||
/// Active states are triggered by the mouse button being pressed down on an element, or the Return button or other activator being pressd.
|
||||
pub element_active: Hsla,
|
||||
/// Background Color. Used for the selected state of an element that should have a different background than the surface it's on.
|
||||
///
|
||||
/// Selected states are triggered by the element being selected (or "activated") by the user.
|
||||
///
|
||||
/// This could include a selected checkbox, a toggleable button that is toggled on, etc.
|
||||
pub element_selected: Hsla,
|
||||
/// Background Color. Used for the disabled state of an element that should have a different background than the surface it's on.
|
||||
///
|
||||
/// Disabled states are shown when a user cannot interact with an element, like a disabled button or input.
|
||||
pub element_disabled: Hsla,
|
||||
pub element_placeholder: Hsla,
|
||||
pub element_drop_target: Hsla,
|
||||
/// Background Color. Used for the area that shows where a dragged element will be dropped.
|
||||
pub drop_target_background: Hsla,
|
||||
/// Border Color. Used to show the area that shows where a dragged element will be dropped.
|
||||
// pub drop_target_border: Hsla,
|
||||
/// Used for the background of a ghost element that should have the same background as the surface it's on.
|
||||
///
|
||||
/// Elements might include: Buttons, Inputs, Checkboxes, Radio Buttons...
|
||||
///
|
||||
/// For an element that should have a different background than the surface it's on, use `element_background`.
|
||||
pub ghost_element_background: Hsla,
|
||||
/// Background Color. Used for the hover state of a ghost element that should have the same background as the surface it's on.
|
||||
///
|
||||
/// Hover states are triggered by the mouse entering an element, or a finger touching an element on a touch screen.
|
||||
pub ghost_element_hover: Hsla,
|
||||
/// Background Color. Used for the active state of a ghost element that should have the same background as the surface it's on.
|
||||
///
|
||||
/// Active states are triggered by the mouse button being pressed down on an element, or the Return button or other activator being pressd.
|
||||
pub ghost_element_active: Hsla,
|
||||
/// Background Color. Used for the selected state of a ghost element that should have the same background as the surface it's on.
|
||||
///
|
||||
/// Selected states are triggered by the element being selected (or "activated") by the user.
|
||||
///
|
||||
/// This could include a selected checkbox, a toggleable button that is toggled on, etc.
|
||||
pub ghost_element_selected: Hsla,
|
||||
/// Background Color. Used for the disabled state of a ghost element that should have the same background as the surface it's on.
|
||||
///
|
||||
/// Disabled states are shown when a user cannot interact with an element, like a disabled button or input.
|
||||
pub ghost_element_disabled: Hsla,
|
||||
/// Text Color. Default text color used for most text.
|
||||
pub text: Hsla,
|
||||
/// Text Color. Color of muted or deemphasized text. It is a subdued version of the standard text color.
|
||||
pub text_muted: Hsla,
|
||||
/// Text Color. Color of the placeholder text typically shown in input fields to guide the user to enter valid data.
|
||||
pub text_placeholder: Hsla,
|
||||
/// Text Color. Color used for text denoting disabled elements. Typically, the color is faded or grayed out to emphasize the disabled state.
|
||||
pub text_disabled: Hsla,
|
||||
/// Text Color. Color used for emphasis or highlighting certain text, like an active filter or a matched character in a search.
|
||||
pub text_accent: Hsla,
|
||||
/// Fill Color. Used for the default fill color of an icon.
|
||||
pub icon: Hsla,
|
||||
/// Fill Color. Used for the muted or deemphasized fill color of an icon.
|
||||
///
|
||||
/// This might be used to show an icon in an inactive pane, or to demphasize a series of icons to give them less visual weight.
|
||||
pub icon_muted: Hsla,
|
||||
/// Fill Color. Used for the disabled fill color of an icon.
|
||||
///
|
||||
/// Disabled states are shown when a user cannot interact with an element, like a icon button.
|
||||
pub icon_disabled: Hsla,
|
||||
/// Fill Color. Used for the placeholder fill color of an icon.
|
||||
///
|
||||
/// This might be used to show an icon in an input that disappears when the user enters text.
|
||||
pub icon_placeholder: Hsla,
|
||||
/// Fill Color. Used for the accent fill color of an icon.
|
||||
///
|
||||
/// This might be used to show when a toggleable icon button is selected.
|
||||
pub icon_accent: Hsla,
|
||||
|
||||
// ===
|
||||
// UI Elements
|
||||
// ===
|
||||
pub status_bar_background: Hsla,
|
||||
pub title_bar_background: Hsla,
|
||||
pub toolbar_background: Hsla,
|
||||
pub tab_bar_background: Hsla,
|
||||
pub tab_inactive_background: Hsla,
|
||||
pub tab_active_background: Hsla,
|
||||
// pub panel_background: Hsla,
|
||||
// pub pane_focused_border: Hsla,
|
||||
// /// The color of the scrollbar thumb.
|
||||
// pub scrollbar_thumb_background: Hsla,
|
||||
// /// The color of the scrollbar thumb when hovered over.
|
||||
// pub scrollbar_thumb_hover_background: Hsla,
|
||||
// /// The border color of the scrollbar thumb.
|
||||
// pub scrollbar_thumb_border: Hsla,
|
||||
// /// The background color of the scrollbar track.
|
||||
// pub scrollbar_track_background: Hsla,
|
||||
// /// The border color of the scrollbar track.
|
||||
// pub scrollbar_track_border: Hsla,
|
||||
// /// The opacity of the scrollbar status marks, like diagnostic states and git status..
|
||||
// pub scrollbar_status_opacity: Hsla,
|
||||
|
||||
// ===
|
||||
// Editor
|
||||
// ===
|
||||
pub editor_background: Hsla,
|
||||
// pub editor_inactive_background: Hsla,
|
||||
pub editor_gutter_background: Hsla,
|
||||
pub editor_subheader_background: Hsla,
|
||||
pub editor_active_line: Hsla,
|
||||
pub editor_active_line_background: Hsla,
|
||||
pub editor_highlighted_line_background: Hsla,
|
||||
/// Text Color. Used for the text of the line number in the editor gutter.
|
||||
pub editor_line_number: Hsla,
|
||||
/// Text Color. Used for the text of the line number in the editor gutter when the line is highlighted.
|
||||
pub editor_active_line_number: Hsla,
|
||||
/// Text Color. Used to mark invisible characters in the editor.
|
||||
///
|
||||
/// Example: spaces, tabs, carriage returns, etc.
|
||||
pub editor_invisible: Hsla,
|
||||
pub editor_wrap_guide: Hsla,
|
||||
pub editor_active_wrap_guide: Hsla,
|
||||
pub editor_document_highlight_read_background: Hsla,
|
||||
pub editor_document_highlight_write_background: Hsla,
|
||||
|
||||
// ===
|
||||
// Terminal
|
||||
// ===
|
||||
/// Terminal Background Color
|
||||
pub terminal_background: Hsla,
|
||||
/// Bright Black Color for ANSI Terminal
|
||||
pub terminal_ansi_bright_black: Hsla,
|
||||
/// Bright Red Color for ANSI Terminal
|
||||
pub terminal_ansi_bright_red: Hsla,
|
||||
/// Bright Green Color for ANSI Terminal
|
||||
pub terminal_ansi_bright_green: Hsla,
|
||||
/// Bright Yellow Color for ANSI Terminal
|
||||
pub terminal_ansi_bright_yellow: Hsla,
|
||||
/// Bright Blue Color for ANSI Terminal
|
||||
pub terminal_ansi_bright_blue: Hsla,
|
||||
/// Bright Magenta Color for ANSI Terminal
|
||||
pub terminal_ansi_bright_magenta: Hsla,
|
||||
/// Bright Cyan Color for ANSI Terminal
|
||||
pub terminal_ansi_bright_cyan: Hsla,
|
||||
/// Bright White Color for ANSI Terminal
|
||||
pub terminal_ansi_bright_white: Hsla,
|
||||
/// Black Color for ANSI Terminal
|
||||
pub terminal_ansi_black: Hsla,
|
||||
/// Red Color for ANSI Terminal
|
||||
pub terminal_ansi_red: Hsla,
|
||||
/// Green Color for ANSI Terminal
|
||||
pub terminal_ansi_green: Hsla,
|
||||
/// Yellow Color for ANSI Terminal
|
||||
pub terminal_ansi_yellow: Hsla,
|
||||
/// Blue Color for ANSI Terminal
|
||||
pub terminal_ansi_blue: Hsla,
|
||||
/// Magenta Color for ANSI Terminal
|
||||
pub terminal_ansi_magenta: Hsla,
|
||||
/// Cyan Color for ANSI Terminal
|
||||
pub terminal_ansi_cyan: Hsla,
|
||||
/// White Color for ANSI Terminal
|
||||
pub terminal_ansi_white: Hsla,
|
||||
// new colors
|
||||
|
||||
// ===
|
||||
// Elevation
|
||||
// ===
|
||||
// elevation_0_shadow
|
||||
// elevation_0_shadow_color
|
||||
// elevation_1_shadow
|
||||
// elevation_1_shadow_color
|
||||
// elevation_2_shadow
|
||||
// elevation_2_shadow_color
|
||||
// elevation_3_shadow
|
||||
// elevation_3_shadow_color
|
||||
// elevation_4_shadow
|
||||
// elevation_4_shadow_color
|
||||
// elevation_5_shadow
|
||||
// elevation_5_shadow_color
|
||||
|
||||
// ===
|
||||
// UI Text
|
||||
// ===
|
||||
// pub headline: Hsla,
|
||||
// pub paragraph: Hsla,
|
||||
// pub link: Hsla,
|
||||
// pub link_hover: Hsla,
|
||||
// pub code_block_background: Hsla,
|
||||
// pub code_block_border: Hsla,
|
||||
}
|
||||
|
||||
#[derive(Refineable, Clone)]
|
||||
|
@ -117,9 +249,8 @@ pub struct ThemeStyles {
|
|||
#[refineable]
|
||||
pub colors: ThemeColors,
|
||||
pub status: StatusColors,
|
||||
pub git: GitStatusColors,
|
||||
pub player: PlayerColors,
|
||||
pub syntax: SyntaxTheme,
|
||||
pub syntax: Arc<SyntaxTheme>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -2,12 +2,104 @@ use std::num::ParseIntError;
|
|||
|
||||
use gpui::{hsla, Hsla, Rgba};
|
||||
|
||||
use crate::{
|
||||
colors::{GitStatusColors, PlayerColor, PlayerColors, StatusColors, SystemColors, ThemeColors},
|
||||
scale::{ColorScaleSet, ColorScales},
|
||||
syntax::SyntaxTheme,
|
||||
ColorScale,
|
||||
};
|
||||
use crate::colors::{StatusColors, SystemColors, ThemeColors};
|
||||
use crate::scale::{ColorScaleSet, ColorScales};
|
||||
use crate::syntax::SyntaxTheme;
|
||||
use crate::{ColorScale, PlayerColor, PlayerColors};
|
||||
|
||||
impl Default for PlayerColors {
|
||||
fn default() -> Self {
|
||||
Self(vec![
|
||||
PlayerColor {
|
||||
cursor: blue().dark().step_9(),
|
||||
background: blue().dark().step_5(),
|
||||
selection: blue().dark().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: orange().dark().step_9(),
|
||||
background: orange().dark().step_5(),
|
||||
selection: orange().dark().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: pink().dark().step_9(),
|
||||
background: pink().dark().step_5(),
|
||||
selection: pink().dark().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: lime().dark().step_9(),
|
||||
background: lime().dark().step_5(),
|
||||
selection: lime().dark().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: purple().dark().step_9(),
|
||||
background: purple().dark().step_5(),
|
||||
selection: purple().dark().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: amber().dark().step_9(),
|
||||
background: amber().dark().step_5(),
|
||||
selection: amber().dark().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: jade().dark().step_9(),
|
||||
background: jade().dark().step_5(),
|
||||
selection: jade().dark().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: red().dark().step_9(),
|
||||
background: red().dark().step_5(),
|
||||
selection: red().dark().step_3(),
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayerColors {
|
||||
pub fn default_light() -> Self {
|
||||
Self(vec![
|
||||
PlayerColor {
|
||||
cursor: blue().light().step_9(),
|
||||
background: blue().light().step_4(),
|
||||
selection: blue().light().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: orange().light().step_9(),
|
||||
background: orange().light().step_4(),
|
||||
selection: orange().light().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: pink().light().step_9(),
|
||||
background: pink().light().step_4(),
|
||||
selection: pink().light().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: lime().light().step_9(),
|
||||
background: lime().light().step_4(),
|
||||
selection: lime().light().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: purple().light().step_9(),
|
||||
background: purple().light().step_4(),
|
||||
selection: purple().light().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: amber().light().step_9(),
|
||||
background: amber().light().step_4(),
|
||||
selection: amber().light().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: jade().light().step_9(),
|
||||
background: jade().light().step_4(),
|
||||
selection: jade().light().step_3(),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: red().light().step_9(),
|
||||
background: red().light().step_4(),
|
||||
selection: red().light().step_3(),
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
fn neutral() -> ColorScaleSet {
|
||||
slate()
|
||||
|
@ -27,61 +119,21 @@ impl Default for SystemColors {
|
|||
impl Default for StatusColors {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
conflict: red().dark().step_11(),
|
||||
created: grass().dark().step_11(),
|
||||
deleted: red().dark().step_11(),
|
||||
error: red().dark().step_11(),
|
||||
hidden: neutral().dark().step_11(),
|
||||
ignored: neutral().dark().step_11(),
|
||||
info: blue().dark().step_11(),
|
||||
modified: yellow().dark().step_11(),
|
||||
renamed: blue().dark().step_11(),
|
||||
success: grass().dark().step_11(),
|
||||
warning: yellow().dark().step_11(),
|
||||
conflict: red().dark().step_9(),
|
||||
created: grass().dark().step_9(),
|
||||
deleted: red().dark().step_9(),
|
||||
error: red().dark().step_9(),
|
||||
hidden: neutral().dark().step_9(),
|
||||
ignored: neutral().dark().step_9(),
|
||||
info: blue().dark().step_9(),
|
||||
modified: yellow().dark().step_9(),
|
||||
renamed: blue().dark().step_9(),
|
||||
success: grass().dark().step_9(),
|
||||
warning: yellow().dark().step_9(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GitStatusColors {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
conflict: orange().dark().step_11(),
|
||||
created: grass().dark().step_11(),
|
||||
deleted: red().dark().step_11(),
|
||||
ignored: neutral().dark().step_11(),
|
||||
modified: yellow().dark().step_11(),
|
||||
renamed: blue().dark().step_11(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PlayerColors {
|
||||
fn default() -> Self {
|
||||
Self(vec![
|
||||
PlayerColor {
|
||||
cursor: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
background: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
selection: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
background: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
selection: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
background: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
selection: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
},
|
||||
PlayerColor {
|
||||
cursor: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
background: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
selection: hsla(0.0, 0.0, 0.0, 0.0),
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl SyntaxTheme {
|
||||
pub fn default_light() -> Self {
|
||||
Self {
|
||||
|
@ -138,6 +190,8 @@ impl SyntaxTheme {
|
|||
("variable.special".into(), red().light().step_7().into()),
|
||||
("variant".into(), red().light().step_7().into()),
|
||||
],
|
||||
inlay_style: tomato().light().step_1().into(), // todo!("nate: use a proper style")
|
||||
suggestion_style: orange().light().step_1().into(), // todo!("nate: use proper style")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,6 +247,8 @@ impl SyntaxTheme {
|
|||
("variable.special".into(), red().dark().step_7().into()),
|
||||
("variant".into(), red().dark().step_7().into()),
|
||||
],
|
||||
inlay_style: tomato().dark().step_1().into(), // todo!("nate: use a proper style")
|
||||
suggestion_style: orange().dark().step_1().into(), // todo!("nate: use a proper style")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -216,8 +272,7 @@ impl ThemeColors {
|
|||
element_active: neutral().light().step_5(),
|
||||
element_selected: neutral().light().step_5(),
|
||||
element_disabled: neutral().light_alpha().step_3(),
|
||||
element_placeholder: neutral().light().step_11(),
|
||||
element_drop_target: blue().light_alpha().step_2(),
|
||||
drop_target_background: blue().light_alpha().step_2(),
|
||||
ghost_element_background: system.transparent,
|
||||
ghost_element_hover: neutral().light().step_4(),
|
||||
ghost_element_active: neutral().light().step_5(),
|
||||
|
@ -240,8 +295,17 @@ impl ThemeColors {
|
|||
tab_active_background: neutral().light().step_1(),
|
||||
tab_inactive_background: neutral().light().step_2(),
|
||||
editor_background: neutral().light().step_1(),
|
||||
editor_gutter_background: neutral().light().step_1(), // todo!("pick the right colors")
|
||||
editor_subheader_background: neutral().light().step_2(),
|
||||
editor_active_line: neutral().light_alpha().step_3(),
|
||||
editor_active_line_background: neutral().light_alpha().step_3(),
|
||||
editor_line_number: neutral().light_alpha().step_3(), // todo!("pick the right colors")
|
||||
editor_active_line_number: neutral().light_alpha().step_3(), // todo!("pick the right colors")
|
||||
editor_highlighted_line_background: neutral().light_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_invisible: neutral().light_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_wrap_guide: neutral().light_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_active_wrap_guide: neutral().light_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_document_highlight_read_background: neutral().light_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_document_highlight_write_background: neutral().light_alpha().step_4(), // todo!("pick the right colors")
|
||||
terminal_background: neutral().light().step_1(),
|
||||
terminal_ansi_black: black().light().step_12(),
|
||||
terminal_ansi_red: red().light().step_11(),
|
||||
|
@ -280,8 +344,7 @@ impl ThemeColors {
|
|||
element_active: neutral().dark().step_5(),
|
||||
element_selected: neutral().dark().step_5(),
|
||||
element_disabled: neutral().dark_alpha().step_3(),
|
||||
element_placeholder: neutral().dark().step_11(),
|
||||
element_drop_target: blue().dark_alpha().step_2(),
|
||||
drop_target_background: blue().dark_alpha().step_2(),
|
||||
ghost_element_background: system.transparent,
|
||||
ghost_element_hover: neutral().dark().step_4(),
|
||||
ghost_element_active: neutral().dark().step_5(),
|
||||
|
@ -304,8 +367,17 @@ impl ThemeColors {
|
|||
tab_active_background: neutral().dark().step_1(),
|
||||
tab_inactive_background: neutral().dark().step_2(),
|
||||
editor_background: neutral().dark().step_1(),
|
||||
editor_gutter_background: neutral().dark().step_1(), // todo!("pick the right colors")
|
||||
editor_subheader_background: neutral().dark().step_2(),
|
||||
editor_active_line: neutral().dark_alpha().step_3(),
|
||||
editor_active_line_background: neutral().dark_alpha().step_3(),
|
||||
editor_line_number: neutral().dark_alpha().step_3(), // todo!("pick the right colors")
|
||||
editor_active_line_number: neutral().dark_alpha().step_3(), // todo!("pick the right colors")
|
||||
editor_highlighted_line_background: neutral().dark_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_invisible: neutral().dark_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_wrap_guide: neutral().dark_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_active_wrap_guide: neutral().dark_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_document_highlight_read_background: neutral().dark_alpha().step_4(), // todo!("pick the right colors")
|
||||
editor_document_highlight_write_background: neutral().dark_alpha().step_4(), // todo!("pick the right colors")
|
||||
terminal_background: neutral().dark().step_1(),
|
||||
terminal_ansi_black: black().dark().step_12(),
|
||||
terminal_ansi_red: red().dark().step_11(),
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
colors::{GitStatusColors, PlayerColors, StatusColors, SystemColors, ThemeColors, ThemeStyles},
|
||||
default_color_scales, Appearance, SyntaxTheme, ThemeFamily, ThemeVariant,
|
||||
colors::{StatusColors, SystemColors, ThemeColors, ThemeStyles},
|
||||
default_color_scales, Appearance, PlayerColors, SyntaxTheme, Theme, ThemeFamily,
|
||||
};
|
||||
|
||||
fn zed_pro_daylight() -> ThemeVariant {
|
||||
ThemeVariant {
|
||||
fn zed_pro_daylight() -> Theme {
|
||||
Theme {
|
||||
id: "zed_pro_daylight".to_string(),
|
||||
name: "Zed Pro Daylight".into(),
|
||||
appearance: Appearance::Light,
|
||||
|
@ -12,15 +14,14 @@ fn zed_pro_daylight() -> ThemeVariant {
|
|||
system: SystemColors::default(),
|
||||
colors: ThemeColors::default_light(),
|
||||
status: StatusColors::default(),
|
||||
git: GitStatusColors::default(),
|
||||
player: PlayerColors::default(),
|
||||
syntax: SyntaxTheme::default_light(),
|
||||
player: PlayerColors::default_light(),
|
||||
syntax: Arc::new(SyntaxTheme::default_light()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn zed_pro_moonlight() -> ThemeVariant {
|
||||
ThemeVariant {
|
||||
pub(crate) fn zed_pro_moonlight() -> Theme {
|
||||
Theme {
|
||||
id: "zed_pro_moonlight".to_string(),
|
||||
name: "Zed Pro Moonlight".into(),
|
||||
appearance: Appearance::Dark,
|
||||
|
@ -28,9 +29,8 @@ pub(crate) fn zed_pro_moonlight() -> ThemeVariant {
|
|||
system: SystemColors::default(),
|
||||
colors: ThemeColors::default_dark(),
|
||||
status: StatusColors::default(),
|
||||
git: GitStatusColors::default(),
|
||||
player: PlayerColors::default(),
|
||||
syntax: SyntaxTheme::default_dark(),
|
||||
syntax: Arc::new(SyntaxTheme::default_dark()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ impl Default for ThemeFamily {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for ThemeVariant {
|
||||
impl Default for Theme {
|
||||
fn default() -> Self {
|
||||
zed_pro_daylight()
|
||||
}
|
||||
|
|
170
crates/theme2/src/players.rs
Normal file
170
crates/theme2/src/players.rs
Normal file
|
@ -0,0 +1,170 @@
|
|||
use gpui::Hsla;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PlayerColor {
|
||||
pub cursor: Hsla,
|
||||
pub background: Hsla,
|
||||
pub selection: Hsla,
|
||||
}
|
||||
|
||||
/// A collection of colors that are used to color players in the editor.
|
||||
///
|
||||
/// The first color is always the local player's color, usually a blue.
|
||||
///
|
||||
/// The rest of the default colors crisscross back and forth on the
|
||||
/// color wheel so that the colors are as distinct as possible.
|
||||
#[derive(Clone)]
|
||||
pub struct PlayerColors(pub Vec<PlayerColor>);
|
||||
|
||||
impl PlayerColors {
|
||||
pub fn local(&self) -> PlayerColor {
|
||||
// todo!("use a valid color");
|
||||
*self.0.first().unwrap()
|
||||
}
|
||||
|
||||
pub fn absent(&self) -> PlayerColor {
|
||||
// todo!("use a valid color");
|
||||
*self.0.last().unwrap()
|
||||
}
|
||||
|
||||
pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
|
||||
let len = self.0.len() - 1;
|
||||
self.0[(participant_index as usize % len) + 1]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "stories")]
|
||||
pub use stories::*;
|
||||
|
||||
#[cfg(feature = "stories")]
|
||||
mod stories {
|
||||
use super::*;
|
||||
use crate::{ActiveTheme, Story};
|
||||
use gpui::{div, img, px, Div, ParentElement, Render, Styled, ViewContext};
|
||||
|
||||
pub struct PlayerStory;
|
||||
|
||||
impl Render for PlayerStory {
|
||||
type Element = Div<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx).child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_4()
|
||||
.child(Story::title_for::<_, PlayerColors>(cx))
|
||||
.child(Story::label(cx, "Player Colors"))
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_1()
|
||||
.child(
|
||||
div().flex().gap_1().children(
|
||||
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||
div().w_8().h_8().rounded_md().bg(player.cursor)
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(div().flex().gap_1().children(
|
||||
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||
div().w_8().h_8().rounded_md().bg(player.background)
|
||||
}),
|
||||
))
|
||||
.child(div().flex().gap_1().children(
|
||||
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||
div().w_8().h_8().rounded_md().bg(player.selection)
|
||||
}),
|
||||
)),
|
||||
)
|
||||
.child(Story::label(cx, "Avatar Rings"))
|
||||
.child(div().flex().gap_1().children(
|
||||
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||
div()
|
||||
.my_1()
|
||||
.rounded_full()
|
||||
.border_2()
|
||||
.border_color(player.cursor)
|
||||
.child(
|
||||
img()
|
||||
.rounded_full()
|
||||
.uri("https://avatars.githubusercontent.com/u/1714999?v=4")
|
||||
.size_6()
|
||||
.bg(gpui::red()),
|
||||
)
|
||||
}),
|
||||
))
|
||||
.child(Story::label(cx, "Player Backgrounds"))
|
||||
.child(div().flex().gap_1().children(
|
||||
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||
div()
|
||||
.my_1()
|
||||
.rounded_xl()
|
||||
.flex()
|
||||
.items_center()
|
||||
.h_8()
|
||||
.py_0p5()
|
||||
.px_1p5()
|
||||
.bg(player.background)
|
||||
.child(
|
||||
div().relative().neg_mx_1().rounded_full().z_index(3)
|
||||
.border_2()
|
||||
.border_color(player.background)
|
||||
.size(px(28.))
|
||||
.child(
|
||||
img()
|
||||
.rounded_full()
|
||||
.uri("https://avatars.githubusercontent.com/u/1714999?v=4")
|
||||
.size(px(24.))
|
||||
.bg(gpui::red()),
|
||||
),
|
||||
).child(
|
||||
div().relative().neg_mx_1().rounded_full().z_index(2)
|
||||
.border_2()
|
||||
.border_color(player.background)
|
||||
.size(px(28.))
|
||||
.child(
|
||||
img()
|
||||
.rounded_full()
|
||||
.uri("https://avatars.githubusercontent.com/u/1714999?v=4")
|
||||
.size(px(24.))
|
||||
.bg(gpui::red()),
|
||||
),
|
||||
).child(
|
||||
div().relative().neg_mx_1().rounded_full().z_index(1)
|
||||
.border_2()
|
||||
.border_color(player.background)
|
||||
.size(px(28.))
|
||||
.child(
|
||||
img()
|
||||
.rounded_full()
|
||||
.uri("https://avatars.githubusercontent.com/u/1714999?v=4")
|
||||
.size(px(24.))
|
||||
.bg(gpui::red()),
|
||||
),
|
||||
)
|
||||
}),
|
||||
))
|
||||
.child(Story::label(cx, "Player Selections"))
|
||||
.child(div().flex().flex_col().gap_px().children(
|
||||
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||
div()
|
||||
.flex()
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.flex_none()
|
||||
.rounded_sm()
|
||||
.px_0p5()
|
||||
.text_color(cx.theme().colors().text)
|
||||
.bg(player.selection)
|
||||
.child("The brown fox jumped over the lazy dog."),
|
||||
)
|
||||
.child(div().flex_1())
|
||||
}),
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,17 @@
|
|||
use crate::{zed_pro_family, ThemeFamily, ThemeVariant};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use gpui::SharedString;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use refineable::Refineable;
|
||||
|
||||
use crate::{
|
||||
zed_pro_family, Appearance, PlayerColors, StatusColors, SyntaxTheme, SystemColors, Theme,
|
||||
ThemeColors, ThemeFamily, ThemeStyles, UserTheme, UserThemeFamily,
|
||||
};
|
||||
|
||||
pub struct ThemeRegistry {
|
||||
themes: HashMap<SharedString, Arc<ThemeVariant>>,
|
||||
themes: HashMap<SharedString, Arc<Theme>>,
|
||||
}
|
||||
|
||||
impl ThemeRegistry {
|
||||
|
@ -14,12 +21,45 @@ impl ThemeRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
fn insert_themes(&mut self, themes: impl IntoIterator<Item = ThemeVariant>) {
|
||||
fn insert_themes(&mut self, themes: impl IntoIterator<Item = Theme>) {
|
||||
for theme in themes.into_iter() {
|
||||
self.themes.insert(theme.name.clone(), Arc::new(theme));
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_user_theme_familes(&mut self, families: impl IntoIterator<Item = UserThemeFamily>) {
|
||||
for family in families.into_iter() {
|
||||
self.insert_user_themes(family.themes);
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_user_themes(&mut self, themes: impl IntoIterator<Item = UserTheme>) {
|
||||
self.insert_themes(themes.into_iter().map(|user_theme| {
|
||||
let mut theme_colors = match user_theme.appearance {
|
||||
Appearance::Light => ThemeColors::default_light(),
|
||||
Appearance::Dark => ThemeColors::default_dark(),
|
||||
};
|
||||
|
||||
theme_colors.refine(&user_theme.styles.colors);
|
||||
|
||||
Theme {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
name: user_theme.name.into(),
|
||||
appearance: user_theme.appearance,
|
||||
styles: ThemeStyles {
|
||||
system: SystemColors::default(),
|
||||
colors: theme_colors,
|
||||
status: StatusColors::default(),
|
||||
player: PlayerColors::default(),
|
||||
syntax: match user_theme.appearance {
|
||||
Appearance::Light => Arc::new(SyntaxTheme::default_light()),
|
||||
Appearance::Dark => Arc::new(SyntaxTheme::default_dark()),
|
||||
},
|
||||
},
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn list_names(&self, _staff: bool) -> impl Iterator<Item = SharedString> + '_ {
|
||||
self.themes.keys().cloned()
|
||||
}
|
||||
|
@ -28,7 +68,7 @@ impl ThemeRegistry {
|
|||
self.themes.values().map(|theme| theme.name.clone())
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> Result<Arc<ThemeVariant>> {
|
||||
pub fn get(&self, name: &str) -> Result<Arc<Theme>> {
|
||||
self.themes
|
||||
.get(name)
|
||||
.ok_or_else(|| anyhow!("theme not found: {}", name))
|
||||
|
@ -43,6 +83,7 @@ impl Default for ThemeRegistry {
|
|||
};
|
||||
|
||||
this.insert_theme_families([zed_pro_family()]);
|
||||
this.insert_user_theme_familes(crate::all_user_themes());
|
||||
|
||||
this
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{ThemeRegistry, ThemeVariant};
|
||||
use crate::{Theme, ThemeRegistry};
|
||||
use anyhow::Result;
|
||||
use gpui::{px, AppContext, Font, FontFeatures, FontStyle, FontWeight, Pixels};
|
||||
use schemars::{
|
||||
|
@ -21,7 +21,7 @@ pub struct ThemeSettings {
|
|||
pub buffer_font: Font,
|
||||
pub buffer_font_size: Pixels,
|
||||
pub buffer_line_height: BufferLineHeight,
|
||||
pub active_theme: Arc<ThemeVariant>,
|
||||
pub active_theme: Arc<Theme>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
38
crates/theme2/src/story.rs
Normal file
38
crates/theme2/src/story.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use gpui::{div, Component, Div, ParentElement, Styled, ViewContext};
|
||||
|
||||
use crate::ActiveTheme;
|
||||
|
||||
pub struct Story {}
|
||||
|
||||
impl Story {
|
||||
pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> {
|
||||
div()
|
||||
.size_full()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.pt_2()
|
||||
.px_4()
|
||||
.font("Zed Mono")
|
||||
.bg(cx.theme().colors().background)
|
||||
}
|
||||
|
||||
pub fn title<V: 'static>(cx: &mut ViewContext<V>, title: &str) -> impl Component<V> {
|
||||
div()
|
||||
.text_xl()
|
||||
.text_color(cx.theme().colors().text)
|
||||
.child(title.to_owned())
|
||||
}
|
||||
|
||||
pub fn title_for<V: 'static, T>(cx: &mut ViewContext<V>) -> impl Component<V> {
|
||||
Self::title(cx, std::any::type_name::<T>())
|
||||
}
|
||||
|
||||
pub fn label<V: 'static>(cx: &mut ViewContext<V>, label: &str) -> impl Component<V> {
|
||||
div()
|
||||
.mt_4()
|
||||
.mb_2()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().colors().text)
|
||||
.child(label.to_owned())
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ use gpui::{HighlightStyle, Hsla};
|
|||
#[derive(Clone, Default)]
|
||||
pub struct SyntaxTheme {
|
||||
pub highlights: Vec<(String, HighlightStyle)>,
|
||||
pub inlay_style: HighlightStyle,
|
||||
pub suggestion_style: HighlightStyle,
|
||||
}
|
||||
|
||||
impl SyntaxTheme {
|
||||
|
@ -21,6 +23,8 @@ impl SyntaxTheme {
|
|||
)
|
||||
})
|
||||
.collect(),
|
||||
inlay_style: HighlightStyle::default(),
|
||||
suggestion_style: HighlightStyle::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,32 @@
|
|||
mod colors;
|
||||
mod default_colors;
|
||||
mod default_theme;
|
||||
mod players;
|
||||
mod registry;
|
||||
mod scale;
|
||||
mod settings;
|
||||
mod syntax;
|
||||
mod themes;
|
||||
mod user_theme;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use ::settings::Settings;
|
||||
pub use colors::*;
|
||||
pub use default_colors::*;
|
||||
pub use default_theme::*;
|
||||
pub use players::*;
|
||||
pub use registry::*;
|
||||
pub use scale::*;
|
||||
pub use settings::*;
|
||||
pub use syntax::*;
|
||||
pub use themes::*;
|
||||
pub use user_theme::*;
|
||||
|
||||
use gpui::{AppContext, Hsla, SharedString};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Deserialize)]
|
||||
pub enum Appearance {
|
||||
Light,
|
||||
Dark,
|
||||
|
@ -29,35 +38,45 @@ pub fn init(cx: &mut AppContext) {
|
|||
}
|
||||
|
||||
pub trait ActiveTheme {
|
||||
fn theme(&self) -> &ThemeVariant;
|
||||
fn theme(&self) -> &Arc<Theme>;
|
||||
}
|
||||
|
||||
impl ActiveTheme for AppContext {
|
||||
fn theme(&self) -> &ThemeVariant {
|
||||
fn theme(&self) -> &Arc<Theme> {
|
||||
&ThemeSettings::get_global(self).active_theme
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ThemeFamily {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) id: String,
|
||||
pub id: String,
|
||||
pub name: SharedString,
|
||||
pub author: SharedString,
|
||||
pub themes: Vec<ThemeVariant>,
|
||||
pub themes: Vec<Theme>,
|
||||
pub scales: ColorScales,
|
||||
}
|
||||
|
||||
impl ThemeFamily {}
|
||||
|
||||
pub struct ThemeVariant {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) id: String,
|
||||
pub struct Theme {
|
||||
pub id: String,
|
||||
pub name: SharedString,
|
||||
pub appearance: Appearance,
|
||||
pub styles: ThemeStyles,
|
||||
}
|
||||
|
||||
impl ThemeVariant {
|
||||
impl Theme {
|
||||
/// Returns the [`SystemColors`] for the theme.
|
||||
#[inline(always)]
|
||||
pub fn system(&self) -> &SystemColors {
|
||||
&self.styles.system
|
||||
}
|
||||
|
||||
/// Returns the [`ThemeColors`] for the theme.
|
||||
#[inline(always)]
|
||||
pub fn players(&self) -> &PlayerColors {
|
||||
&self.styles.player
|
||||
}
|
||||
|
||||
/// Returns the [`ThemeColors`] for the theme.
|
||||
#[inline(always)]
|
||||
pub fn colors(&self) -> &ThemeColors {
|
||||
|
@ -66,7 +85,7 @@ impl ThemeVariant {
|
|||
|
||||
/// Returns the [`SyntaxTheme`] for the theme.
|
||||
#[inline(always)]
|
||||
pub fn syntax(&self) -> &SyntaxTheme {
|
||||
pub fn syntax(&self) -> &Arc<SyntaxTheme> {
|
||||
&self.styles.syntax
|
||||
}
|
||||
|
||||
|
@ -76,15 +95,35 @@ impl ThemeVariant {
|
|||
&self.styles.status
|
||||
}
|
||||
|
||||
/// Returns the [`GitStatusColors`] for the theme.
|
||||
#[inline(always)]
|
||||
pub fn git(&self) -> &GitStatusColors {
|
||||
&self.styles.git
|
||||
}
|
||||
|
||||
/// Returns the color for the syntax node with the given name.
|
||||
#[inline(always)]
|
||||
pub fn syntax_color(&self, name: &str) -> Hsla {
|
||||
self.syntax().color(name)
|
||||
}
|
||||
|
||||
/// Returns the [`DiagnosticStyle`] for the theme.
|
||||
#[inline(always)]
|
||||
pub fn diagnostic_style(&self) -> DiagnosticStyle {
|
||||
DiagnosticStyle {
|
||||
error: self.status().error,
|
||||
warning: self.status().warning,
|
||||
info: self.status().info,
|
||||
hint: self.status().info,
|
||||
ignored: self.status().ignored,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DiagnosticStyle {
|
||||
pub error: Hsla,
|
||||
pub warning: Hsla,
|
||||
pub info: Hsla,
|
||||
pub hint: Hsla,
|
||||
pub ignored: Hsla,
|
||||
}
|
||||
|
||||
#[cfg(feature = "stories")]
|
||||
mod story;
|
||||
#[cfg(feature = "stories")]
|
||||
pub use story::*;
|
||||
|
|
85
crates/theme2/src/themes/andromeda.rs
Normal file
85
crates/theme2/src/themes/andromeda.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn andromeda() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Andromeda".into(),
|
||||
author: "Eliver Lara (EliverLara)".into(),
|
||||
themes: vec![
|
||||
UserTheme {
|
||||
name: "Andromeda".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x1b1d23ff).into()),
|
||||
border_variant: Some(rgba(0x1b1d23ff).into()),
|
||||
border_focused: Some(rgba(0x1b1d23ff).into()),
|
||||
border_selected: Some(rgba(0x1b1d23ff).into()),
|
||||
border_transparent: Some(rgba(0x1b1d23ff).into()),
|
||||
border_disabled: Some(rgba(0x1b1d23ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x23262eff).into()),
|
||||
surface_background: Some(rgba(0x23262eff).into()),
|
||||
background: Some(rgba(0x23262eff).into()),
|
||||
element_background: Some(rgba(0x00e8c5cc).into()),
|
||||
text: Some(rgba(0xd4cdd8ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x23262eff).into()),
|
||||
tab_active_background: Some(rgba(0x23262eff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xee5d42ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x95e072ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xffe66dff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x7bb7ffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xff00a9ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x00e8c6ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xee5d42ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x95e072ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xffe66dff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x7bb7ffff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xff00a9ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x00e8c6ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Andromeda Bordered".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x1b1d23ff).into()),
|
||||
border_variant: Some(rgba(0x1b1d23ff).into()),
|
||||
border_focused: Some(rgba(0x1b1d23ff).into()),
|
||||
border_selected: Some(rgba(0x1b1d23ff).into()),
|
||||
border_transparent: Some(rgba(0x1b1d23ff).into()),
|
||||
border_disabled: Some(rgba(0x1b1d23ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x23262eff).into()),
|
||||
surface_background: Some(rgba(0x23262eff).into()),
|
||||
background: Some(rgba(0x262933ff).into()),
|
||||
element_background: Some(rgba(0x00e8c5cc).into()),
|
||||
text: Some(rgba(0xd4cdd8ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x23262eff).into()),
|
||||
tab_active_background: Some(rgba(0x262933ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xee5d42ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x95e072ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xffe66dff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x7bb7ffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xff00a9ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x00e8c6ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xee5d42ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x95e072ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xffe66dff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x7bb7ffff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xff00a9ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x00e8c6ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
134
crates/theme2/src/themes/ayu.rs
Normal file
134
crates/theme2/src/themes/ayu.rs
Normal file
|
@ -0,0 +1,134 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn ayu() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Ayu".into(),
|
||||
author: "dempfi (Ike Ku)".into(),
|
||||
themes: vec![
|
||||
UserTheme {
|
||||
name: "Ayu Light".into(),
|
||||
appearance: Appearance::Light,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x6b7d8f1f).into()),
|
||||
border_variant: Some(rgba(0x6b7d8f1f).into()),
|
||||
border_focused: Some(rgba(0x6b7d8f1f).into()),
|
||||
border_selected: Some(rgba(0x6b7d8f1f).into()),
|
||||
border_transparent: Some(rgba(0x6b7d8f1f).into()),
|
||||
border_disabled: Some(rgba(0x6b7d8f1f).into()),
|
||||
elevated_surface_background: Some(rgba(0xf8f9faff).into()),
|
||||
surface_background: Some(rgba(0xf8f9faff).into()),
|
||||
background: Some(rgba(0xf8f9faff).into()),
|
||||
element_background: Some(rgba(0xffaa32ff).into()),
|
||||
text: Some(rgba(0x8a9199ff).into()),
|
||||
tab_inactive_background: Some(rgba(0xf8f9faff).into()),
|
||||
tab_active_background: Some(rgba(0xf8f9faff).into()),
|
||||
terminal_background: Some(rgba(0xf8f9faff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x686868ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xef7070ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x86b300ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xf2ad48ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x389ee6ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xa37accff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x4bbf98ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xd1d1d1ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x000000ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xea6c6dff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x6cbf43ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xeca944ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x3198e1ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0x9e75c7ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x46ba94ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xc7c7c7ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Ayu Mirage".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x171a24ff).into()),
|
||||
border_variant: Some(rgba(0x171a24ff).into()),
|
||||
border_focused: Some(rgba(0x171a24ff).into()),
|
||||
border_selected: Some(rgba(0x171a24ff).into()),
|
||||
border_transparent: Some(rgba(0x171a24ff).into()),
|
||||
border_disabled: Some(rgba(0x171a24ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x1f2430ff).into()),
|
||||
surface_background: Some(rgba(0x1f2430ff).into()),
|
||||
background: Some(rgba(0x1f2430ff).into()),
|
||||
element_background: Some(rgba(0xffcb65ff).into()),
|
||||
text: Some(rgba(0x707a8cff).into()),
|
||||
tab_inactive_background: Some(rgba(0x1f2430ff).into()),
|
||||
tab_active_background: Some(rgba(0x1f2430ff).into()),
|
||||
terminal_background: Some(rgba(0x1f2430ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x686868ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xf18678ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0xd4fe7fff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xffd173ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x73cfffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xdfbfffff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x95e6cbff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xffffffff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x171a24ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xed8173ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x86d96bff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xfacc6eff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x6ccafaff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xdabafaff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x90e1c6ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xc7c7c7ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Ayu Dark".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x1e232bff).into()),
|
||||
border_variant: Some(rgba(0x1e232bff).into()),
|
||||
border_focused: Some(rgba(0x1e232bff).into()),
|
||||
border_selected: Some(rgba(0x1e232bff).into()),
|
||||
border_transparent: Some(rgba(0x1e232bff).into()),
|
||||
border_disabled: Some(rgba(0x1e232bff).into()),
|
||||
elevated_surface_background: Some(rgba(0x0b0e14ff).into()),
|
||||
surface_background: Some(rgba(0x0b0e14ff).into()),
|
||||
background: Some(rgba(0x0b0e14ff).into()),
|
||||
element_background: Some(rgba(0xe6b450ff).into()),
|
||||
text: Some(rgba(0x565b66ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x0b0e14ff).into()),
|
||||
tab_active_background: Some(rgba(0x0b0e14ff).into()),
|
||||
terminal_background: Some(rgba(0x0b0e14ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x686868ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xef7077ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0xa9d94bff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xffb353ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x59c2ffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xd2a6ffff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x95e6cbff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xffffffff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x1e232bff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xea6c72ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x7ed962ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xf9af4fff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x52bdfaff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xcca1faff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x90e1c6ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xc7c7c7ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
54
crates/theme2/src/themes/dracula.rs
Normal file
54
crates/theme2/src/themes/dracula.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn dracula() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Dracula".into(),
|
||||
author: "Zeno Rocha".into(),
|
||||
themes: vec![UserTheme {
|
||||
name: "Dracula".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0xbd93f9ff).into()),
|
||||
border_variant: Some(rgba(0xbd93f9ff).into()),
|
||||
border_focused: Some(rgba(0xbd93f9ff).into()),
|
||||
border_selected: Some(rgba(0xbd93f9ff).into()),
|
||||
border_transparent: Some(rgba(0xbd93f9ff).into()),
|
||||
border_disabled: Some(rgba(0xbd93f9ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x282a35ff).into()),
|
||||
surface_background: Some(rgba(0x282a35ff).into()),
|
||||
background: Some(rgba(0x282a35ff).into()),
|
||||
element_background: Some(rgba(0x44475aff).into()),
|
||||
text: Some(rgba(0xf8f8f2ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x21222cff).into()),
|
||||
tab_active_background: Some(rgba(0x282a35ff).into()),
|
||||
terminal_background: Some(rgba(0x282a35ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x6272a4ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xff6d6dff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x69ff94ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xffffa5ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0xd6abfeff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xff92dfff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0xa3fefeff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xffffffff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x21222cff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xff5555ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x50fa7bff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xf1fa8cff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0xbd93f9ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xff79c6ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x8be9fdff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xf8f8f2ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
}],
|
||||
}
|
||||
}
|
239
crates/theme2/src/themes/gruvbox.rs
Normal file
239
crates/theme2/src/themes/gruvbox.rs
Normal file
|
@ -0,0 +1,239 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn gruvbox() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Gruvbox".into(),
|
||||
author: "morhetz".into(),
|
||||
themes: vec![
|
||||
UserTheme {
|
||||
name: "Gruvbox Dark Hard".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x3c3836ff).into()),
|
||||
border_variant: Some(rgba(0x3c3836ff).into()),
|
||||
border_focused: Some(rgba(0x3c3836ff).into()),
|
||||
border_selected: Some(rgba(0x3c3836ff).into()),
|
||||
border_transparent: Some(rgba(0x3c3836ff).into()),
|
||||
border_disabled: Some(rgba(0x3c3836ff).into()),
|
||||
background: Some(rgba(0x1d2021ff).into()),
|
||||
element_background: Some(rgba(0x44858780).into()),
|
||||
text: Some(rgba(0xebdbb2ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x1d2021ff).into()),
|
||||
tab_active_background: Some(rgba(0x32302fff).into()),
|
||||
terminal_background: Some(rgba(0x1d2021ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xfb4833ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0xb8bb25ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xfabd2eff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x83a598ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xd3869bff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x8ec07cff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xebdbb2ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x3c3836ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xcc241cff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x989719ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xd79920ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x448587ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xb16185ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x679d6aff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xa89984ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Gruvbox Dark Medium".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x3c3836ff).into()),
|
||||
border_variant: Some(rgba(0x3c3836ff).into()),
|
||||
border_focused: Some(rgba(0x3c3836ff).into()),
|
||||
border_selected: Some(rgba(0x3c3836ff).into()),
|
||||
border_transparent: Some(rgba(0x3c3836ff).into()),
|
||||
border_disabled: Some(rgba(0x3c3836ff).into()),
|
||||
background: Some(rgba(0x282828ff).into()),
|
||||
element_background: Some(rgba(0x44858780).into()),
|
||||
text: Some(rgba(0xebdbb2ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x282828ff).into()),
|
||||
tab_active_background: Some(rgba(0x3c3836ff).into()),
|
||||
terminal_background: Some(rgba(0x282828ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xfb4833ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0xb8bb25ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xfabd2eff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x83a598ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xd3869bff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x8ec07cff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xebdbb2ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x3c3836ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xcc241cff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x989719ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xd79920ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x448587ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xb16185ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x679d6aff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xa89984ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Gruvbox Dark Soft".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x3c3836ff).into()),
|
||||
border_variant: Some(rgba(0x3c3836ff).into()),
|
||||
border_focused: Some(rgba(0x3c3836ff).into()),
|
||||
border_selected: Some(rgba(0x3c3836ff).into()),
|
||||
border_transparent: Some(rgba(0x3c3836ff).into()),
|
||||
border_disabled: Some(rgba(0x3c3836ff).into()),
|
||||
background: Some(rgba(0x32302fff).into()),
|
||||
element_background: Some(rgba(0x44858780).into()),
|
||||
text: Some(rgba(0xebdbb2ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x32302fff).into()),
|
||||
tab_active_background: Some(rgba(0x504945ff).into()),
|
||||
terminal_background: Some(rgba(0x32302fff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xfb4833ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0xb8bb25ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xfabd2eff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x83a598ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xd3869bff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x8ec07cff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xebdbb2ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x3c3836ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xcc241cff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x989719ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xd79920ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x448587ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xb16185ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x679d6aff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xa89984ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Gruvbox Light Hard".into(),
|
||||
appearance: Appearance::Light,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0xebdbb2ff).into()),
|
||||
border_variant: Some(rgba(0xebdbb2ff).into()),
|
||||
border_focused: Some(rgba(0xebdbb2ff).into()),
|
||||
border_selected: Some(rgba(0xebdbb2ff).into()),
|
||||
border_transparent: Some(rgba(0xebdbb2ff).into()),
|
||||
border_disabled: Some(rgba(0xebdbb2ff).into()),
|
||||
background: Some(rgba(0xf9f5d7ff).into()),
|
||||
element_background: Some(rgba(0x44858780).into()),
|
||||
text: Some(rgba(0x3c3836ff).into()),
|
||||
tab_inactive_background: Some(rgba(0xf9f5d7ff).into()),
|
||||
tab_active_background: Some(rgba(0xf2e5bcff).into()),
|
||||
terminal_background: Some(rgba(0xf9f5d7ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0x9d0006ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x79740eff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xb57613ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x066578ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0x8f3e71ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x427b58ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0x3c3836ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0xebdbb2ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xcc241cff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x989719ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xd79920ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x448587ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xb16185ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x679d6aff).into()),
|
||||
terminal_ansi_white: Some(rgba(0x7c6f64ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Gruvbox Light Medium".into(),
|
||||
appearance: Appearance::Light,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0xebdbb2ff).into()),
|
||||
border_variant: Some(rgba(0xebdbb2ff).into()),
|
||||
border_focused: Some(rgba(0xebdbb2ff).into()),
|
||||
border_selected: Some(rgba(0xebdbb2ff).into()),
|
||||
border_transparent: Some(rgba(0xebdbb2ff).into()),
|
||||
border_disabled: Some(rgba(0xebdbb2ff).into()),
|
||||
background: Some(rgba(0xfbf1c7ff).into()),
|
||||
element_background: Some(rgba(0x44858780).into()),
|
||||
text: Some(rgba(0x3c3836ff).into()),
|
||||
tab_inactive_background: Some(rgba(0xfbf1c7ff).into()),
|
||||
tab_active_background: Some(rgba(0xebdbb2ff).into()),
|
||||
terminal_background: Some(rgba(0xfbf1c7ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0x9d0006ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x79740eff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xb57613ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x066578ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0x8f3e71ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x427b58ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0x3c3836ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0xebdbb2ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xcc241cff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x989719ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xd79920ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x448587ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xb16185ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x679d6aff).into()),
|
||||
terminal_ansi_white: Some(rgba(0x7c6f64ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Gruvbox Light Soft".into(),
|
||||
appearance: Appearance::Light,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0xebdbb2ff).into()),
|
||||
border_variant: Some(rgba(0xebdbb2ff).into()),
|
||||
border_focused: Some(rgba(0xebdbb2ff).into()),
|
||||
border_selected: Some(rgba(0xebdbb2ff).into()),
|
||||
border_transparent: Some(rgba(0xebdbb2ff).into()),
|
||||
border_disabled: Some(rgba(0xebdbb2ff).into()),
|
||||
background: Some(rgba(0xf2e5bcff).into()),
|
||||
element_background: Some(rgba(0x44858780).into()),
|
||||
text: Some(rgba(0x3c3836ff).into()),
|
||||
tab_inactive_background: Some(rgba(0xf2e5bcff).into()),
|
||||
tab_active_background: Some(rgba(0xd5c4a1ff).into()),
|
||||
terminal_background: Some(rgba(0xf2e5bcff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0x9d0006ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x79740eff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xb57613ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x066578ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0x8f3e71ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x427b58ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0x3c3836ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0xebdbb2ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xcc241cff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x989719ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xd79920ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x448587ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xb16185ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x679d6aff).into()),
|
||||
terminal_ansi_white: Some(rgba(0x7c6f64ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
44
crates/theme2/src/themes/mod.rs
Normal file
44
crates/theme2/src/themes/mod.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
mod andromeda;
|
||||
mod ayu;
|
||||
mod dracula;
|
||||
mod gruvbox;
|
||||
mod night_owl;
|
||||
mod nord;
|
||||
mod notctis;
|
||||
mod palenight;
|
||||
mod rose_pine;
|
||||
mod solarized;
|
||||
mod synthwave_84;
|
||||
|
||||
pub use andromeda::*;
|
||||
pub use ayu::*;
|
||||
pub use dracula::*;
|
||||
pub use gruvbox::*;
|
||||
pub use night_owl::*;
|
||||
pub use nord::*;
|
||||
pub use notctis::*;
|
||||
pub use palenight::*;
|
||||
pub use rose_pine::*;
|
||||
pub use solarized::*;
|
||||
pub use synthwave_84::*;
|
||||
|
||||
use crate::UserThemeFamily;
|
||||
|
||||
pub(crate) fn all_user_themes() -> Vec<UserThemeFamily> {
|
||||
vec![
|
||||
rose_pine(),
|
||||
night_owl(),
|
||||
andromeda(),
|
||||
synthwave_84(),
|
||||
palenight(),
|
||||
dracula(),
|
||||
solarized(),
|
||||
nord(),
|
||||
notctis(),
|
||||
ayu(),
|
||||
gruvbox(),
|
||||
]
|
||||
}
|
94
crates/theme2/src/themes/night_owl.rs
Normal file
94
crates/theme2/src/themes/night_owl.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn night_owl() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Night Owl".into(),
|
||||
author: "Sarah Drasner (sdras)".into(),
|
||||
themes: vec![
|
||||
UserTheme {
|
||||
name: "Night Owl".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x5f7e97ff).into()),
|
||||
border_variant: Some(rgba(0x5f7e97ff).into()),
|
||||
border_focused: Some(rgba(0x5f7e97ff).into()),
|
||||
border_selected: Some(rgba(0x5f7e97ff).into()),
|
||||
border_transparent: Some(rgba(0x5f7e97ff).into()),
|
||||
border_disabled: Some(rgba(0x5f7e97ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x011526ff).into()),
|
||||
surface_background: Some(rgba(0x011526ff).into()),
|
||||
background: Some(rgba(0x011526ff).into()),
|
||||
element_background: Some(rgba(0x7d56c1cc).into()),
|
||||
text: Some(rgba(0xd6deebff).into()),
|
||||
tab_inactive_background: Some(rgba(0x01101cff).into()),
|
||||
tab_active_background: Some(rgba(0x0a2842ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x575656ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xef524fff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x21da6eff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xffeb95ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x82aaffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xc792eaff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x7fdbcaff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xffffffff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x011526ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xef524fff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x21da6eff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xc5e478ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x82aaffff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xc792eaff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x20c7a7ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xffffffff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Night Owl Light".into(),
|
||||
appearance: Appearance::Light,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0xd9d9d9ff).into()),
|
||||
border_variant: Some(rgba(0xd9d9d9ff).into()),
|
||||
border_focused: Some(rgba(0xd9d9d9ff).into()),
|
||||
border_selected: Some(rgba(0xd9d9d9ff).into()),
|
||||
border_transparent: Some(rgba(0xd9d9d9ff).into()),
|
||||
border_disabled: Some(rgba(0xd9d9d9ff).into()),
|
||||
elevated_surface_background: Some(rgba(0xf0f0f0ff).into()),
|
||||
surface_background: Some(rgba(0xf0f0f0ff).into()),
|
||||
background: Some(rgba(0xfbfbfbff).into()),
|
||||
element_background: Some(rgba(0x29a298ff).into()),
|
||||
text: Some(rgba(0x403f53ff).into()),
|
||||
tab_inactive_background: Some(rgba(0xf0f0f0ff).into()),
|
||||
tab_active_background: Some(rgba(0xf6f6f6ff).into()),
|
||||
terminal_background: Some(rgba(0xf6f6f6ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x403f53ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xde3c3aff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x07916aff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xdaa900ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x278dd7ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xd64289ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x29a298ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xf0f0f0ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x403f53ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xde3c3aff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x07916aff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xe0ae01ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x278dd7ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xd64289ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x29a298ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xf0f0f0ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
54
crates/theme2/src/themes/nord.rs
Normal file
54
crates/theme2/src/themes/nord.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn nord() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Nord".into(),
|
||||
author: "Sven Greb (svengreb)".into(),
|
||||
themes: vec![UserTheme {
|
||||
name: "Nord".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x3b4252ff).into()),
|
||||
border_variant: Some(rgba(0x3b4252ff).into()),
|
||||
border_focused: Some(rgba(0x3b4252ff).into()),
|
||||
border_selected: Some(rgba(0x3b4252ff).into()),
|
||||
border_transparent: Some(rgba(0x3b4252ff).into()),
|
||||
border_disabled: Some(rgba(0x3b4252ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x2e3440ff).into()),
|
||||
surface_background: Some(rgba(0x2e3440ff).into()),
|
||||
background: Some(rgba(0x2e3440ff).into()),
|
||||
element_background: Some(rgba(0x88bfd0ee).into()),
|
||||
text: Some(rgba(0xd8dee9ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x2e3440ff).into()),
|
||||
tab_active_background: Some(rgba(0x3b4252ff).into()),
|
||||
terminal_background: Some(rgba(0x2e3440ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x4c566aff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xbf616aff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0xa3be8cff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xebcb8bff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x81a1c1ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xb48eacff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x8fbcbbff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xeceff4ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x3b4252ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xbf616aff).into()),
|
||||
terminal_ansi_green: Some(rgba(0xa3be8cff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xebcb8bff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x81a1c1ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xb48eacff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x88bfd0ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xe5e9f0ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
}],
|
||||
}
|
||||
}
|
446
crates/theme2/src/themes/notctis.rs
Normal file
446
crates/theme2/src/themes/notctis.rs
Normal file
|
@ -0,0 +1,446 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn notctis() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Notctis".into(),
|
||||
author: "Liviu Schera (liviuschera)".into(),
|
||||
themes: vec![
|
||||
UserTheme {
|
||||
name: "Noctis Azureus".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x1579b6ff).into()),
|
||||
border_variant: Some(rgba(0x1579b6ff).into()),
|
||||
border_focused: Some(rgba(0x1579b6ff).into()),
|
||||
border_selected: Some(rgba(0x1579b6ff).into()),
|
||||
border_transparent: Some(rgba(0x1579b6ff).into()),
|
||||
border_disabled: Some(rgba(0x1579b6ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x051b28ff).into()),
|
||||
surface_background: Some(rgba(0x051b28ff).into()),
|
||||
background: Some(rgba(0x07263aff).into()),
|
||||
element_background: Some(rgba(0x007e99ff).into()),
|
||||
text: Some(rgba(0xbecfdaff).into()),
|
||||
tab_inactive_background: Some(rgba(0x08324eff).into()),
|
||||
tab_active_background: Some(rgba(0x07263aff).into()),
|
||||
terminal_background: Some(rgba(0x051b28ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x475e6cff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xbecfdaff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x28343dff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe66432ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xaec3d0ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctis Bordo".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x997582ff).into()),
|
||||
border_variant: Some(rgba(0x997582ff).into()),
|
||||
border_focused: Some(rgba(0x997582ff).into()),
|
||||
border_selected: Some(rgba(0x997582ff).into()),
|
||||
border_transparent: Some(rgba(0x997582ff).into()),
|
||||
border_disabled: Some(rgba(0x997582ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x272022ff).into()),
|
||||
surface_background: Some(rgba(0x272022ff).into()),
|
||||
background: Some(rgba(0x322a2dff).into()),
|
||||
element_background: Some(rgba(0x007e99ff).into()),
|
||||
text: Some(rgba(0xcbbec2ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x413036ff).into()),
|
||||
tab_active_background: Some(rgba(0x322a2dff).into()),
|
||||
terminal_background: Some(rgba(0x272022ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x69545bff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xcbbec2ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x47393eff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe66432ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xb9acb0ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctus Hibernus".into(),
|
||||
appearance: Appearance::Light,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x00c6e0ff).into()),
|
||||
border_variant: Some(rgba(0x00c6e0ff).into()),
|
||||
border_focused: Some(rgba(0x00c6e0ff).into()),
|
||||
border_selected: Some(rgba(0x00c6e0ff).into()),
|
||||
border_transparent: Some(rgba(0x00c6e0ff).into()),
|
||||
border_disabled: Some(rgba(0x00c6e0ff).into()),
|
||||
elevated_surface_background: Some(rgba(0xe1eeefff).into()),
|
||||
surface_background: Some(rgba(0xe1eeefff).into()),
|
||||
background: Some(rgba(0xf4f6f6ff).into()),
|
||||
element_background: Some(rgba(0x089099ff).into()),
|
||||
text: Some(rgba(0x005661ff).into()),
|
||||
tab_inactive_background: Some(rgba(0xcaedf2ff).into()),
|
||||
tab_active_background: Some(rgba(0xf4f6f6ff).into()),
|
||||
terminal_background: Some(rgba(0xe1eeefff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x004d57ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xff3f00ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x00d17aff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xff8c00ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x0ea3ffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xff6b9eff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x00cae6ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xbbc3c4ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x003b41ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe34d1bff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x00b368ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xf49724ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x0094f0ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xff5792ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x00bdd6ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0x8ca6a6ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctis Lilac".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0xaea4f4ff).into()),
|
||||
border_variant: Some(rgba(0xaea4f4ff).into()),
|
||||
border_focused: Some(rgba(0xaea4f4ff).into()),
|
||||
border_selected: Some(rgba(0xaea4f4ff).into()),
|
||||
border_transparent: Some(rgba(0xaea4f4ff).into()),
|
||||
border_disabled: Some(rgba(0xaea4f4ff).into()),
|
||||
elevated_surface_background: Some(rgba(0xe9e7f3ff).into()),
|
||||
surface_background: Some(rgba(0xe9e7f3ff).into()),
|
||||
background: Some(rgba(0xf2f1f8ff).into()),
|
||||
element_background: Some(rgba(0x8d7ffeff).into()),
|
||||
text: Some(rgba(0x0c006bff).into()),
|
||||
tab_inactive_background: Some(rgba(0xe2dff6ff).into()),
|
||||
tab_active_background: Some(rgba(0xf2f1f8ff).into()),
|
||||
terminal_background: Some(rgba(0xe9e7f3ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x0f0080ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xff3f00ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x00d17aff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xff8c00ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x0ea3ffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xff6b9eff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x00cae6ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xbbc3c4ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x0c006bff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe34d1bff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x00b368ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xf49724ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x0094f0ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xff5792ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x00bdd6ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0x8ca6a6ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctis Lux".into(),
|
||||
appearance: Appearance::Light,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x00c6e0ff).into()),
|
||||
border_variant: Some(rgba(0x00c6e0ff).into()),
|
||||
border_focused: Some(rgba(0x00c6e0ff).into()),
|
||||
border_selected: Some(rgba(0x00c6e0ff).into()),
|
||||
border_transparent: Some(rgba(0x00c6e0ff).into()),
|
||||
border_disabled: Some(rgba(0x00c6e0ff).into()),
|
||||
elevated_surface_background: Some(rgba(0xf6eddaff).into()),
|
||||
surface_background: Some(rgba(0xf6eddaff).into()),
|
||||
background: Some(rgba(0xfef8ecff).into()),
|
||||
element_background: Some(rgba(0x089099ff).into()),
|
||||
text: Some(rgba(0x005661ff).into()),
|
||||
tab_inactive_background: Some(rgba(0xf0e9d6ff).into()),
|
||||
tab_active_background: Some(rgba(0xfef8ecff).into()),
|
||||
terminal_background: Some(rgba(0xf6eddaff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x004d57ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xff3f00ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x00d17aff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xff8c00ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x0ea3ffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xff6b9eff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x00cae6ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xbbc3c4ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x003b41ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe34d1bff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x00b368ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xf49724ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x0094f0ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xff5792ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x00bdd6ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0x8ca6a6ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctis Minimus".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x496c83ff).into()),
|
||||
border_variant: Some(rgba(0x496c83ff).into()),
|
||||
border_focused: Some(rgba(0x496c83ff).into()),
|
||||
border_selected: Some(rgba(0x496c83ff).into()),
|
||||
border_transparent: Some(rgba(0x496c83ff).into()),
|
||||
border_disabled: Some(rgba(0x496c83ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x0e1920ff).into()),
|
||||
surface_background: Some(rgba(0x0e1920ff).into()),
|
||||
background: Some(rgba(0x1b2932ff).into()),
|
||||
element_background: Some(rgba(0x2e616bff).into()),
|
||||
text: Some(rgba(0xc5cdd3ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x202d37ff).into()),
|
||||
tab_active_background: Some(rgba(0x1b2932ff).into()),
|
||||
terminal_background: Some(rgba(0x0e1920ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x425866ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xca8468ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x84c8abff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xd1aa7bff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x68a4caff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xc88da2ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x84bfc8ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xc5d1d3ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x182935ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xc08872ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x72c09fff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xc8a984ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x6095b7ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xc28097ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x72b7c0ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xc5cdd3ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctis".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x0d6571ff).into()),
|
||||
border_variant: Some(rgba(0x0d6571ff).into()),
|
||||
border_focused: Some(rgba(0x0d6571ff).into()),
|
||||
border_selected: Some(rgba(0x0d6571ff).into()),
|
||||
border_transparent: Some(rgba(0x0d6571ff).into()),
|
||||
border_disabled: Some(rgba(0x0d6571ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x03181aff).into()),
|
||||
surface_background: Some(rgba(0x03181aff).into()),
|
||||
background: Some(rgba(0x052428ff).into()),
|
||||
element_background: Some(rgba(0x089099ff).into()),
|
||||
text: Some(rgba(0xb1c9ccff).into()),
|
||||
tab_inactive_background: Some(rgba(0x052e32ff).into()),
|
||||
tab_active_background: Some(rgba(0x052428ff).into()),
|
||||
terminal_background: Some(rgba(0x03181aff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x47686cff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xc1d4d7ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x324a4dff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe66432ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xb1c9ccff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctis Obscuro".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x0d6571ff).into()),
|
||||
border_variant: Some(rgba(0x0d6571ff).into()),
|
||||
border_focused: Some(rgba(0x0d6571ff).into()),
|
||||
border_selected: Some(rgba(0x0d6571ff).into()),
|
||||
border_transparent: Some(rgba(0x0d6571ff).into()),
|
||||
border_disabled: Some(rgba(0x0d6571ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x020c0eff).into()),
|
||||
surface_background: Some(rgba(0x020c0eff).into()),
|
||||
background: Some(rgba(0x031316ff).into()),
|
||||
element_background: Some(rgba(0x089099ff).into()),
|
||||
text: Some(rgba(0xb1c9ccff).into()),
|
||||
tab_inactive_background: Some(rgba(0x052e32ff).into()),
|
||||
tab_active_background: Some(rgba(0x031316ff).into()),
|
||||
terminal_background: Some(rgba(0x020c0eff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x47686cff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xc1d4d7ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x324a4dff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe66432ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xb1c9ccff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctis Sereno".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x0d6571ff).into()),
|
||||
border_variant: Some(rgba(0x0d6571ff).into()),
|
||||
border_focused: Some(rgba(0x0d6571ff).into()),
|
||||
border_selected: Some(rgba(0x0d6571ff).into()),
|
||||
border_transparent: Some(rgba(0x0d6571ff).into()),
|
||||
border_disabled: Some(rgba(0x0d6571ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x020c0eff).into()),
|
||||
surface_background: Some(rgba(0x020c0eff).into()),
|
||||
background: Some(rgba(0x031316ff).into()),
|
||||
element_background: Some(rgba(0x089099ff).into()),
|
||||
text: Some(rgba(0xb1c9ccff).into()),
|
||||
tab_inactive_background: Some(rgba(0x052e32ff).into()),
|
||||
tab_active_background: Some(rgba(0x031316ff).into()),
|
||||
terminal_background: Some(rgba(0x020c0eff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x47686cff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xc1d4d7ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x324a4dff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe66432ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xb1c9ccff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctis Uva".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x6d66a7ff).into()),
|
||||
border_variant: Some(rgba(0x6d66a7ff).into()),
|
||||
border_focused: Some(rgba(0x6d66a7ff).into()),
|
||||
border_selected: Some(rgba(0x6d66a7ff).into()),
|
||||
border_transparent: Some(rgba(0x6d66a7ff).into()),
|
||||
border_disabled: Some(rgba(0x6d66a7ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x1f1d30ff).into()),
|
||||
surface_background: Some(rgba(0x1f1d30ff).into()),
|
||||
background: Some(rgba(0x292640ff).into()),
|
||||
element_background: Some(rgba(0x007e99ff).into()),
|
||||
text: Some(rgba(0xc5c2d6ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x2f2c49ff).into()),
|
||||
tab_active_background: Some(rgba(0x292640ff).into()),
|
||||
terminal_background: Some(rgba(0x1f1d30ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x504e65ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xc5c2d6ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x302f3dff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe66432ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xb6b3ccff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Noctis Viola".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x8666a7ff).into()),
|
||||
border_variant: Some(rgba(0x8666a7ff).into()),
|
||||
border_focused: Some(rgba(0x8666a7ff).into()),
|
||||
border_selected: Some(rgba(0x8666a7ff).into()),
|
||||
border_transparent: Some(rgba(0x8666a7ff).into()),
|
||||
border_disabled: Some(rgba(0x8666a7ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x291d35ff).into()),
|
||||
surface_background: Some(rgba(0x291d35ff).into()),
|
||||
background: Some(rgba(0x30243dff).into()),
|
||||
element_background: Some(rgba(0x007e99ff).into()),
|
||||
text: Some(rgba(0xccbfd9ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x3d2e4dff).into()),
|
||||
tab_active_background: Some(rgba(0x30243dff).into()),
|
||||
terminal_background: Some(rgba(0x291d35ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x594e65ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xccbfd9ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x362f3dff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xe66432ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xbfafcfff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
131
crates/theme2/src/themes/palenight.rs
Normal file
131
crates/theme2/src/themes/palenight.rs
Normal file
|
@ -0,0 +1,131 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn palenight() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Palenight".into(),
|
||||
author: "Olaolu Olawuyi (whizkydee)".into(),
|
||||
themes: vec![
|
||||
UserTheme {
|
||||
name: "Palenight".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x282b3bff).into()),
|
||||
border_variant: Some(rgba(0x282b3bff).into()),
|
||||
border_focused: Some(rgba(0x282b3bff).into()),
|
||||
border_selected: Some(rgba(0x282b3bff).into()),
|
||||
border_transparent: Some(rgba(0x282b3bff).into()),
|
||||
border_disabled: Some(rgba(0x282b3bff).into()),
|
||||
elevated_surface_background: Some(rgba(0x292c3eff).into()),
|
||||
surface_background: Some(rgba(0x292c3eff).into()),
|
||||
background: Some(rgba(0x292c3eff).into()),
|
||||
element_background: Some(rgba(0x7d56c1cc).into()),
|
||||
text: Some(rgba(0xffffffff).into()),
|
||||
tab_inactive_background: Some(rgba(0x31364aff).into()),
|
||||
tab_active_background: Some(rgba(0x292c3eff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x676e95ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xff5571ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0xc3e88dff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xffcb6bff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x82aaffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xc792eaff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x89ddffff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xffffffff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x676e95ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xff5571ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0xa9c77dff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xffcb6bff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x82aaffff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xc792eaff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x89ddffff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xffffffff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Palenight Operator".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x282b3bff).into()),
|
||||
border_variant: Some(rgba(0x282b3bff).into()),
|
||||
border_focused: Some(rgba(0x282b3bff).into()),
|
||||
border_selected: Some(rgba(0x282b3bff).into()),
|
||||
border_transparent: Some(rgba(0x282b3bff).into()),
|
||||
border_disabled: Some(rgba(0x282b3bff).into()),
|
||||
elevated_surface_background: Some(rgba(0x292c3eff).into()),
|
||||
surface_background: Some(rgba(0x292c3eff).into()),
|
||||
background: Some(rgba(0x292c3eff).into()),
|
||||
element_background: Some(rgba(0x7d56c1cc).into()),
|
||||
text: Some(rgba(0xffffffff).into()),
|
||||
tab_inactive_background: Some(rgba(0x31364aff).into()),
|
||||
tab_active_background: Some(rgba(0x292c3eff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x676e95ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xff5571ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0xc3e88dff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xffcb6bff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x82aaffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xc792eaff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x89ddffff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xffffffff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x676e95ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xff5571ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0xa9c77dff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xffcb6bff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x82aaffff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xc792eaff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x89ddffff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xffffffff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Palenight (Mild Contrast)".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x2c2f40ff).into()),
|
||||
border_variant: Some(rgba(0x2c2f40ff).into()),
|
||||
border_focused: Some(rgba(0x2c2f40ff).into()),
|
||||
border_selected: Some(rgba(0x2c2f40ff).into()),
|
||||
border_transparent: Some(rgba(0x2c2f40ff).into()),
|
||||
border_disabled: Some(rgba(0x2c2f40ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x25283aff).into()),
|
||||
surface_background: Some(rgba(0x25283aff).into()),
|
||||
background: Some(rgba(0x292c3eff).into()),
|
||||
element_background: Some(rgba(0x7d56c1cc).into()),
|
||||
text: Some(rgba(0xffffffff).into()),
|
||||
tab_inactive_background: Some(rgba(0x31364aff).into()),
|
||||
tab_active_background: Some(rgba(0x25283aff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x676e95ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xff5571ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0xc3e88dff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xffcb6bff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x82aaffff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xc792eaff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x89ddffff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xffffffff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x676e95ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xff5571ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0xa9c77dff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xffcb6bff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x82aaffff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xc792eaff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x89ddffff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xffffffff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
131
crates/theme2/src/themes/rose_pine.rs
Normal file
131
crates/theme2/src/themes/rose_pine.rs
Normal file
|
@ -0,0 +1,131 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn rose_pine() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Rose Pine".into(),
|
||||
author: "Rosé Pine".into(),
|
||||
themes: vec![
|
||||
UserTheme {
|
||||
name: "Rose Pine".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x000000ff).into()),
|
||||
border_variant: Some(rgba(0x000000ff).into()),
|
||||
border_focused: Some(rgba(0x000000ff).into()),
|
||||
border_selected: Some(rgba(0x000000ff).into()),
|
||||
border_transparent: Some(rgba(0x000000ff).into()),
|
||||
border_disabled: Some(rgba(0x000000ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x1f1d2eff).into()),
|
||||
surface_background: Some(rgba(0x1f1d2eff).into()),
|
||||
background: Some(rgba(0x191724ff).into()),
|
||||
element_background: Some(rgba(0xebbcbaff).into()),
|
||||
text: Some(rgba(0xe0def4ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x000000ff).into()),
|
||||
tab_active_background: Some(rgba(0x6e6a861a).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x908caaff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xeb6f92ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x30738fff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xf5c177ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x9ccfd8ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xc4a7e7ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0xebbcbaff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xe0def4ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x26233aff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xeb6f92ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x30738fff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xf5c177ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x9ccfd8ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xc4a7e7ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0xebbcbaff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xe0def4ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Rose Moon".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x000000ff).into()),
|
||||
border_variant: Some(rgba(0x000000ff).into()),
|
||||
border_focused: Some(rgba(0x000000ff).into()),
|
||||
border_selected: Some(rgba(0x000000ff).into()),
|
||||
border_transparent: Some(rgba(0x000000ff).into()),
|
||||
border_disabled: Some(rgba(0x000000ff).into()),
|
||||
elevated_surface_background: Some(rgba(0x2a273eff).into()),
|
||||
surface_background: Some(rgba(0x2a273eff).into()),
|
||||
background: Some(rgba(0x232136ff).into()),
|
||||
element_background: Some(rgba(0xea9a97ff).into()),
|
||||
text: Some(rgba(0xe0def4ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x000000ff).into()),
|
||||
tab_active_background: Some(rgba(0x817c9c14).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x908caaff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xeb6f92ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x3d8fb0ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xf5c177ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x9ccfd8ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xc4a7e7ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0xea9a97ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xe0def4ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x393552ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xeb6f92ff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x3d8fb0ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xf5c177ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x9ccfd8ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xc4a7e7ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0xea9a97ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xe0def4ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Rose Pine Dawn".into(),
|
||||
appearance: Appearance::Light,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x000000ff).into()),
|
||||
border_variant: Some(rgba(0x000000ff).into()),
|
||||
border_focused: Some(rgba(0x000000ff).into()),
|
||||
border_selected: Some(rgba(0x000000ff).into()),
|
||||
border_transparent: Some(rgba(0x000000ff).into()),
|
||||
border_disabled: Some(rgba(0x000000ff).into()),
|
||||
elevated_surface_background: Some(rgba(0xfffaf3ff).into()),
|
||||
surface_background: Some(rgba(0xfffaf3ff).into()),
|
||||
background: Some(rgba(0xfaf4edff).into()),
|
||||
element_background: Some(rgba(0xd7827dff).into()),
|
||||
text: Some(rgba(0x575279ff).into()),
|
||||
tab_inactive_background: Some(rgba(0x000000ff).into()),
|
||||
tab_active_background: Some(rgba(0x6e6a860d).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x797593ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xb3627aff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x276983ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xea9d34ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x55949fff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0x9079a9ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0xd7827dff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0x575279ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0xf2e9e1ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xb3627aff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x276983ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xea9d34ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x55949fff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0x9079a9ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0xd7827dff).into()),
|
||||
terminal_ansi_white: Some(rgba(0x575279ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
87
crates/theme2/src/themes/solarized.rs
Normal file
87
crates/theme2/src/themes/solarized.rs
Normal file
|
@ -0,0 +1,87 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn solarized() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Solarized".into(),
|
||||
author: "Ethan Schoonover (altercation)".into(),
|
||||
themes: vec![
|
||||
UserTheme {
|
||||
name: "Solarized Dark".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0x003847ff).into()),
|
||||
border_variant: Some(rgba(0x003847ff).into()),
|
||||
border_focused: Some(rgba(0x003847ff).into()),
|
||||
border_selected: Some(rgba(0x003847ff).into()),
|
||||
border_transparent: Some(rgba(0x003847ff).into()),
|
||||
border_disabled: Some(rgba(0x003847ff).into()),
|
||||
background: Some(rgba(0x002a35ff).into()),
|
||||
element_background: Some(rgba(0x29a19899).into()),
|
||||
tab_inactive_background: Some(rgba(0x003f51ff).into()),
|
||||
tab_active_background: Some(rgba(0x002a36ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x586e75ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xcb4b15ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x859900ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0x657b83ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x839496ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0x6c71c4ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x93a1a1ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0x839496ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x063642ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xdc312eff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x859900ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xb58800ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x258ad2ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xd33582ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x29a198ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0x839496ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
UserTheme {
|
||||
name: "Solarized Light".into(),
|
||||
appearance: Appearance::Light,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
border: Some(rgba(0xddd6c1ff).into()),
|
||||
border_variant: Some(rgba(0xddd6c1ff).into()),
|
||||
border_focused: Some(rgba(0xddd6c1ff).into()),
|
||||
border_selected: Some(rgba(0xddd6c1ff).into()),
|
||||
border_transparent: Some(rgba(0xddd6c1ff).into()),
|
||||
border_disabled: Some(rgba(0xddd6c1ff).into()),
|
||||
background: Some(rgba(0xfdf6e3ff).into()),
|
||||
element_background: Some(rgba(0xab9d56ff).into()),
|
||||
tab_inactive_background: Some(rgba(0xd3cbb7ff).into()),
|
||||
tab_active_background: Some(rgba(0xfdf6e3ff).into()),
|
||||
terminal_ansi_bright_black: Some(rgba(0x657b83ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xcb4b15ff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x859900ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0x657b83ff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x839496ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0x6c71c4ff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x93a1a1ff).into()),
|
||||
terminal_ansi_bright_white: Some(rgba(0xeee8d5ff).into()),
|
||||
terminal_ansi_black: Some(rgba(0x657b83ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xdc312eff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x859900ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xb58800ff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x258ad2ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xd33582ff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x29a198ff).into()),
|
||||
terminal_ansi_white: Some(rgba(0xeee8d5ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
40
crates/theme2/src/themes/synthwave_84.rs
Normal file
40
crates/theme2/src/themes/synthwave_84.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
pub fn synthwave_84() -> UserThemeFamily {
|
||||
UserThemeFamily {
|
||||
name: "Synthwave 84".into(),
|
||||
author: "Robb Owen (robb0wen)".into(),
|
||||
themes: vec![UserTheme {
|
||||
name: "Synthwave 84".into(),
|
||||
appearance: Appearance::Dark,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: ThemeColorsRefinement {
|
||||
background: Some(rgba(0x252334ff).into()),
|
||||
element_background: Some(rgba(0x614d85ff).into()),
|
||||
text: Some(rgba(0xffffffff).into()),
|
||||
tab_inactive_background: Some(rgba(0x252334ff).into()),
|
||||
terminal_ansi_bright_red: Some(rgba(0xfe444fff).into()),
|
||||
terminal_ansi_bright_green: Some(rgba(0x71f1b7ff).into()),
|
||||
terminal_ansi_bright_yellow: Some(rgba(0xfede5cff).into()),
|
||||
terminal_ansi_bright_blue: Some(rgba(0x02edf9ff).into()),
|
||||
terminal_ansi_bright_magenta: Some(rgba(0xff7ddaff).into()),
|
||||
terminal_ansi_bright_cyan: Some(rgba(0x02edf9ff).into()),
|
||||
terminal_ansi_red: Some(rgba(0xfe444fff).into()),
|
||||
terminal_ansi_green: Some(rgba(0x71f1b7ff).into()),
|
||||
terminal_ansi_yellow: Some(rgba(0xf3e70fff).into()),
|
||||
terminal_ansi_blue: Some(rgba(0x02edf9ff).into()),
|
||||
terminal_ansi_magenta: Some(rgba(0xff7ddaff).into()),
|
||||
terminal_ansi_cyan: Some(rgba(0x02edf9ff).into()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
}],
|
||||
}
|
||||
}
|
25
crates/theme2/src/user_theme.rs
Normal file
25
crates/theme2/src/user_theme.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use refineable::Refineable;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{Appearance, ThemeColors, ThemeColorsRefinement};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct UserThemeFamily {
|
||||
pub name: String,
|
||||
pub author: String,
|
||||
pub themes: Vec<UserTheme>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct UserTheme {
|
||||
pub name: String,
|
||||
pub appearance: Appearance,
|
||||
pub styles: UserThemeStylesRefinement,
|
||||
}
|
||||
|
||||
#[derive(Refineable, Clone)]
|
||||
#[refineable(deserialize)]
|
||||
pub struct UserThemeStyles {
|
||||
#[refineable]
|
||||
pub colors: ThemeColors,
|
||||
}
|
18
crates/theme_importer/Cargo.toml
Normal file
18
crates/theme_importer/Cargo.toml
Normal file
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "theme_importer"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
convert_case = "0.6.0"
|
||||
gpui = { package = "gpui2", path = "../gpui2" }
|
||||
log.workspace = true
|
||||
rust-embed.workspace = true
|
||||
serde.workspace = true
|
||||
simplelog = "0.9"
|
||||
theme = { package = "theme2", path = "../theme2" }
|
||||
uuid.workspace = true
|
124
crates/theme_importer/README.md
Normal file
124
crates/theme_importer/README.md
Normal file
|
@ -0,0 +1,124 @@
|
|||
# Zed Theme Importer
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
- `cargo run -p theme_importer` - Import the context of `assets/themes/src`
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
As the importer generates rust files, you may need to manually do some cleanup in `registry.rs` and `themes/mod.rs` if you remove themes or delete the `themes` folder in the theme crate.
|
||||
|
||||
---
|
||||
|
||||
## Required Structure
|
||||
|
||||
To import a theme or series of themes 3 things are required:
|
||||
|
||||
- `family.json`: A JSON file containing the theme family metadata and list of theme variants
|
||||
- `{theme_name}.json`: One theme json for each theme variant
|
||||
- `LICENSE`: A license file for the theme family
|
||||
|
||||
### `family.json`
|
||||
|
||||
#### `name`
|
||||
|
||||
The name of the theme family. Avoid special characters.
|
||||
|
||||
This will be used for the theme family directory name (lowercased) and the theme family name in the Zed UI.
|
||||
|
||||
Good:
|
||||
|
||||
- `Rose Pine`
|
||||
- `Synthwave 84`
|
||||
- `Monokai Solarized`
|
||||
|
||||
Bad:
|
||||
|
||||
- `Rosé Pine`
|
||||
- `Synthwave '84`
|
||||
- `Monokai (Solarized)`
|
||||
|
||||
#### `author`
|
||||
|
||||
The author of the theme family. This can be a name or a username.
|
||||
|
||||
This will be used for the theme family author in the Zed UI.
|
||||
|
||||
#### `themes`
|
||||
|
||||
A list of theme variants.
|
||||
|
||||
`appearance` can be either `light` or `dark`. This will impact which default fallback colors are used, and where the theme shows up in the Zed UI.
|
||||
|
||||
### `{theme_name}.json`
|
||||
|
||||
Each theme added to the family must have a corresponding JSON file. This JSON file can be obtained from the VSCode extensions folder (once you have installed it.) This is usually located at `~/.vscode/extensions` (on macOS).
|
||||
|
||||
You can use `open ~/.vscode/extensions` to open the folder in Finder directly.
|
||||
|
||||
Copy that json file into the theme family directory and tidy up the filenames as needed.
|
||||
|
||||
### `LICENSE`
|
||||
|
||||
A LICENSE file is required to import a theme family. Failing to provide a complete text license will cause it to be skipped when the import is run.
|
||||
|
||||
If the theme only provices a license code (e.g. MIT, Apache 2.0, etc.) then put that code into the LICENSE file.
|
||||
|
||||
If no license is provided, either contact the theme creator or don't add the theme.
|
||||
|
||||
---
|
||||
|
||||
### Complete Example:
|
||||
|
||||
An example family with multiple variants:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Ayu",
|
||||
// When both name and username are available
|
||||
// prefer the `username (name)` format
|
||||
"author": "dempfi (Ike Ku)",
|
||||
"themes": [
|
||||
{
|
||||
"name": "Ayu Light",
|
||||
"file_name": "ayu-light.json",
|
||||
"appearance": "light"
|
||||
},
|
||||
{
|
||||
"name": "Ayu Mirage",
|
||||
"file_name": "ayu-mirage.json",
|
||||
"appearance": "dark"
|
||||
},
|
||||
{
|
||||
"name": "Ayu Dark",
|
||||
"file_name": "ayu-dark.json",
|
||||
"appearance": "dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
An example single variant family:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Andromeda",
|
||||
"author": "Eliver Lara (EliverLara)",
|
||||
"themes": [
|
||||
{
|
||||
"name": "Andromeda",
|
||||
"file_name": "andromeda.json",
|
||||
"appearance": "dark"
|
||||
},
|
||||
{
|
||||
"name": "Andromeda Bordered",
|
||||
"file_name": "andromeda-bordered.json",
|
||||
"appearance": "dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
237
crates/theme_importer/src/main.rs
Normal file
237
crates/theme_importer/src/main.rs
Normal file
|
@ -0,0 +1,237 @@
|
|||
mod theme_printer;
|
||||
mod util;
|
||||
mod vscode;
|
||||
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use convert_case::{Case, Casing};
|
||||
use gpui::serde_json;
|
||||
use log::LevelFilter;
|
||||
use serde::Deserialize;
|
||||
use simplelog::SimpleLogger;
|
||||
use theme::{Appearance, UserThemeFamily};
|
||||
use vscode::VsCodeThemeConverter;
|
||||
|
||||
use crate::theme_printer::UserThemeFamilyPrinter;
|
||||
use crate::vscode::VsCodeTheme;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct FamilyMetadata {
|
||||
pub name: String,
|
||||
pub author: String,
|
||||
pub themes: Vec<ThemeMetadata>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ThemeAppearanceJson {
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
impl From<ThemeAppearanceJson> for Appearance {
|
||||
fn from(value: ThemeAppearanceJson) -> Self {
|
||||
match value {
|
||||
ThemeAppearanceJson::Light => Self::Light,
|
||||
ThemeAppearanceJson::Dark => Self::Dark,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ThemeMetadata {
|
||||
pub name: String,
|
||||
pub file_name: String,
|
||||
pub appearance: ThemeAppearanceJson,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
const SOURCE_PATH: &str = "assets/themes/src/vscode";
|
||||
const OUT_PATH: &str = "crates/theme2/src/themes";
|
||||
|
||||
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
||||
|
||||
println!("Loading themes source...");
|
||||
let vscode_themes_path = PathBuf::from_str(SOURCE_PATH)?;
|
||||
if !vscode_themes_path.exists() {
|
||||
return Err(anyhow!(format!(
|
||||
"Couldn't find {}, make sure it exists",
|
||||
SOURCE_PATH
|
||||
)));
|
||||
}
|
||||
|
||||
let mut theme_families = Vec::new();
|
||||
|
||||
for theme_family_dir in fs::read_dir(&vscode_themes_path)? {
|
||||
let theme_family_dir = theme_family_dir?;
|
||||
|
||||
if !theme_family_dir.file_type()?.is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let theme_family_slug = theme_family_dir
|
||||
.path()
|
||||
.file_stem()
|
||||
.ok_or(anyhow!("no file stem"))
|
||||
.map(|stem| stem.to_string_lossy().to_string())?;
|
||||
|
||||
let family_metadata_file = File::open(theme_family_dir.path().join("family.json"))
|
||||
.context(format!(
|
||||
"no `family.json` found for '{}'",
|
||||
theme_family_slug
|
||||
))?;
|
||||
|
||||
let license_file_path = theme_family_dir.path().join("LICENSE");
|
||||
|
||||
if !license_file_path.exists() {
|
||||
println!("Skipping theme family '{}' because it does not have a LICENSE file. This theme will only be imported once a LICENSE file is provided.", theme_family_slug);
|
||||
continue;
|
||||
}
|
||||
|
||||
let family_metadata: FamilyMetadata = serde_json::from_reader(family_metadata_file)
|
||||
.context(format!(
|
||||
"failed to parse `family.json` for '{theme_family_slug}'"
|
||||
))?;
|
||||
|
||||
let mut themes = Vec::new();
|
||||
|
||||
for theme_metadata in family_metadata.themes {
|
||||
let theme_file_path = theme_family_dir.path().join(&theme_metadata.file_name);
|
||||
|
||||
let theme_file = match File::open(&theme_file_path) {
|
||||
Ok(file) => file,
|
||||
Err(_) => {
|
||||
println!("Failed to open file at path: {:?}", theme_file_path);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let vscode_theme: VsCodeTheme = serde_json::from_reader(theme_file)
|
||||
.context(format!("failed to parse theme {theme_file_path:?}"))?;
|
||||
|
||||
let converter = VsCodeThemeConverter::new(vscode_theme, theme_metadata);
|
||||
|
||||
let theme = converter.convert()?;
|
||||
|
||||
themes.push(theme);
|
||||
}
|
||||
|
||||
let theme_family = UserThemeFamily {
|
||||
name: family_metadata.name.into(),
|
||||
author: family_metadata.author.into(),
|
||||
themes,
|
||||
};
|
||||
|
||||
theme_families.push(theme_family);
|
||||
}
|
||||
|
||||
let themes_output_path = PathBuf::from_str(OUT_PATH)?;
|
||||
|
||||
if !themes_output_path.exists() {
|
||||
println!("Creating directory: {:?}", themes_output_path);
|
||||
fs::create_dir_all(&themes_output_path)?;
|
||||
}
|
||||
|
||||
let mut mod_rs_file = File::create(themes_output_path.join(format!("mod.rs")))?;
|
||||
|
||||
let mut theme_modules = Vec::new();
|
||||
|
||||
for theme_family in theme_families {
|
||||
let theme_family_slug = theme_family.name.to_string().to_case(Case::Snake);
|
||||
|
||||
let mut output_file =
|
||||
File::create(themes_output_path.join(format!("{theme_family_slug}.rs")))?;
|
||||
println!(
|
||||
"Creating file: {:?}",
|
||||
themes_output_path.join(format!("{theme_family_slug}.rs"))
|
||||
);
|
||||
|
||||
let theme_module = format!(
|
||||
r#"
|
||||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
use gpui::rgba;
|
||||
|
||||
use crate::{{
|
||||
Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
}};
|
||||
|
||||
pub fn {theme_family_slug}() -> UserThemeFamily {{
|
||||
{theme_family_definition}
|
||||
}}
|
||||
"#,
|
||||
theme_family_definition = format!("{:#?}", UserThemeFamilyPrinter::new(theme_family))
|
||||
);
|
||||
|
||||
output_file.write_all(theme_module.as_bytes())?;
|
||||
|
||||
theme_modules.push(theme_family_slug);
|
||||
}
|
||||
|
||||
let themes_vector_contents = format!(
|
||||
r#"
|
||||
use crate::UserThemeFamily;
|
||||
|
||||
pub(crate) fn all_user_themes() -> Vec<UserThemeFamily> {{
|
||||
vec![{all_themes}]
|
||||
}}
|
||||
"#,
|
||||
all_themes = theme_modules
|
||||
.iter()
|
||||
.map(|module| format!("{}()", module))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
|
||||
let mod_rs_contents = format!(
|
||||
r#"
|
||||
// This file was generated by the `theme_importer`.
|
||||
// Be careful when modifying it by hand.
|
||||
|
||||
{mod_statements}
|
||||
|
||||
{use_statements}
|
||||
|
||||
{themes_vector_contents}
|
||||
"#,
|
||||
mod_statements = theme_modules
|
||||
.iter()
|
||||
.map(|module| format!("mod {module};"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
use_statements = theme_modules
|
||||
.iter()
|
||||
.map(|module| format!("pub use {module}::*;"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
themes_vector_contents = themes_vector_contents
|
||||
);
|
||||
|
||||
mod_rs_file.write_all(mod_rs_contents.as_bytes())?;
|
||||
|
||||
println!("Formatting themes...");
|
||||
|
||||
let format_result = format_themes_crate()
|
||||
// We need to format a second time to catch all of the formatting issues.
|
||||
.and_then(|_| format_themes_crate());
|
||||
|
||||
if let Err(err) = format_result {
|
||||
eprintln!("Failed to format themes: {}", err);
|
||||
}
|
||||
|
||||
println!("Done!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn format_themes_crate() -> std::io::Result<std::process::Output> {
|
||||
Command::new("cargo")
|
||||
.args(["fmt", "--package", "theme2"])
|
||||
.output()
|
||||
}
|
322
crates/theme_importer/src/theme_printer.rs
Normal file
322
crates/theme_importer/src/theme_printer.rs
Normal file
|
@ -0,0 +1,322 @@
|
|||
use std::fmt::{self, Debug};
|
||||
|
||||
use gpui::{Hsla, Rgba};
|
||||
use theme::{
|
||||
Appearance, PlayerColor, PlayerColors, StatusColors, SyntaxTheme, SystemColors,
|
||||
ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
|
||||
};
|
||||
|
||||
struct RawSyntaxPrinter<'a>(&'a str);
|
||||
|
||||
impl<'a> Debug for RawSyntaxPrinter<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct HslaPrinter(Hsla);
|
||||
|
||||
impl Debug for HslaPrinter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", IntoPrinter(&Rgba::from(self.0)))
|
||||
}
|
||||
}
|
||||
|
||||
struct IntoPrinter<'a, D: Debug>(&'a D);
|
||||
|
||||
impl<'a, D: Debug> Debug for IntoPrinter<'a, D> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}.into()", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VecPrinter<'a, T>(&'a Vec<T>);
|
||||
|
||||
impl<'a, T: Debug> Debug for VecPrinter<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "vec!{:?}", &self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserThemeFamilyPrinter(UserThemeFamily);
|
||||
|
||||
impl UserThemeFamilyPrinter {
|
||||
pub fn new(theme_family: UserThemeFamily) -> Self {
|
||||
Self(theme_family)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for UserThemeFamilyPrinter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("UserThemeFamily")
|
||||
.field("name", &IntoPrinter(&self.0.name))
|
||||
.field("author", &IntoPrinter(&self.0.author))
|
||||
.field(
|
||||
"themes",
|
||||
&VecPrinter(
|
||||
&self
|
||||
.0
|
||||
.themes
|
||||
.iter()
|
||||
.map(|theme| UserThemePrinter(theme))
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserThemePrinter<'a>(&'a UserTheme);
|
||||
|
||||
impl<'a> Debug for UserThemePrinter<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("UserTheme")
|
||||
.field("name", &IntoPrinter(&self.0.name))
|
||||
.field("appearance", &AppearancePrinter(self.0.appearance))
|
||||
.field("styles", &UserThemeStylesRefinementPrinter(&self.0.styles))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AppearancePrinter(Appearance);
|
||||
|
||||
impl Debug for AppearancePrinter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Appearance::{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserThemeStylesRefinementPrinter<'a>(&'a UserThemeStylesRefinement);
|
||||
|
||||
impl<'a> Debug for UserThemeStylesRefinementPrinter<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("UserThemeStylesRefinement")
|
||||
.field("colors", &ThemeColorsRefinementPrinter(&self.0.colors))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SystemColorsPrinter<'a>(&'a SystemColors);
|
||||
|
||||
impl<'a> Debug for SystemColorsPrinter<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SystemColors")
|
||||
.field("transparent", &HslaPrinter(self.0.transparent))
|
||||
.field(
|
||||
"mac_os_traffic_light_red",
|
||||
&HslaPrinter(self.0.mac_os_traffic_light_red),
|
||||
)
|
||||
.field(
|
||||
"mac_os_traffic_light_yellow",
|
||||
&HslaPrinter(self.0.mac_os_traffic_light_yellow),
|
||||
)
|
||||
.field(
|
||||
"mac_os_traffic_light_green",
|
||||
&HslaPrinter(self.0.mac_os_traffic_light_green),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ThemeColorsRefinementPrinter<'a>(&'a ThemeColorsRefinement);
|
||||
|
||||
impl<'a> Debug for ThemeColorsRefinementPrinter<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let theme_colors = vec![
|
||||
("border", self.0.border),
|
||||
("border_variant", self.0.border_variant),
|
||||
("border_focused", self.0.border_focused),
|
||||
("border_selected", self.0.border_selected),
|
||||
("border_transparent", self.0.border_transparent),
|
||||
("border_disabled", self.0.border_disabled),
|
||||
(
|
||||
"elevated_surface_background",
|
||||
self.0.elevated_surface_background,
|
||||
),
|
||||
("surface_background", self.0.surface_background),
|
||||
("background", self.0.background),
|
||||
("element_background", self.0.element_background),
|
||||
("element_hover", self.0.element_hover),
|
||||
("element_active", self.0.element_active),
|
||||
("element_selected", self.0.element_selected),
|
||||
("element_disabled", self.0.element_disabled),
|
||||
("drop_target_background", self.0.drop_target_background),
|
||||
("ghost_element_background", self.0.ghost_element_background),
|
||||
("ghost_element_hover", self.0.ghost_element_hover),
|
||||
("ghost_element_active", self.0.ghost_element_active),
|
||||
("ghost_element_selected", self.0.ghost_element_selected),
|
||||
("ghost_element_disabled", self.0.ghost_element_disabled),
|
||||
("text", self.0.text),
|
||||
("text_muted", self.0.text_muted),
|
||||
("text_placeholder", self.0.text_placeholder),
|
||||
("text_disabled", self.0.text_disabled),
|
||||
("text_accent", self.0.text_accent),
|
||||
("icon", self.0.icon),
|
||||
("icon_muted", self.0.icon_muted),
|
||||
("icon_disabled", self.0.icon_disabled),
|
||||
("icon_placeholder", self.0.icon_placeholder),
|
||||
("icon_accent", self.0.icon_accent),
|
||||
("status_bar_background", self.0.status_bar_background),
|
||||
("title_bar_background", self.0.title_bar_background),
|
||||
("toolbar_background", self.0.toolbar_background),
|
||||
("tab_bar_background", self.0.tab_bar_background),
|
||||
("tab_inactive_background", self.0.tab_inactive_background),
|
||||
("tab_active_background", self.0.tab_active_background),
|
||||
("editor_background", self.0.editor_background),
|
||||
("editor_gutter_background", self.0.editor_gutter_background),
|
||||
(
|
||||
"editor_subheader_background",
|
||||
self.0.editor_subheader_background,
|
||||
),
|
||||
(
|
||||
"editor_active_line_background",
|
||||
self.0.editor_active_line_background,
|
||||
),
|
||||
(
|
||||
"editor_highlighted_line_background",
|
||||
self.0.editor_highlighted_line_background,
|
||||
),
|
||||
("editor_line_number", self.0.editor_line_number),
|
||||
(
|
||||
"editor_active_line_number",
|
||||
self.0.editor_active_line_number,
|
||||
),
|
||||
("editor_invisible", self.0.editor_invisible),
|
||||
("editor_wrap_guide", self.0.editor_wrap_guide),
|
||||
("editor_active_wrap_guide", self.0.editor_active_wrap_guide),
|
||||
(
|
||||
"editor_document_highlight_read_background",
|
||||
self.0.editor_document_highlight_read_background,
|
||||
),
|
||||
(
|
||||
"editor_document_highlight_write_background",
|
||||
self.0.editor_document_highlight_write_background,
|
||||
),
|
||||
("terminal_background", self.0.terminal_background),
|
||||
(
|
||||
"terminal_ansi_bright_black",
|
||||
self.0.terminal_ansi_bright_black,
|
||||
),
|
||||
("terminal_ansi_bright_red", self.0.terminal_ansi_bright_red),
|
||||
(
|
||||
"terminal_ansi_bright_green",
|
||||
self.0.terminal_ansi_bright_green,
|
||||
),
|
||||
(
|
||||
"terminal_ansi_bright_yellow",
|
||||
self.0.terminal_ansi_bright_yellow,
|
||||
),
|
||||
(
|
||||
"terminal_ansi_bright_blue",
|
||||
self.0.terminal_ansi_bright_blue,
|
||||
),
|
||||
(
|
||||
"terminal_ansi_bright_magenta",
|
||||
self.0.terminal_ansi_bright_magenta,
|
||||
),
|
||||
(
|
||||
"terminal_ansi_bright_cyan",
|
||||
self.0.terminal_ansi_bright_cyan,
|
||||
),
|
||||
(
|
||||
"terminal_ansi_bright_white",
|
||||
self.0.terminal_ansi_bright_white,
|
||||
),
|
||||
("terminal_ansi_black", self.0.terminal_ansi_black),
|
||||
("terminal_ansi_red", self.0.terminal_ansi_red),
|
||||
("terminal_ansi_green", self.0.terminal_ansi_green),
|
||||
("terminal_ansi_yellow", self.0.terminal_ansi_yellow),
|
||||
("terminal_ansi_blue", self.0.terminal_ansi_blue),
|
||||
("terminal_ansi_magenta", self.0.terminal_ansi_magenta),
|
||||
("terminal_ansi_cyan", self.0.terminal_ansi_cyan),
|
||||
("terminal_ansi_white", self.0.terminal_ansi_white),
|
||||
];
|
||||
|
||||
f.write_str("ThemeColorsRefinement {")?;
|
||||
|
||||
for (color_name, color) in theme_colors {
|
||||
if let Some(color) = color {
|
||||
f.write_str(color_name)?;
|
||||
f.write_str(": ")?;
|
||||
f.write_str("Some(")?;
|
||||
HslaPrinter(color).fmt(f)?;
|
||||
f.write_str(")")?;
|
||||
f.write_str(",")?;
|
||||
}
|
||||
}
|
||||
|
||||
f.write_str("..Default::default()")?;
|
||||
f.write_str("}")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StatusColorsPrinter<'a>(&'a StatusColors);
|
||||
|
||||
impl<'a> Debug for StatusColorsPrinter<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("StatusColors")
|
||||
.field("conflict", &HslaPrinter(self.0.conflict))
|
||||
.field("created", &HslaPrinter(self.0.created))
|
||||
.field("deleted", &HslaPrinter(self.0.deleted))
|
||||
.field("error", &HslaPrinter(self.0.error))
|
||||
.field("hidden", &HslaPrinter(self.0.hidden))
|
||||
.field("ignored", &HslaPrinter(self.0.ignored))
|
||||
.field("info", &HslaPrinter(self.0.info))
|
||||
.field("modified", &HslaPrinter(self.0.modified))
|
||||
.field("renamed", &HslaPrinter(self.0.renamed))
|
||||
.field("success", &HslaPrinter(self.0.success))
|
||||
.field("warning", &HslaPrinter(self.0.warning))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PlayerColorsPrinter<'a>(&'a PlayerColors);
|
||||
|
||||
impl<'a> Debug for PlayerColorsPrinter<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("PlayerColors")
|
||||
.field(&VecPrinter(
|
||||
&self
|
||||
.0
|
||||
.0
|
||||
.iter()
|
||||
.map(|player_color| PlayerColorPrinter(player_color))
|
||||
.collect(),
|
||||
))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PlayerColorPrinter<'a>(&'a PlayerColor);
|
||||
|
||||
impl<'a> Debug for PlayerColorPrinter<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PlayerColor")
|
||||
.field("cursor", &HslaPrinter(self.0.cursor))
|
||||
.field("background", &HslaPrinter(self.0.background))
|
||||
.field("selection", &HslaPrinter(self.0.selection))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SyntaxThemePrinter<'a>(&'a SyntaxTheme);
|
||||
|
||||
impl<'a> Debug for SyntaxThemePrinter<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SyntaxTheme")
|
||||
.field(
|
||||
"highlights",
|
||||
&VecPrinter(
|
||||
&self
|
||||
.0
|
||||
.highlights
|
||||
.iter()
|
||||
.map(|(token, highlight)| {
|
||||
(IntoPrinter(token), HslaPrinter(highlight.color.unwrap()))
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
11
crates/theme_importer/src/util.rs
Normal file
11
crates/theme_importer/src/util.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use anyhow::Result;
|
||||
|
||||
pub trait Traverse<T, U> {
|
||||
fn traverse(self, f: impl FnOnce(T) -> Result<U>) -> Result<Option<U>>;
|
||||
}
|
||||
|
||||
impl<T, U> Traverse<T, U> for Option<T> {
|
||||
fn traverse(self, f: impl FnOnce(T) -> Result<U>) -> Result<Option<U>> {
|
||||
self.map_or(Ok(None), |value| f(value).map(Some))
|
||||
}
|
||||
}
|
570
crates/theme_importer/src/vscode.rs
Normal file
570
crates/theme_importer/src/vscode.rs
Normal file
|
@ -0,0 +1,570 @@
|
|||
use anyhow::Result;
|
||||
use gpui::{Hsla, Rgba};
|
||||
use serde::Deserialize;
|
||||
use theme::{ThemeColorsRefinement, UserTheme, UserThemeStylesRefinement};
|
||||
|
||||
use crate::util::Traverse;
|
||||
use crate::ThemeMetadata;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct VsCodeTheme {
|
||||
#[serde(rename = "$schema")]
|
||||
pub schema: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub author: Option<String>,
|
||||
pub maintainers: Option<Vec<String>>,
|
||||
#[serde(rename = "semanticClass")]
|
||||
pub semantic_class: Option<String>,
|
||||
#[serde(rename = "semanticHighlighting")]
|
||||
pub semantic_highlighting: Option<bool>,
|
||||
pub colors: VsCodeColors,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct VsCodeColors {
|
||||
#[serde(rename = "terminal.background")]
|
||||
pub terminal_background: Option<String>,
|
||||
#[serde(rename = "terminal.foreground")]
|
||||
pub terminal_foreground: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBrightBlack")]
|
||||
pub terminal_ansi_bright_black: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBrightRed")]
|
||||
pub terminal_ansi_bright_red: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBrightGreen")]
|
||||
pub terminal_ansi_bright_green: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBrightYellow")]
|
||||
pub terminal_ansi_bright_yellow: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBrightBlue")]
|
||||
pub terminal_ansi_bright_blue: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBrightMagenta")]
|
||||
pub terminal_ansi_bright_magenta: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBrightCyan")]
|
||||
pub terminal_ansi_bright_cyan: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBrightWhite")]
|
||||
pub terminal_ansi_bright_white: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBlack")]
|
||||
pub terminal_ansi_black: Option<String>,
|
||||
#[serde(rename = "terminal.ansiRed")]
|
||||
pub terminal_ansi_red: Option<String>,
|
||||
#[serde(rename = "terminal.ansiGreen")]
|
||||
pub terminal_ansi_green: Option<String>,
|
||||
#[serde(rename = "terminal.ansiYellow")]
|
||||
pub terminal_ansi_yellow: Option<String>,
|
||||
#[serde(rename = "terminal.ansiBlue")]
|
||||
pub terminal_ansi_blue: Option<String>,
|
||||
#[serde(rename = "terminal.ansiMagenta")]
|
||||
pub terminal_ansi_magenta: Option<String>,
|
||||
#[serde(rename = "terminal.ansiCyan")]
|
||||
pub terminal_ansi_cyan: Option<String>,
|
||||
#[serde(rename = "terminal.ansiWhite")]
|
||||
pub terminal_ansi_white: Option<String>,
|
||||
#[serde(rename = "focusBorder")]
|
||||
pub focus_border: Option<String>,
|
||||
pub foreground: Option<String>,
|
||||
#[serde(rename = "selection.background")]
|
||||
pub selection_background: Option<String>,
|
||||
#[serde(rename = "errorForeground")]
|
||||
pub error_foreground: Option<String>,
|
||||
#[serde(rename = "button.background")]
|
||||
pub button_background: Option<String>,
|
||||
#[serde(rename = "button.foreground")]
|
||||
pub button_foreground: Option<String>,
|
||||
#[serde(rename = "button.secondaryBackground")]
|
||||
pub button_secondary_background: Option<String>,
|
||||
#[serde(rename = "button.secondaryForeground")]
|
||||
pub button_secondary_foreground: Option<String>,
|
||||
#[serde(rename = "button.secondaryHoverBackground")]
|
||||
pub button_secondary_hover_background: Option<String>,
|
||||
#[serde(rename = "dropdown.background")]
|
||||
pub dropdown_background: Option<String>,
|
||||
#[serde(rename = "dropdown.border")]
|
||||
pub dropdown_border: Option<String>,
|
||||
#[serde(rename = "dropdown.foreground")]
|
||||
pub dropdown_foreground: Option<String>,
|
||||
#[serde(rename = "input.background")]
|
||||
pub input_background: Option<String>,
|
||||
#[serde(rename = "input.foreground")]
|
||||
pub input_foreground: Option<String>,
|
||||
#[serde(rename = "input.border")]
|
||||
pub input_border: Option<String>,
|
||||
#[serde(rename = "input.placeholderForeground")]
|
||||
pub input_placeholder_foreground: Option<String>,
|
||||
#[serde(rename = "inputOption.activeBorder")]
|
||||
pub input_option_active_border: Option<String>,
|
||||
#[serde(rename = "inputValidation.infoBorder")]
|
||||
pub input_validation_info_border: Option<String>,
|
||||
#[serde(rename = "inputValidation.warningBorder")]
|
||||
pub input_validation_warning_border: Option<String>,
|
||||
#[serde(rename = "inputValidation.errorBorder")]
|
||||
pub input_validation_error_border: Option<String>,
|
||||
#[serde(rename = "badge.foreground")]
|
||||
pub badge_foreground: Option<String>,
|
||||
#[serde(rename = "badge.background")]
|
||||
pub badge_background: Option<String>,
|
||||
#[serde(rename = "progressBar.background")]
|
||||
pub progress_bar_background: Option<String>,
|
||||
#[serde(rename = "list.activeSelectionBackground")]
|
||||
pub list_active_selection_background: Option<String>,
|
||||
#[serde(rename = "list.activeSelectionForeground")]
|
||||
pub list_active_selection_foreground: Option<String>,
|
||||
#[serde(rename = "list.dropBackground")]
|
||||
pub list_drop_background: Option<String>,
|
||||
#[serde(rename = "list.focusBackground")]
|
||||
pub list_focus_background: Option<String>,
|
||||
#[serde(rename = "list.highlightForeground")]
|
||||
pub list_highlight_foreground: Option<String>,
|
||||
#[serde(rename = "list.hoverBackground")]
|
||||
pub list_hover_background: Option<String>,
|
||||
#[serde(rename = "list.inactiveSelectionBackground")]
|
||||
pub list_inactive_selection_background: Option<String>,
|
||||
#[serde(rename = "list.warningForeground")]
|
||||
pub list_warning_foreground: Option<String>,
|
||||
#[serde(rename = "list.errorForeground")]
|
||||
pub list_error_foreground: Option<String>,
|
||||
#[serde(rename = "activityBar.background")]
|
||||
pub activity_bar_background: Option<String>,
|
||||
#[serde(rename = "activityBar.inactiveForeground")]
|
||||
pub activity_bar_inactive_foreground: Option<String>,
|
||||
#[serde(rename = "activityBar.foreground")]
|
||||
pub activity_bar_foreground: Option<String>,
|
||||
#[serde(rename = "activityBar.activeBorder")]
|
||||
pub activity_bar_active_border: Option<String>,
|
||||
#[serde(rename = "activityBar.activeBackground")]
|
||||
pub activity_bar_active_background: Option<String>,
|
||||
#[serde(rename = "activityBarBadge.background")]
|
||||
pub activity_bar_badge_background: Option<String>,
|
||||
#[serde(rename = "activityBarBadge.foreground")]
|
||||
pub activity_bar_badge_foreground: Option<String>,
|
||||
#[serde(rename = "sideBar.background")]
|
||||
pub side_bar_background: Option<String>,
|
||||
#[serde(rename = "sideBarTitle.foreground")]
|
||||
pub side_bar_title_foreground: Option<String>,
|
||||
#[serde(rename = "sideBarSectionHeader.background")]
|
||||
pub side_bar_section_header_background: Option<String>,
|
||||
#[serde(rename = "sideBarSectionHeader.border")]
|
||||
pub side_bar_section_header_border: Option<String>,
|
||||
#[serde(rename = "editorGroup.border")]
|
||||
pub editor_group_border: Option<String>,
|
||||
#[serde(rename = "editorGroup.dropBackground")]
|
||||
pub editor_group_drop_background: Option<String>,
|
||||
#[serde(rename = "editorGroupHeader.tabsBackground")]
|
||||
pub editor_group_header_tabs_background: Option<String>,
|
||||
#[serde(rename = "tab.activeBackground")]
|
||||
pub tab_active_background: Option<String>,
|
||||
#[serde(rename = "tab.activeForeground")]
|
||||
pub tab_active_foreground: Option<String>,
|
||||
#[serde(rename = "tab.border")]
|
||||
pub tab_border: Option<String>,
|
||||
#[serde(rename = "tab.activeBorderTop")]
|
||||
pub tab_active_border_top: Option<String>,
|
||||
#[serde(rename = "tab.inactiveBackground")]
|
||||
pub tab_inactive_background: Option<String>,
|
||||
#[serde(rename = "tab.inactiveForeground")]
|
||||
pub tab_inactive_foreground: Option<String>,
|
||||
#[serde(rename = "editor.foreground")]
|
||||
pub editor_foreground: Option<String>,
|
||||
#[serde(rename = "editor.background")]
|
||||
pub editor_background: Option<String>,
|
||||
#[serde(rename = "editorLineNumber.foreground")]
|
||||
pub editor_line_number_foreground: Option<String>,
|
||||
#[serde(rename = "editor.selectionBackground")]
|
||||
pub editor_selection_background: Option<String>,
|
||||
#[serde(rename = "editor.selectionHighlightBackground")]
|
||||
pub editor_selection_highlight_background: Option<String>,
|
||||
#[serde(rename = "editor.foldBackground")]
|
||||
pub editor_fold_background: Option<String>,
|
||||
#[serde(rename = "editor.wordHighlightBackground")]
|
||||
pub editor_word_highlight_background: Option<String>,
|
||||
#[serde(rename = "editor.wordHighlightStrongBackground")]
|
||||
pub editor_word_highlight_strong_background: Option<String>,
|
||||
#[serde(rename = "editor.findMatchBackground")]
|
||||
pub editor_find_match_background: Option<String>,
|
||||
#[serde(rename = "editor.findMatchHighlightBackground")]
|
||||
pub editor_find_match_highlight_background: Option<String>,
|
||||
#[serde(rename = "editor.findRangeHighlightBackground")]
|
||||
pub editor_find_range_highlight_background: Option<String>,
|
||||
#[serde(rename = "editor.hoverHighlightBackground")]
|
||||
pub editor_hover_highlight_background: Option<String>,
|
||||
#[serde(rename = "editor.lineHighlightBorder")]
|
||||
pub editor_line_highlight_border: Option<String>,
|
||||
#[serde(rename = "editorLink.activeForeground")]
|
||||
pub editor_link_active_foreground: Option<String>,
|
||||
#[serde(rename = "editor.rangeHighlightBackground")]
|
||||
pub editor_range_highlight_background: Option<String>,
|
||||
#[serde(rename = "editor.snippetTabstopHighlightBackground")]
|
||||
pub editor_snippet_tabstop_highlight_background: Option<String>,
|
||||
#[serde(rename = "editor.snippetTabstopHighlightBorder")]
|
||||
pub editor_snippet_tabstop_highlight_border: Option<String>,
|
||||
#[serde(rename = "editor.snippetFinalTabstopHighlightBackground")]
|
||||
pub editor_snippet_final_tabstop_highlight_background: Option<String>,
|
||||
#[serde(rename = "editor.snippetFinalTabstopHighlightBorder")]
|
||||
pub editor_snippet_final_tabstop_highlight_border: Option<String>,
|
||||
#[serde(rename = "editorWhitespace.foreground")]
|
||||
pub editor_whitespace_foreground: Option<String>,
|
||||
#[serde(rename = "editorIndentGuide.background")]
|
||||
pub editor_indent_guide_background: Option<String>,
|
||||
#[serde(rename = "editorIndentGuide.activeBackground")]
|
||||
pub editor_indent_guide_active_background: Option<String>,
|
||||
#[serde(rename = "editorRuler.foreground")]
|
||||
pub editor_ruler_foreground: Option<String>,
|
||||
#[serde(rename = "editorCodeLens.foreground")]
|
||||
pub editor_code_lens_foreground: Option<String>,
|
||||
#[serde(rename = "editorBracketHighlight.foreground1")]
|
||||
pub editor_bracket_highlight_foreground1: Option<String>,
|
||||
#[serde(rename = "editorBracketHighlight.foreground2")]
|
||||
pub editor_bracket_highlight_foreground2: Option<String>,
|
||||
#[serde(rename = "editorBracketHighlight.foreground3")]
|
||||
pub editor_bracket_highlight_foreground3: Option<String>,
|
||||
#[serde(rename = "editorBracketHighlight.foreground4")]
|
||||
pub editor_bracket_highlight_foreground4: Option<String>,
|
||||
#[serde(rename = "editorBracketHighlight.foreground5")]
|
||||
pub editor_bracket_highlight_foreground5: Option<String>,
|
||||
#[serde(rename = "editorBracketHighlight.foreground6")]
|
||||
pub editor_bracket_highlight_foreground6: Option<String>,
|
||||
#[serde(rename = "editorBracketHighlight.unexpectedBracket.foreground")]
|
||||
pub editor_bracket_highlight_unexpected_bracket_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.border")]
|
||||
pub editor_overview_ruler_border: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.selectionHighlightForeground")]
|
||||
pub editor_overview_ruler_selection_highlight_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.wordHighlightForeground")]
|
||||
pub editor_overview_ruler_word_highlight_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.wordHighlightStrongForeground")]
|
||||
pub editor_overview_ruler_word_highlight_strong_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.modifiedForeground")]
|
||||
pub editor_overview_ruler_modified_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.addedForeground")]
|
||||
pub editor_overview_ruler_added_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.deletedForeground")]
|
||||
pub editor_overview_ruler_deleted_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.errorForeground")]
|
||||
pub editor_overview_ruler_error_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.warningForeground")]
|
||||
pub editor_overview_ruler_warning_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.infoForeground")]
|
||||
pub editor_overview_ruler_info_foreground: Option<String>,
|
||||
#[serde(rename = "editorError.foreground")]
|
||||
pub editor_error_foreground: Option<String>,
|
||||
#[serde(rename = "editorWarning.foreground")]
|
||||
pub editor_warning_foreground: Option<String>,
|
||||
#[serde(rename = "editorGutter.modifiedBackground")]
|
||||
pub editor_gutter_modified_background: Option<String>,
|
||||
#[serde(rename = "editorGutter.addedBackground")]
|
||||
pub editor_gutter_added_background: Option<String>,
|
||||
#[serde(rename = "editorGutter.deletedBackground")]
|
||||
pub editor_gutter_deleted_background: Option<String>,
|
||||
#[serde(rename = "gitDecoration.modifiedResourceForeground")]
|
||||
pub git_decoration_modified_resource_foreground: Option<String>,
|
||||
#[serde(rename = "gitDecoration.deletedResourceForeground")]
|
||||
pub git_decoration_deleted_resource_foreground: Option<String>,
|
||||
#[serde(rename = "gitDecoration.untrackedResourceForeground")]
|
||||
pub git_decoration_untracked_resource_foreground: Option<String>,
|
||||
#[serde(rename = "gitDecoration.ignoredResourceForeground")]
|
||||
pub git_decoration_ignored_resource_foreground: Option<String>,
|
||||
#[serde(rename = "gitDecoration.conflictingResourceForeground")]
|
||||
pub git_decoration_conflicting_resource_foreground: Option<String>,
|
||||
#[serde(rename = "diffEditor.insertedTextBackground")]
|
||||
pub diff_editor_inserted_text_background: Option<String>,
|
||||
#[serde(rename = "diffEditor.removedTextBackground")]
|
||||
pub diff_editor_removed_text_background: Option<String>,
|
||||
#[serde(rename = "inlineChat.regionHighlight")]
|
||||
pub inline_chat_region_highlight: Option<String>,
|
||||
#[serde(rename = "editorWidget.background")]
|
||||
pub editor_widget_background: Option<String>,
|
||||
#[serde(rename = "editorSuggestWidget.background")]
|
||||
pub editor_suggest_widget_background: Option<String>,
|
||||
#[serde(rename = "editorSuggestWidget.foreground")]
|
||||
pub editor_suggest_widget_foreground: Option<String>,
|
||||
#[serde(rename = "editorSuggestWidget.selectedBackground")]
|
||||
pub editor_suggest_widget_selected_background: Option<String>,
|
||||
#[serde(rename = "editorHoverWidget.background")]
|
||||
pub editor_hover_widget_background: Option<String>,
|
||||
#[serde(rename = "editorHoverWidget.border")]
|
||||
pub editor_hover_widget_border: Option<String>,
|
||||
#[serde(rename = "editorMarkerNavigation.background")]
|
||||
pub editor_marker_navigation_background: Option<String>,
|
||||
#[serde(rename = "peekView.border")]
|
||||
pub peek_view_border: Option<String>,
|
||||
#[serde(rename = "peekViewEditor.background")]
|
||||
pub peek_view_editor_background: Option<String>,
|
||||
#[serde(rename = "peekViewEditor.matchHighlightBackground")]
|
||||
pub peek_view_editor_match_highlight_background: Option<String>,
|
||||
#[serde(rename = "peekViewResult.background")]
|
||||
pub peek_view_result_background: Option<String>,
|
||||
#[serde(rename = "peekViewResult.fileForeground")]
|
||||
pub peek_view_result_file_foreground: Option<String>,
|
||||
#[serde(rename = "peekViewResult.lineForeground")]
|
||||
pub peek_view_result_line_foreground: Option<String>,
|
||||
#[serde(rename = "peekViewResult.matchHighlightBackground")]
|
||||
pub peek_view_result_match_highlight_background: Option<String>,
|
||||
#[serde(rename = "peekViewResult.selectionBackground")]
|
||||
pub peek_view_result_selection_background: Option<String>,
|
||||
#[serde(rename = "peekViewResult.selectionForeground")]
|
||||
pub peek_view_result_selection_foreground: Option<String>,
|
||||
#[serde(rename = "peekViewTitle.background")]
|
||||
pub peek_view_title_background: Option<String>,
|
||||
#[serde(rename = "peekViewTitleDescription.foreground")]
|
||||
pub peek_view_title_description_foreground: Option<String>,
|
||||
#[serde(rename = "peekViewTitleLabel.foreground")]
|
||||
pub peek_view_title_label_foreground: Option<String>,
|
||||
#[serde(rename = "merge.currentHeaderBackground")]
|
||||
pub merge_current_header_background: Option<String>,
|
||||
#[serde(rename = "merge.incomingHeaderBackground")]
|
||||
pub merge_incoming_header_background: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.currentContentForeground")]
|
||||
pub editor_overview_ruler_current_content_foreground: Option<String>,
|
||||
#[serde(rename = "editorOverviewRuler.incomingContentForeground")]
|
||||
pub editor_overview_ruler_incoming_content_foreground: Option<String>,
|
||||
#[serde(rename = "panel.background")]
|
||||
pub panel_background: Option<String>,
|
||||
#[serde(rename = "panel.border")]
|
||||
pub panel_border: Option<String>,
|
||||
#[serde(rename = "panelTitle.activeBorder")]
|
||||
pub panel_title_active_border: Option<String>,
|
||||
#[serde(rename = "panelTitle.activeForeground")]
|
||||
pub panel_title_active_foreground: Option<String>,
|
||||
#[serde(rename = "panelTitle.inactiveForeground")]
|
||||
pub panel_title_inactive_foreground: Option<String>,
|
||||
#[serde(rename = "statusBar.background")]
|
||||
pub status_bar_background: Option<String>,
|
||||
#[serde(rename = "statusBar.foreground")]
|
||||
pub status_bar_foreground: Option<String>,
|
||||
#[serde(rename = "statusBar.debuggingBackground")]
|
||||
pub status_bar_debugging_background: Option<String>,
|
||||
#[serde(rename = "statusBar.debuggingForeground")]
|
||||
pub status_bar_debugging_foreground: Option<String>,
|
||||
#[serde(rename = "statusBar.noFolderBackground")]
|
||||
pub status_bar_no_folder_background: Option<String>,
|
||||
#[serde(rename = "statusBar.noFolderForeground")]
|
||||
pub status_bar_no_folder_foreground: Option<String>,
|
||||
#[serde(rename = "statusBarItem.prominentBackground")]
|
||||
pub status_bar_item_prominent_background: Option<String>,
|
||||
#[serde(rename = "statusBarItem.prominentHoverBackground")]
|
||||
pub status_bar_item_prominent_hover_background: Option<String>,
|
||||
#[serde(rename = "statusBarItem.remoteForeground")]
|
||||
pub status_bar_item_remote_foreground: Option<String>,
|
||||
#[serde(rename = "statusBarItem.remoteBackground")]
|
||||
pub status_bar_item_remote_background: Option<String>,
|
||||
#[serde(rename = "titleBar.activeBackground")]
|
||||
pub title_bar_active_background: Option<String>,
|
||||
#[serde(rename = "titleBar.activeForeground")]
|
||||
pub title_bar_active_foreground: Option<String>,
|
||||
#[serde(rename = "titleBar.inactiveBackground")]
|
||||
pub title_bar_inactive_background: Option<String>,
|
||||
#[serde(rename = "titleBar.inactiveForeground")]
|
||||
pub title_bar_inactive_foreground: Option<String>,
|
||||
#[serde(rename = "extensionButton.prominentForeground")]
|
||||
pub extension_button_prominent_foreground: Option<String>,
|
||||
#[serde(rename = "extensionButton.prominentBackground")]
|
||||
pub extension_button_prominent_background: Option<String>,
|
||||
#[serde(rename = "extensionButton.prominentHoverBackground")]
|
||||
pub extension_button_prominent_hover_background: Option<String>,
|
||||
#[serde(rename = "pickerGroup.border")]
|
||||
pub picker_group_border: Option<String>,
|
||||
#[serde(rename = "pickerGroup.foreground")]
|
||||
pub picker_group_foreground: Option<String>,
|
||||
#[serde(rename = "debugToolBar.background")]
|
||||
pub debug_tool_bar_background: Option<String>,
|
||||
#[serde(rename = "walkThrough.embeddedEditorBackground")]
|
||||
pub walk_through_embedded_editor_background: Option<String>,
|
||||
#[serde(rename = "settings.headerForeground")]
|
||||
pub settings_header_foreground: Option<String>,
|
||||
#[serde(rename = "settings.modifiedItemIndicator")]
|
||||
pub settings_modified_item_indicator: Option<String>,
|
||||
#[serde(rename = "settings.dropdownBackground")]
|
||||
pub settings_dropdown_background: Option<String>,
|
||||
#[serde(rename = "settings.dropdownForeground")]
|
||||
pub settings_dropdown_foreground: Option<String>,
|
||||
#[serde(rename = "settings.dropdownBorder")]
|
||||
pub settings_dropdown_border: Option<String>,
|
||||
#[serde(rename = "settings.checkboxBackground")]
|
||||
pub settings_checkbox_background: Option<String>,
|
||||
#[serde(rename = "settings.checkboxForeground")]
|
||||
pub settings_checkbox_foreground: Option<String>,
|
||||
#[serde(rename = "settings.checkboxBorder")]
|
||||
pub settings_checkbox_border: Option<String>,
|
||||
#[serde(rename = "settings.textInputBackground")]
|
||||
pub settings_text_input_background: Option<String>,
|
||||
#[serde(rename = "settings.textInputForeground")]
|
||||
pub settings_text_input_foreground: Option<String>,
|
||||
#[serde(rename = "settings.textInputBorder")]
|
||||
pub settings_text_input_border: Option<String>,
|
||||
#[serde(rename = "settings.numberInputBackground")]
|
||||
pub settings_number_input_background: Option<String>,
|
||||
#[serde(rename = "settings.numberInputForeground")]
|
||||
pub settings_number_input_foreground: Option<String>,
|
||||
#[serde(rename = "settings.numberInputBorder")]
|
||||
pub settings_number_input_border: Option<String>,
|
||||
#[serde(rename = "breadcrumb.foreground")]
|
||||
pub breadcrumb_foreground: Option<String>,
|
||||
#[serde(rename = "breadcrumb.background")]
|
||||
pub breadcrumb_background: Option<String>,
|
||||
#[serde(rename = "breadcrumb.focusForeground")]
|
||||
pub breadcrumb_focus_foreground: Option<String>,
|
||||
#[serde(rename = "breadcrumb.activeSelectionForeground")]
|
||||
pub breadcrumb_active_selection_foreground: Option<String>,
|
||||
#[serde(rename = "breadcrumbPicker.background")]
|
||||
pub breadcrumb_picker_background: Option<String>,
|
||||
#[serde(rename = "listFilterWidget.background")]
|
||||
pub list_filter_widget_background: Option<String>,
|
||||
#[serde(rename = "listFilterWidget.outline")]
|
||||
pub list_filter_widget_outline: Option<String>,
|
||||
#[serde(rename = "listFilterWidget.noMatchesOutline")]
|
||||
pub list_filter_widget_no_matches_outline: Option<String>,
|
||||
}
|
||||
|
||||
fn try_parse_color(color: &str) -> Result<Hsla> {
|
||||
Ok(Rgba::try_from(color)?.into())
|
||||
}
|
||||
|
||||
pub struct VsCodeThemeConverter {
|
||||
theme: VsCodeTheme,
|
||||
theme_metadata: ThemeMetadata,
|
||||
}
|
||||
|
||||
impl VsCodeThemeConverter {
|
||||
pub fn new(theme: VsCodeTheme, theme_metadata: ThemeMetadata) -> Self {
|
||||
Self {
|
||||
theme,
|
||||
theme_metadata,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert(self) -> Result<UserTheme> {
|
||||
let appearance = self.theme_metadata.appearance.into();
|
||||
|
||||
let vscode_colors = &self.theme.colors;
|
||||
|
||||
let theme_colors_refinements = ThemeColorsRefinement {
|
||||
border: vscode_colors
|
||||
.panel_border
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
border_variant: vscode_colors
|
||||
.panel_border
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
border_focused: vscode_colors
|
||||
.panel_border
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
border_disabled: vscode_colors
|
||||
.panel_border
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
border_selected: vscode_colors
|
||||
.panel_border
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
border_transparent: vscode_colors
|
||||
.panel_border
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
elevated_surface_background: vscode_colors
|
||||
.panel_background
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
surface_background: vscode_colors
|
||||
.panel_background
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
background: vscode_colors
|
||||
.editor_background
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
element_background: vscode_colors
|
||||
.button_background
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
text: vscode_colors
|
||||
.foreground
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
tab_active_background: vscode_colors
|
||||
.tab_active_background
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
tab_inactive_background: vscode_colors
|
||||
.tab_inactive_background
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_background: vscode_colors
|
||||
.terminal_background
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_bright_black: vscode_colors
|
||||
.terminal_ansi_bright_black
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_bright_red: vscode_colors
|
||||
.terminal_ansi_bright_red
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_bright_green: vscode_colors
|
||||
.terminal_ansi_bright_green
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_bright_yellow: vscode_colors
|
||||
.terminal_ansi_bright_yellow
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_bright_blue: vscode_colors
|
||||
.terminal_ansi_bright_blue
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_bright_magenta: vscode_colors
|
||||
.terminal_ansi_bright_magenta
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_bright_cyan: vscode_colors
|
||||
.terminal_ansi_bright_cyan
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_bright_white: vscode_colors
|
||||
.terminal_ansi_bright_white
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_black: vscode_colors
|
||||
.terminal_ansi_black
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_red: vscode_colors
|
||||
.terminal_ansi_red
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_green: vscode_colors
|
||||
.terminal_ansi_green
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_yellow: vscode_colors
|
||||
.terminal_ansi_yellow
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_blue: vscode_colors
|
||||
.terminal_ansi_blue
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_magenta: vscode_colors
|
||||
.terminal_ansi_magenta
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_cyan: vscode_colors
|
||||
.terminal_ansi_cyan
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
terminal_ansi_white: vscode_colors
|
||||
.terminal_ansi_white
|
||||
.as_ref()
|
||||
.traverse(|color| try_parse_color(&color))?,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(UserTheme {
|
||||
name: self.theme_metadata.name.into(),
|
||||
appearance,
|
||||
styles: UserThemeStylesRefinement {
|
||||
colors: theme_colors_refinements,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
|
@ -128,7 +128,7 @@ impl<V: 'static> Checkbox<V> {
|
|||
// click area for the checkbox.
|
||||
.size_5()
|
||||
// Because we've enlarged the click area, we need to create a
|
||||
// `group` to pass down interaction events to the checkbox.
|
||||
// `group` to pass down interactivity events to the checkbox.
|
||||
.group(group_id.clone())
|
||||
.child(
|
||||
div()
|
||||
|
@ -148,7 +148,7 @@ impl<V: 'static> Checkbox<V> {
|
|||
.bg(bg_color)
|
||||
.border()
|
||||
.border_color(border_color)
|
||||
// We only want the interaction states to fire when we
|
||||
// We only want the interactivity states to fire when we
|
||||
// are in a checkbox that isn't disabled.
|
||||
.when(!self.disabled, |this| {
|
||||
// Here instead of `hover()` we use `group_hover()`
|
||||
|
|
|
@ -309,6 +309,10 @@ impl ListEntry {
|
|||
.group("")
|
||||
.bg(cx.theme().colors().surface_background)
|
||||
// TODO: Add focus state
|
||||
// .when(self.state == InteractionState::Focused, |this| {
|
||||
// this.border()
|
||||
// .border_color(cx.theme().colors().border_focused)
|
||||
// })
|
||||
.child(
|
||||
sized_item
|
||||
.when(self.variant == ListItemVariant::Inset, |this| this.px_2())
|
||||
|
|
|
@ -127,7 +127,7 @@ impl Tab {
|
|||
div()
|
||||
.id(self.id.clone())
|
||||
.on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone()))
|
||||
.drag_over::<TabDragState>(|d| d.bg(cx.theme().colors().element_drop_target))
|
||||
.drag_over::<TabDragState>(|d| d.bg(cx.theme().colors().drop_target_background))
|
||||
.on_drop(|_view, state: View<TabDragState>, cx| {
|
||||
eprintln!("{:?}", state.read(cx));
|
||||
})
|
||||
|
|
|
@ -46,12 +46,12 @@ pub enum GitStatus {
|
|||
impl GitStatus {
|
||||
pub fn hsla(&self, cx: &WindowContext) -> Hsla {
|
||||
match self {
|
||||
Self::None => cx.theme().styles.system.transparent,
|
||||
Self::Created => cx.theme().styles.git.created,
|
||||
Self::Modified => cx.theme().styles.git.modified,
|
||||
Self::Deleted => cx.theme().styles.git.deleted,
|
||||
Self::Conflict => cx.theme().styles.git.conflict,
|
||||
Self::Renamed => cx.theme().styles.git.renamed,
|
||||
Self::None => cx.theme().system().transparent,
|
||||
Self::Created => cx.theme().status().created,
|
||||
Self::Modified => cx.theme().status().modified,
|
||||
Self::Deleted => cx.theme().status().deleted,
|
||||
Self::Conflict => cx.theme().status().conflict,
|
||||
Self::Renamed => cx.theme().status().renamed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ impl Buffer {
|
|||
|
||||
fn render_row<V: 'static>(row: BufferRow, cx: &WindowContext) -> impl Component<V> {
|
||||
let line_background = if row.current {
|
||||
cx.theme().colors().editor_active_line
|
||||
cx.theme().colors().editor_active_line_background
|
||||
} else {
|
||||
cx.theme().styles.system.transparent
|
||||
};
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue