diff --git a/Cargo.lock b/Cargo.lock index 983f6946ab..76de671620 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2210,6 +2210,9 @@ dependencies = [ "lsp", "postage", "project", + "schemars", + "serde", + "serde_derive", "serde_json", "settings", "smallvec", @@ -7398,8 +7401,10 @@ name = "storybook" version = "0.1.0" dependencies = [ "anyhow", + "chrono", "clap 4.4.4", "gpui2", + "itertools 0.11.0", "log", "rust-embed", "serde", @@ -8631,9 +8636,12 @@ name = "ui" version = "0.1.0" dependencies = [ "anyhow", + "chrono", "gpui2", "serde", "settings", + "smallvec", + "strum", "theme", ] diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 5362f7c0e5..07ba8a121f 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -95,6 +95,7 @@ } ], "ctrl-o": "pane::GoBack", + "ctrl-i": "pane::GoForward", "ctrl-]": "editor::GoToDefinition", "escape": [ "vim::SwitchMode", @@ -145,6 +146,7 @@ "g shift-s": "project_symbols::Toggle", "g .": "editor::ToggleCodeActions", // zed specific "g shift-a": "editor::FindAllReferences", // zed specific + "g space": "editor::OpenExcerpts", // zed specific "g *": [ "vim::MoveToNext", { @@ -415,6 +417,8 @@ "o": "vim::InsertLineBelow", "shift-o": "vim::InsertLineAbove", "~": "vim::ChangeCase", + "ctrl-a": "vim::Increment", + "ctrl-x": "vim::Decrement", "p": "vim::Paste", "shift-p": [ "vim::Paste", @@ -526,6 +530,20 @@ "shift-r": "vim::SubstituteLine", "c": "vim::Substitute", "~": "vim::ChangeCase", + "ctrl-a": "vim::Increment", + "ctrl-x": "vim::Decrement", + "g ctrl-a": [ + "vim::Increment", + { + "step": true + } + ], + "g ctrl-x": [ + "vim::Decrement", + { + "step": true + } + ], "shift-i": "vim::InsertBefore", "shift-a": "vim::InsertAfter", "shift-j": "vim::JoinLines", @@ -566,11 +584,16 @@ } }, { - "context": "Editor && vim_mode == insert && !menu", + "context": "Editor && vim_mode == insert", "bindings": { "escape": "vim::NormalBefore", "ctrl-c": "vim::NormalBefore", - "ctrl-[": "vim::NormalBefore" + "ctrl-[": "vim::NormalBefore", + "ctrl-x ctrl-o": "editor::ShowCompletions", + "ctrl-x ctrl-a": "assistant::InlineAssist", // zed specific + "ctrl-x ctrl-c": "copilot::Suggest", // zed specific + "ctrl-x ctrl-l": "editor::ToggleCodeActions", // zed specific + "ctrl-x ctrl-z": "editor::Cancel" } }, { diff --git a/assets/settings/default.json b/assets/settings/default.json index 1f8068d109..95f99a78e9 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -227,6 +227,11 @@ }, // Automatically update Zed "auto_update": true, + // Diagnostics configuration. + "diagnostics": { + // Whether to show warnings or not by default. + "include_warnings": true + }, // Git gutter behavior configuration. "git": { // Control whether the git gutter is shown. May take 2 values: @@ -370,7 +375,7 @@ }, // Difference settings for semantic_index "semantic_index": { - "enabled": false + "enabled": true }, // Settings specific to our elixir integration "elixir": { diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index 90c4481374..10c9ba7b86 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -265,7 +265,7 @@ impl PickerDelegate for CommandPaletteDelegate { .with_children( [ (keystroke.ctrl, "^"), - (keystroke.alt, "⎇"), + (keystroke.alt, "⌥"), (keystroke.cmd, "⌘"), (keystroke.shift, "⇧"), ] diff --git a/crates/diagnostics/Cargo.toml b/crates/diagnostics/Cargo.toml index 4e898cca0a..b0b2450f05 100644 --- a/crates/diagnostics/Cargo.toml +++ b/crates/diagnostics/Cargo.toml @@ -21,6 +21,9 @@ util = { path = "../util" } workspace = { path = "../workspace" } anyhow.workspace = true +schemars.workspace = true +serde.workspace = true +serde_derive.workspace = true smallvec.workspace = true postage.workspace = true diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index ac45bcbb79..0b1c6f8470 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -1,4 +1,6 @@ pub mod items; +mod project_diagnostics_settings; +mod toolbar_controls; use anyhow::Result; use collections::{BTreeSet, HashSet}; @@ -19,6 +21,7 @@ use language::{ }; use lsp::LanguageServerId; use project::{DiagnosticSummary, Project, ProjectPath}; +use project_diagnostics_settings::ProjectDiagnosticsSettings; use serde_json::json; use smallvec::SmallVec; use std::{ @@ -30,18 +33,21 @@ use std::{ sync::Arc, }; use theme::ThemeSettings; +pub use toolbar_controls::ToolbarControls; use util::TryFutureExt; use workspace::{ item::{BreadcrumbText, Item, ItemEvent, ItemHandle}, ItemNavHistory, Pane, PaneBackdrop, ToolbarItemLocation, Workspace, }; -actions!(diagnostics, [Deploy]); +actions!(diagnostics, [Deploy, ToggleWarnings]); const CONTEXT_LINE_COUNT: u32 = 1; pub fn init(cx: &mut AppContext) { + settings::register::(cx); cx.add_action(ProjectDiagnosticsEditor::deploy); + cx.add_action(ProjectDiagnosticsEditor::toggle_warnings); items::init(cx); } @@ -55,6 +61,7 @@ struct ProjectDiagnosticsEditor { excerpts: ModelHandle, path_states: Vec, paths_to_update: BTreeSet<(ProjectPath, LanguageServerId)>, + include_warnings: bool, } struct PathState { @@ -187,6 +194,7 @@ impl ProjectDiagnosticsEditor { editor, path_states: Default::default(), paths_to_update, + include_warnings: settings::get::(cx).include_warnings, }; this.update_excerpts(None, cx); this @@ -204,6 +212,18 @@ impl ProjectDiagnosticsEditor { } } + fn toggle_warnings(&mut self, _: &ToggleWarnings, cx: &mut ViewContext) { + self.include_warnings = !self.include_warnings; + self.paths_to_update = self + .project + .read(cx) + .diagnostic_summaries(cx) + .map(|(path, server_id, _)| (path, server_id)) + .collect(); + self.update_excerpts(None, cx); + cx.notify(); + } + fn update_excerpts( &mut self, language_server_id: Option, @@ -277,14 +297,18 @@ impl ProjectDiagnosticsEditor { let mut blocks_to_add = Vec::new(); let mut blocks_to_remove = HashSet::default(); let mut first_excerpt_id = None; + let max_severity = if self.include_warnings { + DiagnosticSeverity::WARNING + } else { + DiagnosticSeverity::ERROR + }; let excerpts_snapshot = self.excerpts.update(cx, |excerpts, excerpts_cx| { let mut old_groups = path_state.diagnostic_groups.iter().enumerate().peekable(); let mut new_groups = snapshot .diagnostic_groups(language_server_id) .into_iter() .filter(|(_, group)| { - group.entries[group.primary_ix].diagnostic.severity - <= DiagnosticSeverity::WARNING + group.entries[group.primary_ix].diagnostic.severity <= max_severity }) .peekable(); loop { @@ -1501,6 +1525,7 @@ mod tests { client::init_settings(cx); workspace::init_settings(cx); Project::init_settings(cx); + crate::init(cx); }); } diff --git a/crates/diagnostics/src/project_diagnostics_settings.rs b/crates/diagnostics/src/project_diagnostics_settings.rs new file mode 100644 index 0000000000..1592d3c7f0 --- /dev/null +++ b/crates/diagnostics/src/project_diagnostics_settings.rs @@ -0,0 +1,28 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Debug)] +pub struct ProjectDiagnosticsSettings { + pub include_warnings: bool, +} + +#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)] +pub struct ProjectDiagnosticsSettingsContent { + include_warnings: Option, +} + +impl settings::Setting for ProjectDiagnosticsSettings { + const KEY: Option<&'static str> = Some("diagnostics"); + type FileContent = ProjectDiagnosticsSettingsContent; + + fn load( + default_value: &Self::FileContent, + user_values: &[&Self::FileContent], + _cx: &gpui::AppContext, + ) -> anyhow::Result + where + Self: Sized, + { + Self::load_via_json_merge(default_value, user_values) + } +} diff --git a/crates/diagnostics/src/toolbar_controls.rs b/crates/diagnostics/src/toolbar_controls.rs new file mode 100644 index 0000000000..421571eede --- /dev/null +++ b/crates/diagnostics/src/toolbar_controls.rs @@ -0,0 +1,115 @@ +use crate::{ProjectDiagnosticsEditor, ToggleWarnings}; +use gpui::{ + elements::*, + platform::{CursorStyle, MouseButton}, + Action, Entity, EventContext, View, ViewContext, WeakViewHandle, +}; +use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView}; + +pub struct ToolbarControls { + editor: Option>, +} + +impl Entity for ToolbarControls { + type Event = (); +} + +impl View for ToolbarControls { + fn ui_name() -> &'static str { + "ToolbarControls" + } + + fn render(&mut self, cx: &mut ViewContext) -> AnyElement { + let include_warnings = self + .editor + .as_ref() + .and_then(|editor| editor.upgrade(cx)) + .map(|editor| editor.read(cx).include_warnings) + .unwrap_or(false); + let tooltip = if include_warnings { + "Exclude Warnings".into() + } else { + "Include Warnings".into() + }; + Flex::row() + .with_child(render_toggle_button( + 0, + "icons/warning.svg", + include_warnings, + (tooltip, Some(Box::new(ToggleWarnings))), + cx, + move |this, cx| { + if let Some(editor) = this.editor.and_then(|editor| editor.upgrade(cx)) { + editor.update(cx, |editor, cx| { + editor.toggle_warnings(&Default::default(), cx) + }); + } + }, + )) + .into_any() + } +} + +impl ToolbarItemView for ToolbarControls { + fn set_active_pane_item( + &mut self, + active_pane_item: Option<&dyn ItemHandle>, + _: &mut ViewContext, + ) -> ToolbarItemLocation { + if let Some(pane_item) = active_pane_item.as_ref() { + if let Some(editor) = pane_item.downcast::() { + self.editor = Some(editor.downgrade()); + ToolbarItemLocation::PrimaryRight { flex: None } + } else { + ToolbarItemLocation::Hidden + } + } else { + ToolbarItemLocation::Hidden + } + } +} + +impl ToolbarControls { + pub fn new() -> Self { + ToolbarControls { editor: None } + } +} + +fn render_toggle_button< + F: 'static + Fn(&mut ToolbarControls, &mut EventContext), +>( + index: usize, + icon: &'static str, + toggled: bool, + tooltip: (String, Option>), + cx: &mut ViewContext, + on_click: F, +) -> AnyElement { + enum Button {} + + let theme = theme::current(cx); + let (tooltip_text, action) = tooltip; + + MouseEventHandler::new::(index, cx, |mouse_state, _| { + let style = theme + .workspace + .toolbar + .toggleable_tool + .in_state(toggled) + .style_for(mouse_state); + Svg::new(icon) + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .aligned() + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .contained() + .with_style(style.container) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, view, cx| on_click(view, cx)) + .with_tooltip::