Compare commits
21 Commits
tsx-tags
...
slash-delt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fff6a06226 | ||
|
|
3aeea93847 | ||
|
|
3613ebd93c | ||
|
|
461812d7b6 | ||
|
|
af819bf661 | ||
|
|
ee96d69e37 | ||
|
|
b9b62842f8 | ||
|
|
4d26f83d23 | ||
|
|
3b37db4140 | ||
|
|
bba380e41a | ||
|
|
6841f7b9d7 | ||
|
|
f39c175bd3 | ||
|
|
0043b0d957 | ||
|
|
b341079d8a | ||
|
|
02d5f320ad | ||
|
|
9db68ee6ae | ||
|
|
092f29d394 | ||
|
|
25b6e43b0f | ||
|
|
3a6a29f117 | ||
|
|
9407d86ce6 | ||
|
|
b5c42edf1e |
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -9928,9 +9928,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json_lenient"
|
||||
version = "0.1.8"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc61c66b53a4035fcce237ef38043f4b2f0ebf918fd0e69541a5166104065581"
|
||||
checksum = "a5d0bae483150302560d7cb52e7932f39b69a6fbdd099e48d33ef060a8c9c078"
|
||||
dependencies = [
|
||||
"indexmap 2.4.0",
|
||||
"itoa",
|
||||
|
||||
@@ -393,7 +393,7 @@ semver = "1.0"
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
serde_derive = { version = "1.0", features = ["deserialize_in_place"] }
|
||||
serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] }
|
||||
serde_json_lenient = { version = "0.1", features = [
|
||||
serde_json_lenient = { version = "0.2", features = [
|
||||
"preserve_order",
|
||||
"raw_value",
|
||||
] }
|
||||
@@ -483,6 +483,7 @@ version = "0.58"
|
||||
features = [
|
||||
"implement",
|
||||
"Foundation_Numerics",
|
||||
"Storage",
|
||||
"System",
|
||||
"System_Threading",
|
||||
"UI_ViewManagement",
|
||||
|
||||
@@ -162,6 +162,7 @@ impl ContextOperation {
|
||||
)?,
|
||||
icon: section.icon_name.parse()?,
|
||||
label: section.label.into(),
|
||||
path: section.path.map(Into::into),
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?,
|
||||
@@ -242,6 +243,10 @@ impl ContextOperation {
|
||||
)),
|
||||
icon_name: icon_name.to_string(),
|
||||
label: section.label.to_string(),
|
||||
path: section
|
||||
.path
|
||||
.as_ref()
|
||||
.map(|p| p.to_string_lossy().to_string()),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
@@ -641,6 +646,7 @@ impl Context {
|
||||
range,
|
||||
icon: section.icon,
|
||||
label: section.label.clone(),
|
||||
path: section.path.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -1825,6 +1831,7 @@ impl Context {
|
||||
..buffer.anchor_before(start + section.range.end),
|
||||
icon: section.icon,
|
||||
label: section.label,
|
||||
path: section.path,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
sections.sort_by(|a, b| a.range.cmp(&b.range, buffer));
|
||||
@@ -2977,6 +2984,7 @@ impl SavedContext {
|
||||
..buffer.anchor_before(section.range.end),
|
||||
icon: section.icon,
|
||||
label: section.label,
|
||||
path: section.path,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
|
||||
@@ -1089,6 +1089,7 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
|
||||
range: section_start..section_end,
|
||||
icon: ui::IconName::Ai,
|
||||
label: "section".into(),
|
||||
path: None,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -141,6 +141,7 @@ impl SlashCommand for ContextServerSlashCommand {
|
||||
.description
|
||||
.unwrap_or(format!("Result from {}", prompt_name)),
|
||||
),
|
||||
path: None,
|
||||
}],
|
||||
text: prompt,
|
||||
run_commands_in_text: false,
|
||||
|
||||
@@ -70,6 +70,7 @@ impl SlashCommand for DefaultSlashCommand {
|
||||
range: 0..text.len(),
|
||||
icon: IconName::Library,
|
||||
label: "Default".into(),
|
||||
path: None,
|
||||
}],
|
||||
text,
|
||||
run_commands_in_text: true,
|
||||
|
||||
@@ -182,6 +182,7 @@ impl SlashCommand for DiagnosticsSlashCommand {
|
||||
range: 0..1,
|
||||
icon: IconName::Library,
|
||||
label: "No Diagnostics".into(),
|
||||
path: None,
|
||||
}],
|
||||
text: "\n".to_string(),
|
||||
run_commands_in_text: true,
|
||||
@@ -228,6 +229,7 @@ impl SlashCommand for DiagnosticsSlashCommand {
|
||||
PlaceholderType::File(file_path) => file_path.into(),
|
||||
PlaceholderType::Diagnostic(_, message) => message.into(),
|
||||
},
|
||||
path: None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
@@ -349,6 +349,7 @@ impl SlashCommand for DocsSlashCommand {
|
||||
range,
|
||||
icon: IconName::FileDoc,
|
||||
label: format!("docs ({provider}): {key}",).into(),
|
||||
path: None,
|
||||
})
|
||||
.collect(),
|
||||
run_commands_in_text: false,
|
||||
|
||||
@@ -161,6 +161,7 @@ impl SlashCommand for FetchSlashCommand {
|
||||
range,
|
||||
icon: IconName::AtSign,
|
||||
label: format!("fetch {}", url).into(),
|
||||
path: None,
|
||||
}],
|
||||
run_commands_in_text: false,
|
||||
})
|
||||
|
||||
@@ -171,7 +171,6 @@ impl SlashCommand for FileSlashCommand {
|
||||
.collect())
|
||||
})
|
||||
}
|
||||
|
||||
fn run(
|
||||
self: Arc<Self>,
|
||||
arguments: &[String],
|
||||
@@ -428,7 +427,6 @@ pub fn codeblock_fence_for_path(path: Option<&Path>, row_range: Option<Range<u32
|
||||
text.push('\n');
|
||||
text
|
||||
}
|
||||
|
||||
pub fn build_entry_output_section(
|
||||
range: Range<usize>,
|
||||
path: Option<&Path>,
|
||||
@@ -454,6 +452,7 @@ pub fn build_entry_output_section(
|
||||
range,
|
||||
icon,
|
||||
label: label.into(),
|
||||
path: path.map(|p| p.to_path_buf()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ impl SlashCommand for NowSlashCommand {
|
||||
range,
|
||||
icon: IconName::CountdownTimer,
|
||||
label: now.to_rfc2822().into(),
|
||||
path: None,
|
||||
}],
|
||||
run_commands_in_text: false,
|
||||
}))
|
||||
|
||||
@@ -140,6 +140,7 @@ impl SlashCommand for ProjectSlashCommand {
|
||||
range,
|
||||
icon: IconName::FileTree,
|
||||
label: "Project".into(),
|
||||
path: None,
|
||||
}],
|
||||
run_commands_in_text: false,
|
||||
})
|
||||
|
||||
@@ -95,6 +95,7 @@ impl SlashCommand for PromptSlashCommand {
|
||||
range,
|
||||
icon: IconName::Library,
|
||||
label: title,
|
||||
path: None,
|
||||
}],
|
||||
run_commands_in_text: true,
|
||||
})
|
||||
|
||||
@@ -165,6 +165,7 @@ impl SlashCommand for SearchSlashCommand {
|
||||
range: 0..text.len(),
|
||||
icon: IconName::MagnifyingGlass,
|
||||
label: query,
|
||||
path: None,
|
||||
});
|
||||
|
||||
SlashCommandOutput {
|
||||
|
||||
@@ -77,6 +77,7 @@ impl SlashCommand for OutlineSlashCommand {
|
||||
range: 0..outline_text.len(),
|
||||
icon: IconName::ListTree,
|
||||
label: path.to_string_lossy().to_string().into(),
|
||||
path: None,
|
||||
}],
|
||||
text: outline_text,
|
||||
run_commands_in_text: false,
|
||||
|
||||
@@ -91,6 +91,7 @@ impl SlashCommand for TerminalSlashCommand {
|
||||
range,
|
||||
icon: IconName::Terminal,
|
||||
label: "Terminal".into(),
|
||||
path: None,
|
||||
}],
|
||||
run_commands_in_text: false,
|
||||
}))
|
||||
|
||||
@@ -100,10 +100,10 @@ pub struct SlashCommandOutput {
|
||||
pub sections: Vec<SlashCommandOutputSection<usize>>,
|
||||
pub run_commands_in_text: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SlashCommandOutputSection<T> {
|
||||
pub range: Range<T>,
|
||||
pub icon: IconName,
|
||||
pub label: SharedString,
|
||||
pub path: Option<std::path::PathBuf>,
|
||||
}
|
||||
|
||||
@@ -116,30 +116,27 @@ impl Drop for MacOsUnmounter {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether or not to automatically check for updates.
|
||||
#[derive(Clone, Copy, JsonSchema, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
#[serde(transparent)]
|
||||
struct AutoUpdateSetting(bool);
|
||||
|
||||
impl Default for AutoUpdateSetting {
|
||||
fn default() -> Self {
|
||||
Self(true)
|
||||
}
|
||||
}
|
||||
/// Whether or not to automatically check for updates.
|
||||
///
|
||||
/// Default: true
|
||||
#[derive(Clone, Copy, Default, JsonSchema, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
struct AutoUpdateSettingContent(bool);
|
||||
|
||||
impl Settings for AutoUpdateSetting {
|
||||
const KEY: Option<&'static str> = Some("auto_update");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = Option<AutoUpdateSettingContent>;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
let auto_update = [sources.release_channel, sources.user]
|
||||
.into_iter()
|
||||
.find_map(|value| value.copied())
|
||||
.unwrap_or(*sources.default);
|
||||
.find_map(|value| value.copied().flatten())
|
||||
.unwrap_or(sources.default.ok_or_else(Self::missing_default)?);
|
||||
|
||||
Ok(auto_update)
|
||||
Ok(Self(auto_update.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,20 +4,30 @@ use schemars::JsonSchema;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
|
||||
/// Configuration of voice calls in Zed.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct CallSettings {
|
||||
/// Whether the microphone should be muted when joining a channel or a call.
|
||||
pub mute_on_join: bool,
|
||||
/// Whether your current project should be shared when joining an empty channel.
|
||||
pub share_on_join: bool,
|
||||
}
|
||||
|
||||
/// Configuration of voice calls in Zed.
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
pub struct CallSettingsContent {
|
||||
/// Whether the microphone should be muted when joining a channel or a call.
|
||||
///
|
||||
/// Default: false
|
||||
pub mute_on_join: Option<bool>,
|
||||
|
||||
/// Whether your current project should be shared when joining an empty channel.
|
||||
///
|
||||
/// Default: true
|
||||
pub share_on_join: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for CallSettings {
|
||||
const KEY: Option<&'static str> = Some("calls");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = CallSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
|
||||
@@ -99,26 +99,20 @@ pub const CONNECTION_TIMEOUT: Duration = Duration::from_secs(20);
|
||||
|
||||
actions!(client, [SignIn, SignOut, Reconnect]);
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
pub struct ClientSettings {
|
||||
/// The server to connect to. If the environment variable
|
||||
/// ZED_SERVER_URL is set, it will override this setting.
|
||||
pub server_url: String,
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ClientSettingsContent {
|
||||
server_url: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for ClientSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
server_url: "https://zed.dev".to_owned(),
|
||||
}
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
pub struct ClientSettings {
|
||||
pub server_url: String,
|
||||
}
|
||||
|
||||
impl Settings for ClientSettings {
|
||||
const KEY: Option<&'static str> = None;
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = ClientSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
let mut result = sources.json_merge::<Self>()?;
|
||||
@@ -130,37 +124,19 @@ impl Settings for ClientSettings {
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
pub struct ProxySettings {
|
||||
/// Set a proxy to use. The proxy protocol is specified by the URI scheme.
|
||||
///
|
||||
/// Supported URI scheme: `http`, `https`, `socks4`, `socks4a`, `socks5`,
|
||||
/// `socks5h`. `http` will be used when no scheme is specified.
|
||||
///
|
||||
/// By default no proxy will be used, or Zed will try get proxy settings from
|
||||
/// environment variables.
|
||||
///
|
||||
/// Examples:
|
||||
/// - "proxy": "socks5://localhost:10808"
|
||||
/// - "proxy": "http://127.0.0.1:10809"
|
||||
#[schemars(example = "Self::example_1")]
|
||||
#[schemars(example = "Self::example_2")]
|
||||
pub proxy: Option<String>,
|
||||
pub struct ProxySettingsContent {
|
||||
proxy: Option<String>,
|
||||
}
|
||||
|
||||
impl ProxySettings {
|
||||
fn example_1() -> String {
|
||||
"http://127.0.0.1:10809".to_owned()
|
||||
}
|
||||
fn example_2() -> String {
|
||||
"socks5://localhost:10808".to_owned()
|
||||
}
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct ProxySettings {
|
||||
pub proxy: Option<String>,
|
||||
}
|
||||
|
||||
impl Settings for ProxySettings {
|
||||
const KEY: Option<&'static str> = None;
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = ProxySettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
Ok(Self {
|
||||
|
||||
@@ -2261,11 +2261,11 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
|
||||
cx_a.update(editor::init);
|
||||
cx_b.update(editor::init);
|
||||
// Turn inline-blame-off by default so no state is transferred without us explicitly doing so
|
||||
let inline_blame_off_settings = InlineBlameSettings {
|
||||
let inline_blame_off_settings = Some(InlineBlameSettings {
|
||||
enabled: false,
|
||||
delay_ms: 0,
|
||||
min_column: 0,
|
||||
};
|
||||
delay_ms: None,
|
||||
min_column: None,
|
||||
});
|
||||
cx_a.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<ProjectSettings>(cx, |settings| {
|
||||
|
||||
@@ -1649,7 +1649,7 @@ async fn test_following_into_excluded_file(
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
|
||||
settings.file_scan_exclusions = vec!["**/.git".to_string()];
|
||||
settings.file_scan_exclusions = Some(vec!["**/.git".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1108,7 +1108,7 @@ impl Panel for ChatPanel {
|
||||
settings::update_settings_file::<ChatPanelSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.dock = position,
|
||||
move |settings, _| settings.dock = Some(position),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,9 @@ impl MessageEditor {
|
||||
editor.set_show_indent_guides(false, cx);
|
||||
editor.set_completion_provider(Box::new(MessageEditorCompletionProvider(this)));
|
||||
editor.set_auto_replace_emoji_shortcode(
|
||||
MessageEditorSettings::get_global(cx).auto_replace_emoji_shortcode,
|
||||
MessageEditorSettings::get_global(cx)
|
||||
.auto_replace_emoji_shortcode
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -128,7 +130,9 @@ impl MessageEditor {
|
||||
cx.observe_global::<settings::SettingsStore>(|view, cx| {
|
||||
view.editor.update(cx, |editor, cx| {
|
||||
editor.set_auto_replace_emoji_shortcode(
|
||||
MessageEditorSettings::get_global(cx).auto_replace_emoji_shortcode,
|
||||
MessageEditorSettings::get_global(cx)
|
||||
.auto_replace_emoji_shortcode
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2813,7 +2813,7 @@ impl Panel for CollabPanel {
|
||||
settings::update_settings_file::<CollaborationPanelSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.dock = position,
|
||||
move |settings, _| settings.dock = Some(position),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -672,7 +672,7 @@ impl Panel for NotificationPanel {
|
||||
settings::update_settings_file::<NotificationPanelSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.dock = position,
|
||||
move |settings, _| settings.dock = Some(position),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,84 +2,58 @@ use gpui::Pixels;
|
||||
use schemars::JsonSchema;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
use ui::px;
|
||||
use workspace::dock::DockPosition;
|
||||
|
||||
#[derive(Clone, Deserialize, Debug, JsonSchema, Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct CollaborationPanelSettings {
|
||||
/// Whether to show the panel button in the status bar.
|
||||
pub button: bool,
|
||||
/// Where to dock the panel.
|
||||
pub dock: DockPosition,
|
||||
/// Default width of the panel in pixels.
|
||||
pub default_width: Pixels,
|
||||
}
|
||||
|
||||
impl Default for CollaborationPanelSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
button: true,
|
||||
dock: DockPosition::Left,
|
||||
default_width: px(240.),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Debug, JsonSchema, Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ChatPanelSettings {
|
||||
/// Whether to show the panel button in the status bar.
|
||||
pub button: bool,
|
||||
/// Where to dock the panel.
|
||||
pub dock: DockPosition,
|
||||
/// Default width of the panel in pixels.
|
||||
pub default_width: Pixels,
|
||||
}
|
||||
|
||||
impl Default for ChatPanelSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
button: true,
|
||||
dock: DockPosition::Right,
|
||||
default_width: px(240.),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Debug, JsonSchema, Serialize)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct NotificationPanelSettings {
|
||||
/// Whether to show the panel button in the status bar.
|
||||
pub button: bool,
|
||||
/// Where to dock the panel.
|
||||
pub dock: DockPosition,
|
||||
/// Default width of the panel in pixels.
|
||||
pub default_width: Pixels,
|
||||
}
|
||||
|
||||
impl Default for NotificationPanelSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
button: true,
|
||||
dock: DockPosition::Right,
|
||||
default_width: px(380.),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
#[serde(default)]
|
||||
pub struct PanelSettingsContent {
|
||||
/// Whether to show the panel button in the status bar.
|
||||
///
|
||||
/// Default: true
|
||||
pub button: Option<bool>,
|
||||
/// Where to dock the panel.
|
||||
///
|
||||
/// Default: left
|
||||
pub dock: Option<DockPosition>,
|
||||
/// Default width of the panel in pixels.
|
||||
///
|
||||
/// Default: 240
|
||||
pub default_width: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
pub struct MessageEditorSettings {
|
||||
/// Whether to automatically replace emoji shortcodes with emoji characters.
|
||||
/// For example: typing `:wave:` gets replaced with `👋`.
|
||||
pub auto_replace_emoji_shortcode: bool,
|
||||
///
|
||||
/// Default: false
|
||||
pub auto_replace_emoji_shortcode: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for CollaborationPanelSettings {
|
||||
const KEY: Option<&'static str> = Some("collaboration_panel");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = PanelSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
@@ -92,7 +66,7 @@ impl Settings for CollaborationPanelSettings {
|
||||
impl Settings for ChatPanelSettings {
|
||||
const KEY: Option<&'static str> = Some("chat_panel");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = PanelSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
@@ -105,7 +79,7 @@ impl Settings for ChatPanelSettings {
|
||||
impl Settings for NotificationPanelSettings {
|
||||
const KEY: Option<&'static str> = Some("notification_panel");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = PanelSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
@@ -118,7 +92,7 @@ impl Settings for NotificationPanelSettings {
|
||||
impl Settings for MessageEditorSettings {
|
||||
const KEY: Option<&'static str> = Some("message_editor");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = MessageEditorSettings;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
|
||||
@@ -4,25 +4,23 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
#[serde(default)]
|
||||
/// Diagnostics configuration.
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ProjectDiagnosticsSettings {
|
||||
/// Whether to show warnings or not by default.
|
||||
pub include_warnings: bool,
|
||||
}
|
||||
|
||||
impl Default for ProjectDiagnosticsSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
include_warnings: true,
|
||||
}
|
||||
}
|
||||
/// Diagnostics configuration.
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
pub struct ProjectDiagnosticsSettingsContent {
|
||||
/// Whether to show warnings or not by default.
|
||||
///
|
||||
/// Default: true
|
||||
include_warnings: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for ProjectDiagnosticsSettings {
|
||||
const KEY: Option<&'static str> = Some("diagnostics");
|
||||
type FileContent = Self;
|
||||
type FileContent = ProjectDiagnosticsSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
|
||||
@@ -4975,9 +4975,10 @@ impl Editor {
|
||||
let cursor = self.selections.newest_anchor().head();
|
||||
let (buffer, cursor_buffer_position) =
|
||||
self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
|
||||
|
||||
if !user_requested
|
||||
&& self.enable_inline_completions
|
||||
&& !self.should_show_inline_completions(&buffer, cursor_buffer_position, cx)
|
||||
&& (!self.enable_inline_completions
|
||||
|| !self.should_show_inline_completions(&buffer, cursor_buffer_position, cx))
|
||||
{
|
||||
self.discard_inline_completion(false, cx);
|
||||
return None;
|
||||
@@ -6670,7 +6671,11 @@ impl Editor {
|
||||
let is_entire_line = selection.is_empty() || self.selections.line_mode;
|
||||
if is_entire_line {
|
||||
selection.start = Point::new(selection.start.row, 0);
|
||||
selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
|
||||
if !selection.is_empty() && selection.end.column == 0 {
|
||||
selection.end = cmp::min(max_point, selection.end);
|
||||
} else {
|
||||
selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
|
||||
}
|
||||
selection.goal = SelectionGoal::None;
|
||||
}
|
||||
if is_first {
|
||||
@@ -10639,7 +10644,7 @@ impl Editor {
|
||||
let fs = workspace.read(cx).app_state().fs.clone();
|
||||
let current_show = TabBarSettings::get_global(cx).show;
|
||||
update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
|
||||
setting.show = !current_show;
|
||||
setting.show = Some(!current_show);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12562,7 +12567,7 @@ impl EditorSnapshot {
|
||||
let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
|
||||
matches!(
|
||||
ProjectSettings::get_global(cx).git.git_gutter,
|
||||
GitGutterSetting::TrackedFiles
|
||||
Some(GitGutterSetting::TrackedFiles)
|
||||
)
|
||||
});
|
||||
let gutter_settings = EditorSettings::get_global(cx).gutter;
|
||||
|
||||
@@ -3,105 +3,38 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize, Clone)]
|
||||
pub struct EditorSettings {
|
||||
/// Whether the cursor blinks in the editor.
|
||||
pub cursor_blink: bool,
|
||||
/// How to highlight the current line in the editor.
|
||||
pub current_line_highlight: CurrentLineHighlight,
|
||||
/// Whether to show the informational hover box when moving the mouse
|
||||
/// over symbols in the editor.
|
||||
pub hover_popover_enabled: bool,
|
||||
/// Whether to pop the completions menu while typing in an editor without
|
||||
/// explicitly requesting it.
|
||||
pub show_completions_on_input: bool,
|
||||
/// Whether to display inline and alongside documentation for items in the
|
||||
/// completions menu.
|
||||
pub show_completion_documentation: bool,
|
||||
/// The debounce delay before re-querying the language server for completion
|
||||
/// documentation when not included in original completion list.
|
||||
pub completion_documentation_secondary_query_debounce: u64,
|
||||
/// Whether to use additional LSP queries to format (and amend) the code after
|
||||
/// every "trigger" symbol input, defined by LSP server capabilities.
|
||||
pub use_on_type_format: bool,
|
||||
/// Toolbar related settings
|
||||
pub toolbar: Toolbar,
|
||||
/// Scrollbar related settings
|
||||
pub scrollbar: Scrollbar,
|
||||
/// Gutter related settings
|
||||
pub gutter: Gutter,
|
||||
/// Whether the editor will scroll beyond the last line.
|
||||
pub scroll_beyond_last_line: ScrollBeyondLastLine,
|
||||
/// The number of lines to keep above/below the cursor when auto-scrolling.
|
||||
pub vertical_scroll_margin: f32,
|
||||
/// Scroll sensitivity multiplier. This multiplier is applied
|
||||
/// to both the horizontal and vertical delta values while scrolling.
|
||||
pub scroll_sensitivity: f32,
|
||||
/// Whether the line numbers on editors gutter are relative or not.
|
||||
pub relative_line_numbers: bool,
|
||||
/// When to populate a new search's query based on the text under the cursor.
|
||||
pub seed_search_query_from_cursor: SeedQuerySetting,
|
||||
pub use_smartcase_search: bool,
|
||||
/// The key to use for adding multiple cursors
|
||||
pub multi_cursor_modifier: MultiCursorModifier,
|
||||
/// Hide the values of variables in `private` files, as defined by the
|
||||
/// private_files setting. This only changes the visual representation,
|
||||
/// the values are still present in the file and can be selected / copied / pasted
|
||||
pub redact_private_values: bool,
|
||||
|
||||
/// How many lines to expand the multibuffer excerpts by default
|
||||
pub expand_excerpt_lines: u32,
|
||||
pub middle_click_paste: bool,
|
||||
/// What to do when multibuffer is double clicked in some of its excerpts
|
||||
/// (parts of singleton buffers).
|
||||
#[serde(default)]
|
||||
pub double_click_in_multibuffer: DoubleClickInMultibuffer,
|
||||
/// Whether the editor search results will loop
|
||||
pub search_wrap: bool,
|
||||
#[serde(default)]
|
||||
pub search: SearchSettings,
|
||||
/// Show method signatures in the editor, when inside parentheses.
|
||||
pub auto_signature_help: bool,
|
||||
/// Whether to show the signature help after completion or a bracket pair inserted.
|
||||
/// If `auto_signature_help` is enabled, this setting will be treated as enabled also.
|
||||
pub show_signature_help_after_edits: bool,
|
||||
/// Jupyter REPL settings.
|
||||
pub jupyter: Jupyter,
|
||||
}
|
||||
|
||||
impl Default for EditorSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
cursor_blink: true,
|
||||
current_line_highlight: CurrentLineHighlight::All,
|
||||
hover_popover_enabled: true,
|
||||
show_completions_on_input: true,
|
||||
show_completion_documentation: true,
|
||||
completion_documentation_secondary_query_debounce: 300,
|
||||
use_on_type_format: true,
|
||||
toolbar: Default::default(),
|
||||
scrollbar: Default::default(),
|
||||
gutter: Default::default(),
|
||||
scroll_beyond_last_line: ScrollBeyondLastLine::OnePage,
|
||||
vertical_scroll_margin: 3.,
|
||||
scroll_sensitivity: 1.0,
|
||||
relative_line_numbers: false,
|
||||
seed_search_query_from_cursor: SeedQuerySetting::Always,
|
||||
multi_cursor_modifier: MultiCursorModifier::Alt,
|
||||
redact_private_values: false,
|
||||
expand_excerpt_lines: 3,
|
||||
double_click_in_multibuffer: DoubleClickInMultibuffer::Select,
|
||||
search_wrap: true,
|
||||
auto_signature_help: false,
|
||||
show_signature_help_after_edits: true,
|
||||
jupyter: Default::default(),
|
||||
use_smartcase_search: false,
|
||||
middle_click_paste: true,
|
||||
search: SearchSettings::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CurrentLineHighlight {
|
||||
@@ -139,93 +72,48 @@ pub enum DoubleClickInMultibuffer {
|
||||
Open,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Jupyter {
|
||||
/// Whether the Jupyter feature is enabled.
|
||||
///
|
||||
/// Default: true
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for Jupyter {
|
||||
fn default() -> Self {
|
||||
Self { enabled: true }
|
||||
}
|
||||
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct JupyterContent {
|
||||
/// Whether the Jupyter feature is enabled.
|
||||
///
|
||||
/// Default: true
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
#[serde(default)]
|
||||
pub struct Toolbar {
|
||||
/// Whether to display breadcrumbs in the editor toolbar.
|
||||
pub breadcrumbs: bool,
|
||||
/// Whether to display quick action buttons in the editor toolbar.
|
||||
pub quick_actions: bool,
|
||||
/// Whether to show the selections menu in the editor toolbar
|
||||
pub selections_menu: bool,
|
||||
}
|
||||
|
||||
impl Default for Toolbar {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
breadcrumbs: true,
|
||||
quick_actions: true,
|
||||
selections_menu: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
pub struct Scrollbar {
|
||||
/// When to show the scrollbar in the editor.
|
||||
pub show: ShowScrollbar,
|
||||
/// Whether to show git diff indicators in the scrollbar.
|
||||
pub git_diff: bool,
|
||||
/// Whether to show buffer search result indicators in the scrollbar.
|
||||
pub selected_symbol: bool,
|
||||
/// Whether to show selected symbol occurrences in the scrollbar.
|
||||
pub search_results: bool,
|
||||
/// Whether to show diagnostic indicators in the scrollbar.
|
||||
pub diagnostics: bool,
|
||||
/// Whether to show cursor positions in the scrollbar.
|
||||
pub cursors: bool,
|
||||
}
|
||||
|
||||
impl Default for Scrollbar {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
show: ShowScrollbar::Auto,
|
||||
git_diff: true,
|
||||
selected_symbol: true,
|
||||
search_results: true,
|
||||
diagnostics: true,
|
||||
cursors: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gutter-related settings.
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
#[serde(default)]
|
||||
pub struct Gutter {
|
||||
/// Whether to show line numbers in the gutter.
|
||||
pub line_numbers: bool,
|
||||
/// Whether to show code action buttons in the gutter.
|
||||
pub code_actions: bool,
|
||||
/// Whether to show runnable buttons in the gutter.
|
||||
pub runnables: bool,
|
||||
/// Whether to show fold buttons in the gutter.
|
||||
pub folds: bool,
|
||||
}
|
||||
|
||||
impl Default for Gutter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
line_numbers: true,
|
||||
code_actions: true,
|
||||
runnables: true,
|
||||
folds: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// When to show the scrollbar in the editor.
|
||||
///
|
||||
/// Default: auto
|
||||
@@ -283,6 +171,188 @@ pub struct SearchSettings {
|
||||
pub regex: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct EditorSettingsContent {
|
||||
/// Whether the cursor blinks in the editor.
|
||||
///
|
||||
/// Default: true
|
||||
pub cursor_blink: Option<bool>,
|
||||
/// How to highlight the current line in the editor.
|
||||
///
|
||||
/// Default: all
|
||||
pub current_line_highlight: Option<CurrentLineHighlight>,
|
||||
/// Whether to show the informational hover box when moving the mouse
|
||||
/// over symbols in the editor.
|
||||
///
|
||||
/// Default: true
|
||||
pub hover_popover_enabled: Option<bool>,
|
||||
|
||||
/// Whether to pop the completions menu while typing in an editor without
|
||||
/// explicitly requesting it.
|
||||
///
|
||||
/// Default: true
|
||||
pub show_completions_on_input: Option<bool>,
|
||||
/// Whether to display inline and alongside documentation for items in the
|
||||
/// completions menu.
|
||||
///
|
||||
/// Default: true
|
||||
pub show_completion_documentation: Option<bool>,
|
||||
/// The debounce delay before re-querying the language server for completion
|
||||
/// documentation when not included in original completion list.
|
||||
///
|
||||
/// Default: 300 ms
|
||||
pub completion_documentation_secondary_query_debounce: Option<u64>,
|
||||
/// Whether to use additional LSP queries to format (and amend) the code after
|
||||
/// every "trigger" symbol input, defined by LSP server capabilities.
|
||||
///
|
||||
/// Default: true
|
||||
pub use_on_type_format: Option<bool>,
|
||||
/// Toolbar related settings
|
||||
pub toolbar: Option<ToolbarContent>,
|
||||
/// Scrollbar related settings
|
||||
pub scrollbar: Option<ScrollbarContent>,
|
||||
/// Gutter related settings
|
||||
pub gutter: Option<GutterContent>,
|
||||
/// Whether the editor will scroll beyond the last line.
|
||||
///
|
||||
/// Default: one_page
|
||||
pub scroll_beyond_last_line: Option<ScrollBeyondLastLine>,
|
||||
/// The number of lines to keep above/below the cursor when auto-scrolling.
|
||||
///
|
||||
/// Default: 3.
|
||||
pub vertical_scroll_margin: Option<f32>,
|
||||
/// Scroll sensitivity multiplier. This multiplier is applied
|
||||
/// to both the horizontal and vertical delta values while scrolling.
|
||||
///
|
||||
/// Default: 1.0
|
||||
pub scroll_sensitivity: Option<f32>,
|
||||
/// Whether the line numbers on editors gutter are relative or not.
|
||||
///
|
||||
/// Default: false
|
||||
pub relative_line_numbers: Option<bool>,
|
||||
/// When to populate a new search's query based on the text under the cursor.
|
||||
///
|
||||
/// Default: always
|
||||
pub seed_search_query_from_cursor: Option<SeedQuerySetting>,
|
||||
pub use_smartcase_search: Option<bool>,
|
||||
/// The key to use for adding multiple cursors
|
||||
///
|
||||
/// Default: alt
|
||||
pub multi_cursor_modifier: Option<MultiCursorModifier>,
|
||||
/// Hide the values of variables in `private` files, as defined by the
|
||||
/// private_files setting. This only changes the visual representation,
|
||||
/// the values are still present in the file and can be selected / copied / pasted
|
||||
///
|
||||
/// Default: false
|
||||
pub redact_private_values: Option<bool>,
|
||||
|
||||
/// How many lines to expand the multibuffer excerpts by default
|
||||
///
|
||||
/// Default: 3
|
||||
pub expand_excerpt_lines: Option<u32>,
|
||||
|
||||
/// Whether to enable middle-click paste on Linux
|
||||
///
|
||||
/// Default: true
|
||||
pub middle_click_paste: Option<bool>,
|
||||
|
||||
/// What to do when multibuffer is double clicked in some of its excerpts
|
||||
/// (parts of singleton buffers).
|
||||
///
|
||||
/// Default: select
|
||||
pub double_click_in_multibuffer: Option<DoubleClickInMultibuffer>,
|
||||
/// Whether the editor search results will loop
|
||||
///
|
||||
/// Default: true
|
||||
pub search_wrap: Option<bool>,
|
||||
|
||||
/// Defaults to use when opening a new buffer and project search items.
|
||||
///
|
||||
/// Default: nothing is enabled
|
||||
pub search: Option<SearchSettings>,
|
||||
|
||||
/// Whether to automatically show a signature help pop-up or not.
|
||||
///
|
||||
/// Default: false
|
||||
pub auto_signature_help: Option<bool>,
|
||||
|
||||
/// Whether to show the signature help pop-up after completions or bracket pairs inserted.
|
||||
///
|
||||
/// Default: true
|
||||
pub show_signature_help_after_edits: Option<bool>,
|
||||
|
||||
/// Jupyter REPL settings.
|
||||
pub jupyter: Option<JupyterContent>,
|
||||
}
|
||||
|
||||
// Toolbar related settings
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
pub struct ToolbarContent {
|
||||
/// Whether to display breadcrumbs in the editor toolbar.
|
||||
///
|
||||
/// Default: true
|
||||
pub breadcrumbs: Option<bool>,
|
||||
/// Whether to display quick action buttons in the editor toolbar.
|
||||
///
|
||||
/// Default: true
|
||||
pub quick_actions: Option<bool>,
|
||||
|
||||
/// Whether to show the selections menu in the editor toolbar
|
||||
///
|
||||
/// Default: true
|
||||
pub selections_menu: Option<bool>,
|
||||
}
|
||||
|
||||
/// Scrollbar related settings
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
pub struct ScrollbarContent {
|
||||
/// When to show the scrollbar in the editor.
|
||||
///
|
||||
/// Default: auto
|
||||
pub show: Option<ShowScrollbar>,
|
||||
/// Whether to show git diff indicators in the scrollbar.
|
||||
///
|
||||
/// Default: true
|
||||
pub git_diff: Option<bool>,
|
||||
/// Whether to show buffer search result indicators in the scrollbar.
|
||||
///
|
||||
/// Default: true
|
||||
pub search_results: Option<bool>,
|
||||
/// Whether to show selected symbol occurrences in the scrollbar.
|
||||
///
|
||||
/// Default: true
|
||||
pub selected_symbol: Option<bool>,
|
||||
/// Whether to show diagnostic indicators in the scrollbar.
|
||||
///
|
||||
/// Default: true
|
||||
pub diagnostics: Option<bool>,
|
||||
/// Whether to show cursor positions in the scrollbar.
|
||||
///
|
||||
/// Default: true
|
||||
pub cursors: Option<bool>,
|
||||
}
|
||||
|
||||
/// Gutter related settings
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
pub struct GutterContent {
|
||||
/// Whether to show line numbers in the gutter.
|
||||
///
|
||||
/// Default: true
|
||||
pub line_numbers: Option<bool>,
|
||||
/// Whether to show code action buttons in the gutter.
|
||||
///
|
||||
/// Default: true
|
||||
pub code_actions: Option<bool>,
|
||||
/// Whether to show runnable buttons in the gutter.
|
||||
///
|
||||
/// Default: true
|
||||
pub runnables: Option<bool>,
|
||||
/// Whether to show fold buttons in the gutter.
|
||||
///
|
||||
/// Default: true
|
||||
pub folds: Option<bool>,
|
||||
}
|
||||
|
||||
impl EditorSettings {
|
||||
pub fn jupyter_enabled(cx: &AppContext) -> bool {
|
||||
EditorSettings::get_global(cx).jupyter.enabled
|
||||
@@ -292,7 +362,7 @@ impl EditorSettings {
|
||||
impl Settings for EditorSettings {
|
||||
const KEY: Option<&'static str> = None;
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = EditorSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use gpui::{AppContext, FontFeatures, FontWeight};
|
||||
use project::project_settings::ProjectSettings;
|
||||
use project::project_settings::{InlineBlameSettings, ProjectSettings};
|
||||
use settings::{EditableSettingControl, Settings};
|
||||
use theme::{FontFamilyCache, ThemeSettings};
|
||||
use ui::{
|
||||
@@ -296,7 +296,14 @@ impl EditableSettingControl for InlineGitBlameControl {
|
||||
value: Self::Value,
|
||||
_cx: &AppContext,
|
||||
) {
|
||||
settings.git.inline_blame.enabled = value;
|
||||
if let Some(inline_blame) = settings.git.inline_blame.as_mut() {
|
||||
inline_blame.enabled = value;
|
||||
} else {
|
||||
settings.git.inline_blame = Some(InlineBlameSettings {
|
||||
enabled: false,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +349,14 @@ impl EditableSettingControl for LineNumbersControl {
|
||||
value: Self::Value,
|
||||
_cx: &AppContext,
|
||||
) {
|
||||
settings.gutter.line_numbers = value;
|
||||
if let Some(gutter) = settings.gutter.as_mut() {
|
||||
gutter.line_numbers = Some(value);
|
||||
} else {
|
||||
settings.gutter = Some(crate::editor_settings::GutterContent {
|
||||
line_numbers: Some(value),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +402,7 @@ impl EditableSettingControl for RelativeLineNumbersControl {
|
||||
value: Self::Value,
|
||||
_cx: &AppContext,
|
||||
) {
|
||||
settings.relative_line_numbers = value;
|
||||
settings.relative_line_numbers = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6964,7 +6964,7 @@ async fn test_handle_input_for_show_signature_help_auto_signature_help_true(
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = true;
|
||||
settings.auto_signature_help = Some(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7105,8 +7105,8 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui:
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = false;
|
||||
settings.show_signature_help_after_edits = false;
|
||||
settings.auto_signature_help = Some(false);
|
||||
settings.show_signature_help_after_edits = Some(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7232,8 +7232,8 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui:
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = false;
|
||||
settings.show_signature_help_after_edits = true;
|
||||
settings.auto_signature_help = Some(false);
|
||||
settings.show_signature_help_after_edits = Some(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7274,8 +7274,8 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui:
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = true;
|
||||
settings.show_signature_help_after_edits = false;
|
||||
settings.auto_signature_help = Some(true);
|
||||
settings.show_signature_help_after_edits = Some(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7318,7 +7318,7 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.auto_signature_help = true;
|
||||
settings.auto_signature_help = Some(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7759,7 +7759,7 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.show_completions_on_input = false;
|
||||
settings.show_completions_on_input = Some(false);
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1283,7 +1283,10 @@ impl EditorElement {
|
||||
.row,
|
||||
);
|
||||
|
||||
let git_gutter_setting = ProjectSettings::get_global(cx).git.git_gutter;
|
||||
let git_gutter_setting = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
.git_gutter
|
||||
.unwrap_or_default();
|
||||
let display_hunks = buffer_snapshot
|
||||
.git_diff_hunks_in_range(buffer_start_row..buffer_end_row)
|
||||
.map(|hunk| diff_hunk_to_display(&hunk, snapshot))
|
||||
@@ -1363,10 +1366,12 @@ impl EditorElement {
|
||||
};
|
||||
let padded_line_end = line_end + em_width * INLINE_BLAME_PADDING_EM_WIDTHS;
|
||||
|
||||
let min_column_in_pixels = self.column_pixels(
|
||||
ProjectSettings::get_global(cx).git.inline_blame.min_column as usize,
|
||||
cx,
|
||||
);
|
||||
let min_column_in_pixels = ProjectSettings::get_global(cx)
|
||||
.git
|
||||
.inline_blame
|
||||
.and_then(|settings| settings.min_column)
|
||||
.map(|col| self.column_pixels(col as usize, cx))
|
||||
.unwrap_or(px(0.));
|
||||
let min_start = content_origin.x - scroll_pixel_position.x + min_column_in_pixels;
|
||||
|
||||
cmp::max(padded_line_end, min_start)
|
||||
@@ -3326,7 +3331,7 @@ impl EditorElement {
|
||||
.unwrap_or_else(|| {
|
||||
matches!(
|
||||
ProjectSettings::get_global(cx).git.git_gutter,
|
||||
GitGutterSetting::TrackedFiles
|
||||
Some(GitGutterSetting::TrackedFiles)
|
||||
)
|
||||
});
|
||||
if show_git_gutter {
|
||||
|
||||
@@ -518,19 +518,22 @@ async fn parse_blocks(
|
||||
let rendered_block = cx
|
||||
.new_view(|cx| {
|
||||
let settings = ThemeSettings::get_global(cx);
|
||||
let ui_font_family = settings.ui_font.family.clone();
|
||||
let buffer_font_family = settings.buffer_font.family.clone();
|
||||
let mut base_style = cx.text_style();
|
||||
base_style.refine(&TextStyleRefinement {
|
||||
font_family: Some(buffer_font_family.clone()),
|
||||
|
||||
let mut base_text_style = cx.text_style();
|
||||
base_text_style.refine(&TextStyleRefinement {
|
||||
font_family: Some(ui_font_family.clone()),
|
||||
color: Some(cx.theme().colors().editor_foreground),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let markdown_style = MarkdownStyle {
|
||||
base_text_style: base_style,
|
||||
code_block: StyleRefinement::default().mt(rems(1.)).mb(rems(1.)),
|
||||
base_text_style,
|
||||
code_block: StyleRefinement::default().my(rems(1.)).font_buffer(cx),
|
||||
inline_code: TextStyleRefinement {
|
||||
background_color: Some(cx.theme().colors().background),
|
||||
font_family: Some(buffer_font_family),
|
||||
..Default::default()
|
||||
},
|
||||
rule_color: Color::Muted.color(cx),
|
||||
|
||||
@@ -6,25 +6,18 @@ use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)]
|
||||
pub struct ExtensionSettings {
|
||||
/// The extensions that should be automatically installed by Zed.
|
||||
///
|
||||
/// This is used to make functionality provided by extensions (e.g., language support)
|
||||
/// available out-of-the-box.
|
||||
#[serde(default)]
|
||||
pub auto_install_extensions: HashMap<Arc<str>, bool>,
|
||||
#[serde(default)]
|
||||
pub auto_update_extensions: HashMap<Arc<str>, bool>,
|
||||
}
|
||||
|
||||
impl Default for ExtensionSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
auto_install_extensions: HashMap::from_iter([("html".into(), true)]),
|
||||
auto_update_extensions: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ExtensionSettings {
|
||||
/// Returns whether the given extension should be auto-installed.
|
||||
pub fn should_auto_install(&self, extension_id: &str) -> bool {
|
||||
|
||||
@@ -1000,7 +1000,7 @@ impl ExtensionsPage {
|
||||
this.update_settings::<VimModeSetting>(
|
||||
selection,
|
||||
cx,
|
||||
|setting, value| *setting = VimModeSetting(value),
|
||||
|setting, value| *setting = Some(value),
|
||||
);
|
||||
}),
|
||||
)),
|
||||
|
||||
@@ -342,6 +342,24 @@ impl Fs for RealFs {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
async fn trash_file(&self, path: &Path, _options: RemoveOptions) -> Result<()> {
|
||||
use windows::{
|
||||
core::HSTRING,
|
||||
Storage::{StorageDeleteOption, StorageFile},
|
||||
};
|
||||
// todo(windows)
|
||||
// When new version of `windows-rs` release, make this operation `async`
|
||||
let path = path.canonicalize()?.to_string_lossy().to_string();
|
||||
let path_str = path.trim_start_matches("\\\\?\\");
|
||||
if path_str.is_empty() {
|
||||
anyhow::bail!("File path is empty!");
|
||||
}
|
||||
let file = StorageFile::GetFileFromPathAsync(&HSTRING::from(path_str))?.get()?;
|
||||
file.DeleteAsync(StorageDeleteOption::Default)?.get()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
async fn trash_dir(&self, path: &Path, options: RemoveOptions) -> Result<()> {
|
||||
self.trash_file(path, options).await
|
||||
@@ -352,6 +370,25 @@ impl Fs for RealFs {
|
||||
self.trash_file(path, options).await
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
async fn trash_dir(&self, path: &Path, _options: RemoveOptions) -> Result<()> {
|
||||
use windows::{
|
||||
core::HSTRING,
|
||||
Storage::{StorageDeleteOption, StorageFolder},
|
||||
};
|
||||
|
||||
let path = path.canonicalize()?.to_string_lossy().to_string();
|
||||
let path_str = path.trim_start_matches("\\\\?\\");
|
||||
if path_str.is_empty() {
|
||||
anyhow::bail!("Folder path is empty!");
|
||||
}
|
||||
// todo(windows)
|
||||
// When new version of `windows-rs` release, make this operation `async`
|
||||
let folder = StorageFolder::GetFolderFromPathAsync(&HSTRING::from(path_str))?.get()?;
|
||||
folder.DeleteAsync(StorageDeleteOption::Default)?.get()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn open_sync(&self, path: &Path) -> Result<Box<dyn io::Read>> {
|
||||
Ok(Box::new(std::fs::File::open(path)?))
|
||||
}
|
||||
|
||||
@@ -180,10 +180,18 @@ pub(crate) enum LineIndicatorFormat {
|
||||
Long,
|
||||
}
|
||||
|
||||
/// Whether or not to automatically check for updates.
|
||||
///
|
||||
/// Values: short, long
|
||||
/// Default: short
|
||||
#[derive(Clone, Copy, Default, JsonSchema, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub(crate) struct LineIndicatorFormatContent(LineIndicatorFormat);
|
||||
|
||||
impl Settings for LineIndicatorFormat {
|
||||
const KEY: Option<&'static str> = Some("line_indicator_format");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = Option<LineIndicatorFormatContent>;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
@@ -191,9 +199,9 @@ impl Settings for LineIndicatorFormat {
|
||||
) -> anyhow::Result<Self> {
|
||||
let format = [sources.release_channel, sources.user]
|
||||
.into_iter()
|
||||
.find_map(|value| value.copied())
|
||||
.unwrap_or(*sources.default);
|
||||
.find_map(|value| value.copied().flatten())
|
||||
.unwrap_or(sources.default.ok_or_else(Self::missing_default)?);
|
||||
|
||||
Ok(format)
|
||||
Ok(format.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ struct HelloWorld {}
|
||||
|
||||
impl Render for HelloWorld {
|
||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
let text = "The longest word in any of the major English language 以及中文的测试 dictionaries is pneumonoultramicroscopicsilicovolcanoconiosis, a word that refers to a lung disease contracted from the inhalation of very fine silica particles, specifically from a volcano; medically, it is the same as silicosis.";
|
||||
let text = "The longest word 你好世界这段是中文,こんにちはこの段落は日本語です in any of the major English language dictionaries is pneumonoultramicroscopicsilicovolcanoconiosis, a word that refers to a lung disease contracted from the inhalation of very fine silica particles, specifically from a volcano; medically, it is the same as silicosis.";
|
||||
div()
|
||||
.id("page")
|
||||
.size_full()
|
||||
@@ -40,6 +40,7 @@ impl Render for HelloWorld {
|
||||
.border_1()
|
||||
.border_color(gpui::red())
|
||||
.text_ellipsis()
|
||||
.w_full()
|
||||
.child("A short text in normal div"),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
use core::fmt::Debug;
|
||||
use derive_more::{Add, AddAssign, Div, DivAssign, Mul, Neg, Sub, SubAssign};
|
||||
use refineable::Refineable;
|
||||
use schemars::JsonSchema;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{
|
||||
cmp::{self, PartialOrd},
|
||||
@@ -2202,7 +2201,6 @@ impl From<Percentage> for Radians {
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
JsonSchema,
|
||||
)]
|
||||
#[repr(transparent)]
|
||||
pub struct Pixels(pub f32);
|
||||
|
||||
@@ -401,14 +401,19 @@ impl Platform for WindowsPlatform {
|
||||
}
|
||||
|
||||
fn open_with_system(&self, path: &Path) {
|
||||
let executor = self.background_executor().clone();
|
||||
let path = path.to_owned();
|
||||
executor
|
||||
let Ok(full_path) = path.canonicalize() else {
|
||||
log::error!("unable to parse file full path: {}", path.display());
|
||||
return;
|
||||
};
|
||||
self.background_executor()
|
||||
.spawn(async move {
|
||||
let _ = std::process::Command::new("cmd")
|
||||
.args(&["/c", "start", "", path.to_str().expect("path to string")])
|
||||
.spawn()
|
||||
.expect("Failed to open file");
|
||||
let Some(full_path_str) = full_path.to_str() else {
|
||||
return;
|
||||
};
|
||||
if full_path_str.is_empty() {
|
||||
return;
|
||||
};
|
||||
open_target(full_path_str);
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use super::LineWrapper;
|
||||
|
||||
/// A laid out and styled line of text
|
||||
#[derive(Default, Debug)]
|
||||
pub struct LineLayout {
|
||||
@@ -152,9 +154,18 @@ impl LineLayout {
|
||||
continue;
|
||||
}
|
||||
|
||||
if prev_ch == ' ' && ch != ' ' && first_non_whitespace_ix.is_some() {
|
||||
last_candidate_ix = Some(boundary);
|
||||
last_candidate_x = x;
|
||||
// Here is very similar to `LineWrapper::wrap_line` to determine text wrapping,
|
||||
// but there are some differences, so we have to duplicate the code here.
|
||||
if LineWrapper::is_word_char(ch) {
|
||||
if prev_ch == ' ' && ch != ' ' && first_non_whitespace_ix.is_some() {
|
||||
last_candidate_ix = Some(boundary);
|
||||
last_candidate_x = x;
|
||||
}
|
||||
} else {
|
||||
if ch != ' ' && first_non_whitespace_ix.is_some() {
|
||||
last_candidate_ix = Some(boundary);
|
||||
last_candidate_x = x;
|
||||
}
|
||||
}
|
||||
|
||||
if ch != ' ' && first_non_whitespace_ix.is_none() {
|
||||
|
||||
@@ -833,7 +833,7 @@ impl LanguageRegistry {
|
||||
) -> Option<PendingLanguageServer> {
|
||||
let server_id = self.state.write().next_language_server_id();
|
||||
log::info!(
|
||||
"starting language server {:?}, path: {root_path:?}, id: {server_id}",
|
||||
"attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
|
||||
adapter.name.0
|
||||
);
|
||||
|
||||
|
||||
@@ -70,10 +70,10 @@ pub struct LanguageSettings {
|
||||
/// The column at which to soft-wrap lines, for buffers where soft-wrap
|
||||
/// is enabled.
|
||||
pub preferred_line_length: u32,
|
||||
/// Whether to show wrap guides (vertical rulers) in the editor.
|
||||
/// Setting this to true will show a guide at the 'preferred_line_length' value
|
||||
/// if softwrap is set to 'preferred_line_length', and will show any
|
||||
/// additional guides as specified by the 'wrap_guides' setting.
|
||||
// Whether to show wrap guides (vertical rulers) in the editor.
|
||||
// Setting this to true will show a guide at the 'preferred_line_length' value
|
||||
// if softwrap is set to 'preferred_line_length', and will show any
|
||||
// additional guides as specified by the 'wrap_guides' setting.
|
||||
pub show_wrap_guides: bool,
|
||||
/// Character counts at which to show wrap guides (vertical rulers) in the editor.
|
||||
pub wrap_guides: Vec<usize>,
|
||||
|
||||
@@ -5,8 +5,7 @@ use gpui::AsyncAppContext;
|
||||
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
|
||||
pub use language::*;
|
||||
use lsp::LanguageServerBinary;
|
||||
use project::project_settings::{BinarySettings, ProjectSettings};
|
||||
use settings::Settings;
|
||||
use project::{lsp_store::language_server_settings, project_settings::BinarySettings};
|
||||
use smol::fs::{self, File};
|
||||
use std::{any::Any, env::consts, path::PathBuf, sync::Arc};
|
||||
use util::{fs::remove_matching, maybe, ResultExt};
|
||||
@@ -29,10 +28,7 @@ impl super::LspAdapter for CLspAdapter {
|
||||
cx: &AsyncAppContext,
|
||||
) -> Option<LanguageServerBinary> {
|
||||
let configured_binary = cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
.and_then(|s| s.binary.clone())
|
||||
language_server_settings(delegate, Self::SERVER_NAME, cx).and_then(|s| s.binary.clone())
|
||||
});
|
||||
|
||||
match configured_binary {
|
||||
|
||||
@@ -5,10 +5,9 @@ use gpui::{AppContext, AsyncAppContext, Task};
|
||||
use http_client::github::latest_github_release;
|
||||
pub use language::*;
|
||||
use lsp::LanguageServerBinary;
|
||||
use project::project_settings::{BinarySettings, ProjectSettings};
|
||||
use project::{lsp_store::language_server_settings, project_settings::BinarySettings};
|
||||
use regex::Regex;
|
||||
use serde_json::json;
|
||||
use settings::Settings;
|
||||
use smol::{fs, process};
|
||||
use std::{
|
||||
any::Any,
|
||||
@@ -71,10 +70,7 @@ impl super::LspAdapter for GoLspAdapter {
|
||||
cx: &AsyncAppContext,
|
||||
) -> Option<LanguageServerBinary> {
|
||||
let configured_binary = cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
.and_then(|s| s.binary.clone())
|
||||
language_server_settings(delegate, Self::SERVER_NAME, cx).and_then(|s| s.binary.clone())
|
||||
});
|
||||
|
||||
match configured_binary {
|
||||
|
||||
@@ -7,13 +7,10 @@ use feature_flags::FeatureFlagAppExt;
|
||||
use futures::StreamExt;
|
||||
use gpui::{AppContext, AsyncAppContext};
|
||||
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
|
||||
use language::{
|
||||
CodeLabel, Language, LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate,
|
||||
};
|
||||
use language::{LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||
use lsp::LanguageServerBinary;
|
||||
use node_runtime::NodeRuntime;
|
||||
use project::ContextProviderWithTasks;
|
||||
use rope::Rope;
|
||||
use serde_json::{json, Value};
|
||||
use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
|
||||
use smol::{
|
||||
@@ -205,30 +202,6 @@ impl LspAdapter for JsonLspAdapter {
|
||||
})))
|
||||
}
|
||||
|
||||
async fn label_for_completion(
|
||||
&self,
|
||||
item: &lsp::CompletionItem,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
let text = if let Some(description) = item
|
||||
.label_details
|
||||
.as_ref()
|
||||
.and_then(|label_details| label_details.description.as_ref())
|
||||
{
|
||||
format!("{} {}", item.label, description)
|
||||
} else if let Some(detail) = &item.detail {
|
||||
format!("{} {}", item.label, detail)
|
||||
} else {
|
||||
item.label.clone()
|
||||
};
|
||||
let rope = Rope::from(item.label.as_str());
|
||||
let runs = language.highlight_text(&rope, 0..item.label.len());
|
||||
Some(language::CodeLabel {
|
||||
text,
|
||||
runs,
|
||||
filter_range: 0..item.label.len(),
|
||||
})
|
||||
}
|
||||
async fn workspace_configuration(
|
||||
self: Arc<Self>,
|
||||
_: &Arc<dyn LspAdapterDelegate>,
|
||||
|
||||
@@ -5,9 +5,9 @@ use gpui::AsyncAppContext;
|
||||
use language::{ContextProvider, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||
use lsp::LanguageServerBinary;
|
||||
use node_runtime::NodeRuntime;
|
||||
use project::project_settings::ProjectSettings;
|
||||
use project::lsp_store::language_server_settings;
|
||||
use serde_json::Value;
|
||||
use settings::Settings;
|
||||
|
||||
use std::{
|
||||
any::Any,
|
||||
borrow::Cow,
|
||||
@@ -177,13 +177,11 @@ impl LspAdapter for PythonLspAdapter {
|
||||
|
||||
async fn workspace_configuration(
|
||||
self: Arc<Self>,
|
||||
_: &Arc<dyn LspAdapterDelegate>,
|
||||
adapter: &Arc<dyn LspAdapterDelegate>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Value> {
|
||||
cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
language_server_settings(adapter.as_ref(), Self::SERVER_NAME, cx)
|
||||
.and_then(|s| s.settings.clone())
|
||||
.unwrap_or_default()
|
||||
})
|
||||
|
||||
@@ -7,9 +7,8 @@ use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
|
||||
pub use language::*;
|
||||
use language_settings::all_language_settings;
|
||||
use lsp::LanguageServerBinary;
|
||||
use project::project_settings::{BinarySettings, ProjectSettings};
|
||||
use project::{lsp_store::language_server_settings, project_settings::BinarySettings};
|
||||
use regex::Regex;
|
||||
use settings::Settings;
|
||||
use smol::fs::{self, File};
|
||||
use std::{
|
||||
any::Any,
|
||||
@@ -40,10 +39,7 @@ impl LspAdapter for RustLspAdapter {
|
||||
cx: &AsyncAppContext,
|
||||
) -> Option<LanguageServerBinary> {
|
||||
let configured_binary = cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
.and_then(|s| s.binary.clone())
|
||||
language_server_settings(delegate, Self::SERVER_NAME, cx).and_then(|s| s.binary.clone())
|
||||
});
|
||||
|
||||
match configured_binary {
|
||||
|
||||
@@ -6,9 +6,8 @@ use gpui::AsyncAppContext;
|
||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||
use lsp::LanguageServerBinary;
|
||||
use node_runtime::NodeRuntime;
|
||||
use project::project_settings::ProjectSettings;
|
||||
use project::lsp_store::language_server_settings;
|
||||
use serde_json::{json, Value};
|
||||
use settings::Settings;
|
||||
use smol::fs;
|
||||
use std::{
|
||||
any::Any,
|
||||
@@ -53,14 +52,12 @@ impl LspAdapter for TailwindLspAdapter {
|
||||
|
||||
async fn check_if_user_installed(
|
||||
&self,
|
||||
_delegate: &dyn LspAdapterDelegate,
|
||||
delegate: &dyn LspAdapterDelegate,
|
||||
cx: &AsyncAppContext,
|
||||
) -> Option<LanguageServerBinary> {
|
||||
let configured_binary = cx
|
||||
.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
language_server_settings(delegate, Self::SERVER_NAME, cx)
|
||||
.and_then(|s| s.binary.clone())
|
||||
})
|
||||
.ok()??;
|
||||
@@ -171,13 +168,11 @@ impl LspAdapter for TailwindLspAdapter {
|
||||
|
||||
async fn workspace_configuration(
|
||||
self: Arc<Self>,
|
||||
_: &Arc<dyn LspAdapterDelegate>,
|
||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Value> {
|
||||
let tailwind_user_settings = cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
language_server_settings(delegate.as_ref(), Self::SERVER_NAME, cx)
|
||||
.and_then(|s| s.settings.clone())
|
||||
.unwrap_or_default()
|
||||
})?;
|
||||
|
||||
@@ -181,6 +181,7 @@
|
||||
"import"
|
||||
"in"
|
||||
"instanceof"
|
||||
"is"
|
||||
"let"
|
||||
"new"
|
||||
"of"
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
(template_string)
|
||||
] @string
|
||||
|
||||
[
|
||||
(jsx_element)
|
||||
] @element
|
||||
(jsx_element) @element
|
||||
|
||||
[
|
||||
(jsx_attribute)
|
||||
(jsx_opening_element)
|
||||
(jsx_closing_element)
|
||||
(jsx_self_closing_element)
|
||||
(jsx_expression)
|
||||
] @default
|
||||
|
||||
@@ -8,10 +8,9 @@ use http_client::github::{build_asset_url, AssetKind, GitHubLspBinaryVersion};
|
||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||
use lsp::{CodeActionKind, LanguageServerBinary};
|
||||
use node_runtime::NodeRuntime;
|
||||
use project::project_settings::ProjectSettings;
|
||||
use project::lsp_store::language_server_settings;
|
||||
use project::ContextProviderWithTasks;
|
||||
use serde_json::{json, Value};
|
||||
use settings::Settings;
|
||||
use smol::{fs, io::BufReader, stream::StreamExt};
|
||||
use std::{
|
||||
any::Any,
|
||||
@@ -58,7 +57,11 @@ fn typescript_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
|
||||
}
|
||||
|
||||
fn eslint_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
|
||||
vec![server_path.into(), "--stdio".into()]
|
||||
vec![
|
||||
"--max-old-space-size=8192".into(),
|
||||
server_path.into(),
|
||||
"--stdio".into(),
|
||||
]
|
||||
}
|
||||
|
||||
pub struct TypeScriptLspAdapter {
|
||||
@@ -232,14 +235,12 @@ impl LspAdapter for TypeScriptLspAdapter {
|
||||
|
||||
async fn workspace_configuration(
|
||||
self: Arc<Self>,
|
||||
_: &Arc<dyn LspAdapterDelegate>,
|
||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Value> {
|
||||
let override_options = cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
.and_then(|s| s.initialization_options.clone())
|
||||
language_server_settings(delegate.as_ref(), Self::SERVER_NAME, cx)
|
||||
.and_then(|s| s.settings.clone())
|
||||
})?;
|
||||
if let Some(options) = override_options {
|
||||
return Ok(options);
|
||||
@@ -330,9 +331,7 @@ impl LspAdapter for EsLintLspAdapter {
|
||||
let workspace_root = delegate.worktree_root_path();
|
||||
|
||||
let eslint_user_settings = cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
language_server_settings(delegate.as_ref(), Self::SERVER_NAME, cx)
|
||||
.and_then(|s| s.settings.clone())
|
||||
.unwrap_or_default()
|
||||
})?;
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
"..."
|
||||
"-"
|
||||
"--"
|
||||
"-="
|
||||
@@ -181,6 +182,7 @@
|
||||
"import"
|
||||
"in"
|
||||
"instanceof"
|
||||
"is"
|
||||
"let"
|
||||
"new"
|
||||
"of"
|
||||
|
||||
@@ -5,16 +5,15 @@ use gpui::AsyncAppContext;
|
||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||
use lsp::{CodeActionKind, LanguageServerBinary};
|
||||
use node_runtime::NodeRuntime;
|
||||
use project::project_settings::{BinarySettings, ProjectSettings};
|
||||
use project::{lsp_store::language_server_settings, project_settings::BinarySettings};
|
||||
use serde_json::{json, Value};
|
||||
use settings::{Settings, SettingsLocation};
|
||||
use std::{
|
||||
any::Any,
|
||||
ffi::OsString,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use util::{maybe, merge_json_value_into, ResultExt};
|
||||
use util::{maybe, ResultExt};
|
||||
|
||||
fn typescript_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
|
||||
vec![server_path.into(), "--stdio".into()]
|
||||
@@ -75,10 +74,7 @@ impl LspAdapter for VtslsLspAdapter {
|
||||
cx: &AsyncAppContext,
|
||||
) -> Option<LanguageServerBinary> {
|
||||
let configured_binary = cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(SERVER_NAME)
|
||||
.and_then(|s| s.binary.clone())
|
||||
language_server_settings(delegate, SERVER_NAME, cx).and_then(|s| s.binary.clone())
|
||||
});
|
||||
|
||||
match configured_binary {
|
||||
@@ -226,9 +222,6 @@ impl LspAdapter for VtslsLspAdapter {
|
||||
"suggest": {
|
||||
"completeFunctionCalls": true
|
||||
},
|
||||
"tsserver": {
|
||||
"maxTsServerMemory": 8092
|
||||
},
|
||||
"inlayHints": {
|
||||
"parameterNames": {
|
||||
"enabled": "all",
|
||||
@@ -270,33 +263,28 @@ impl LspAdapter for VtslsLspAdapter {
|
||||
|
||||
async fn workspace_configuration(
|
||||
self: Arc<Self>,
|
||||
adapter: &Arc<dyn LspAdapterDelegate>,
|
||||
delegate: &Arc<dyn LspAdapterDelegate>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Value> {
|
||||
let override_options = cx.update(|cx| {
|
||||
ProjectSettings::get(
|
||||
Some(SettingsLocation {
|
||||
worktree_id: adapter.worktree_id(),
|
||||
path: adapter.worktree_root_path(),
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
.lsp
|
||||
.get(SERVER_NAME)
|
||||
.and_then(|s| s.initialization_options.clone())
|
||||
language_server_settings(delegate.as_ref(), SERVER_NAME, cx)
|
||||
.and_then(|s| s.settings.clone())
|
||||
})?;
|
||||
|
||||
if let Some(options) = override_options {
|
||||
return Ok(options);
|
||||
}
|
||||
let mut initialization_options = self
|
||||
.initialization_options(adapter)
|
||||
.await
|
||||
.map(|o| o.unwrap())?;
|
||||
|
||||
if let Some(override_options) = override_options {
|
||||
merge_json_value_into(override_options, &mut initialization_options)
|
||||
}
|
||||
Ok(initialization_options)
|
||||
let config = serde_json::json!({
|
||||
"tsserver": {
|
||||
"maxTsServerMemory": 8092
|
||||
},
|
||||
});
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"typescript": config,
|
||||
"javascript": config
|
||||
}))
|
||||
}
|
||||
|
||||
fn language_ids(&self) -> HashMap<String, String> {
|
||||
|
||||
@@ -7,7 +7,7 @@ use language::{
|
||||
};
|
||||
use lsp::LanguageServerBinary;
|
||||
use node_runtime::NodeRuntime;
|
||||
use project::project_settings::ProjectSettings;
|
||||
use project::lsp_store::language_server_settings;
|
||||
use serde_json::Value;
|
||||
use settings::{Settings, SettingsLocation};
|
||||
use smol::fs;
|
||||
@@ -44,14 +44,12 @@ impl LspAdapter for YamlLspAdapter {
|
||||
|
||||
async fn check_if_user_installed(
|
||||
&self,
|
||||
_delegate: &dyn LspAdapterDelegate,
|
||||
delegate: &dyn LspAdapterDelegate,
|
||||
cx: &AsyncAppContext,
|
||||
) -> Option<LanguageServerBinary> {
|
||||
let configured_binary = cx
|
||||
.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
language_server_settings(delegate, Self::SERVER_NAME, cx)
|
||||
.and_then(|s| s.binary.clone())
|
||||
})
|
||||
.ok()??;
|
||||
@@ -147,10 +145,8 @@ impl LspAdapter for YamlLspAdapter {
|
||||
let mut options = serde_json::json!({"[yaml]": {"editor.tabSize": tab_size}});
|
||||
|
||||
let project_options = cx.update(|cx| {
|
||||
ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(Self::SERVER_NAME)
|
||||
.and_then(|s| s.initialization_options.clone())
|
||||
language_server_settings(delegate.as_ref(), Self::SERVER_NAME, cx)
|
||||
.and_then(|s| s.settings.clone())
|
||||
})?;
|
||||
if let Some(override_options) = project_options {
|
||||
merge_json_value_into(override_options, &mut options);
|
||||
|
||||
@@ -272,7 +272,7 @@ impl LanguageServer {
|
||||
};
|
||||
|
||||
log::info!(
|
||||
"starting language server. binary path: {:?}, working directory: {:?}, args: {:?}",
|
||||
"starting language server process. binary path: {:?}, working directory: {:?}, args: {:?}",
|
||||
binary.path,
|
||||
working_dir,
|
||||
&binary.arguments
|
||||
|
||||
@@ -24,12 +24,12 @@ use editor::{
|
||||
use file_icons::FileIcons;
|
||||
use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
|
||||
use gpui::{
|
||||
actions, anchored, deferred, div, impl_actions, uniform_list, Action, AnyElement, AppContext,
|
||||
AssetSource, AsyncWindowContext, ClipboardItem, DismissEvent, Div, ElementId, EventEmitter,
|
||||
FocusHandle, FocusableView, HighlightStyle, InteractiveElement, IntoElement, KeyContext, Model,
|
||||
MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Render, SharedString, Stateful,
|
||||
Styled, Subscription, Task, UniformListScrollHandle, View, ViewContext, VisualContext,
|
||||
WeakView, WindowContext,
|
||||
actions, anchored, deferred, div, impl_actions, px, uniform_list, Action, AnyElement,
|
||||
AppContext, AssetSource, AsyncWindowContext, ClipboardItem, DismissEvent, Div, ElementId,
|
||||
EventEmitter, FocusHandle, FocusableView, HighlightStyle, InteractiveElement, IntoElement,
|
||||
KeyContext, Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Render,
|
||||
SharedString, Stateful, Styled, Subscription, Task, UniformListScrollHandle, View, ViewContext,
|
||||
VisualContext, WeakView, WindowContext,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::{BufferId, BufferSnapshot, OffsetRangeExt, OutlineItem};
|
||||
@@ -1938,7 +1938,7 @@ impl OutlinePanel {
|
||||
.child(
|
||||
ListItem::new(item_id)
|
||||
.indent_level(depth)
|
||||
.indent_step_size(settings.indent_size)
|
||||
.indent_step_size(px(settings.indent_size))
|
||||
.selected(is_active)
|
||||
.when_some(icon_element, |list_item, icon_element| {
|
||||
list_item.child(h_flex().child(icon_element))
|
||||
@@ -3801,7 +3801,7 @@ impl Panel for OutlinePanel {
|
||||
DockPosition::Left | DockPosition::Bottom => OutlinePanelDockPosition::Left,
|
||||
DockPosition::Right => OutlinePanelDockPosition::Right,
|
||||
};
|
||||
settings.dock = dock;
|
||||
settings.dock = Some(dock);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use anyhow;
|
||||
use gpui::{px, Pixels};
|
||||
use gpui::Pixels;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
@@ -11,51 +10,66 @@ pub enum OutlinePanelDockPosition {
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, JsonSchema)]
|
||||
#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
|
||||
pub struct OutlinePanelSettings {
|
||||
/// Whether to show the outline panel button in the status bar.
|
||||
pub button: bool,
|
||||
/// Customize default width (in pixels) taken by outline panel
|
||||
pub default_width: Pixels,
|
||||
/// The position of outline panel
|
||||
pub dock: OutlinePanelDockPosition,
|
||||
/// Whether to show file icons in the outline panel.
|
||||
pub file_icons: bool,
|
||||
/// Whether to show folder icons or chevrons for directories in the outline panel.
|
||||
pub folder_icons: bool,
|
||||
/// Whether to show the git status in the outline panel.
|
||||
pub git_status: bool,
|
||||
/// Amount of indentation (in pixels) for nested items.
|
||||
pub indent_size: Pixels,
|
||||
/// Whether to reveal it in the outline panel automatically,
|
||||
/// when a corresponding project entry becomes active.
|
||||
/// Gitignored entries are never auto revealed.
|
||||
pub indent_size: f32,
|
||||
pub auto_reveal_entries: bool,
|
||||
/// Whether to fold directories automatically
|
||||
/// when directory has only one directory inside.
|
||||
pub auto_fold_dirs: bool,
|
||||
}
|
||||
|
||||
impl Default for OutlinePanelSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
button: true,
|
||||
default_width: px(240.),
|
||||
dock: OutlinePanelDockPosition::Left,
|
||||
file_icons: true,
|
||||
folder_icons: true,
|
||||
auto_fold_dirs: true,
|
||||
auto_reveal_entries: true,
|
||||
indent_size: px(20.),
|
||||
git_status: true,
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
pub struct OutlinePanelSettingsContent {
|
||||
/// Whether to show the outline panel button in the status bar.
|
||||
///
|
||||
/// Default: true
|
||||
pub button: Option<bool>,
|
||||
/// Customize default width (in pixels) taken by outline panel
|
||||
///
|
||||
/// Default: 240
|
||||
pub default_width: Option<f32>,
|
||||
/// The position of outline panel
|
||||
///
|
||||
/// Default: left
|
||||
pub dock: Option<OutlinePanelDockPosition>,
|
||||
/// Whether to show file icons in the outline panel.
|
||||
///
|
||||
/// Default: true
|
||||
pub file_icons: Option<bool>,
|
||||
/// Whether to show folder icons or chevrons for directories in the outline panel.
|
||||
///
|
||||
/// Default: true
|
||||
pub folder_icons: Option<bool>,
|
||||
/// Whether to show the git status in the outline panel.
|
||||
///
|
||||
/// Default: true
|
||||
pub git_status: Option<bool>,
|
||||
/// Amount of indentation (in pixels) for nested items.
|
||||
///
|
||||
/// Default: 20
|
||||
pub indent_size: Option<f32>,
|
||||
/// Whether to reveal it in the outline panel automatically,
|
||||
/// when a corresponding project entry becomes active.
|
||||
/// Gitignored entries are never auto revealed.
|
||||
///
|
||||
/// Default: true
|
||||
pub auto_reveal_entries: Option<bool>,
|
||||
/// Whether to fold directories automatically
|
||||
/// when directory has only one directory inside.
|
||||
///
|
||||
/// Default: true
|
||||
pub auto_fold_dirs: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for OutlinePanelSettings {
|
||||
const KEY: Option<&'static str> = Some("outline_panel");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = OutlinePanelSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use anyhow::Result;
|
||||
use gpui::{
|
||||
div, AppContext, InteractiveElement as _, Render, StatefulInteractiveElement as _,
|
||||
Subscription, ViewContext, VisualContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources, SettingsStore};
|
||||
use workspace::{
|
||||
ui::{Label, LabelCommon, LabelSize, Tooltip},
|
||||
ItemHandle, StatusItemView, Workspace,
|
||||
};
|
||||
|
||||
const SHOW_STARTUP_TIME_DURATION: std::time::Duration = std::time::Duration::from_secs(5);
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
PerformanceSettings::register(cx);
|
||||
|
||||
let mut enabled = PerformanceSettings::get_global(cx).show_in_status_bar;
|
||||
let start_time = Instant::now();
|
||||
let mut _observe_workspaces = toggle_status_bar_items(enabled, start_time, cx);
|
||||
|
||||
cx.observe_global::<SettingsStore>(move |cx| {
|
||||
let new_value = PerformanceSettings::get_global(cx).show_in_status_bar;
|
||||
if new_value != enabled {
|
||||
enabled = new_value;
|
||||
_observe_workspaces = toggle_status_bar_items(enabled, start_time, cx);
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn toggle_status_bar_items(
|
||||
enabled: bool,
|
||||
start_time: Instant,
|
||||
cx: &mut AppContext,
|
||||
) -> Option<Subscription> {
|
||||
for window in cx.windows() {
|
||||
if let Some(workspace) = window.downcast::<Workspace>() {
|
||||
workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
toggle_status_bar_item(workspace, enabled, start_time, cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
if enabled {
|
||||
log::info!("performance metrics display enabled");
|
||||
Some(cx.observe_new_views::<Workspace>(move |workspace, cx| {
|
||||
toggle_status_bar_item(workspace, true, start_time, cx);
|
||||
}))
|
||||
} else {
|
||||
log::info!("performance metrics display disabled");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct PerformanceStatusBarItem {
|
||||
display_mode: DisplayMode,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum DisplayMode {
|
||||
StartupTime,
|
||||
Fps,
|
||||
}
|
||||
|
||||
impl PerformanceStatusBarItem {
|
||||
fn new(start_time: Instant, cx: &mut ViewContext<Self>) -> Self {
|
||||
let now = Instant::now();
|
||||
let display_mode = if now < start_time + SHOW_STARTUP_TIME_DURATION {
|
||||
DisplayMode::StartupTime
|
||||
} else {
|
||||
DisplayMode::Fps
|
||||
};
|
||||
|
||||
let this = Self { display_mode };
|
||||
|
||||
if let DisplayMode::StartupTime = display_mode {
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let now = Instant::now();
|
||||
let remaining_duration =
|
||||
(start_time + SHOW_STARTUP_TIME_DURATION).saturating_duration_since(now);
|
||||
cx.background_executor().timer(remaining_duration).await;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.display_mode = DisplayMode::Fps;
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for PerformanceStatusBarItem {
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl gpui::IntoElement {
|
||||
let text = match self.display_mode {
|
||||
DisplayMode::StartupTime => cx
|
||||
.time_to_first_window_draw()
|
||||
.map_or("Pending".to_string(), |duration| {
|
||||
format!("{}ms", duration.as_millis())
|
||||
}),
|
||||
DisplayMode::Fps => cx.fps().map_or("".to_string(), |fps| {
|
||||
format!("{:3} FPS", fps.round() as u32)
|
||||
}),
|
||||
};
|
||||
|
||||
use gpui::ParentElement;
|
||||
let display_mode = self.display_mode;
|
||||
div()
|
||||
.id("performance status")
|
||||
.child(Label::new(text).size(LabelSize::Small))
|
||||
.tooltip(move |cx| match display_mode {
|
||||
DisplayMode::StartupTime => Tooltip::text("Time to first window draw", cx),
|
||||
DisplayMode::Fps => cx
|
||||
.new_view(|cx| {
|
||||
let tooltip = Tooltip::new("Current FPS");
|
||||
if let Some(time_to_first) = cx.time_to_first_window_draw() {
|
||||
tooltip.meta(format!(
|
||||
"Time to first window draw: {}ms",
|
||||
time_to_first.as_millis()
|
||||
))
|
||||
} else {
|
||||
tooltip
|
||||
}
|
||||
})
|
||||
.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl StatusItemView for PerformanceStatusBarItem {
|
||||
fn set_active_pane_item(
|
||||
&mut self,
|
||||
_active_pane_item: Option<&dyn ItemHandle>,
|
||||
_cx: &mut gpui::ViewContext<Self>,
|
||||
) {
|
||||
// This is not currently used.
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_status_bar_item(
|
||||
workspace: &mut Workspace,
|
||||
enabled: bool,
|
||||
start_time: Instant,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
if enabled {
|
||||
workspace.status_bar().update(cx, |bar, cx| {
|
||||
bar.add_right_item(
|
||||
cx.new_view(|cx| PerformanceStatusBarItem::new(start_time, cx)),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
} else {
|
||||
workspace.status_bar().update(cx, |bar, cx| {
|
||||
bar.remove_items_of_type::<PerformanceStatusBarItem>(cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration of the display of performance details.
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
#[serde(default)]
|
||||
pub struct PerformanceSettings {
|
||||
/// Display the time to first window draw and frame rate in the status bar.
|
||||
pub show_in_status_bar: bool,
|
||||
}
|
||||
|
||||
impl Settings for PerformanceSettings {
|
||||
const KEY: Option<&'static str> = Some("performance");
|
||||
|
||||
type FileContent = Self;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
}
|
||||
}
|
||||
@@ -219,7 +219,7 @@ async fn load_shell_environment(
|
||||
);
|
||||
|
||||
let output = smol::process::Command::new(&shell)
|
||||
.args(["-i", "-c", &command])
|
||||
.args(["-l", "-i", "-c", &command])
|
||||
.envs(direnv_environment)
|
||||
.output()
|
||||
.await
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{
|
||||
environment::ProjectEnvironment,
|
||||
lsp_command::{self, *},
|
||||
lsp_ext_command,
|
||||
project_settings::ProjectSettings,
|
||||
project_settings::{LspSettings, ProjectSettings},
|
||||
relativize_path, resolve_path,
|
||||
worktree_store::{WorktreeStore, WorktreeStoreEvent},
|
||||
yarn::YarnPathStore,
|
||||
@@ -26,7 +26,6 @@ use gpui::{
|
||||
Task, WeakModel,
|
||||
};
|
||||
use http_client::{AsyncBody, Error, HttpClient, Request, Response, Uri};
|
||||
use itertools::Itertools;
|
||||
use language::{
|
||||
language_settings::{
|
||||
all_language_settings, language_settings, AllLanguageSettings, LanguageSettings,
|
||||
@@ -3500,7 +3499,7 @@ impl LspStore {
|
||||
.to_owned();
|
||||
let path = if Path::new(path).components().next().is_none()
|
||||
{
|
||||
Arc::from(Path::new("/"))
|
||||
Arc::from(Path::new(worktree_root_path))
|
||||
} else {
|
||||
PathBuf::from(path).into()
|
||||
};
|
||||
@@ -4489,14 +4488,6 @@ impl LspStore {
|
||||
);
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"starting language servers for {language}: {adapters}",
|
||||
adapters = enabled_lsp_adapters
|
||||
.iter()
|
||||
.map(|adapter| adapter.name.0.as_ref())
|
||||
.join(", ")
|
||||
);
|
||||
|
||||
for adapter in &enabled_lsp_adapters {
|
||||
self.start_language_server(worktree, adapter.clone(), language.clone(), cx);
|
||||
}
|
||||
@@ -7044,6 +7035,23 @@ impl HttpClient for BlockedHttpClient {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn language_server_settings<'a, 'b: 'a>(
|
||||
delegate: &'a dyn LspAdapterDelegate,
|
||||
language: &str,
|
||||
cx: &'b AppContext,
|
||||
) -> Option<&'a LspSettings> {
|
||||
ProjectSettings::get(
|
||||
Some(SettingsLocation {
|
||||
worktree_id: delegate.worktree_id(),
|
||||
path: delegate.worktree_root_path(),
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
.lsp
|
||||
.get(language)
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl LspAdapterDelegate for ProjectLspAdapterDelegate {
|
||||
fn show_notification(&self, message: &str, cx: &mut AppContext) {
|
||||
|
||||
@@ -20,7 +20,6 @@ use worktree::{PathChange, UpdatedEntriesSet, Worktree, WorktreeId};
|
||||
use crate::worktree_store::{WorktreeStore, WorktreeStoreEvent};
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
pub struct ProjectSettings {
|
||||
/// Configuration for language servers.
|
||||
///
|
||||
@@ -42,6 +41,7 @@ pub struct ProjectSettings {
|
||||
pub load_direnv: DirenvSettings,
|
||||
|
||||
/// Configuration for session-related features
|
||||
#[serde(default)]
|
||||
pub session: SessionSettings,
|
||||
}
|
||||
|
||||
@@ -59,31 +59,36 @@ pub enum DirenvSettings {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
pub struct GitSettings {
|
||||
/// Whether or not to show the git gutter.
|
||||
///
|
||||
/// Default: tracked_files
|
||||
pub git_gutter: GitGutterSetting,
|
||||
pub git_gutter: Option<GitGutterSetting>,
|
||||
pub gutter_debounce: Option<u64>,
|
||||
/// Whether or not to show git blame data inline in
|
||||
/// the currently focused line.
|
||||
///
|
||||
/// Default: on
|
||||
pub inline_blame: InlineBlameSettings,
|
||||
pub inline_blame: Option<InlineBlameSettings>,
|
||||
}
|
||||
|
||||
impl GitSettings {
|
||||
pub fn inline_blame_enabled(&self) -> bool {
|
||||
#[allow(unknown_lints, clippy::manual_unwrap_or_default)]
|
||||
self.inline_blame.enabled
|
||||
match self.inline_blame {
|
||||
Some(InlineBlameSettings { enabled, .. }) => enabled,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inline_blame_delay(&self) -> Option<Duration> {
|
||||
self.inline_blame
|
||||
.delay_ms
|
||||
.gt(&0)
|
||||
.then(|| Duration::from_millis(self.inline_blame.delay_ms))
|
||||
match self.inline_blame {
|
||||
Some(InlineBlameSettings {
|
||||
delay_ms: Some(delay_ms),
|
||||
..
|
||||
}) if delay_ms > 0 => Some(Duration::from_millis(delay_ms)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,34 +102,28 @@ pub enum GitGutterSetting {
|
||||
Hide,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[serde(default)]
|
||||
pub struct InlineBlameSettings {
|
||||
/// Whether or not to show git blame data inline in
|
||||
/// the currently focused line.
|
||||
///
|
||||
/// Default: true
|
||||
#[serde(default = "true_value")]
|
||||
pub enabled: bool,
|
||||
/// Whether to only show the inline blame information
|
||||
/// after a delay once the cursor stops moving.
|
||||
///
|
||||
/// Default: 0
|
||||
pub delay_ms: u64,
|
||||
pub delay_ms: Option<u64>,
|
||||
/// The minimum column number to show the inline blame information at
|
||||
///
|
||||
/// Default: 0
|
||||
pub min_column: u32,
|
||||
pub min_column: Option<u32>,
|
||||
}
|
||||
|
||||
impl Default for InlineBlameSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
delay_ms: 0,
|
||||
min_column: 0,
|
||||
}
|
||||
}
|
||||
const fn true_value() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
|
||||
@@ -2289,7 +2289,7 @@ impl ProjectPanel {
|
||||
.child(
|
||||
ListItem::new(entry_id.to_proto() as usize)
|
||||
.indent_level(depth)
|
||||
.indent_step_size(settings.indent_size)
|
||||
.indent_step_size(px(settings.indent_size))
|
||||
.selected(is_marked || is_active)
|
||||
.when_some(canonical_path, |this, path| {
|
||||
this.end_slot::<AnyElement>(
|
||||
@@ -2817,7 +2817,7 @@ impl Render for DraggedProjectEntryView {
|
||||
this.bg(cx.theme().colors().background).w(self.width).child(
|
||||
ListItem::new(self.selection.entry_id.to_proto() as usize)
|
||||
.indent_level(self.details.depth)
|
||||
.indent_step_size(settings.indent_size)
|
||||
.indent_step_size(px(settings.indent_size))
|
||||
.child(if let Some(icon) = &self.details.icon {
|
||||
div().child(Icon::from_path(icon.clone()))
|
||||
} else {
|
||||
@@ -2855,7 +2855,7 @@ impl Panel for ProjectPanel {
|
||||
DockPosition::Left | DockPosition::Bottom => ProjectPanelDockPosition::Left,
|
||||
DockPosition::Right => ProjectPanelDockPosition::Right,
|
||||
};
|
||||
settings.dock = dock;
|
||||
settings.dock = Some(dock);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -3029,7 +3029,7 @@ mod tests {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
|
||||
worktree_settings.file_scan_exclusions =
|
||||
vec!["**/.git".to_string(), "**/4/**".to_string()];
|
||||
Some(vec!["**/.git".to_string(), "**/4/**".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4818,10 +4818,10 @@ mod tests {
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
|
||||
worktree_settings.file_scan_exclusions = Vec::new();
|
||||
worktree_settings.file_scan_exclusions = Some(Vec::new());
|
||||
});
|
||||
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
|
||||
project_panel_settings.auto_reveal_entries = false
|
||||
project_panel_settings.auto_reveal_entries = Some(false)
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -4940,7 +4940,7 @@ mod tests {
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
|
||||
project_panel_settings.auto_reveal_entries = true
|
||||
project_panel_settings.auto_reveal_entries = Some(true)
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -5054,10 +5054,10 @@ mod tests {
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
|
||||
worktree_settings.file_scan_exclusions = Vec::new();
|
||||
worktree_settings.file_scan_exclusions = Some(Vec::new());
|
||||
});
|
||||
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
|
||||
project_panel_settings.auto_reveal_entries = false
|
||||
project_panel_settings.auto_reveal_entries = Some(false)
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -5256,7 +5256,7 @@ mod tests {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
|
||||
project_settings.file_scan_exclusions =
|
||||
vec!["excluded_dir".to_string(), "**/.git".to_string()];
|
||||
Some(vec!["excluded_dir".to_string(), "**/.git".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5569,10 +5569,10 @@ mod tests {
|
||||
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
|
||||
project_panel_settings.auto_fold_dirs = false;
|
||||
project_panel_settings.auto_fold_dirs = Some(false);
|
||||
});
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
|
||||
worktree_settings.file_scan_exclusions = Vec::new();
|
||||
worktree_settings.file_scan_exclusions = Some(Vec::new());
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5591,10 +5591,10 @@ mod tests {
|
||||
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
|
||||
project_panel_settings.auto_fold_dirs = false;
|
||||
project_panel_settings.auto_fold_dirs = Some(false);
|
||||
});
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
|
||||
worktree_settings.file_scan_exclusions = Vec::new();
|
||||
worktree_settings.file_scan_exclusions = Some(Vec::new());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ use gpui::Pixels;
|
||||
use schemars::JsonSchema;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
use ui::px;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Copy, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
@@ -11,50 +10,20 @@ pub enum ProjectPanelDockPosition {
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
|
||||
pub struct ProjectPanelSettings {
|
||||
/// Whether to show the project panel button in the status bar.
|
||||
pub button: bool,
|
||||
/// Customize default width (in pixels) taken by project panel
|
||||
pub default_width: Pixels,
|
||||
/// The position of project panel
|
||||
pub dock: ProjectPanelDockPosition,
|
||||
/// Whether to show file icons in the project panel.
|
||||
pub file_icons: bool,
|
||||
/// Whether to show folder icons or chevrons for directories in the project panel.
|
||||
pub folder_icons: bool,
|
||||
/// Whether to show the git status in the project panel.
|
||||
pub git_status: bool,
|
||||
/// Amount of indentation (in pixels) for nested items.
|
||||
pub indent_size: Pixels,
|
||||
/// Whether to reveal it in the project panel automatically,
|
||||
/// when a corresponding project entry becomes active.
|
||||
/// Gitignored entries are never auto revealed.
|
||||
pub indent_size: f32,
|
||||
pub auto_reveal_entries: bool,
|
||||
/// Whether to fold directories automatically
|
||||
/// when directory has only one directory inside.
|
||||
pub auto_fold_dirs: bool,
|
||||
/// Scrollbar-related settings
|
||||
pub scrollbar: ScrollbarSettings,
|
||||
}
|
||||
|
||||
impl Default for ProjectPanelSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
button: true,
|
||||
default_width: px(240.),
|
||||
dock: ProjectPanelDockPosition::Left,
|
||||
file_icons: true,
|
||||
folder_icons: true,
|
||||
git_status: true,
|
||||
indent_size: px(20.),
|
||||
auto_reveal_entries: true,
|
||||
auto_fold_dirs: true,
|
||||
scrollbar: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// When to show the scrollbar in the project panel.
|
||||
///
|
||||
/// Default: always
|
||||
@@ -68,7 +37,7 @@ pub enum ShowScrollbar {
|
||||
Never,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
pub struct ScrollbarSettings {
|
||||
/// When to show the scrollbar in the project panel.
|
||||
///
|
||||
@@ -76,10 +45,63 @@ pub struct ScrollbarSettings {
|
||||
pub show: ShowScrollbar,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
pub struct ScrollbarSettingsContent {
|
||||
/// When to show the scrollbar in the project panel.
|
||||
///
|
||||
/// Default: always
|
||||
pub show: Option<ShowScrollbar>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
pub struct ProjectPanelSettingsContent {
|
||||
/// Whether to show the project panel button in the status bar.
|
||||
///
|
||||
/// Default: true
|
||||
pub button: Option<bool>,
|
||||
/// Customize default width (in pixels) taken by project panel
|
||||
///
|
||||
/// Default: 240
|
||||
pub default_width: Option<f32>,
|
||||
/// The position of project panel
|
||||
///
|
||||
/// Default: left
|
||||
pub dock: Option<ProjectPanelDockPosition>,
|
||||
/// Whether to show file icons in the project panel.
|
||||
///
|
||||
/// Default: true
|
||||
pub file_icons: Option<bool>,
|
||||
/// Whether to show folder icons or chevrons for directories in the project panel.
|
||||
///
|
||||
/// Default: true
|
||||
pub folder_icons: Option<bool>,
|
||||
/// Whether to show the git status in the project panel.
|
||||
///
|
||||
/// Default: true
|
||||
pub git_status: Option<bool>,
|
||||
/// Amount of indentation (in pixels) for nested items.
|
||||
///
|
||||
/// Default: 20
|
||||
pub indent_size: Option<f32>,
|
||||
/// Whether to reveal it in the project panel automatically,
|
||||
/// when a corresponding project entry becomes active.
|
||||
/// Gitignored entries are never auto revealed.
|
||||
///
|
||||
/// Default: true
|
||||
pub auto_reveal_entries: Option<bool>,
|
||||
/// Whether to fold directories automatically
|
||||
/// when directory has only one directory inside.
|
||||
///
|
||||
/// Default: false
|
||||
pub auto_fold_dirs: Option<bool>,
|
||||
/// Scrollbar-related settings
|
||||
pub scrollbar: Option<ScrollbarSettingsContent>,
|
||||
}
|
||||
|
||||
impl Settings for ProjectPanelSettings {
|
||||
const KEY: Option<&'static str> = Some("project_panel");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = ProjectPanelSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
|
||||
@@ -2388,6 +2388,7 @@ message SlashCommandOutputSection {
|
||||
AnchorRange range = 1;
|
||||
string icon_name = 2;
|
||||
string label = 3;
|
||||
optional string path = 4;
|
||||
}
|
||||
|
||||
message ContextOperation {
|
||||
|
||||
@@ -48,6 +48,7 @@ use workspace::{notifications::DetachAndPromptErr, AppState, ModalView, Workspac
|
||||
use crate::open_dev_server_project;
|
||||
use crate::ssh_connections::connect_over_ssh;
|
||||
use crate::ssh_connections::open_ssh_project;
|
||||
use crate::ssh_connections::RemoteSettingsContent;
|
||||
use crate::ssh_connections::SshConnection;
|
||||
use crate::ssh_connections::SshConnectionModal;
|
||||
use crate::ssh_connections::SshProject;
|
||||
@@ -1023,7 +1024,7 @@ impl DevServerProjects {
|
||||
fn update_settings_file(
|
||||
&mut self,
|
||||
cx: &mut ViewContext<Self>,
|
||||
f: impl FnOnce(&mut SshSettings) + Send + Sync + 'static,
|
||||
f: impl FnOnce(&mut RemoteSettingsContent) + Send + Sync + 'static,
|
||||
) {
|
||||
let Some(fs) = self
|
||||
.workspace
|
||||
|
||||
@@ -22,24 +22,8 @@ use ui::{
|
||||
use util::paths::PathWithPosition;
|
||||
use workspace::{AppState, ModalView, Workspace};
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize)]
|
||||
pub struct SshSettings {
|
||||
/// ssh_connections is an array of ssh connections.
|
||||
/// By default this setting is null, which disables the direct ssh connection support.
|
||||
/// You can configure these from `project: Open Remote` in the command palette.
|
||||
/// Zed's ssh support will pull configuration from your ~/.ssh too.
|
||||
/// Examples:
|
||||
/// [
|
||||
/// {
|
||||
/// "host": "example-box",
|
||||
/// "projects": [
|
||||
/// {
|
||||
/// "paths": ["/home/user/code/zed"]
|
||||
/// }
|
||||
/// ]
|
||||
/// }
|
||||
/// ]
|
||||
pub ssh_connections: Option<Vec<SshConnection>>,
|
||||
}
|
||||
|
||||
@@ -78,10 +62,15 @@ pub struct SshProject {
|
||||
pub paths: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct RemoteSettingsContent {
|
||||
pub ssh_connections: Option<Vec<SshConnection>>,
|
||||
}
|
||||
|
||||
impl Settings for SshSettings {
|
||||
const KEY: Option<&'static str> = None;
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = RemoteSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
|
||||
@@ -6,10 +6,8 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct JupyterSettings {
|
||||
/// Default kernels to select for each language.
|
||||
pub kernel_selections: HashMap<String, String>,
|
||||
}
|
||||
|
||||
@@ -22,10 +20,26 @@ impl JupyterSettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
|
||||
pub struct JupyterSettingsContent {
|
||||
/// Default kernels to select for each language.
|
||||
///
|
||||
/// Default: `{}`
|
||||
pub kernel_selections: Option<HashMap<String, String>>,
|
||||
}
|
||||
|
||||
impl Default for JupyterSettingsContent {
|
||||
fn default() -> Self {
|
||||
JupyterSettingsContent {
|
||||
kernel_selections: Some(HashMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings for JupyterSettings {
|
||||
const KEY: Option<&'static str> = Some("jupyter");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = JupyterSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
@@ -37,8 +51,10 @@ impl Settings for JupyterSettings {
|
||||
let mut settings = JupyterSettings::default();
|
||||
|
||||
for value in sources.defaults_and_customizations() {
|
||||
for (k, v) in &value.kernel_selections {
|
||||
settings.kernel_selections.insert(k.clone(), v.clone());
|
||||
if let Some(source) = &value.kernel_selections {
|
||||
for (k, v) in source {
|
||||
settings.kernel_selections.insert(k.clone(), v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,26 +2,22 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
|
||||
#[serde(default)]
|
||||
/// Task-related settings.
|
||||
#[derive(Serialize, Deserialize, PartialEq, Default)]
|
||||
pub(crate) struct TaskSettings {
|
||||
/// Whether to show task status indicator in the status bar. Default: true
|
||||
pub(crate) show_status_indicator: bool,
|
||||
}
|
||||
|
||||
impl Default for TaskSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
show_status_indicator: true,
|
||||
}
|
||||
}
|
||||
/// Task-related settings.
|
||||
#[derive(Serialize, Deserialize, PartialEq, Default, Clone, JsonSchema)]
|
||||
pub(crate) struct TaskSettingsContent {
|
||||
/// Whether to show task status indicator in the status bar. Default: true
|
||||
show_status_indicator: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for TaskSettings {
|
||||
const KEY: Option<&'static str> = Some("task");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = TaskSettingsContent;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
|
||||
@@ -644,7 +644,7 @@ impl<T: Ord + Clone> RangeExt<T> for RangeInclusive<T> {
|
||||
/// This is useful for turning regular alphanumerically sorted sequences as `1-abc, 10, 11-def, .., 2, 21-abc`
|
||||
/// into `1-abc, 2, 10, 11-def, .., 21-abc`
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct NumericPrefixWithSuffix<'a>(Option<u32>, &'a str);
|
||||
pub struct NumericPrefixWithSuffix<'a>(Option<u64>, &'a str);
|
||||
|
||||
impl<'a> NumericPrefixWithSuffix<'a> {
|
||||
pub fn from_numeric_prefixed_str(str: &'a str) -> Self {
|
||||
|
||||
@@ -132,7 +132,7 @@ mod test {
|
||||
let mut custom_digraphs = HashMap::default();
|
||||
custom_digraphs.insert("|-".into(), "⊢".into());
|
||||
custom_digraphs.insert(":)".into(), "👨💻".into());
|
||||
s.custom_digraphs = custom_digraphs;
|
||||
s.custom_digraphs = Some(custom_digraphs);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1184,7 +1184,7 @@ mod test {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<VimSettings>(cx, |s| {
|
||||
s.use_multiline_find = true;
|
||||
s.use_multiline_find = Some(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1226,7 +1226,7 @@ mod test {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<VimSettings>(cx, |s| {
|
||||
s.use_multiline_find = true;
|
||||
s.use_multiline_find = Some(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1268,7 +1268,7 @@ mod test {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<VimSettings>(cx, |s| {
|
||||
s.use_smartcase_find = true;
|
||||
s.use_smartcase_find = Some(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ mod test {
|
||||
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<VimSettings>(cx, |s| {
|
||||
s.use_system_clipboard = UseSystemClipboard::Never
|
||||
s.use_system_clipboard = Some(UseSystemClipboard::Never)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -327,7 +327,7 @@ mod test {
|
||||
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<VimSettings>(cx, |s| {
|
||||
s.use_system_clipboard = UseSystemClipboard::OnYank
|
||||
s.use_system_clipboard = Some(UseSystemClipboard::OnYank)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -584,7 +584,7 @@ mod test {
|
||||
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<VimSettings>(cx, |s| {
|
||||
s.use_system_clipboard = UseSystemClipboard::Never
|
||||
s.use_system_clipboard = Some(UseSystemClipboard::Never)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -630,7 +630,7 @@ mod test {
|
||||
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<VimSettings>(cx, |s| {
|
||||
s.use_system_clipboard = UseSystemClipboard::Never
|
||||
s.use_system_clipboard = Some(UseSystemClipboard::Never)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -659,7 +659,7 @@ mod test {
|
||||
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<VimSettings>(cx, |s| {
|
||||
s.use_system_clipboard = UseSystemClipboard::Never
|
||||
s.use_system_clipboard = Some(UseSystemClipboard::Never)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -707,7 +707,7 @@ mod test {
|
||||
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<VimSettings>(cx, |s| {
|
||||
s.use_system_clipboard = UseSystemClipboard::Never
|
||||
s.use_system_clipboard = Some(UseSystemClipboard::Never)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -294,7 +294,7 @@ mod test {
|
||||
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<EditorSettings>(cx, |s| {
|
||||
s.scroll_beyond_last_line = ScrollBeyondLastLine::Off
|
||||
s.scroll_beyond_last_line = Some(ScrollBeyondLastLine::Off)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -542,7 +542,7 @@ mod test {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = false);
|
||||
store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = Some(false));
|
||||
});
|
||||
|
||||
cx.set_state("ˇhi\nhigh\nhi\n", Mode::Normal);
|
||||
@@ -655,7 +655,7 @@ mod test {
|
||||
|
||||
// check that searching with unable search wrap
|
||||
cx.update_global(|store: &mut SettingsStore, cx| {
|
||||
store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = false);
|
||||
store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = Some(false));
|
||||
});
|
||||
cx.set_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal);
|
||||
cx.simulate_keystrokes("/ c c enter");
|
||||
|
||||
@@ -1300,7 +1300,7 @@ async fn test_command_alias(cx: &mut gpui::TestAppContext) {
|
||||
store.update_user_settings::<WorkspaceSettings>(cx, |s| {
|
||||
let mut aliases = HashMap::default();
|
||||
aliases.insert("Q".to_string(), "upper".to_string());
|
||||
s.command_aliases = aliases
|
||||
s.command_aliases = Some(aliases)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ impl VimTestContext {
|
||||
pub fn new_with_lsp(mut cx: EditorLspTestContext, enabled: bool) -> VimTestContext {
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<VimModeSetting>(cx, |s| *s = VimModeSetting(enabled));
|
||||
store.update_user_settings::<VimModeSetting>(cx, |s| *s = Some(enabled));
|
||||
});
|
||||
settings::KeymapFile::load_asset("keymaps/default-macos.json", cx).unwrap();
|
||||
if enabled {
|
||||
@@ -105,7 +105,7 @@ impl VimTestContext {
|
||||
pub fn enable_vim(&mut self) {
|
||||
self.cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<VimModeSetting>(cx, |s| *s = VimModeSetting(true));
|
||||
store.update_user_settings::<VimModeSetting>(cx, |s| *s = Some(true));
|
||||
});
|
||||
})
|
||||
}
|
||||
@@ -113,7 +113,7 @@ impl VimTestContext {
|
||||
pub fn disable_vim(&mut self) {
|
||||
self.cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings::<VimModeSetting>(cx, |s| *s = VimModeSetting(false));
|
||||
store.update_user_settings::<VimModeSetting>(cx, |s| *s = Some(false));
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@@ -46,8 +46,6 @@ use crate::state::ReplayableAction;
|
||||
/// Whether or not to enable Vim mode.
|
||||
///
|
||||
/// Default: false
|
||||
#[derive(Copy, Clone, Default, Deserialize, Serialize, JsonSchema)]
|
||||
#[serde(default, transparent)]
|
||||
pub struct VimModeSetting(pub bool);
|
||||
|
||||
/// An Action to Switch between modes
|
||||
@@ -101,7 +99,7 @@ pub fn init(cx: &mut AppContext) {
|
||||
let fs = workspace.app_state().fs.clone();
|
||||
let currently_enabled = Vim::enabled(cx);
|
||||
update_settings_file::<VimModeSetting>(fs, cx, move |setting, _| {
|
||||
*setting = VimModeSetting(!currently_enabled);
|
||||
*setting = Some(!currently_enabled)
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1070,10 +1068,12 @@ impl Vim {
|
||||
impl Settings for VimModeSetting {
|
||||
const KEY: Option<&'static str> = Some("vim_mode");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = Option<bool>;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
Ok(sources.user.copied().unwrap_or(*sources.default))
|
||||
Ok(Self(sources.user.copied().flatten().unwrap_or(
|
||||
sources.default.ok_or_else(Self::missing_default)?,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1089,8 +1089,7 @@ pub enum UseSystemClipboard {
|
||||
OnYank,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize)]
|
||||
struct VimSettings {
|
||||
pub toggle_relative_line_numbers: bool,
|
||||
pub use_system_clipboard: UseSystemClipboard,
|
||||
@@ -1099,22 +1098,19 @@ struct VimSettings {
|
||||
pub custom_digraphs: HashMap<String, Arc<str>>,
|
||||
}
|
||||
|
||||
impl Default for VimSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
toggle_relative_line_numbers: false,
|
||||
use_system_clipboard: UseSystemClipboard::Always,
|
||||
use_multiline_find: false,
|
||||
use_smartcase_find: false,
|
||||
custom_digraphs: Default::default(),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
struct VimSettingsContent {
|
||||
pub toggle_relative_line_numbers: Option<bool>,
|
||||
pub use_system_clipboard: Option<UseSystemClipboard>,
|
||||
pub use_multiline_find: Option<bool>,
|
||||
pub use_smartcase_find: Option<bool>,
|
||||
pub custom_digraphs: Option<HashMap<String, Arc<str>>>,
|
||||
}
|
||||
|
||||
impl Settings for VimSettings {
|
||||
const KEY: Option<&'static str> = Some("vim");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = VimSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
|
||||
@@ -177,7 +177,7 @@ impl PickerDelegate for BaseKeymapSelectorDelegate {
|
||||
.report_setting_event("keymap", base_keymap.to_string());
|
||||
|
||||
update_settings_file::<BaseKeymap>(self.fs.clone(), cx, move |setting, _| {
|
||||
*setting = base_keymap;
|
||||
*setting = Some(base_keymap)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -87,15 +87,15 @@ impl BaseKeymap {
|
||||
impl Settings for BaseKeymap {
|
||||
const KEY: Option<&'static str> = Some("base_keymap");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = Option<Self>;
|
||||
|
||||
fn load(
|
||||
sources: SettingsSources<Self::FileContent>,
|
||||
_: &mut gpui::AppContext,
|
||||
) -> anyhow::Result<Self> {
|
||||
if let Some(user_value) = sources.user.copied() {
|
||||
if let Some(Some(user_value)) = sources.user.copied() {
|
||||
return Ok(user_value);
|
||||
}
|
||||
Ok(*sources.default)
|
||||
sources.default.ok_or_else(Self::missing_default)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ impl Render for WelcomePage {
|
||||
this.update_settings::<VimModeSetting>(
|
||||
selection,
|
||||
cx,
|
||||
|setting, value| *setting = VimModeSetting(value),
|
||||
|setting, value| *setting = Some(value),
|
||||
);
|
||||
}),
|
||||
))
|
||||
|
||||
@@ -36,49 +36,20 @@ use util::ResultExt;
|
||||
|
||||
pub const LEADER_UPDATE_THROTTLE: Duration = Duration::from_millis(200);
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize)]
|
||||
pub struct ItemSettings {
|
||||
/// Whether to show the Git file status on a tab item.
|
||||
pub git_status: bool,
|
||||
/// Position of the close button in a tab.
|
||||
pub close_position: ClosePosition,
|
||||
/// Whether to show the file icon for a tab.
|
||||
pub file_icons: bool,
|
||||
}
|
||||
|
||||
impl Default for ItemSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
git_status: false,
|
||||
close_position: ClosePosition::Right,
|
||||
file_icons: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize)]
|
||||
pub struct PreviewTabsSettings {
|
||||
/// Whether to show opened editors as preview tabs.
|
||||
/// Preview tabs do not stay open, are reused until explicitly set to be kept open opened (via double-click or editing) and show file names in italic.
|
||||
pub enabled: bool,
|
||||
/// Whether to open tabs in preview mode when selected from the file finder.
|
||||
pub enable_preview_from_file_finder: bool,
|
||||
/// Whether a preview tab gets replaced when code navigation is used to navigate away from the tab.
|
||||
pub enable_preview_from_code_navigation: bool,
|
||||
}
|
||||
|
||||
impl Default for PreviewTabsSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
enable_preview_from_file_finder: false,
|
||||
enable_preview_from_code_navigation: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ClosePosition {
|
||||
@@ -96,10 +67,43 @@ impl ClosePosition {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ItemSettingsContent {
|
||||
/// Whether to show the Git file status on a tab item.
|
||||
///
|
||||
/// Default: false
|
||||
git_status: Option<bool>,
|
||||
/// Position of the close button in a tab.
|
||||
///
|
||||
/// Default: right
|
||||
close_position: Option<ClosePosition>,
|
||||
/// Whether to show the file icon for a tab.
|
||||
///
|
||||
/// Default: false
|
||||
file_icons: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PreviewTabsSettingsContent {
|
||||
/// Whether to show opened editors as preview tabs.
|
||||
/// Preview tabs do not stay open, are reused until explicitly set to be kept open opened (via double-click or editing) and show file names in italic.
|
||||
///
|
||||
/// Default: true
|
||||
enabled: Option<bool>,
|
||||
/// Whether to open tabs in preview mode when selected from the file finder.
|
||||
///
|
||||
/// Default: false
|
||||
enable_preview_from_file_finder: Option<bool>,
|
||||
/// Whether a preview tab gets replaced when code navigation is used to navigate away from the tab.
|
||||
///
|
||||
/// Default: false
|
||||
enable_preview_from_code_navigation: Option<bool>,
|
||||
}
|
||||
|
||||
impl Settings for ItemSettings {
|
||||
const KEY: Option<&'static str> = Some("tabs");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = ItemSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
@@ -109,7 +113,7 @@ impl Settings for ItemSettings {
|
||||
impl Settings for PreviewTabsSettings {
|
||||
const KEY: Option<&'static str> = Some("preview_tabs");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = PreviewTabsSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
|
||||
@@ -4644,7 +4644,7 @@ fn notify_if_database_failed(workspace: WindowHandle<Workspace>, cx: &mut AsyncA
|
||||
|cx| {
|
||||
cx.new_view(|_| {
|
||||
MessageNotification::new("Failed to load the database file.")
|
||||
.with_click_message("Click to let us know about this error")
|
||||
.with_click_message("File an issue")
|
||||
.on_click(|cx| cx.open_url(REPORT_ISSUE_URL))
|
||||
})
|
||||
},
|
||||
@@ -6465,7 +6465,7 @@ mod tests {
|
||||
item.update(cx, |item, cx| {
|
||||
SettingsStore::update_global(cx, |settings, cx| {
|
||||
settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
|
||||
settings.autosave = AutosaveSetting::OnWindowChange;
|
||||
settings.autosave = Some(AutosaveSetting::OnWindowChange);
|
||||
})
|
||||
});
|
||||
item.is_dirty = true;
|
||||
@@ -6485,7 +6485,7 @@ mod tests {
|
||||
cx.focus_self();
|
||||
SettingsStore::update_global(cx, |settings, cx| {
|
||||
settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
|
||||
settings.autosave = AutosaveSetting::OnFocusChange;
|
||||
settings.autosave = Some(AutosaveSetting::OnFocusChange);
|
||||
})
|
||||
});
|
||||
item.is_dirty = true;
|
||||
@@ -6508,7 +6508,7 @@ mod tests {
|
||||
item.update(cx, |item, cx| {
|
||||
SettingsStore::update_global(cx, |settings, cx| {
|
||||
settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
|
||||
settings.autosave = AutosaveSetting::AfterDelay { milliseconds: 500 };
|
||||
settings.autosave = Some(AutosaveSetting::AfterDelay { milliseconds: 500 });
|
||||
})
|
||||
});
|
||||
item.is_dirty = true;
|
||||
@@ -6527,7 +6527,7 @@ mod tests {
|
||||
item.update(cx, |item, cx| {
|
||||
SettingsStore::update_global(cx, |settings, cx| {
|
||||
settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
|
||||
settings.autosave = AutosaveSetting::OnFocusChange;
|
||||
settings.autosave = Some(AutosaveSetting::OnFocusChange);
|
||||
})
|
||||
});
|
||||
item.is_dirty = true;
|
||||
|
||||
@@ -5,58 +5,22 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Deserialize)]
|
||||
pub struct WorkspaceSettings {
|
||||
/// Scale by which to zoom the active pane.
|
||||
/// When set to 1.0, the active pane has the same size as others,
|
||||
/// but when set to a larger value, the active pane takes up more space.
|
||||
pub active_pane_magnification: f32,
|
||||
/// Direction to split horizontally.
|
||||
pub pane_split_direction_horizontal: PaneSplitDirectionHorizontal,
|
||||
/// Direction to split vertically.
|
||||
pub pane_split_direction_vertical: PaneSplitDirectionVertical,
|
||||
/// Centered layout related settings.
|
||||
pub centered_layout: CenteredLayoutSettings,
|
||||
/// Whether or not to prompt the user to confirm before closing the application.
|
||||
pub confirm_quit: bool,
|
||||
/// Whether or not to show the call status icon in the status bar.
|
||||
pub show_call_status_icon: bool,
|
||||
/// When to automatically save edited buffers.
|
||||
pub autosave: AutosaveSetting,
|
||||
/// Controls previous session restoration in freshly launched Zed instance.
|
||||
pub restore_on_startup: RestoreOnStartupBehavior,
|
||||
/// The size of the workspace split drop targets on the outer edges.
|
||||
/// Given as a fraction that will be multiplied by the smaller dimension of the workspace.
|
||||
pub drop_target_size: f32,
|
||||
/// Whether to close the window when using 'close active item' on a workspace with no tabs
|
||||
pub when_closing_with_no_tabs: CloseWindowWhenNoItems,
|
||||
/// Whether to use the system provided dialogs for Open and Save As.
|
||||
/// When set to false, Zed will use the built-in keyboard-first pickers.
|
||||
pub use_system_path_prompts: bool,
|
||||
/// Aliases for the command palette. When you type a key in this map,
|
||||
/// it will be assumed to equal the value.
|
||||
pub command_aliases: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Default for WorkspaceSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
active_pane_magnification: 1.0,
|
||||
pane_split_direction_horizontal: PaneSplitDirectionHorizontal::Up,
|
||||
pane_split_direction_vertical: PaneSplitDirectionVertical::Left,
|
||||
centered_layout: CenteredLayoutSettings::default(),
|
||||
confirm_quit: false,
|
||||
show_call_status_icon: true,
|
||||
autosave: AutosaveSetting::Off,
|
||||
restore_on_startup: RestoreOnStartupBehavior::default(),
|
||||
drop_target_size: 0.2,
|
||||
when_closing_with_no_tabs: CloseWindowWhenNoItems::default(),
|
||||
use_system_path_prompts: true,
|
||||
command_aliases: HashMap::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CloseWindowWhenNoItems {
|
||||
@@ -91,22 +55,77 @@ pub enum RestoreOnStartupBehavior {
|
||||
LastSession,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct WorkspaceSettingsContent {
|
||||
/// Scale by which to zoom the active pane.
|
||||
/// When set to 1.0, the active pane has the same size as others,
|
||||
/// but when set to a larger value, the active pane takes up more space.
|
||||
///
|
||||
/// Default: `1.0`
|
||||
pub active_pane_magnification: Option<f32>,
|
||||
// Direction to split horizontally.
|
||||
//
|
||||
// Default: "up"
|
||||
pub pane_split_direction_horizontal: Option<PaneSplitDirectionHorizontal>,
|
||||
// Direction to split vertically.
|
||||
//
|
||||
// Default: "left"
|
||||
pub pane_split_direction_vertical: Option<PaneSplitDirectionVertical>,
|
||||
// Centered layout related settings.
|
||||
pub centered_layout: Option<CenteredLayoutSettings>,
|
||||
/// Whether or not to prompt the user to confirm before closing the application.
|
||||
///
|
||||
/// Default: false
|
||||
pub confirm_quit: Option<bool>,
|
||||
/// Whether or not to show the call status icon in the status bar.
|
||||
///
|
||||
/// Default: true
|
||||
pub show_call_status_icon: Option<bool>,
|
||||
/// When to automatically save edited buffers.
|
||||
///
|
||||
/// Default: off
|
||||
pub autosave: Option<AutosaveSetting>,
|
||||
/// Controls previous session restoration in freshly launched Zed instance.
|
||||
/// Values: none, last_workspace, last_session
|
||||
/// Default: last_session
|
||||
pub restore_on_startup: Option<RestoreOnStartupBehavior>,
|
||||
/// The size of the workspace split drop targets on the outer edges.
|
||||
/// Given as a fraction that will be multiplied by the smaller dimension of the workspace.
|
||||
///
|
||||
/// Default: `0.2` (20% of the smaller dimension of the workspace)
|
||||
pub drop_target_size: Option<f32>,
|
||||
/// Whether to close the window when using 'close active item' on a workspace with no tabs
|
||||
///
|
||||
/// Default: auto ("on" on macOS, "off" otherwise)
|
||||
pub when_closing_with_no_tabs: Option<CloseWindowWhenNoItems>,
|
||||
/// Whether to use the system provided dialogs for Open and Save As.
|
||||
/// When set to false, Zed will use the built-in keyboard-first pickers.
|
||||
///
|
||||
/// Default: true
|
||||
pub use_system_path_prompts: Option<bool>,
|
||||
/// Aliases for the command palette. When you type a key in this map,
|
||||
/// it will be assumed to equal the value.
|
||||
///
|
||||
/// Default: true
|
||||
pub command_aliases: Option<HashMap<String, String>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct TabBarSettings {
|
||||
/// Whether or not to show the tab bar in the editor.
|
||||
pub show: bool,
|
||||
/// Whether or not to show the navigation history buttons in the tab bar.
|
||||
pub show_nav_history_buttons: bool,
|
||||
}
|
||||
|
||||
impl Default for TabBarSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
show_nav_history_buttons: true,
|
||||
show: true,
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct TabBarSettingsContent {
|
||||
/// Whether or not to show the tab bar in the editor.
|
||||
///
|
||||
/// Default: true
|
||||
pub show: Option<bool>,
|
||||
/// Whether or not to show the navigation history buttons in the tab bar.
|
||||
///
|
||||
/// Default: true
|
||||
pub show_nav_history_buttons: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
@@ -144,26 +163,17 @@ pub struct CenteredLayoutSettings {
|
||||
///
|
||||
/// Default: 0.2
|
||||
pub left_padding: Option<f32>,
|
||||
/// The relative width of the right padding of the central pane from the
|
||||
/// workspace when the centered layout is used.
|
||||
// The relative width of the right padding of the central pane from the
|
||||
// workspace when the centered layout is used.
|
||||
///
|
||||
/// Default: 0.2
|
||||
pub right_padding: Option<f32>,
|
||||
}
|
||||
|
||||
impl Default for CenteredLayoutSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
left_padding: Some(0.2),
|
||||
right_padding: Some(0.2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings for WorkspaceSettings {
|
||||
const KEY: Option<&'static str> = None;
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = WorkspaceSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
@@ -173,7 +183,7 @@ impl Settings for WorkspaceSettings {
|
||||
impl Settings for TabBarSettings {
|
||||
const KEY: Option<&'static str> = Some("tab_bar");
|
||||
|
||||
type FileContent = Self;
|
||||
type FileContent = TabBarSettingsContent;
|
||||
|
||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
|
||||
sources.json_merge()
|
||||
|
||||
@@ -25,8 +25,7 @@ impl WorktreeSettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(default)]
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct WorktreeSettingsContent {
|
||||
/// Completely ignore files matching globs from `file_scan_exclusions`
|
||||
///
|
||||
@@ -40,42 +39,12 @@ pub struct WorktreeSettingsContent {
|
||||
/// "**/.classpath",
|
||||
/// "**/.settings"
|
||||
/// ]
|
||||
pub file_scan_exclusions: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub file_scan_exclusions: Option<Vec<String>>,
|
||||
|
||||
/// Treat the files matching these globs as `.env` files.
|
||||
/// Default: [ "**/.env*" ]
|
||||
pub private_files: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for WorktreeSettingsContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
private_files: [
|
||||
"**/.env*",
|
||||
"**/*.pem",
|
||||
"**/*.key",
|
||||
"**/*.cert",
|
||||
"**/*.crt",
|
||||
"**/secrets.yml",
|
||||
]
|
||||
.into_iter()
|
||||
.map(str::to_owned)
|
||||
.collect(),
|
||||
file_scan_exclusions: [
|
||||
"**/.git",
|
||||
"**/.svn",
|
||||
"**/.hg",
|
||||
"**/CVS",
|
||||
"**/.DS_Store",
|
||||
"**/Thumbs.db",
|
||||
"**/.classpath",
|
||||
"**/.settings",
|
||||
]
|
||||
.into_iter()
|
||||
.map(str::to_owned)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
pub private_files: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl Settings for WorktreeSettings {
|
||||
@@ -88,8 +57,8 @@ impl Settings for WorktreeSettings {
|
||||
_: &mut AppContext,
|
||||
) -> anyhow::Result<Self> {
|
||||
let result: WorktreeSettingsContent = sources.json_merge()?;
|
||||
let mut file_scan_exclusions = result.file_scan_exclusions;
|
||||
let mut private_files = result.private_files;
|
||||
let mut file_scan_exclusions = result.file_scan_exclusions.unwrap_or_default();
|
||||
let mut private_files = result.private_files.unwrap_or_default();
|
||||
file_scan_exclusions.sort();
|
||||
private_files.sort();
|
||||
Ok(Self {
|
||||
|
||||
@@ -673,7 +673,7 @@ async fn test_rescan_with_gitignore(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
|
||||
project_settings.file_scan_exclusions = Vec::new();
|
||||
project_settings.file_scan_exclusions = Some(Vec::new());
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -910,7 +910,7 @@ async fn test_file_scan_exclusions(cx: &mut TestAppContext) {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
|
||||
project_settings.file_scan_exclusions =
|
||||
vec!["**/foo/**".to_string(), "**/.DS_Store".to_string()];
|
||||
Some(vec!["**/foo/**".to_string(), "**/.DS_Store".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -945,7 +945,8 @@ async fn test_file_scan_exclusions(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
|
||||
project_settings.file_scan_exclusions = vec!["**/node_modules/**".to_string()];
|
||||
project_settings.file_scan_exclusions =
|
||||
Some(vec!["**/node_modules/**".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1008,11 +1009,11 @@ async fn test_fs_events_in_exclusions(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
|
||||
project_settings.file_scan_exclusions = vec![
|
||||
project_settings.file_scan_exclusions = Some(vec![
|
||||
"**/.git".to_string(),
|
||||
"node_modules/".to_string(),
|
||||
"build_output".to_string(),
|
||||
];
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1996,7 +1996,7 @@ mod tests {
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
|
||||
project_settings.file_scan_exclusions =
|
||||
vec!["excluded_dir".to_string(), "**/.git".to_string()];
|
||||
Some(vec!["excluded_dir".to_string(), "**/.git".to_string()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -52,7 +52,7 @@ Prettier will also be used for TypeScript files by default. To disable this:
|
||||
{
|
||||
"lsp": {
|
||||
"vtsls": {
|
||||
"initialization_options": {
|
||||
"settings": {
|
||||
// For TypeScript:
|
||||
"typescript": { "tsserver": { "maxTsServerMemory": 16184 } },
|
||||
// For JavaScript:
|
||||
|
||||
@@ -12,7 +12,7 @@ So, Zed's vim mode does not replicate Vim one-to-one, but it meshes Vim's modal
|
||||
|
||||
## Enabling and disabling vim mode
|
||||
|
||||
When you first open Zed, a checkbox will appear on the welcome screen, allowing you to enable vim mode.
|
||||
When you first open Zed, you'll see a checkbox on the welcome screen that allows you to enable vim mode.
|
||||
|
||||
If you missed this, you can toggle vim mode on or off anytime by opening the command palette and using the workspace command `toggle vim mode`.
|
||||
|
||||
@@ -83,7 +83,7 @@ ctrl-x ctrl-z Hides all suggestions
|
||||
:Ext[ensions] Open the extensions window
|
||||
```
|
||||
|
||||
Vim mode uses Zed to define concepts like "brackets" (for the `%` key) and "words" (for motions like `w` and `e`). This does lead to some differences, but they are mostly positive. For example `%` considers `|` to be a bracket in languages like Rust; and `w` considers `$` to be a word-character in languages like Javascript.
|
||||
Vim mode uses Zed to define concepts like "brackets" (for the `%` key) and "words" (for motions like `w` and `e`). This does lead to some differences, but they are mostly positive. For example `%` considers `|` to be a bracket in languages like Rust; and `w` considers `$` to be a word-character in languages like JavaScript.
|
||||
|
||||
Vim mode emulates visual block mode using Zed's multiple cursor support. This again leads to some differences, but is much more powerful.
|
||||
|
||||
@@ -129,11 +129,13 @@ For vim-specific shortcuts, you may find the following template a good place to
|
||||
|
||||
If you would like to emulate vim's `map` (`nmap` etc.) commands you can bind to the [`workspace::SendKeystrokes`](./key-bindings.md#remapping-keys) action in the correct context.
|
||||
|
||||
You can see the bindings that are enabled by default in vim mode [here](https://github.com/zed-industries/zed/blob/main/assets/keymaps/vim.json).
|
||||
Check out the [bindings that are enabled by default in vim mode](https://github.com/zed-industries/zed/blob/main/assets/keymaps/vim.json).
|
||||
|
||||
### Contexts
|
||||
|
||||
Zed's keyboard bindings are evaluated only when the `"context"` matches the location you are in on the screen. Locations are nested, so when you're editing you're in the `"Workspace"` location is at the top, containing a `"Pane"` which contains an `"Editor"`. Contexts are matched only on one level at a time. So it is possible to combine `Editor && vim_mode == normal`, but `Workspace && vim_mode == normal` will never match because we set the vim context at the `Editor` level.
|
||||
Zed's keyboard bindings are evaluated only when the `"context"` matches the location you are in on the screen. Locations are nested, so when you're editing, you're in the `"Workspace"` location, which is at the top, containing a `"Pane"` that contains an `"Editor"`.
|
||||
|
||||
Contexts are matched only on one level at a time. So, it is possible to combine `Editor && vim_mode == normal`, but `Workspace && vim_mode == normal` will never match because we set the vim context at the `Editor` level.
|
||||
|
||||
Vim mode adds several contexts to the `Editor`:
|
||||
|
||||
@@ -164,13 +166,13 @@ If you're using vim mode on Linux or Windows, you may find it overrides keybindi
|
||||
|
||||
Vim mode allows you to enable Zed’s command palette with `:`. This means that you can use vim's command palette to run any action that Zed supports.
|
||||
|
||||
Additionally, vim mode contains a number of aliases for popular vim commands to ensure that muscle memory works. For example `:w<enter>` will save the file.
|
||||
Additionally, vim mode contains a number of aliases for popular Vim commands to ensure that muscle memory works. For example, `:w<enter>` will save the file.
|
||||
|
||||
We do not (yet) emulate the full power of vim’s command line, in particular, we do not support arguments to commands yet. Please reach out on [GitHub](https://github.com/zed-industries/zed) as you find things that are missing from the command palette.
|
||||
We do not (yet) emulate the full power of Vim’s command line, in particular, we do not support arguments to commands yet. Please [file issues on GitHub](https://github.com/zed-industries/zed) as you find things that are missing from the command palette.
|
||||
|
||||
As mentioned above, one thing to be aware of is that the regex engine is slightly different from vim's in `:%s/a/b`.
|
||||
|
||||
Currently supported vim-specific commands:
|
||||
Currently supported Vim-specific commands:
|
||||
|
||||
```
|
||||
# window management
|
||||
@@ -296,7 +298,7 @@ There are also a few Zed settings that you may also enjoy if you use vim mode:
|
||||
}
|
||||
```
|
||||
|
||||
If you want to navigate between the editor and docks (terminal, project panel, AI assistant, ...) just like you navigate between splits you can use the following key bindings:
|
||||
If you want to navigate between the editor and docks (terminal, project panel, AI assistant panel, etc...), just like you navigate between splits, you can use the following key bindings:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -366,4 +368,4 @@ Notably:
|
||||
|
||||
To help with the transition, the command palette will fix parentheses and replace groups for you when you run `:%s//`. So `%s:/\(a\)(b)/\1/` will be converted into a search for "(a)\(b\)" and a replacement of "$1".
|
||||
|
||||
For the full syntax supported by Zed's regex engine see the [regex crate documentation](https://docs.rs/regex/latest/regex/#syntax).
|
||||
For the full syntax supported by Zed's regex engine [see the regex crate documentation](https://docs.rs/regex/latest/regex/#syntax).
|
||||
|
||||
4
script/update_top_ranking_issues/poetry.lock
generated
4
script/update_top_ranking_issues/poetry.lock
generated
@@ -529,5 +529,5 @@ files = [
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "3.12.5"
|
||||
content-hash = "3e6aa4dc758eb933f7e2d1a305d1e397b13a960ac4846ef54c5a11b906b77015"
|
||||
python-versions = "3.12.6"
|
||||
content-hash = "7827704e06a8c195297507e0d05e7a7c3843ed299bd353f31570ee4c435c6896"
|
||||
|
||||
@@ -8,7 +8,7 @@ readme = "README.md"
|
||||
[tool.poetry.dependencies]
|
||||
mypy = "1.6.0"
|
||||
PyGithub = "1.55"
|
||||
python = "3.12.5"
|
||||
python = "3.12.6"
|
||||
pytz = "2022.1"
|
||||
typer = "0.9.0"
|
||||
types-pytz = "2023.3.1.1"
|
||||
|
||||
Reference in New Issue
Block a user