Detailed changes
@@ -26,7 +26,7 @@ pub struct TextStyle {
pub font_properties: Properties,
}
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug)]
pub struct HighlightStyle {
pub color: Color,
pub font_properties: Properties,
@@ -65,6 +65,11 @@ corner_radius = 6
border = { color = "#000000", width = 1 }
background = "$surface.0"
+[chat_panel.input_editor]
+text = "$text.1.color"
+background = "$surface.1"
+selection = "$selection.host"
+
[selector]
background = "$surface.2"
text = "$text.0"
@@ -72,6 +77,7 @@ padding = 6
margin.top = 12
corner_radius = 6
shadow = { offset = [0, 0], blur = 12, color = "#00000088" }
+input_editor = "$chat_panel.input_editor"
[selector.item]
background = "#424344"
@@ -85,15 +91,11 @@ extends = "$selector.item"
background = "#094771"
[editor]
+text = "$text.1.color"
background = "$surface.1"
gutter_background = "$surface.1"
active_line_background = "$surface.2"
line_number = "$text.2.color"
line_number_active = "$text.0.color"
-replicas = [
- { selection = "#264f78", cursor = "$text.0.color" },
- { selection = "#504f31", cursor = "#fcf154" },
-]
-
-[syntax]
-default = "$text.1.color"
+selection = "$selection.host"
+guest_selections = "$selection.guests"
@@ -11,6 +11,10 @@ base = { family = "Helvetica", size = 14.0 }
1 = { extends = "$text.base", color = "#b3b3b3" }
2 = { extends = "$text.base", color = "#7b7d80" }
+[selection]
+host = { selection = "#264f78", cursor = "$text.0.color" }
+guests = [{ selection = "#504f31", cursor = "#fcf154" }]
+
[status]
good = "#4fac63"
info = "#3c5dd4"
@@ -12,6 +12,10 @@ base = { family = "Helvetica", size = 14.0 }
1 = { extends = "$text.base", color = "#111111" }
2 = { extends = "$text.base", color = "#333333" }
+[selection]
+host = { selection = "#264f78", cursor = "$text.0.color" }
+guests = [{ selection = "#504f31", cursor = "#fcf154" }]
+
[status]
good = "#4fac63"
info = "#3c5dd4"
@@ -46,7 +46,12 @@ impl ChatPanel {
settings: watch::Receiver<Settings>,
cx: &mut ViewContext<Self>,
) -> Self {
- let input_editor = cx.add_view(|cx| Editor::auto_height(settings.clone(), cx));
+ let input_editor = cx.add_view(|cx| {
+ Editor::auto_height(settings.clone(), cx).with_style({
+ let settings = settings.clone();
+ move |_| settings.borrow().theme.chat_panel.input_editor.as_editor()
+ })
+ });
let channel_select = cx.add_view(|cx| {
let channel_list = channel_list.clone();
Select::new(0, cx, {
@@ -2397,6 +2397,7 @@ impl Snapshot {
pub fn layout_lines(
&mut self,
mut rows: Range<u32>,
+ style: &EditorStyle,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
) -> Result<Vec<text_layout::Line>> {
@@ -2433,7 +2434,11 @@ impl Snapshot {
}
if !line_chunk.is_empty() && !line_exceeded_max_len {
- let style = self.theme.syntax.highlight_style(style_ix);
+ let style = self
+ .theme
+ .syntax
+ .highlight_style(style_ix)
+ .unwrap_or(style.text.clone());
// Avoid a lookup if the font properties match the previous ones.
let font_id = if style.font_properties == prev_font_properties {
prev_font_id
@@ -661,13 +661,10 @@ mod tests {
(function_item name: (identifier) @fn.name)"#,
)
.unwrap();
- let theme = SyntaxTheme::new(
- Default::default(),
- vec![
- ("mod.body".to_string(), Color::from_u32(0xff0000ff).into()),
- ("fn.name".to_string(), Color::from_u32(0x00ff00ff).into()),
- ],
- );
+ let theme = SyntaxTheme::new(vec![
+ ("mod.body".to_string(), Color::from_u32(0xff0000ff).into()),
+ ("fn.name".to_string(), Color::from_u32(0x00ff00ff).into()),
+ ]);
let lang = Arc::new(Language {
config: LanguageConfig {
name: "Test".to_string(),
@@ -754,13 +751,10 @@ mod tests {
(function_item name: (identifier) @fn.name)"#,
)
.unwrap();
- let theme = SyntaxTheme::new(
- Default::default(),
- vec![
- ("mod.body".to_string(), Color::from_u32(0xff0000ff).into()),
- ("fn.name".to_string(), Color::from_u32(0x00ff00ff).into()),
- ],
- );
+ let theme = SyntaxTheme::new(vec![
+ ("mod.body".to_string(), Color::from_u32(0xff0000ff).into()),
+ ("fn.name".to_string(), Color::from_u32(0x00ff00ff).into()),
+ ]);
let lang = Arc::new(Language {
config: LanguageConfig {
name: "Test".to_string(),
@@ -280,7 +280,12 @@ impl EditorElement {
let content_origin = bounds.origin() + layout.text_offset;
for (replica_id, selections) in &layout.selections {
- let replica_theme = theme.replicas[*replica_id as usize % theme.replicas.len()];
+ let style_ix = *replica_id as usize % (theme.guest_selections.len() + 1);
+ let style = if style_ix == 0 {
+ &theme.selection
+ } else {
+ &theme.guest_selections[style_ix - 1]
+ };
for selection in selections {
if selection.start != selection.end {
@@ -294,7 +299,7 @@ impl EditorElement {
};
let selection = Selection {
- color: replica_theme.selection,
+ color: style.selection,
line_height: layout.line_height,
start_y: content_origin.y() + row_range.start as f32 * layout.line_height
- scroll_top,
@@ -337,7 +342,7 @@ impl EditorElement {
- scroll_left;
let y = selection.end.row() as f32 * layout.line_height - scroll_top;
cursors.push(Cursor {
- color: replica_theme.cursor,
+ color: style.cursor,
origin: content_origin + vec2f(x, y),
line_height: layout.line_height,
});
@@ -507,8 +512,12 @@ impl Element for EditorElement {
};
let mut max_visible_line_width = 0.0;
- let line_layouts = match snapshot.layout_lines(start_row..end_row, font_cache, layout_cache)
- {
+ let line_layouts = match snapshot.layout_lines(
+ start_row..end_row,
+ &self.style,
+ font_cache,
+ layout_cache,
+ ) {
Err(error) => {
log::error!("error laying out lines: {}", error);
return (size, None);
@@ -30,7 +30,7 @@ pub struct FileFinder {
handle: WeakViewHandle<Self>,
settings: watch::Receiver<Settings>,
workspace: WeakViewHandle<Workspace>,
- query_buffer: ViewHandle<Editor>,
+ query_editor: ViewHandle<Editor>,
search_count: usize,
latest_search_id: usize,
latest_search_did_cancel: bool,
@@ -86,7 +86,7 @@ impl View for FileFinder {
ConstrainedBox::new(
Container::new(
Flex::new(Axis::Vertical)
- .with_child(ChildView::new(self.query_buffer.id()).boxed())
+ .with_child(ChildView::new(self.query_editor.id()).boxed())
.with_child(Expanded::new(1.0, self.render_matches()).boxed())
.boxed(),
)
@@ -102,7 +102,7 @@ impl View for FileFinder {
}
fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
- cx.focus(&self.query_buffer);
+ cx.focus(&self.query_editor);
}
fn keymap_context(&self, _: &AppContext) -> keymap::Context {
@@ -266,15 +266,20 @@ impl FileFinder {
) -> Self {
cx.observe(&workspace, Self::workspace_updated).detach();
- let query_buffer = cx.add_view(|cx| Editor::single_line(settings.clone(), cx));
- cx.subscribe(&query_buffer, Self::on_query_editor_event)
+ let query_editor = cx.add_view(|cx| {
+ Editor::single_line(settings.clone(), cx).with_style({
+ let settings = settings.clone();
+ move |_| settings.borrow().theme.selector.input_editor.as_editor()
+ })
+ });
+ cx.subscribe(&query_editor, Self::on_query_editor_event)
.detach();
Self {
handle: cx.handle().downgrade(),
settings,
workspace: workspace.downgrade(),
- query_buffer,
+ query_editor,
search_count: 0,
latest_search_id: 0,
latest_search_did_cancel: false,
@@ -287,7 +292,7 @@ impl FileFinder {
}
fn workspace_updated(&mut self, _: ViewHandle<Workspace>, cx: &mut ViewContext<Self>) {
- let query = self.query_buffer.update(cx, |buffer, cx| buffer.text(cx));
+ let query = self.query_editor.update(cx, |buffer, cx| buffer.text(cx));
if let Some(task) = self.spawn_search(query, cx) {
task.detach();
}
@@ -301,7 +306,7 @@ impl FileFinder {
) {
match event {
editor::Event::Edited => {
- let query = self.query_buffer.update(cx, |buffer, cx| buffer.text(cx));
+ let query = self.query_editor.update(cx, |buffer, cx| buffer.text(cx));
if query.is_empty() {
self.latest_search_id = util::post_inc(&mut self.search_count);
self.matches.clear();
@@ -460,7 +465,7 @@ mod tests {
.downcast::<FileFinder>()
.unwrap()
});
- let query_buffer = cx.read(|cx| finder.read(cx).query_buffer.clone());
+ let query_buffer = cx.read(|cx| finder.read(cx).query_editor.clone());
let chain = vec![finder.id(), query_buffer.id()];
cx.dispatch_action(window_id, chain.clone(), Insert("b".into()));
@@ -7,7 +7,7 @@ use gpui::{
elements::{ContainerStyle, LabelStyle},
fonts::{HighlightStyle, TextStyle},
};
-use serde::{de, Deserialize};
+use serde::Deserialize;
use std::collections::HashMap;
pub use highlight_map::*;
@@ -28,7 +28,6 @@ pub struct Theme {
pub struct SyntaxTheme {
highlights: Vec<(String, HighlightStyle)>,
- default_style: HighlightStyle,
}
#[derive(Deserialize)]
@@ -69,6 +68,7 @@ pub struct ChatPanel {
pub container: ContainerStyle,
pub message: ChatMessage,
pub channel_select: ChannelSelect,
+ pub input_editor: InputEditorStyle,
}
#[derive(Deserialize)]
@@ -107,6 +107,7 @@ pub struct Selector {
#[serde(flatten)]
pub label: LabelStyle,
+ pub input_editor: InputEditorStyle,
pub item: ContainedLabel,
pub active_item: ContainedLabel,
}
@@ -129,33 +130,38 @@ pub struct ContainedLabel {
#[derive(Clone, Deserialize)]
pub struct EditorStyle {
+ pub text: HighlightStyle,
pub background: Color,
+ pub selection: SelectionStyle,
pub gutter_background: Color,
pub active_line_background: Color,
pub line_number: Color,
pub line_number_active: Color,
- pub replicas: Vec<Replica>,
+ pub guest_selections: Vec<SelectionStyle>,
+}
+
+#[derive(Clone, Deserialize)]
+pub struct InputEditorStyle {
+ pub text: HighlightStyle,
+ pub background: Color,
+ pub selection: SelectionStyle,
}
#[derive(Clone, Copy, Default, Deserialize)]
-pub struct Replica {
+pub struct SelectionStyle {
pub cursor: Color,
pub selection: Color,
}
impl SyntaxTheme {
- pub fn new(default_style: HighlightStyle, highlights: Vec<(String, HighlightStyle)>) -> Self {
- Self {
- default_style,
- highlights,
- }
+ pub fn new(highlights: Vec<(String, HighlightStyle)>) -> Self {
+ Self { highlights }
}
- pub fn highlight_style(&self, id: HighlightId) -> HighlightStyle {
+ pub fn highlight_style(&self, id: HighlightId) -> Option<HighlightStyle> {
self.highlights
.get(id.0 as usize)
.map(|entry| entry.1.clone())
- .unwrap_or_else(|| self.default_style.clone())
}
#[cfg(test)]
@@ -167,12 +173,28 @@ impl SyntaxTheme {
impl Default for EditorStyle {
fn default() -> Self {
Self {
+ text: HighlightStyle {
+ color: Color::from_u32(0xff0000ff),
+ font_properties: Default::default(),
+ },
background: Default::default(),
gutter_background: Default::default(),
active_line_background: Default::default(),
line_number: Default::default(),
line_number_active: Default::default(),
- replicas: vec![Default::default()],
+ selection: Default::default(),
+ guest_selections: Default::default(),
+ }
+ }
+}
+
+impl InputEditorStyle {
+ pub fn as_editor(&self) -> EditorStyle {
+ EditorStyle {
+ text: self.text.clone(),
+ background: self.background,
+ selection: self.selection,
+ ..Default::default()
}
}
}
@@ -182,16 +204,9 @@ impl<'de> Deserialize<'de> for SyntaxTheme {
where
D: serde::Deserializer<'de>,
{
- let mut syntax_data: HashMap<String, HighlightStyle> =
- Deserialize::deserialize(deserializer)?;
-
- let mut result = Self {
- highlights: Vec::<(String, HighlightStyle)>::new(),
- default_style: syntax_data
- .remove("default")
- .ok_or_else(|| de::Error::custom("must specify a default color in syntax theme"))?,
- };
+ let syntax_data: HashMap<String, HighlightStyle> = Deserialize::deserialize(deserializer)?;
+ let mut result = Self::new(Vec::new());
for (key, style) in syntax_data {
match result
.highlights
@@ -69,7 +69,6 @@ mod tests {
#[test]
fn test_highlight_map() {
let theme = SyntaxTheme::new(
- Default::default(),
[
("function", Color::from_u32(0x100000ff)),
("function.method", Color::from_u32(0x200000ff)),
@@ -25,7 +25,7 @@ pub struct ThemeSelector {
settings: watch::Receiver<Settings>,
registry: Arc<ThemeRegistry>,
matches: Vec<StringMatch>,
- query_buffer: ViewHandle<Editor>,
+ query_editor: ViewHandle<Editor>,
list_state: UniformListState,
selected_index: usize,
}
@@ -60,15 +60,21 @@ impl ThemeSelector {
registry: Arc<ThemeRegistry>,
cx: &mut ViewContext<Self>,
) -> Self {
- let query_buffer = cx.add_view(|cx| Editor::single_line(settings.clone(), cx));
- cx.subscribe(&query_buffer, Self::on_query_editor_event)
+ let query_editor = cx.add_view(|cx| {
+ Editor::single_line(settings.clone(), cx).with_style({
+ let settings = settings.clone();
+ move |_| settings.borrow().theme.selector.input_editor.as_editor()
+ })
+ });
+
+ cx.subscribe(&query_editor, Self::on_query_editor_event)
.detach();
let mut this = Self {
settings,
settings_tx,
registry,
- query_buffer,
+ query_editor,
matches: Vec::new(),
list_state: Default::default(),
selected_index: 0,
@@ -151,7 +157,7 @@ impl ThemeSelector {
string: name,
})
.collect::<Vec<_>>();
- let query = self.query_buffer.update(cx, |buffer, cx| buffer.text(cx));
+ let query = self.query_editor.update(cx, |buffer, cx| buffer.text(cx));
self.matches = if query.is_empty() {
candidates
@@ -276,7 +282,7 @@ impl View for ThemeSelector {
ConstrainedBox::new(
Container::new(
Flex::new(Axis::Vertical)
- .with_child(ChildView::new(self.query_buffer.id()).boxed())
+ .with_child(ChildView::new(self.query_editor.id()).boxed())
.with_child(Expanded::new(1.0, self.render_matches(cx)).boxed())
.boxed(),
)
@@ -292,7 +298,7 @@ impl View for ThemeSelector {
}
fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
- cx.focus(&self.query_buffer);
+ cx.focus(&self.query_editor);
}
fn keymap_context(&self, _: &AppContext) -> keymap::Context {