Detailed changes
@@ -5278,6 +5278,16 @@ dependencies = [
"regex",
]
+[[package]]
+name = "tree-sitter-c"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7bdc5574c6cbc39c409246caeb1dd4d3c4bd6d30d4e9b399776086c20365fd24"
+dependencies = [
+ "cc",
+ "tree-sitter",
+]
+
[[package]]
name = "tree-sitter-markdown"
version = "0.0.1"
@@ -5887,6 +5897,7 @@ dependencies = [
"tiny_http",
"toml",
"tree-sitter",
+ "tree-sitter-c",
"tree-sitter-markdown",
"tree-sitter-rust",
"unindent",
@@ -2,7 +2,7 @@ use client::{
channel::{Channel, ChannelEvent, ChannelList, ChannelMessage},
Client,
};
-use editor::{Editor, EditorSettings};
+use editor::Editor;
use gpui::{
action,
elements::*,
@@ -16,7 +16,7 @@ use postage::{prelude::Stream, watch};
use std::sync::Arc;
use time::{OffsetDateTime, UtcOffset};
use util::{ResultExt, TryFutureExt};
-use workspace::Settings;
+use workspace::{settings::SoftWrap, Settings};
const MESSAGE_LOADING_THRESHOLD: usize = 50;
@@ -52,21 +52,14 @@ impl ChatPanel {
cx: &mut ViewContext<Self>,
) -> Self {
let input_editor = cx.add_view(|cx| {
- Editor::auto_height(
+ let mut editor = Editor::auto_height(
4,
- {
- let settings = settings.clone();
- Arc::new(move |_| {
- let settings = settings.borrow();
- EditorSettings {
- tab_size: settings.tab_size,
- style: settings.theme.chat_panel.input_editor.as_editor(),
- soft_wrap: editor::SoftWrap::EditorWidth,
- }
- })
- },
+ settings.clone(),
+ Some(|theme| theme.chat_panel.input_editor.clone()),
cx,
- )
+ );
+ editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
+ editor
});
let channel_select = cx.add_view(|cx| {
let channel_list = channel_list.clone();
@@ -7,7 +7,7 @@ use editor::{
display_map::{BlockDisposition, BlockId, BlockProperties, RenderBlock},
highlight_diagnostic_message,
items::BufferItemHandle,
- Autoscroll, BuildSettings, Editor, ExcerptId, MultiBuffer, ToOffset,
+ Autoscroll, Editor, ExcerptId, MultiBuffer, ToOffset,
};
use gpui::{
action, elements::*, fonts::TextStyle, keymap::Binding, AnyViewHandle, AppContext, Entity,
@@ -62,7 +62,6 @@ struct ProjectDiagnosticsEditor {
excerpts: ModelHandle<MultiBuffer>,
path_states: Vec<PathState>,
paths_to_update: BTreeSet<ProjectPath>,
- build_settings: BuildSettings,
settings: watch::Receiver<workspace::Settings>,
}
@@ -142,12 +141,11 @@ impl ProjectDiagnosticsEditor {
.detach();
let excerpts = cx.add_model(|cx| MultiBuffer::new(project.read(cx).replica_id()));
- let build_settings = editor::settings_builder(excerpts.downgrade(), settings.clone());
let editor = cx.add_view(|cx| {
let mut editor = Editor::for_buffer(
excerpts.clone(),
- build_settings.clone(),
Some(project.clone()),
+ settings.clone(),
cx,
);
editor.set_vertical_scroll_margin(5, cx);
@@ -164,7 +162,6 @@ impl ProjectDiagnosticsEditor {
workspace,
excerpts,
editor,
- build_settings,
settings,
path_states: Default::default(),
paths_to_update,
@@ -360,7 +357,7 @@ impl ProjectDiagnosticsEditor {
height: 2,
render: diagnostic_header_renderer(
primary,
- self.build_settings.clone(),
+ self.settings.clone(),
),
disposition: BlockDisposition::Above,
});
@@ -382,7 +379,7 @@ impl ProjectDiagnosticsEditor {
render: diagnostic_block_renderer(
diagnostic,
true,
- self.build_settings.clone(),
+ self.settings.clone(),
),
disposition: BlockDisposition::Below,
});
@@ -644,20 +641,21 @@ impl workspace::ItemView for ProjectDiagnosticsEditor {
fn diagnostic_header_renderer(
diagnostic: Diagnostic,
- build_settings: BuildSettings,
+ settings: watch::Receiver<workspace::Settings>,
) -> RenderBlock {
let (message, highlights) = highlight_diagnostic_message(&diagnostic.message);
Arc::new(move |cx| {
- let settings = build_settings(cx);
- let style = &settings.style.diagnostic_header;
- let font_size = (style.text_scale_factor * settings.style.text.font_size).round();
+ let settings = settings.borrow();
+ let theme = &settings.theme.editor;
+ let style = &theme.diagnostic_header;
+ let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
let icon_width = cx.em_width * style.icon_width_factor;
let icon = if diagnostic.severity == DiagnosticSeverity::ERROR {
Svg::new("icons/diagnostic-error-10.svg")
- .with_color(settings.style.error_diagnostic.message.text.color)
+ .with_color(theme.error_diagnostic.message.text.color)
} else {
Svg::new("icons/diagnostic-warning-10.svg")
- .with_color(settings.style.warning_diagnostic.message.text.color)
+ .with_color(theme.warning_diagnostic.message.text.color)
};
Flex::row()
@@ -14,6 +14,7 @@ test-support = [
"gpui/test-support",
"project/test-support",
"util/test-support",
+ "workspace/test-support",
]
[dependencies]
@@ -50,6 +51,7 @@ lsp = { path = "../lsp", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
util = { path = "../util", features = ["test-support"] }
project = { path = "../project", features = ["test-support"] }
+workspace = { path = "../workspace", features = ["test-support"] }
ctor = "0.1"
env_logger = "0.8"
rand = "0.8"
@@ -26,7 +26,7 @@ use gpui::{
platform::CursorStyle,
text_layout, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
- WeakModelHandle, WeakViewHandle,
+ WeakViewHandle,
};
use items::{BufferItemHandle, MultiBufferItemHandle};
use itertools::Itertools as _;
@@ -57,9 +57,9 @@ use std::{
};
pub use sum_tree::Bias;
use text::rope::TextDimension;
-use theme::{DiagnosticStyle, EditorStyle};
+use theme::DiagnosticStyle;
use util::{post_inc, ResultExt, TryFutureExt};
-use workspace::{ItemNavHistory, PathOpener, Workspace};
+use workspace::{settings, ItemNavHistory, PathOpener, Settings, Workspace};
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
const MAX_LINE_LEN: usize = 1024;
@@ -388,13 +388,6 @@ pub enum EditorMode {
Full,
}
-#[derive(Clone)]
-pub struct EditorSettings {
- pub tab_size: usize,
- pub soft_wrap: SoftWrap,
- pub style: EditorStyle,
-}
-
#[derive(Clone)]
pub enum SoftWrap {
None,
@@ -402,9 +395,16 @@ pub enum SoftWrap {
Column(u32),
}
+#[derive(Clone)]
+pub struct EditorStyle {
+ pub text: TextStyle,
+ pub placeholder_text: Option<TextStyle>,
+ pub theme: theme::Editor,
+}
+
type CompletionId = usize;
-pub type BuildSettings = Arc<dyn 'static + Send + Sync + Fn(&AppContext) -> EditorSettings>;
+pub type GetFieldEditorTheme = fn(&theme::Theme) -> theme::FieldEditor;
pub struct Editor {
handle: WeakViewHandle<Self>,
@@ -425,7 +425,9 @@ pub struct Editor {
scroll_position: Vector2F,
scroll_top_anchor: Option<Anchor>,
autoscroll_request: Option<Autoscroll>,
- build_settings: BuildSettings,
+ settings: watch::Receiver<Settings>,
+ soft_wrap_mode_override: Option<settings::SoftWrap>,
+ get_field_editor_theme: Option<GetFieldEditorTheme>,
project: Option<ModelHandle<Project>>,
focused: bool,
show_local_cursors: bool,
@@ -531,12 +533,12 @@ impl ContextMenu {
fn render(
&self,
cursor_position: DisplayPoint,
- build_settings: BuildSettings,
+ style: EditorStyle,
cx: &AppContext,
) -> (DisplayPoint, ElementBox) {
match self {
- ContextMenu::Completions(menu) => (cursor_position, menu.render(build_settings, cx)),
- ContextMenu::CodeActions(menu) => menu.render(cursor_position, build_settings, cx),
+ ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)),
+ ContextMenu::CodeActions(menu) => menu.render(cursor_position, style),
}
}
}
@@ -573,15 +575,14 @@ impl CompletionsMenu {
!self.matches.is_empty()
}
- fn render(&self, build_settings: BuildSettings, cx: &AppContext) -> ElementBox {
+ fn render(&self, style: EditorStyle, _: &AppContext) -> ElementBox {
enum CompletionTag {}
- let settings = build_settings(cx);
let completions = self.completions.clone();
let matches = self.matches.clone();
let selected_item = self.selected_item;
+ let container_style = style.autocomplete.container;
UniformList::new(self.list.clone(), matches.len(), move |range, items, cx| {
- let settings = build_settings(cx);
let start_ix = range.start;
for (ix, mat) in matches[range].iter().enumerate() {
let completion = &completions[mat.candidate_id];
@@ -592,22 +593,22 @@ impl CompletionsMenu {
cx,
|state, _| {
let item_style = if item_ix == selected_item {
- settings.style.autocomplete.selected_item
+ style.autocomplete.selected_item
} else if state.hovered {
- settings.style.autocomplete.hovered_item
+ style.autocomplete.hovered_item
} else {
- settings.style.autocomplete.item
+ style.autocomplete.item
};
- Text::new(completion.label.text.clone(), settings.style.text.clone())
+ Text::new(completion.label.text.clone(), style.text.clone())
.with_soft_wrap(false)
.with_highlights(combine_syntax_and_fuzzy_match_highlights(
&completion.label.text,
- settings.style.text.color.into(),
+ style.text.color.into(),
styled_runs_for_code_label(
&completion.label,
- settings.style.text.color,
- &settings.style.syntax,
+ style.text.color,
+ &style.syntax,
),
&mat.positions,
))
@@ -638,7 +639,7 @@ impl CompletionsMenu {
.map(|(ix, _)| ix),
)
.contained()
- .with_style(settings.style.autocomplete.container)
+ .with_style(container_style)
.boxed()
}
@@ -714,31 +715,29 @@ impl CodeActionsMenu {
fn render(
&self,
mut cursor_position: DisplayPoint,
- build_settings: BuildSettings,
- cx: &AppContext,
+ style: EditorStyle,
) -> (DisplayPoint, ElementBox) {
enum ActionTag {}
- let settings = build_settings(cx);
+ let container_style = style.autocomplete.container;
let actions = self.actions.clone();
let selected_item = self.selected_item;
let element =
UniformList::new(self.list.clone(), actions.len(), move |range, items, cx| {
- let settings = build_settings(cx);
let start_ix = range.start;
for (ix, action) in actions[range].iter().enumerate() {
let item_ix = start_ix + ix;
items.push(
MouseEventHandler::new::<ActionTag, _, _>(item_ix, cx, |state, _| {
let item_style = if item_ix == selected_item {
- settings.style.autocomplete.selected_item
+ style.autocomplete.selected_item
} else if state.hovered {
- settings.style.autocomplete.hovered_item
+ style.autocomplete.hovered_item
} else {
- settings.style.autocomplete.item
+ style.autocomplete.item
};
- Text::new(action.lsp_action.title.clone(), settings.style.text.clone())
+ Text::new(action.lsp_action.title.clone(), style.text.clone())
.with_soft_wrap(false)
.contained()
.with_style(item_style)
@@ -760,7 +759,7 @@ impl CodeActionsMenu {
.map(|(ix, _)| ix),
)
.contained()
- .with_style(settings.style.autocomplete.container)
+ .with_style(container_style)
.boxed();
if self.deployed_from_indicator {
@@ -791,40 +790,57 @@ pub struct NavigationData {
}
impl Editor {
- pub fn single_line(build_settings: BuildSettings, cx: &mut ViewContext<Self>) -> Self {
+ pub fn single_line(
+ settings: watch::Receiver<Settings>,
+ field_editor_style: Option<GetFieldEditorTheme>,
+ cx: &mut ViewContext<Self>,
+ ) -> Self {
let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
- let mut view = Self::for_buffer(buffer, build_settings, None, cx);
- view.mode = EditorMode::SingleLine;
- view
+ Self::new(
+ EditorMode::SingleLine,
+ buffer,
+ None,
+ settings,
+ field_editor_style,
+ cx,
+ )
}
pub fn auto_height(
max_lines: usize,
- build_settings: BuildSettings,
+ settings: watch::Receiver<Settings>,
+ field_editor_style: Option<GetFieldEditorTheme>,
cx: &mut ViewContext<Self>,
) -> Self {
let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
- let mut view = Self::for_buffer(buffer, build_settings, None, cx);
- view.mode = EditorMode::AutoHeight { max_lines };
- view
+ Self::new(
+ EditorMode::AutoHeight { max_lines },
+ buffer,
+ None,
+ settings,
+ field_editor_style,
+ cx,
+ )
}
pub fn for_buffer(
buffer: ModelHandle<MultiBuffer>,
- build_settings: BuildSettings,
project: Option<ModelHandle<Project>>,
+ settings: watch::Receiver<Settings>,
cx: &mut ViewContext<Self>,
) -> Self {
- Self::new(buffer, build_settings, project, cx)
+ Self::new(EditorMode::Full, buffer, project, settings, None, cx)
}
pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
let mut clone = Self::new(
+ self.mode,
self.buffer.clone(),
- self.build_settings.clone(),
self.project.clone(),
+ self.settings.clone(),
+ self.get_field_editor_theme,
cx,
);
clone.scroll_position = self.scroll_position;
@@ -836,19 +852,22 @@ impl Editor {
clone
}
- pub fn new(
+ fn new(
+ mode: EditorMode,
buffer: ModelHandle<MultiBuffer>,
- build_settings: BuildSettings,
project: Option<ModelHandle<Project>>,
+ settings: watch::Receiver<Settings>,
+ get_field_editor_theme: Option<GetFieldEditorTheme>,
cx: &mut ViewContext<Self>,
) -> Self {
- let settings = build_settings(cx);
let display_map = cx.add_model(|cx| {
+ let settings = settings.borrow();
+ let style = build_style(&*settings, get_field_editor_theme, cx);
DisplayMap::new(
buffer.clone(),
settings.tab_size,
- settings.style.text.font_id,
- settings.style.text.font_size,
+ style.text.font_id,
+ style.text.font_size,
None,
2,
1,
@@ -884,7 +903,9 @@ impl Editor {
snippet_stack: Default::default(),
select_larger_syntax_node_stack: Vec::new(),
active_diagnostics: None,
- build_settings,
+ settings,
+ soft_wrap_mode_override: None,
+ get_field_editor_theme,
project,
scroll_position: Vector2F::zero(),
scroll_top_anchor: None,
@@ -893,7 +914,7 @@ impl Editor {
show_local_cursors: false,
blink_epoch: 0,
blinking_paused: false,
- mode: EditorMode::Full,
+ mode,
vertical_scroll_margin: 3.0,
placeholder_text: None,
highlighted_rows: None,
@@ -951,6 +972,10 @@ impl Editor {
self.buffer.read(cx).language(cx)
}
+ fn style(&self, cx: &AppContext) -> EditorStyle {
+ build_style(&*self.settings.borrow(), self.get_field_editor_theme, cx)
+ }
+
pub fn set_placeholder_text(
&mut self,
placeholder_text: impl Into<Arc<str>>,
@@ -2253,12 +2278,8 @@ impl Editor {
let editor = workspace.open_item(MultiBufferItemHandle(excerpt_buffer), cx);
if let Some(editor) = editor.act_as::<Self>(cx) {
editor.update(cx, |editor, cx| {
- let settings = (editor.build_settings)(cx);
- editor.highlight_ranges::<Self>(
- ranges_to_highlight,
- settings.style.highlighted_line_background,
- cx,
- );
+ let color = editor.style(cx).highlighted_line_background;
+ editor.highlight_ranges::<Self>(ranges_to_highlight, color, cx);
});
}
});
@@ -2322,7 +2343,9 @@ impl Editor {
this.update(&mut cx, |this, cx| {
let buffer_id = cursor_position.buffer_id;
let excerpt_id = cursor_position.excerpt_id.clone();
- let settings = (this.build_settings)(cx);
+ let style = this.style(cx);
+ let read_background = style.document_highlight_read_background;
+ let write_background = style.document_highlight_write_background;
let buffer = this.buffer.read(cx);
if !buffer
.text_anchor_for_position(cursor_position, cx)
@@ -2352,12 +2375,12 @@ impl Editor {
this.highlight_ranges::<DocumentHighlightRead>(
read_ranges,
- settings.style.document_highlight_read_background,
+ read_background,
cx,
);
this.highlight_ranges::<DocumentHighlightWrite>(
write_ranges,
- settings.style.document_highlight_write_background,
+ write_background,
cx,
);
cx.notify();
@@ -2367,10 +2390,13 @@ impl Editor {
None
}
- pub fn render_code_actions_indicator(&self, cx: &mut ViewContext<Self>) -> Option<ElementBox> {
+ pub fn render_code_actions_indicator(
+ &self,
+ style: &EditorStyle,
+ cx: &mut ViewContext<Self>,
+ ) -> Option<ElementBox> {
if self.available_code_actions.is_some() {
enum Tag {}
- let style = (self.build_settings)(cx).style;
Some(
MouseEventHandler::new::<Tag, _, _>(0, cx, |_, _| {
Svg::new("icons/zap.svg")
@@ -2398,11 +2424,12 @@ impl Editor {
pub fn render_context_menu(
&self,
cursor_position: DisplayPoint,
+ style: EditorStyle,
cx: &AppContext,
) -> Option<(DisplayPoint, ElementBox)> {
self.context_menu
.as_ref()
- .map(|menu| menu.render(cursor_position, self.build_settings.clone(), cx))
+ .map(|menu| menu.render(cursor_position, style, cx))
}
fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
@@ -2578,7 +2605,7 @@ impl Editor {
}
self.start_transaction(cx);
- let tab_size = (self.build_settings)(cx).tab_size;
+ let tab_size = self.settings.borrow().tab_size;
let mut selections = self.local_selections::<Point>(cx);
let mut last_indent = None;
self.buffer.update(cx, |buffer, cx| {
@@ -2655,7 +2682,7 @@ impl Editor {
}
self.start_transaction(cx);
- let tab_size = (self.build_settings)(cx).tab_size;
+ let tab_size = self.settings.borrow().tab_size;
let selections = self.local_selections::<Point>(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let mut deletion_ranges = Vec::new();
@@ -4234,12 +4261,8 @@ impl Editor {
let editor = workspace.open_item(MultiBufferItemHandle(excerpt_buffer), cx);
if let Some(editor) = editor.act_as::<Self>(cx) {
editor.update(cx, |editor, cx| {
- let settings = (editor.build_settings)(cx);
- editor.highlight_ranges::<Self>(
- ranges_to_highlight,
- settings.style.highlighted_line_background,
- cx,
- );
+ let color = editor.style(cx).highlighted_line_background;
+ editor.highlight_ranges::<Self>(ranges_to_highlight, color, cx);
});
}
});
@@ -4282,7 +4305,7 @@ impl Editor {
this.update(&mut cx, |this, cx| {
this.take_rename(cx);
- let settings = (this.build_settings)(cx);
+ let style = this.style(cx);
let buffer = this.buffer.read(cx).read(cx);
let cursor_offset = selection.head().to_offset(&buffer);
let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
@@ -4295,7 +4318,7 @@ impl Editor {
// Position the selection in the rename editor so that it matches the current selection.
let rename_editor = cx.add_view(|cx| {
- let mut editor = Editor::single_line(this.build_settings.clone(), cx);
+ let mut editor = Editor::single_line(this.settings.clone(), None, cx);
editor
.buffer
.update(cx, |buffer, cx| buffer.edit([0..0], &old_name, cx));
@@ -4306,14 +4329,14 @@ impl Editor {
);
editor.highlight_ranges::<Rename>(
vec![Anchor::min()..Anchor::max()],
- settings.style.diff_background_inserted,
+ style.diff_background_inserted,
cx,
);
editor
});
this.highlight_ranges::<Rename>(
vec![range.clone()],
- settings.style.diff_background_deleted,
+ style.diff_background_deleted,
cx,
);
this.update_selections(
@@ -4483,7 +4506,7 @@ impl Editor {
diagnostic_block_renderer(
diagnostic.clone(),
is_valid,
- self.build_settings.clone(),
+ self.settings.clone(),
),
);
}
@@ -4522,14 +4545,16 @@ impl Editor {
let blocks = display_map
.insert_blocks(
diagnostic_group.iter().map(|entry| {
- let build_settings = self.build_settings.clone();
let diagnostic = entry.diagnostic.clone();
let message_height = diagnostic.message.lines().count() as u8;
-
BlockProperties {
position: buffer.anchor_after(entry.range.start),
height: message_height,
- render: diagnostic_block_renderer(diagnostic, true, build_settings),
+ render: diagnostic_block_renderer(
+ diagnostic,
+ true,
+ self.settings.clone(),
+ ),
disposition: BlockDisposition::Below,
}
}),
@@ -5126,6 +5151,26 @@ impl Editor {
.text()
}
+ pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
+ let language = self.language(cx);
+ let settings = self.settings.borrow();
+ let mode = self
+ .soft_wrap_mode_override
+ .unwrap_or_else(|| settings.soft_wrap(language));
+ match mode {
+ settings::SoftWrap::None => SoftWrap::None,
+ settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
+ settings::SoftWrap::PreferredLineLength => {
+ SoftWrap::Column(settings.preferred_line_length(language))
+ }
+ }
+ }
+
+ pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
+ self.soft_wrap_mode_override = Some(mode);
+ cx.notify();
+ }
+
pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
self.display_map
.update(cx, |map, cx| map.set_wrap_width(width, cx))
@@ -5327,94 +5372,6 @@ impl Deref for EditorSnapshot {
}
}
-impl EditorSettings {
- #[cfg(any(test, feature = "test-support"))]
- pub fn test(cx: &AppContext) -> Self {
- use theme::{ContainedLabel, ContainedText, DiagnosticHeader, DiagnosticPathHeader};
-
- Self {
- tab_size: 4,
- soft_wrap: SoftWrap::None,
- style: {
- let font_cache: &gpui::FontCache = cx.font_cache();
- let font_family_name = Arc::from("Monaco");
- let font_properties = Default::default();
- let font_family_id = font_cache.load_family(&[&font_family_name]).unwrap();
- let font_id = font_cache
- .select_font(font_family_id, &font_properties)
- .unwrap();
- let text = gpui::fonts::TextStyle {
- font_family_name,
- font_family_id,
- font_id,
- font_size: 14.,
- color: gpui::color::Color::from_u32(0xff0000ff),
- font_properties,
- underline: None,
- };
- let default_diagnostic_style = DiagnosticStyle {
- message: text.clone().into(),
- header: Default::default(),
- text_scale_factor: 1.,
- };
- EditorStyle {
- text: text.clone(),
- placeholder_text: None,
- background: Default::default(),
- gutter_background: Default::default(),
- gutter_padding_factor: 2.,
- active_line_background: Default::default(),
- highlighted_line_background: Default::default(),
- diff_background_deleted: Default::default(),
- diff_background_inserted: Default::default(),
- document_highlight_read_background: Default::default(),
- document_highlight_write_background: Default::default(),
- line_number: Default::default(),
- line_number_active: Default::default(),
- selection: Default::default(),
- guest_selections: Default::default(),
- syntax: Default::default(),
- diagnostic_path_header: DiagnosticPathHeader {
- container: Default::default(),
- filename: ContainedText {
- container: Default::default(),
- text: text.clone(),
- },
- path: ContainedText {
- container: Default::default(),
- text: text.clone(),
- },
- text_scale_factor: 1.,
- },
- diagnostic_header: DiagnosticHeader {
- container: Default::default(),
- message: ContainedLabel {
- container: Default::default(),
- label: text.clone().into(),
- },
- code: ContainedText {
- container: Default::default(),
- text: text.clone(),
- },
- icon_width_factor: 1.,
- text_scale_factor: 1.,
- },
- error_diagnostic: default_diagnostic_style.clone(),
- invalid_error_diagnostic: default_diagnostic_style.clone(),
- warning_diagnostic: default_diagnostic_style.clone(),
- invalid_warning_diagnostic: default_diagnostic_style.clone(),
- information_diagnostic: default_diagnostic_style.clone(),
- invalid_information_diagnostic: default_diagnostic_style.clone(),
- hint_diagnostic: default_diagnostic_style.clone(),
- invalid_hint_diagnostic: default_diagnostic_style.clone(),
- autocomplete: Default::default(),
- code_actions_indicator: Default::default(),
- }
- },
- }
- }
-}
-
fn compute_scroll_position(
snapshot: &DisplaySnapshot,
mut scroll_position: Vector2F,
@@ -5447,15 +5404,11 @@ impl Entity for Editor {
impl View for Editor {
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
- let settings = (self.build_settings)(cx);
+ let style = self.style(cx);
self.display_map.update(cx, |map, cx| {
- map.set_font(
- settings.style.text.font_id,
- settings.style.text.font_size,
- cx,
- )
+ map.set_font(style.text.font_id, style.text.font_size, cx)
});
- EditorElement::new(self.handle.clone(), settings).boxed()
+ EditorElement::new(self.handle.clone(), style.clone()).boxed()
}
fn ui_name() -> &'static str {
@@ -5505,6 +5458,44 @@ impl View for Editor {
}
}
+fn build_style(
+ settings: &Settings,
+ get_field_editor_theme: Option<GetFieldEditorTheme>,
+ cx: &AppContext,
+) -> EditorStyle {
+ let theme = settings.theme.editor.clone();
+ if let Some(get_field_editor_theme) = get_field_editor_theme {
+ let field_editor_theme = get_field_editor_theme(&settings.theme);
+ EditorStyle {
+ text: field_editor_theme.text,
+ placeholder_text: field_editor_theme.placeholder_text,
+ theme,
+ }
+ } else {
+ let font_cache = cx.font_cache();
+ let font_family_id = settings.buffer_font_family;
+ let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
+ let font_properties = Default::default();
+ let font_id = font_cache
+ .select_font(font_family_id, &font_properties)
+ .unwrap();
+ let font_size = settings.buffer_font_size;
+ EditorStyle {
+ text: TextStyle {
+ color: settings.theme.editor.text_color,
+ font_family_name,
+ font_family_id,
+ font_id,
+ font_size,
+ font_properties,
+ underline: None,
+ },
+ placeholder_text: None,
+ theme,
+ }
+ }
+}
+
impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
let start = self.start.to_point(buffer);
@@ -5619,10 +5610,18 @@ impl InvalidationRegion for SnippetState {
}
}
+impl Deref for EditorStyle {
+ type Target = theme::Editor;
+
+ fn deref(&self) -> &Self::Target {
+ &self.theme
+ }
+}
+
pub fn diagnostic_block_renderer(
diagnostic: Diagnostic,
is_valid: bool,
- build_settings: BuildSettings,
+ settings: watch::Receiver<Settings>,
) -> RenderBlock {
let mut highlighted_lines = Vec::new();
for line in diagnostic.message.lines() {
@@ -5630,9 +5629,10 @@ pub fn diagnostic_block_renderer(
}
Arc::new(move |cx: &BlockContext| {
- let settings = build_settings(cx);
- let style = diagnostic_style(diagnostic.severity, is_valid, &settings.style);
- let font_size = (style.text_scale_factor * settings.style.text.font_size).round();
+ let settings = settings.borrow();
+ let theme = &settings.theme.editor;
+ let style = diagnostic_style(diagnostic.severity, is_valid, theme);
+ let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
Flex::column()
.with_children(highlighted_lines.iter().map(|(line, highlights)| {
Label::new(
@@ -5675,67 +5675,21 @@ pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
pub fn diagnostic_style(
severity: DiagnosticSeverity,
valid: bool,
- style: &EditorStyle,
+ theme: &theme::Editor,
) -> DiagnosticStyle {
match (severity, valid) {
- (DiagnosticSeverity::ERROR, true) => style.error_diagnostic.clone(),
- (DiagnosticSeverity::ERROR, false) => style.invalid_error_diagnostic.clone(),
- (DiagnosticSeverity::WARNING, true) => style.warning_diagnostic.clone(),
- (DiagnosticSeverity::WARNING, false) => style.invalid_warning_diagnostic.clone(),
- (DiagnosticSeverity::INFORMATION, true) => style.information_diagnostic.clone(),
- (DiagnosticSeverity::INFORMATION, false) => style.invalid_information_diagnostic.clone(),
- (DiagnosticSeverity::HINT, true) => style.hint_diagnostic.clone(),
- (DiagnosticSeverity::HINT, false) => style.invalid_hint_diagnostic.clone(),
- _ => DiagnosticStyle {
- message: style.text.clone().into(),
- header: Default::default(),
- text_scale_factor: 1.,
- },
+ (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
+ (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
+ (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
+ (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
+ (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
+ (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
+ (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
+ (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
+ _ => theme.invalid_hint_diagnostic.clone(),
}
}
-pub fn settings_builder(
- buffer: WeakModelHandle<MultiBuffer>,
- settings: watch::Receiver<workspace::Settings>,
-) -> BuildSettings {
- Arc::new(move |cx| {
- let settings = settings.borrow();
- let font_cache = cx.font_cache();
- let font_family_id = settings.buffer_font_family;
- let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
- let font_properties = Default::default();
- let font_id = font_cache
- .select_font(font_family_id, &font_properties)
- .unwrap();
- let font_size = settings.buffer_font_size;
-
- let mut theme = settings.theme.editor.clone();
- theme.text = TextStyle {
- color: theme.text.color,
- font_family_name,
- font_family_id,
- font_id,
- font_size,
- font_properties,
- underline: None,
- };
- let language = buffer.upgrade(cx).and_then(|buf| buf.read(cx).language(cx));
- let soft_wrap = match settings.soft_wrap(language) {
- workspace::settings::SoftWrap::None => SoftWrap::None,
- workspace::settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
- workspace::settings::SoftWrap::PreferredLineLength => {
- SoftWrap::Column(settings.preferred_line_length(language).saturating_sub(1))
- }
- };
-
- EditorSettings {
- tab_size: settings.tab_size,
- soft_wrap,
- style: theme,
- }
- })
-}
-
pub fn combine_syntax_and_fuzzy_match_highlights(
text: &str,
default_style: HighlightStyle,
@@ -5874,7 +5828,7 @@ mod tests {
let buffer = cx.add_model(|cx| language::Buffer::new(0, "123456", cx));
let group_interval = buffer.read(cx).transaction_group_interval();
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
- let settings = EditorSettings::test(cx);
+ let settings = Settings::test(cx);
let (_, editor) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -5942,7 +5896,7 @@ mod tests {
#[gpui::test]
fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx);
- let settings = EditorSettings::test(cx);
+ let settings = Settings::test(cx);
let (_, editor) =
cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
@@ -6009,7 +5963,7 @@ mod tests {
#[gpui::test]
fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx);
- let settings = EditorSettings::test(cx);
+ let settings = Settings::test(cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
@@ -6043,7 +5997,7 @@ mod tests {
cx.add_window(Default::default(), |cx| {
use workspace::ItemView;
let nav_history = Rc::new(RefCell::new(workspace::NavHistory::default()));
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let buffer = MultiBuffer::build_simple(&sample_text(30, 5, 'a'), cx);
let mut editor = build_editor(buffer.clone(), settings, cx);
editor.nav_history = Some(ItemNavHistory::new(nav_history.clone(), &cx.handle()));
@@ -6098,7 +6052,7 @@ mod tests {
#[gpui::test]
fn test_cancel(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx);
- let settings = EditorSettings::test(cx);
+ let settings = Settings::test(cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
@@ -6158,7 +6112,7 @@ mod tests {
.unindent(),
cx,
);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -6225,7 +6179,7 @@ mod tests {
#[gpui::test]
fn test_move_cursor(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -6301,7 +6255,7 @@ mod tests {
#[gpui::test]
fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("āāāāā\nabcde\nαβγΓε\n", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -6404,7 +6358,7 @@ mod tests {
#[gpui::test]
fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("āāāāā\nabcd\nαβγ\nabcd\nāāāāā\n", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -6451,7 +6405,7 @@ mod tests {
#[gpui::test]
fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("abc\n def", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
view.select_display_ranges(
@@ -6592,7 +6546,7 @@ mod tests {
#[gpui::test]
fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("use std::str::{foo, bar}\n\n {baz.qux()}", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
view.select_display_ranges(
@@ -6730,7 +6684,7 @@ mod tests {
#[gpui::test]
fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("use one::{\n two::three::four::five\n};", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
@@ -6783,7 +6737,7 @@ mod tests {
#[gpui::test]
fn test_delete_to_word_boundary(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("one two three four", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -6822,7 +6776,7 @@ mod tests {
#[gpui::test]
fn test_newline(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("aaaa\n bbbb\n", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -6859,7 +6813,7 @@ mod tests {
cx,
);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, editor) = cx.add_window(Default::default(), |cx| {
let mut editor = build_editor(buffer.clone(), settings, cx);
editor.select_ranges(
@@ -6931,7 +6885,7 @@ mod tests {
fn test_insert_with_old_selections(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple("a( X ), b( Y ), c( Z )", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, editor) = cx.add_window(Default::default(), |cx| {
let mut editor = build_editor(buffer.clone(), settings, cx);
editor.select_ranges([3..4, 11..12, 19..20], None, cx);
@@ -6958,7 +6912,7 @@ mod tests {
#[gpui::test]
fn test_indent_outdent(cx: &mut gpui::MutableAppContext) {
let buffer = MultiBuffer::build_simple(" one two\nthree\n four", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -7035,7 +6989,7 @@ mod tests {
fn test_backspace(cx: &mut gpui::MutableAppContext) {
let buffer =
MultiBuffer::build_simple("one two three\nfour five six\nseven eight nine\nten\n", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -7065,7 +7019,7 @@ mod tests {
fn test_delete(cx: &mut gpui::MutableAppContext) {
let buffer =
MultiBuffer::build_simple("one two three\nfour five six\nseven eight nine\nten\n", cx);
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let (_, view) = cx.add_window(Default::default(), |cx| {
build_editor(buffer.clone(), settings, cx)
});
@@ -7093,7 +7047,7 @@ mod tests {
#[gpui::test]
fn test_delete_line(cx: &mut gpui::MutableAppContext) {
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
@@ -7116,7 +7070,7 @@ mod tests {
);
});
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
@@ -7132,7 +7086,7 @@ mod tests {
#[gpui::test]
fn test_duplicate_line(cx: &mut gpui::MutableAppContext) {
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
@@ -7158,7 +7112,7 @@ mod tests {
);
});
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
@@ -7183,7 +7137,7 @@ mod tests {
#[gpui::test]
fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) {
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
view.update(cx, |view, cx| {
@@ -7279,7 +7233,7 @@ mod tests {
#[gpui::test]
fn test_move_line_up_down_with_blocks(cx: &mut gpui::MutableAppContext) {
- let settings = EditorSettings::test(&cx);
+ let settings = Settings::test(&cx);
let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
let snapshot = buffer.read(cx).snapshot(cx);
let (_, editor) =
@@ -1,9 +1,9 @@
use super::{
display_map::{BlockContext, ToDisplayPoint},
- Anchor, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, Input,
- Scroll, Select, SelectPhase, SoftWrap, ToPoint, MAX_LINE_LEN,
+ Anchor, DisplayPoint, Editor, EditorMode, EditorSnapshot, Input, Scroll, Select, SelectPhase,
+ SoftWrap, ToPoint, MAX_LINE_LEN,
};
-use crate::display_map::TransformBlock;
+use crate::{display_map::TransformBlock, EditorStyle};
use clock::ReplicaId;
use collections::{BTreeMap, HashMap};
use gpui::{
@@ -31,12 +31,12 @@ use std::{
pub struct EditorElement {
view: WeakViewHandle<Editor>,
- settings: EditorSettings,
+ style: EditorStyle,
}
impl EditorElement {
- pub fn new(view: WeakViewHandle<Editor>, settings: EditorSettings) -> Self {
- Self { view, settings }
+ pub fn new(view: WeakViewHandle<Editor>, style: EditorStyle) -> Self {
+ Self { view, style }
}
fn view<'a>(&self, cx: &'a AppContext) -> &'a Editor {
@@ -209,16 +209,15 @@ impl EditorElement {
let bounds = gutter_bounds.union_rect(text_bounds);
let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
let editor = self.view(cx.app);
- let style = &self.settings.style;
cx.scene.push_quad(Quad {
bounds: gutter_bounds,
- background: Some(style.gutter_background),
+ background: Some(self.style.gutter_background),
border: Border::new(0., Color::transparent_black()),
corner_radius: 0.,
});
cx.scene.push_quad(Quad {
bounds: text_bounds,
- background: Some(style.background),
+ background: Some(self.style.background),
border: Border::new(0., Color::transparent_black()),
corner_radius: 0.,
});
@@ -245,7 +244,7 @@ impl EditorElement {
);
cx.scene.push_quad(Quad {
bounds: RectF::new(origin, size),
- background: Some(style.active_line_background),
+ background: Some(self.style.active_line_background),
border: Border::default(),
corner_radius: 0.,
});
@@ -264,7 +263,7 @@ impl EditorElement {
);
cx.scene.push_quad(Quad {
bounds: RectF::new(origin, size),
- background: Some(style.highlighted_line_background),
+ background: Some(self.style.highlighted_line_background),
border: Border::default(),
corner_radius: 0.,
});
@@ -308,7 +307,7 @@ impl EditorElement {
cx: &mut PaintContext,
) {
let view = self.view(cx.app);
- let style = &self.settings.style;
+ let style = &self.style;
let local_replica_id = view.replica_id(cx);
let scroll_position = layout.snapshot.scroll_position();
let start_row = scroll_position.y() as u32;
@@ -498,7 +497,7 @@ impl EditorElement {
fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &LayoutContext) -> f32 {
let digit_count = (snapshot.max_buffer_row() as f32).log10().floor() as usize + 1;
- let style = &self.settings.style;
+ let style = &self.style;
cx.text_layout_cache
.layout_str(
@@ -523,7 +522,7 @@ impl EditorElement {
snapshot: &EditorSnapshot,
cx: &LayoutContext,
) -> Vec<Option<text_layout::Line>> {
- let style = &self.settings.style;
+ let style = &self.style;
let include_line_numbers = snapshot.mode == EditorMode::Full;
let mut line_number_layouts = Vec::with_capacity(rows.len());
let mut line_number = String::new();
@@ -576,7 +575,11 @@ impl EditorElement {
// When the editor is empty and unfocused, then show the placeholder.
if snapshot.is_empty() && !snapshot.is_focused() {
- let placeholder_style = self.settings.style.placeholder_text();
+ let placeholder_style = self
+ .style
+ .placeholder_text
+ .as_ref()
+ .unwrap_or_else(|| &self.style.text);
let placeholder_text = snapshot.placeholder_text();
let placeholder_lines = placeholder_text
.as_ref()
@@ -601,7 +604,7 @@ impl EditorElement {
})
.collect();
} else {
- let style = &self.settings.style;
+ let style = &self.style;
let chunks = snapshot.chunks(rows.clone(), true).map(|chunk| {
let highlight_style = chunk
.highlight_id
@@ -688,10 +691,9 @@ impl EditorElement {
..
} => {
if *starts_new_buffer {
- let style = &self.settings.style.diagnostic_path_header;
- let font_size = (style.text_scale_factor
- * self.settings.style.text.font_size)
- .round();
+ let style = &self.style.diagnostic_path_header;
+ let font_size =
+ (style.text_scale_factor * self.style.text.font_size).round();
let mut filename = None;
let mut parent_path = None;
@@ -729,7 +731,7 @@ impl EditorElement {
.expanded()
.named("path header block")
} else {
- let text_style = self.settings.style.text.clone();
+ let text_style = self.style.text.clone();
Label::new("ā¦".to_string(), text_style)
.contained()
.with_padding_left(gutter_padding + scroll_x * em_width)
@@ -766,7 +768,7 @@ impl Element for EditorElement {
}
let snapshot = self.snapshot(cx.app);
- let style = self.settings.style.clone();
+ let style = self.style.clone();
let line_height = style.text.line_height(cx.font_cache);
let gutter_padding;
@@ -786,12 +788,15 @@ impl Element for EditorElement {
let em_width = style.text.em_width(cx.font_cache);
let em_advance = style.text.em_advance(cx.font_cache);
let overscroll = vec2f(em_width, 0.);
- let wrap_width = match self.settings.soft_wrap {
- SoftWrap::None => None,
- SoftWrap::EditorWidth => Some(text_width - gutter_margin - overscroll.x() - em_width),
- SoftWrap::Column(column) => Some(column as f32 * em_advance),
- };
let snapshot = self.update_view(cx.app, |view, cx| {
+ let wrap_width = match view.soft_wrap_mode(cx) {
+ SoftWrap::None => None,
+ SoftWrap::EditorWidth => {
+ Some(text_width - gutter_margin - overscroll.x() - em_width)
+ }
+ SoftWrap::Column(column) => Some(column as f32 * em_advance),
+ };
+
if view.set_wrap_width(wrap_width, cx) {
view.snapshot(cx)
} else {
@@ -907,7 +912,7 @@ impl Element for EditorElement {
}
}
- let style = self.settings.style.clone();
+ let style = self.style.clone();
let longest_line_width = layout_line(
snapshot.longest_row(),
&snapshot,
@@ -951,12 +956,14 @@ impl Element for EditorElement {
.to_display_point(&snapshot);
if (start_row..end_row).contains(&newest_selection_head.row()) {
+ let style = view.style(cx);
if view.context_menu_visible() {
- context_menu = view.render_context_menu(newest_selection_head, cx);
+ context_menu =
+ view.render_context_menu(newest_selection_head, style.clone(), cx);
}
code_actions_indicator = view
- .render_code_actions_indicator(cx)
+ .render_code_actions_indicator(&style, cx)
.map(|indicator| (newest_selection_head.row(), indicator));
}
});
@@ -1370,26 +1377,19 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 {
#[cfg(test)]
mod tests {
use super::*;
- use crate::{Editor, EditorSettings, MultiBuffer};
- use std::sync::Arc;
+ use crate::{Editor, MultiBuffer};
+ use postage::watch;
use util::test::sample_text;
+ use workspace::Settings;
#[gpui::test]
fn test_layout_line_numbers(cx: &mut gpui::MutableAppContext) {
- let settings = EditorSettings::test(cx);
+ let settings = watch::channel_with(Settings::test(cx));
let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
let (window_id, editor) = cx.add_window(Default::default(), |cx| {
- Editor::for_buffer(
- buffer,
- {
- let settings = settings.clone();
- Arc::new(move |_| settings.clone())
- },
- None,
- cx,
- )
+ Editor::new(EditorMode::Full, buffer, None, settings.1, None, cx)
});
- let element = EditorElement::new(editor.downgrade(), settings);
+ let element = EditorElement::new(editor.downgrade(), editor.read(cx).style(cx));
let layouts = editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(cx);
@@ -56,12 +56,11 @@ impl ItemHandle for BufferItemHandle {
cx: &mut MutableAppContext,
) -> Box<dyn ItemViewHandle> {
let buffer = cx.add_model(|cx| MultiBuffer::singleton(self.0.clone(), cx));
- let weak_buffer = buffer.downgrade();
Box::new(cx.add_view(window_id, |cx| {
let mut editor = Editor::for_buffer(
buffer,
- crate::settings_builder(weak_buffer, workspace.settings()),
Some(workspace.project().clone()),
+ workspace.settings(),
cx,
);
editor.nav_history = Some(ItemNavHistory::new(nav_history, &cx.handle()));
@@ -101,12 +100,11 @@ impl ItemHandle for MultiBufferItemHandle {
nav_history: Rc<RefCell<NavHistory>>,
cx: &mut MutableAppContext,
) -> Box<dyn ItemViewHandle> {
- let weak_buffer = self.0.downgrade();
Box::new(cx.add_view(window_id, |cx| {
let mut editor = Editor::for_buffer(
self.0.clone(),
- crate::settings_builder(weak_buffer, workspace.settings()),
Some(workspace.project().clone()),
+ workspace.settings(),
cx,
);
editor.nav_history = Some(ItemNavHistory::new(nav_history, &cx.handle()));
@@ -1,4 +1,4 @@
-use editor::{Editor, EditorSettings};
+use editor::Editor;
use fuzzy::PathMatch;
use gpui::{
action,
@@ -266,17 +266,8 @@ impl FileFinder {
let query_editor = cx.add_view(|cx| {
Editor::single_line(
- {
- let settings = settings.clone();
- Arc::new(move |_| {
- let settings = settings.borrow();
- EditorSettings {
- style: settings.theme.selector.input_editor.as_editor(),
- tab_size: settings.tab_size,
- soft_wrap: editor::SoftWrap::None,
- }
- })
- },
+ settings.clone(),
+ Some(|theme| theme.selector.input_editor.clone()),
cx,
)
});
@@ -3,8 +3,7 @@ use aho_corasick::AhoCorasickBuilder;
use anyhow::Result;
use collections::HashMap;
use editor::{
- char_kind, display_map::ToDisplayPoint, Anchor, Autoscroll, Bias, Editor, EditorSettings,
- MultiBufferSnapshot,
+ char_kind, display_map::ToDisplayPoint, Anchor, Autoscroll, Bias, Editor, MultiBufferSnapshot,
};
use gpui::{
action, elements::*, keymap::Binding, platform::CursorStyle, Entity, MutableAppContext,
@@ -16,7 +15,6 @@ use smol::future::yield_now;
use std::{
cmp::{self, Ordering},
ops::Range,
- sync::Arc,
};
use workspace::{ItemViewHandle, Pane, Settings, Toolbar, Workspace};
@@ -173,17 +171,8 @@ impl FindBar {
let query_editor = cx.add_view(|cx| {
Editor::auto_height(
2,
- {
- let settings = settings.clone();
- Arc::new(move |_| {
- let settings = settings.borrow();
- EditorSettings {
- style: settings.theme.find.editor.input.as_editor(),
- tab_size: settings.tab_size,
- soft_wrap: editor::SoftWrap::None,
- }
- })
- },
+ settings.clone(),
+ Some(|theme| theme.find.editor.input.clone()),
cx,
)
});
@@ -639,7 +628,7 @@ async fn regex_search(
#[cfg(test)]
mod tests {
use super::*;
- use editor::{DisplayPoint, Editor, EditorSettings, MultiBuffer};
+ use editor::{DisplayPoint, Editor, MultiBuffer};
use gpui::{color::Color, TestAppContext};
use std::sync::Arc;
use unindent::Unindent as _;
@@ -650,6 +639,7 @@ mod tests {
let mut theme = gpui::fonts::with_font_cache(fonts.clone(), || theme::Theme::default());
theme.find.match_background = Color::red();
let settings = Settings::new("Courier", &fonts, Arc::new(theme)).unwrap();
+ let settings = watch::channel_with(settings).1;
let buffer = cx.update(|cx| {
MultiBuffer::build_simple(
@@ -664,11 +654,11 @@ mod tests {
)
});
let editor = cx.add_view(Default::default(), |cx| {
- Editor::new(buffer.clone(), Arc::new(EditorSettings::test), None, cx)
+ Editor::for_buffer(buffer.clone(), None, settings.clone(), cx)
});
let find_bar = cx.add_view(Default::default(), |cx| {
- let mut find_bar = FindBar::new(watch::channel_with(settings).1, cx);
+ let mut find_bar = FindBar::new(settings, cx);
find_bar.active_item_changed(Some(Box::new(editor.clone())), cx);
find_bar
});
@@ -1,11 +1,10 @@
use anyhow::Result;
use editor::{Editor, MultiBuffer};
use gpui::{
- action, elements::*, keymap::Binding, ElementBox, Entity, Handle, ModelContext, ModelHandle,
+ action, elements::*, keymap::Binding, ElementBox, Entity, ModelContext, ModelHandle,
MutableAppContext, Task, View, ViewContext, ViewHandle,
};
use project::Project;
-use std::{borrow::Borrow, sync::Arc};
use workspace::Workspace;
action!(Deploy);
@@ -75,15 +74,20 @@ impl workspace::Item for ProjectFind {
) -> Self::View {
let settings = workspace.settings();
let excerpts = model.read(cx).excerpts.clone();
- let build_settings = editor::settings_builder(excerpts.downgrade(), workspace.settings());
ProjectFindView {
model,
- query_editor: cx.add_view(|cx| Editor::single_line(build_settings.clone(), cx)),
+ query_editor: cx.add_view(|cx| {
+ Editor::single_line(
+ settings.clone(),
+ Some(|theme| theme.find.editor.input.clone()),
+ cx,
+ )
+ }),
results_editor: cx.add_view(|cx| {
Editor::for_buffer(
excerpts,
- build_settings,
Some(workspace.project().clone()),
+ settings.clone(),
cx,
)
}),
@@ -1,10 +1,9 @@
-use editor::{display_map::ToDisplayPoint, Autoscroll, DisplayPoint, Editor, EditorSettings};
+use editor::{display_map::ToDisplayPoint, Autoscroll, DisplayPoint, Editor};
use gpui::{
action, elements::*, geometry::vector::Vector2F, keymap::Binding, Axis, Entity,
MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
};
use postage::watch;
-use std::sync::Arc;
use text::{Bias, Point};
use workspace::{Settings, Workspace};
@@ -42,17 +41,8 @@ impl GoToLine {
) -> Self {
let line_editor = cx.add_view(|cx| {
Editor::single_line(
- {
- let settings = settings.clone();
- Arc::new(move |_| {
- let settings = settings.borrow();
- EditorSettings {
- tab_size: settings.tab_size,
- style: settings.theme.selector.input_editor.as_editor(),
- soft_wrap: editor::SoftWrap::None,
- }
- })
- },
+ settings.clone(),
+ Some(|theme| theme.selector.input_editor.clone()),
cx,
)
});
@@ -1,6 +1,6 @@
use editor::{
combine_syntax_and_fuzzy_match_highlights, display_map::ToDisplayPoint, Anchor, AnchorRangeExt,
- Autoscroll, DisplayPoint, Editor, EditorSettings, ToPoint,
+ Autoscroll, DisplayPoint, Editor, ToPoint,
};
use fuzzy::StringMatch;
use gpui::{
@@ -14,10 +14,7 @@ use gpui::{
use language::Outline;
use ordered_float::OrderedFloat;
use postage::watch;
-use std::{
- cmp::{self, Reverse},
- sync::Arc,
-};
+use std::cmp::{self, Reverse};
use workspace::{
menu::{Confirm, SelectFirst, SelectLast, SelectNext, SelectPrev},
Settings, Workspace,
@@ -107,17 +104,8 @@ impl OutlineView {
) -> Self {
let query_editor = cx.add_view(|cx| {
Editor::single_line(
- {
- let settings = settings.clone();
- Arc::new(move |_| {
- let settings = settings.borrow();
- EditorSettings {
- style: settings.theme.selector.input_editor.as_editor(),
- tab_size: settings.tab_size,
- soft_wrap: editor::SoftWrap::None,
- }
- })
- },
+ settings.clone(),
+ Some(|theme| theme.selector.input_editor.clone()),
cx,
)
});
@@ -1,6 +1,6 @@
use editor::{
combine_syntax_and_fuzzy_match_highlights, items::BufferItemHandle, styled_runs_for_code_label,
- Autoscroll, Bias, Editor, EditorSettings,
+ Autoscroll, Bias, Editor,
};
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
@@ -16,7 +16,6 @@ use project::{Project, Symbol};
use std::{
borrow::Cow,
cmp::{self, Reverse},
- sync::Arc,
};
use util::ResultExt;
use workspace::{
@@ -105,17 +104,8 @@ impl ProjectSymbolsView {
) -> Self {
let query_editor = cx.add_view(|cx| {
Editor::single_line(
- {
- let settings = settings.clone();
- Arc::new(move |_| {
- let settings = settings.borrow();
- EditorSettings {
- style: settings.theme.selector.input_editor.as_editor(),
- tab_size: settings.tab_size,
- soft_wrap: editor::SoftWrap::None,
- }
- })
- },
+ settings.clone(),
+ Some(|theme| theme.selector.input_editor.clone()),
cx,
)
});
@@ -1177,8 +1177,8 @@ mod tests {
EstablishConnectionError, UserStore,
},
editor::{
- self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, EditorSettings,
- Input, MultiBuffer, Redo, Rename, ToOffset, ToggleCodeActions, Undo,
+ self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Input, MultiBuffer,
+ Redo, Rename, ToOffset, ToggleCodeActions, Undo,
},
fs::{FakeFs, Fs as _},
language::{
@@ -1187,7 +1187,7 @@ mod tests {
},
lsp,
project::{DiagnosticSummary, Project, ProjectPath},
- workspace::{Workspace, WorkspaceParams},
+ workspace::{Settings, Workspace, WorkspaceParams},
};
#[cfg(test)]
@@ -1298,7 +1298,12 @@ mod tests {
.unwrap();
let editor_b = cx_b.add_view(window_b, |cx| {
- Editor::for_buffer(buffer_b, Arc::new(|cx| EditorSettings::test(cx)), None, cx)
+ Editor::for_buffer(
+ buffer_b,
+ None,
+ watch::channel_with(Settings::test(cx)).1,
+ cx,
+ )
});
// TODO
@@ -2330,8 +2335,8 @@ mod tests {
let editor_b = cx_b.add_view(window_b, |cx| {
Editor::for_buffer(
cx.add_model(|cx| MultiBuffer::singleton(buffer_b.clone(), cx)),
- Arc::new(|cx| EditorSettings::test(cx)),
Some(project_b.clone()),
+ watch::channel_with(Settings::test(cx)).1,
cx,
)
});
@@ -23,7 +23,7 @@ pub struct Theme {
pub contacts_panel: ContactsPanel,
pub project_panel: ProjectPanel,
pub selector: Selector,
- pub editor: EditorStyle,
+ pub editor: Editor,
pub find: Find,
pub project_diagnostics: ProjectDiagnostics,
}
@@ -112,7 +112,7 @@ pub struct Find {
#[derive(Clone, Deserialize, Default)]
pub struct FindEditor {
#[serde(flatten)]
- pub input: InputEditorStyle,
+ pub input: FieldEditor,
pub max_width: f32,
}
@@ -151,7 +151,7 @@ pub struct ChatPanel {
pub message: ChatMessage,
pub pending_message: ChatMessage,
pub channel_select: ChannelSelect,
- pub input_editor: InputEditorStyle,
+ pub input_editor: FieldEditor,
pub sign_in_prompt: TextStyle,
pub hovered_sign_in_prompt: TextStyle,
}
@@ -236,7 +236,7 @@ pub struct Selector {
#[serde(flatten)]
pub container: ContainerStyle,
pub empty: ContainedLabel,
- pub input_editor: InputEditorStyle,
+ pub input_editor: FieldEditor,
pub item: ContainedLabel,
pub active_item: ContainedLabel,
}
@@ -269,10 +269,9 @@ pub struct ProjectDiagnostics {
}
#[derive(Clone, Deserialize, Default)]
-pub struct EditorStyle {
- pub text: TextStyle,
+pub struct Editor {
+ pub text_color: Color,
#[serde(default)]
- pub placeholder_text: Option<TextStyle>,
pub background: Color,
pub selection: SelectionStyle,
pub gutter_background: Color,
@@ -345,7 +344,7 @@ pub struct SelectionStyle {
}
#[derive(Clone, Deserialize, Default)]
-pub struct InputEditorStyle {
+pub struct FieldEditor {
#[serde(flatten)]
pub container: ContainerStyle,
pub text: TextStyle,
@@ -354,11 +353,7 @@ pub struct InputEditorStyle {
pub selection: SelectionStyle,
}
-impl EditorStyle {
- pub fn placeholder_text(&self) -> &TextStyle {
- self.placeholder_text.as_ref().unwrap_or(&self.text)
- }
-
+impl Editor {
pub fn replica_selection_style(&self, replica_id: u16) -> &SelectionStyle {
let style_ix = replica_id as usize % (self.guest_selections.len() + 1);
if style_ix == 0 {
@@ -369,72 +364,6 @@ impl EditorStyle {
}
}
-impl InputEditorStyle {
- pub fn as_editor(&self) -> EditorStyle {
- let default_diagnostic_style = DiagnosticStyle {
- message: self.text.clone().into(),
- header: Default::default(),
- text_scale_factor: 1.,
- };
- EditorStyle {
- text: self.text.clone(),
- placeholder_text: self.placeholder_text.clone(),
- background: self
- .container
- .background_color
- .unwrap_or(Color::transparent_black()),
- selection: self.selection,
- gutter_background: Default::default(),
- gutter_padding_factor: Default::default(),
- active_line_background: Default::default(),
- highlighted_line_background: Default::default(),
- document_highlight_read_background: Default::default(),
- document_highlight_write_background: Default::default(),
- diff_background_deleted: Default::default(),
- diff_background_inserted: Default::default(),
- line_number: Default::default(),
- line_number_active: Default::default(),
- guest_selections: Default::default(),
- syntax: Default::default(),
- diagnostic_path_header: DiagnosticPathHeader {
- container: Default::default(),
- filename: ContainedText {
- container: Default::default(),
- text: self.text.clone(),
- },
- path: ContainedText {
- container: Default::default(),
- text: self.text.clone(),
- },
- text_scale_factor: 1.,
- },
- diagnostic_header: DiagnosticHeader {
- container: Default::default(),
- message: ContainedLabel {
- container: Default::default(),
- label: self.text.clone().into(),
- },
- code: ContainedText {
- container: Default::default(),
- text: self.text.clone(),
- },
- icon_width_factor: Default::default(),
- text_scale_factor: 1.,
- },
- error_diagnostic: default_diagnostic_style.clone(),
- invalid_error_diagnostic: default_diagnostic_style.clone(),
- warning_diagnostic: default_diagnostic_style.clone(),
- invalid_warning_diagnostic: default_diagnostic_style.clone(),
- information_diagnostic: default_diagnostic_style.clone(),
- invalid_information_diagnostic: default_diagnostic_style.clone(),
- hint_diagnostic: default_diagnostic_style.clone(),
- invalid_hint_diagnostic: default_diagnostic_style.clone(),
- autocomplete: Default::default(),
- code_actions_indicator: Default::default(),
- }
- }
-}
-
#[derive(Default)]
pub struct SyntaxTheme {
pub highlights: Vec<(String, HighlightStyle)>,
@@ -1,4 +1,4 @@
-use editor::{Editor, EditorSettings};
+use editor::Editor;
use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
use gpui::{
action,
@@ -63,17 +63,8 @@ impl ThemeSelector {
) -> Self {
let query_editor = cx.add_view(|cx| {
Editor::single_line(
- {
- let settings = settings.clone();
- Arc::new(move |_| {
- let settings = settings.borrow();
- EditorSettings {
- tab_size: settings.tab_size,
- style: settings.theme.selector.input_editor.as_editor(),
- soft_wrap: editor::SoftWrap::None,
- }
- })
- },
+ settings.clone(),
+ Some(|theme| theme.selector.input_editor.clone()),
cx,
)
});
@@ -72,4 +72,17 @@ impl Settings {
.and_then(|settings| settings.preferred_line_length)
.unwrap_or(self.preferred_line_length)
}
+
+ #[cfg(any(test, feature = "test-support"))]
+ pub fn test(cx: &gpui::AppContext) -> Settings {
+ Settings {
+ buffer_font_family: cx.font_cache().load_family(&["Monaco"]).unwrap(),
+ buffer_font_size: 14.,
+ tab_size: 4,
+ soft_wrap: SoftWrap::None,
+ preferred_line_length: 80,
+ overrides: Default::default(),
+ theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), || Default::default()),
+ }
+ }
}
@@ -92,6 +92,7 @@ time = "0.3"
tiny_http = "0.8"
toml = "0.5"
tree-sitter = "0.20.4"
+tree-sitter-c = "0.20.1"
tree-sitter-rust = "0.20.1"
tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" }
url = "2.2"
@@ -243,7 +243,7 @@ background = "$state.hover"
text = "$text.0"
[editor]
-text = "$text.1"
+text_color = "$text.1.color"
background = "$surface.1"
gutter_background = "$surface.1"
gutter_padding_factor = 2.5
@@ -282,8 +282,8 @@ header.border = { width = 1, top = true, color = "$border.0" }
text_scale_factor = 0.857
[editor.error_diagnostic.message]
-text = { extends = "$editor.text", size = 14, color = "$status.bad" }
-highlight_text = { extends = "$editor.text", size = 14, color = "$status.bad", weight = "bold" }
+text = { extends = "$text.1", size = 14, color = "$status.bad" }
+highlight_text = { extends = "$text.1", size = 14, color = "$status.bad", weight = "bold" }
[editor.warning_diagnostic]
extends = "$editor.error_diagnostic"
@@ -0,0 +1,13 @@
+name = "C"
+path_suffixes = ["c", "h"]
+line_comment = "// "
+brackets = [
+ { start = "{", end = "}", close = true, newline = true },
+ { start = "[", end = "]", close = true, newline = true },
+ { start = "(", end = ")", close = true, newline = true },
+ { start = "\"", end = "\"", close = true, newline = false },
+ { start = "/*", end = " */", close = true, newline = false },
+]
+
+[language_server]
+disk_based_diagnostic_sources = []
@@ -0,0 +1,101 @@
+[
+ "break"
+ "case"
+ "const"
+ "continue"
+ "default"
+ "do"
+ "else"
+ "enum"
+ "extern"
+ "for"
+ "if"
+ "inline"
+ "return"
+ "sizeof"
+ "static"
+ "struct"
+ "switch"
+ "typedef"
+ "union"
+ "volatile"
+ "while"
+] @keyword
+
+[
+ "#define"
+ "#elif"
+ "#else"
+ "#endif"
+ "#if"
+ "#ifdef"
+ "#ifndef"
+ "#include"
+ (preproc_directive)
+] @keyword
+
+[
+ "--"
+ "-"
+ "-="
+ "->"
+ "="
+ "!="
+ "*"
+ "&"
+ "&&"
+ "+"
+ "++"
+ "+="
+ "<"
+ "=="
+ ">"
+ "||"
+] @operator
+
+[
+ "."
+ ";"
+] @delimiter
+
+[
+ (string_literal)
+ (system_lib_string)
+ (char_literal)
+] @string
+
+(comment) @comment
+
+(null) @constant
+(number_literal) @number
+
+[
+ (true)
+ (false)
+ (null)
+] @constant
+
+(identifier) @variable
+
+((identifier) @constant
+ (#match? @constant "^[A-Z][A-Z\\d_]*$"))
+
+(call_expression
+ function: (identifier) @function)
+(call_expression
+ function: (field_expression
+ field: (field_identifier) @function))
+(function_declarator
+ declarator: (identifier) @function)
+(preproc_function_def
+ name: (identifier) @function.special)
+
+(field_identifier) @property
+(statement_identifier) @label
+
+[
+ (type_identifier)
+ (primitive_type)
+ (sized_type_specifier)
+] @type
+
@@ -0,0 +1,7 @@
+[
+ (field_expression)
+ (assignment_expression)
+] @indent
+
+(_ "{" "}" @end) @indent
+(_ "(" ")" @end) @indent
@@ -0,0 +1,30 @@
+(preproc_def
+ "#define" @context
+ name: (_) @name) @item
+
+(preproc_function_def
+ "#define" @context
+ name: (_) @name
+ parameters: (preproc_params
+ "(" @context
+ ")" @context)) @item
+
+(type_definition
+ "typedef" @context
+ declarator: (_) @name) @item
+
+(declaration
+ type: (_) @context
+ declarator: (function_declarator
+ declarator: (_) @name
+ parameters: (parameter_list
+ "(" @context
+ ")" @context))) @item
+
+(function_definition
+ type: (_) @context
+ declarator: (function_declarator
+ declarator: (_) @name
+ parameters: (parameter_list
+ "(" @context
+ ")" @context))) @item
@@ -1,4 +1,4 @@
-use anyhow::{anyhow, Result};
+use anyhow::{anyhow, Context, Result};
use async_compression::futures::bufread::GzipDecoder;
use client::http::{self, HttpClient, Method};
use futures::{future::BoxFuture, FutureExt, StreamExt};
@@ -22,6 +22,7 @@ use util::{ResultExt, TryFutureExt};
struct LanguageDir;
struct RustLsp;
+struct CLsp;
#[derive(Deserialize)]
struct GithubRelease {
@@ -291,6 +292,135 @@ impl LspExt for RustLsp {
}
}
+impl LspExt for CLsp {
+ fn fetch_latest_server_version(
+ &self,
+ http: Arc<dyn HttpClient>,
+ ) -> BoxFuture<'static, Result<LspBinaryVersion>> {
+ async move {
+ let release = http
+ .send(
+ surf::RequestBuilder::new(
+ Method::Get,
+ http::Url::parse(
+ "https://api.github.com/repos/clangd/clangd/releases/latest",
+ )
+ .unwrap(),
+ )
+ .middleware(surf::middleware::Redirect::default())
+ .build(),
+ )
+ .await
+ .map_err(|err| anyhow!("error fetching latest release: {}", err))?
+ .body_json::<GithubRelease>()
+ .await
+ .map_err(|err| anyhow!("error parsing latest release: {}", err))?;
+ let asset_name = format!("clangd-mac-{}.zip", release.name);
+ let asset = release
+ .assets
+ .iter()
+ .find(|asset| asset.name == asset_name)
+ .ok_or_else(|| anyhow!("no release found matching {:?}", asset_name))?;
+ Ok(LspBinaryVersion {
+ name: release.name,
+ url: asset.browser_download_url.clone(),
+ })
+ }
+ .boxed()
+ }
+
+ fn fetch_server_binary(
+ &self,
+ version: LspBinaryVersion,
+ http: Arc<dyn HttpClient>,
+ download_dir: Arc<Path>,
+ ) -> BoxFuture<'static, Result<PathBuf>> {
+ async move {
+ let container_dir = download_dir.join("clangd");
+ fs::create_dir_all(&container_dir)
+ .await
+ .context("failed to create container directory")?;
+
+ let zip_path = container_dir.join(format!("clangd_{}.zip", version.name));
+ let version_dir = container_dir.join(format!("clangd_{}", version.name));
+ let binary_path = version_dir.join("bin/clangd");
+
+ if fs::metadata(&binary_path).await.is_err() {
+ let response = http
+ .send(
+ surf::RequestBuilder::new(Method::Get, version.url)
+ .middleware(surf::middleware::Redirect::default())
+ .build(),
+ )
+ .await
+ .map_err(|err| anyhow!("error downloading release: {}", err))?;
+ let mut file = File::create(&zip_path).await?;
+ if !response.status().is_success() {
+ Err(anyhow!(
+ "download failed with status {}",
+ response.status().to_string()
+ ))?;
+ }
+ futures::io::copy(response, &mut file).await?;
+
+ let unzip_status = smol::process::Command::new("unzip")
+ .current_dir(&container_dir)
+ .arg(&zip_path)
+ .output()
+ .await?
+ .status;
+ if !unzip_status.success() {
+ Err(anyhow!("failed to unzip clangd archive"))?;
+ }
+
+ if let Some(mut entries) = fs::read_dir(&container_dir).await.log_err() {
+ while let Some(entry) = entries.next().await {
+ if let Some(entry) = entry.log_err() {
+ let entry_path = entry.path();
+ if entry_path.as_path() != version_dir {
+ fs::remove_dir_all(&entry_path).await.log_err();
+ }
+ }
+ }
+ }
+ }
+
+ Ok(binary_path)
+ }
+ .boxed()
+ }
+
+ fn cached_server_binary(&self, download_dir: Arc<Path>) -> BoxFuture<'static, Option<PathBuf>> {
+ async move {
+ let destination_dir_path = download_dir.join("clangd");
+ fs::create_dir_all(&destination_dir_path).await?;
+
+ let mut last_clangd_dir = None;
+ let mut entries = fs::read_dir(&destination_dir_path).await?;
+ while let Some(entry) = entries.next().await {
+ let entry = entry?;
+ if entry.file_type().await?.is_dir() {
+ last_clangd_dir = Some(entry.path());
+ }
+ }
+ let clangd_dir = last_clangd_dir.ok_or_else(|| anyhow!("no cached binary"))?;
+ let clangd_bin = clangd_dir.join("bin/clangd");
+ if clangd_bin.exists() {
+ Ok(clangd_bin)
+ } else {
+ Err(anyhow!(
+ "missing clangd binary in directory {:?}",
+ clangd_dir
+ ))
+ }
+ }
+ .log_err()
+ .boxed()
+ }
+
+ fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
+}
+
pub fn build_language_registry() -> LanguageRegistry {
let mut languages = LanguageRegistry::new();
languages.set_language_server_download_dir(
@@ -298,6 +428,7 @@ pub fn build_language_registry() -> LanguageRegistry {
.expect("failed to determine home directory")
.join(".zed"),
);
+ languages.add(Arc::new(c()));
languages.add(Arc::new(rust()));
languages.add(Arc::new(markdown()));
languages
@@ -318,6 +449,19 @@ fn rust() -> Language {
.with_lsp_ext(RustLsp)
}
+fn c() -> Language {
+ let grammar = tree_sitter_c::language();
+ let config = toml::from_slice(&LanguageDir::get("c/config.toml").unwrap().data).unwrap();
+ Language::new(config, Some(grammar))
+ .with_highlights_query(load_query("c/highlights.scm").as_ref())
+ .unwrap()
+ .with_indents_query(load_query("c/indents.scm").as_ref())
+ .unwrap()
+ .with_outline_query(load_query("c/outline.scm").as_ref())
+ .unwrap()
+ .with_lsp_ext(CLsp)
+}
+
fn markdown() -> Language {
let grammar = tree_sitter_markdown::language();
let config = toml::from_slice(&LanguageDir::get("markdown/config.toml").unwrap().data).unwrap();
@@ -1,12 +1,12 @@
use crate::{assets::Assets, build_window_options, build_workspace, AppState};
use client::{test::FakeHttpClient, ChannelList, Client, UserStore};
-use gpui::{AssetSource, MutableAppContext};
+use gpui::MutableAppContext;
use language::LanguageRegistry;
use parking_lot::Mutex;
use postage::watch;
use project::fs::FakeFs;
use std::sync::Arc;
-use theme::{Theme, ThemeRegistry, DEFAULT_THEME_NAME};
+use theme::ThemeRegistry;
use workspace::Settings;
#[cfg(test)]
@@ -20,7 +20,7 @@ fn init_logger() {
pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
let mut path_openers = Vec::new();
editor::init(cx, &mut path_openers);
- let (settings_tx, settings) = watch::channel_with(build_settings(cx));
+ let (settings_tx, settings) = watch::channel_with(Settings::test(cx));
let themes = ThemeRegistry::new(Assets, cx.font_cache().clone());
let http = FakeHttpClient::with_404_response();
let client = Client::new(http.clone());
@@ -48,27 +48,3 @@ pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
build_workspace: &build_workspace,
})
}
-
-fn build_settings(cx: &gpui::AppContext) -> Settings {
- lazy_static::lazy_static! {
- static ref DEFAULT_THEME: parking_lot::Mutex<Option<Arc<Theme>>> = Default::default();
- static ref FONTS: Vec<Arc<Vec<u8>>> = vec![
- Assets.load("fonts/zed-sans/zed-sans-regular.ttf").unwrap().to_vec().into()
- ];
- }
-
- cx.platform().fonts().add_fonts(&FONTS).unwrap();
-
- let mut theme_guard = DEFAULT_THEME.lock();
- let theme = if let Some(theme) = theme_guard.as_ref() {
- theme.clone()
- } else {
- let theme = ThemeRegistry::new(Assets, cx.font_cache().clone())
- .get(DEFAULT_THEME_NAME)
- .expect("failed to load default theme in tests");
- *theme_guard = Some(theme.clone());
- theme
- };
-
- Settings::new("Zed Sans", cx.font_cache(), theme).unwrap()
-}
@@ -133,9 +133,11 @@ fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {
#[cfg(test)]
mod tests {
+ use crate::assets::Assets;
+
use super::*;
use editor::{DisplayPoint, Editor};
- use gpui::{MutableAppContext, TestAppContext, ViewHandle};
+ use gpui::{AssetSource, MutableAppContext, TestAppContext, ViewHandle};
use project::{Fs, ProjectPath};
use serde_json::json;
use std::{
@@ -143,7 +145,7 @@ mod tests {
path::{Path, PathBuf},
};
use test::test_app_state;
- use theme::DEFAULT_THEME_NAME;
+ use theme::{Theme, ThemeRegistry, DEFAULT_THEME_NAME};
use util::test::temp_tree;
use workspace::{
open_paths, pane, ItemView, ItemViewHandle, OpenNew, Pane, SplitDirection, WorkspaceHandle,
@@ -862,10 +864,20 @@ mod tests {
#[gpui::test]
fn test_bundled_themes(cx: &mut MutableAppContext) {
- let app_state = test_app_state(cx);
+ let themes = ThemeRegistry::new(Assets, cx.font_cache().clone());
+
+ lazy_static::lazy_static! {
+ static ref DEFAULT_THEME: parking_lot::Mutex<Option<Arc<Theme>>> = Default::default();
+ static ref FONTS: Vec<Arc<Vec<u8>>> = vec![
+ Assets.load("fonts/zed-sans/zed-sans-regular.ttf").unwrap().to_vec().into()
+ ];
+ }
+
+ cx.platform().fonts().add_fonts(&FONTS).unwrap();
+
let mut has_default_theme = false;
- for theme_name in app_state.themes.list() {
- let theme = app_state.themes.get(&theme_name).unwrap();
+ for theme_name in themes.list() {
+ let theme = themes.get(&theme_name).unwrap();
if theme.name == DEFAULT_THEME_NAME {
has_default_theme = true;
}