1mod agent;
2mod editor;
3mod extension;
4mod fallible_options;
5mod language;
6mod language_model;
7pub mod merge_from;
8mod project;
9mod serde_helper;
10mod terminal;
11mod theme;
12mod title_bar;
13mod workspace;
14
15pub use agent::*;
16pub use editor::*;
17pub use extension::*;
18pub use fallible_options::*;
19pub use language::*;
20pub use language_model::*;
21pub use merge_from::MergeFrom as MergeFromTrait;
22pub use project::*;
23use serde::de::DeserializeOwned;
24pub use serde_helper::{
25 serialize_f32_with_two_decimal_places, serialize_optional_f32_with_two_decimal_places,
26};
27use settings_json::parse_json_with_comments;
28pub use terminal::*;
29pub use theme::*;
30pub use title_bar::*;
31pub use workspace::*;
32
33use collections::{HashMap, IndexMap};
34use schemars::JsonSchema;
35use serde::{Deserialize, Serialize};
36use settings_macros::{MergeFrom, with_fallible_options};
37
38/// Defines a settings override struct where each field is
39/// `Option<Box<SettingsContent>>`, along with:
40/// - `OVERRIDE_KEYS`: a `&[&str]` of the field names (the JSON keys)
41/// - `get_by_key(&self, key) -> Option<&SettingsContent>`: accessor by key
42///
43/// The field list is the single source of truth for the override key strings.
44macro_rules! settings_overrides {
45 (
46 $(#[$attr:meta])*
47 pub struct $name:ident { $($field:ident),* $(,)? }
48 ) => {
49 $(#[$attr])*
50 pub struct $name {
51 $(pub $field: Option<Box<SettingsContent>>,)*
52 }
53
54 impl $name {
55 /// The JSON override keys, derived from the field names on this struct.
56 pub const OVERRIDE_KEYS: &[&str] = &[$(stringify!($field)),*];
57
58 /// Look up an override by its JSON key name.
59 pub fn get_by_key(&self, key: &str) -> Option<&SettingsContent> {
60 match key {
61 $(stringify!($field) => self.$field.as_deref(),)*
62 _ => None,
63 }
64 }
65 }
66 }
67}
68use std::collections::{BTreeMap, BTreeSet};
69use std::hash::Hash;
70use std::sync::Arc;
71pub use util::serde::default_true;
72
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub enum ParseStatus {
75 /// Settings were parsed successfully
76 Success,
77 /// Settings failed to parse
78 Failed { error: String },
79}
80
81#[with_fallible_options]
82#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
83pub struct SettingsContent {
84 #[serde(flatten)]
85 pub project: ProjectSettingsContent,
86
87 #[serde(flatten)]
88 pub theme: Box<ThemeSettingsContent>,
89
90 #[serde(flatten)]
91 pub extension: ExtensionSettingsContent,
92
93 #[serde(flatten)]
94 pub workspace: WorkspaceSettingsContent,
95
96 #[serde(flatten)]
97 pub editor: EditorSettingsContent,
98
99 #[serde(flatten)]
100 pub remote: RemoteSettingsContent,
101
102 /// Settings related to the file finder.
103 pub file_finder: Option<FileFinderSettingsContent>,
104
105 pub git_panel: Option<GitPanelSettingsContent>,
106
107 pub tabs: Option<ItemSettingsContent>,
108 pub tab_bar: Option<TabBarSettingsContent>,
109 pub status_bar: Option<StatusBarSettingsContent>,
110
111 pub preview_tabs: Option<PreviewTabsSettingsContent>,
112
113 pub agent: Option<AgentSettingsContent>,
114 pub agent_servers: Option<AllAgentServersSettings>,
115
116 /// Configuration of audio in Zed.
117 pub audio: Option<AudioSettingsContent>,
118
119 /// Whether or not to automatically check for updates.
120 ///
121 /// Default: true
122 pub auto_update: Option<bool>,
123
124 /// This base keymap settings adjusts the default keybindings in Zed to be similar
125 /// to other common code editors. By default, Zed's keymap closely follows VSCode's
126 /// keymap, with minor adjustments, this corresponds to the "VSCode" setting.
127 ///
128 /// Default: VSCode
129 pub base_keymap: Option<BaseKeymapContent>,
130
131 /// Configuration for the collab panel visual settings.
132 pub collaboration_panel: Option<PanelSettingsContent>,
133
134 pub debugger: Option<DebuggerSettingsContent>,
135
136 /// Configuration for Diagnostics-related features.
137 pub diagnostics: Option<DiagnosticsSettingsContent>,
138
139 /// Configuration for Git-related features
140 pub git: Option<GitSettings>,
141
142 /// Common language server settings.
143 pub global_lsp_settings: Option<GlobalLspSettingsContent>,
144
145 /// The settings for the image viewer.
146 pub image_viewer: Option<ImageViewerSettingsContent>,
147
148 pub repl: Option<ReplSettingsContent>,
149
150 /// Whether or not to enable Helix mode.
151 ///
152 /// Default: false
153 pub helix_mode: Option<bool>,
154
155 pub journal: Option<JournalSettingsContent>,
156
157 /// A map of log scopes to the desired log level.
158 /// Useful for filtering out noisy logs or enabling more verbose logging.
159 ///
160 /// Example: {"log": {"client": "warn"}}
161 pub log: Option<HashMap<String, String>>,
162
163 pub line_indicator_format: Option<LineIndicatorFormat>,
164
165 pub language_models: Option<AllLanguageModelSettingsContent>,
166
167 pub outline_panel: Option<OutlinePanelSettingsContent>,
168
169 pub project_panel: Option<ProjectPanelSettingsContent>,
170
171 /// Configuration for the Message Editor
172 pub message_editor: Option<MessageEditorSettings>,
173
174 /// Configuration for Node-related features
175 pub node: Option<NodeBinarySettings>,
176
177 /// Configuration for the Notification Panel
178 pub notification_panel: Option<NotificationPanelSettingsContent>,
179
180 pub proxy: Option<String>,
181
182 /// The URL of the Zed server to connect to.
183 pub server_url: Option<String>,
184
185 /// Configuration for session-related features
186 pub session: Option<SessionSettingsContent>,
187 /// Control what info is collected by Zed.
188 pub telemetry: Option<TelemetrySettingsContent>,
189
190 /// Configuration of the terminal in Zed.
191 pub terminal: Option<TerminalSettingsContent>,
192
193 pub title_bar: Option<TitleBarSettingsContent>,
194
195 /// Whether or not to enable Vim mode.
196 ///
197 /// Default: false
198 pub vim_mode: Option<bool>,
199
200 // Settings related to calls in Zed
201 pub calls: Option<CallSettingsContent>,
202
203 /// Settings for the which-key popup.
204 pub which_key: Option<WhichKeySettingsContent>,
205
206 /// Settings related to Vim mode in Zed.
207 pub vim: Option<VimSettingsContent>,
208
209 /// Number of lines to search for modelines at the beginning and end of files.
210 /// Modelines contain editor directives (e.g., vim/emacs settings) that configure
211 /// the editor behavior for specific files.
212 ///
213 /// Default: 5
214 pub modeline_lines: Option<usize>,
215}
216
217impl SettingsContent {
218 pub fn languages_mut(&mut self) -> &mut HashMap<String, LanguageSettingsContent> {
219 &mut self.project.all_languages.languages.0
220 }
221}
222
223// These impls are there to optimize builds by avoiding monomorphization downstream. Yes, they're repetitive, but using default impls
224// break the optimization, for whatever reason.
225pub trait RootUserSettings: Sized + DeserializeOwned {
226 fn parse_json(json: &str) -> (Option<Self>, ParseStatus);
227 fn parse_json_with_comments(json: &str) -> anyhow::Result<Self>;
228}
229
230impl RootUserSettings for SettingsContent {
231 fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
232 fallible_options::parse_json(json)
233 }
234 fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
235 parse_json_with_comments(json)
236 }
237}
238// Explicit opt-in instead of blanket impl to avoid monomorphizing downstream. Just a hunch though.
239impl RootUserSettings for Option<SettingsContent> {
240 fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
241 fallible_options::parse_json(json)
242 }
243 fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
244 parse_json_with_comments(json)
245 }
246}
247impl RootUserSettings for UserSettingsContent {
248 fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
249 fallible_options::parse_json(json)
250 }
251 fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
252 parse_json_with_comments(json)
253 }
254}
255
256settings_overrides! {
257 #[with_fallible_options]
258 #[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
259 pub struct ReleaseChannelOverrides { dev, nightly, preview, stable }
260}
261
262settings_overrides! {
263 #[with_fallible_options]
264 #[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
265 pub struct PlatformOverrides { macos, linux, windows }
266}
267
268/// Determines what settings a profile starts from before applying its overrides.
269#[derive(
270 Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom,
271)]
272#[serde(rename_all = "snake_case")]
273pub enum ProfileBase {
274 /// Apply profile settings on top of the user's current settings.
275 #[default]
276 User,
277 /// Apply profile settings on top of Zed's default settings, ignoring user customizations.
278 Default,
279}
280
281/// A named settings profile that can temporarily override settings.
282#[with_fallible_options]
283#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
284pub struct SettingsProfile {
285 /// What base settings to start from before applying this profile's overrides.
286 ///
287 /// - `user`: Apply on top of user's settings (default)
288 /// - `default`: Apply on top of Zed's default settings, ignoring user customizations
289 #[serde(default)]
290 pub base: ProfileBase,
291
292 /// The settings overrides for this profile.
293 #[serde(default)]
294 pub settings: Box<SettingsContent>,
295}
296
297#[with_fallible_options]
298#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
299pub struct UserSettingsContent {
300 #[serde(flatten)]
301 pub content: Box<SettingsContent>,
302
303 #[serde(flatten)]
304 pub release_channel_overrides: ReleaseChannelOverrides,
305
306 #[serde(flatten)]
307 pub platform_overrides: PlatformOverrides,
308
309 #[serde(default)]
310 pub profiles: IndexMap<String, SettingsProfile>,
311}
312
313pub struct ExtensionsSettingsContent {
314 pub all_languages: AllLanguageSettingsContent,
315}
316
317/// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
318///
319/// Default: VSCode
320#[derive(
321 Copy,
322 Clone,
323 Debug,
324 Serialize,
325 Deserialize,
326 JsonSchema,
327 MergeFrom,
328 PartialEq,
329 Eq,
330 Default,
331 strum::VariantArray,
332)]
333pub enum BaseKeymapContent {
334 #[default]
335 VSCode,
336 JetBrains,
337 SublimeText,
338 Atom,
339 TextMate,
340 Emacs,
341 Cursor,
342 None,
343}
344
345impl strum::VariantNames for BaseKeymapContent {
346 const VARIANTS: &'static [&'static str] = &[
347 "VSCode",
348 "JetBrains",
349 "Sublime Text",
350 "Atom",
351 "TextMate",
352 "Emacs",
353 "Cursor",
354 "None",
355 ];
356}
357
358/// Configuration of audio in Zed.
359#[with_fallible_options]
360#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)]
361pub struct AudioSettingsContent {
362 /// Automatically increase or decrease you microphone's volume. This affects how
363 /// loud you sound to others.
364 ///
365 /// Recommended: off (default)
366 /// Microphones are too quite in zed, until everyone is on experimental
367 /// audio and has auto speaker volume on this will make you very loud
368 /// compared to other speakers.
369 #[serde(rename = "experimental.auto_microphone_volume")]
370 pub auto_microphone_volume: Option<bool>,
371 /// Remove background noises. Works great for typing, cars, dogs, AC. Does
372 /// not work well on music.
373 /// Select specific output audio device.
374 #[serde(rename = "experimental.output_audio_device")]
375 pub output_audio_device: Option<AudioOutputDeviceName>,
376 /// Select specific input audio device.
377 #[serde(rename = "experimental.input_audio_device")]
378 pub input_audio_device: Option<AudioInputDeviceName>,
379}
380
381#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq)]
382#[serde(transparent)]
383pub struct AudioOutputDeviceName(pub Option<String>);
384
385impl AsRef<Option<String>> for AudioInputDeviceName {
386 fn as_ref(&self) -> &Option<String> {
387 &self.0
388 }
389}
390
391impl From<Option<String>> for AudioInputDeviceName {
392 fn from(value: Option<String>) -> Self {
393 Self(value)
394 }
395}
396
397#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq)]
398#[serde(transparent)]
399pub struct AudioInputDeviceName(pub Option<String>);
400
401impl AsRef<Option<String>> for AudioOutputDeviceName {
402 fn as_ref(&self) -> &Option<String> {
403 &self.0
404 }
405}
406
407impl From<Option<String>> for AudioOutputDeviceName {
408 fn from(value: Option<String>) -> Self {
409 Self(value)
410 }
411}
412
413/// Control what info is collected by Zed.
414#[with_fallible_options]
415#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Debug, MergeFrom)]
416pub struct TelemetrySettingsContent {
417 /// Send debug info like crash reports.
418 ///
419 /// Default: true
420 pub diagnostics: Option<bool>,
421 /// Send anonymized usage data like what languages you're using Zed with.
422 ///
423 /// Default: true
424 pub metrics: Option<bool>,
425}
426
427impl Default for TelemetrySettingsContent {
428 fn default() -> Self {
429 Self {
430 diagnostics: Some(true),
431 metrics: Some(true),
432 }
433 }
434}
435
436#[with_fallible_options]
437#[derive(Default, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Clone, MergeFrom)]
438pub struct DebuggerSettingsContent {
439 /// Determines the stepping granularity.
440 ///
441 /// Default: line
442 pub stepping_granularity: Option<SteppingGranularity>,
443 /// Whether the breakpoints should be reused across Zed sessions.
444 ///
445 /// Default: true
446 pub save_breakpoints: Option<bool>,
447 /// Whether to show the debug button in the status bar.
448 ///
449 /// Default: true
450 pub button: Option<bool>,
451 /// Time in milliseconds until timeout error when connecting to a TCP debug adapter
452 ///
453 /// Default: 2000ms
454 pub timeout: Option<u64>,
455 /// Whether to log messages between active debug adapters and Zed
456 ///
457 /// Default: true
458 pub log_dap_communications: Option<bool>,
459 /// Whether to format dap messages in when adding them to debug adapter logger
460 ///
461 /// Default: true
462 pub format_dap_log_messages: Option<bool>,
463 /// The dock position of the debug panel
464 ///
465 /// Default: Bottom
466 pub dock: Option<DockPosition>,
467}
468
469/// The granularity of one 'step' in the stepping requests `next`, `stepIn`, `stepOut`, and `stepBack`.
470#[derive(
471 PartialEq,
472 Eq,
473 Debug,
474 Hash,
475 Clone,
476 Copy,
477 Deserialize,
478 Serialize,
479 JsonSchema,
480 MergeFrom,
481 strum::VariantArray,
482 strum::VariantNames,
483)]
484#[serde(rename_all = "snake_case")]
485pub enum SteppingGranularity {
486 /// The step should allow the program to run until the current statement has finished executing.
487 /// The meaning of a statement is determined by the adapter and it may be considered equivalent to a line.
488 /// For example 'for(int i = 0; i < 10; i++)' could be considered to have 3 statements 'int i = 0', 'i < 10', and 'i++'.
489 Statement,
490 /// The step should allow the program to run until the current source line has executed.
491 Line,
492 /// The step should allow one instruction to execute (e.g. one x86 instruction).
493 Instruction,
494}
495
496#[derive(
497 Copy,
498 Clone,
499 Debug,
500 Serialize,
501 Deserialize,
502 JsonSchema,
503 MergeFrom,
504 PartialEq,
505 Eq,
506 strum::VariantArray,
507 strum::VariantNames,
508)]
509#[serde(rename_all = "snake_case")]
510pub enum DockPosition {
511 Left,
512 Bottom,
513 Right,
514}
515
516/// Configuration of voice calls in Zed.
517#[with_fallible_options]
518#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)]
519pub struct CallSettingsContent {
520 /// Whether the microphone should be muted when joining a channel or a call.
521 ///
522 /// Default: false
523 pub mute_on_join: Option<bool>,
524
525 /// Whether your current project should be shared when joining an empty channel.
526 ///
527 /// Default: false
528 pub share_on_join: Option<bool>,
529}
530
531#[with_fallible_options]
532#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)]
533pub struct GitPanelSettingsContent {
534 /// Whether to show the panel button in the status bar.
535 ///
536 /// Default: true
537 pub button: Option<bool>,
538 /// Where to dock the panel.
539 ///
540 /// Default: left
541 pub dock: Option<DockPosition>,
542 /// Default width of the panel in pixels.
543 ///
544 /// Default: 360
545 #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
546 pub default_width: Option<f32>,
547 /// How entry statuses are displayed.
548 ///
549 /// Default: icon
550 pub status_style: Option<StatusStyle>,
551
552 /// Whether to show file icons in the git panel.
553 ///
554 /// Default: false
555 pub file_icons: Option<bool>,
556
557 /// Whether to show folder icons or chevrons for directories in the git panel.
558 ///
559 /// Default: true
560 pub folder_icons: Option<bool>,
561
562 /// How and when the scrollbar should be displayed.
563 ///
564 /// Default: inherits editor scrollbar settings
565 pub scrollbar: Option<ScrollbarSettings>,
566
567 /// What the default branch name should be when
568 /// `init.defaultBranch` is not set in git
569 ///
570 /// Default: main
571 pub fallback_branch_name: Option<String>,
572
573 /// Whether to sort entries in the panel by path
574 /// or by status (the default).
575 ///
576 /// Default: false
577 pub sort_by_path: Option<bool>,
578
579 /// Whether to collapse untracked files in the diff panel.
580 ///
581 /// Default: false
582 pub collapse_untracked_diff: Option<bool>,
583
584 /// Whether to show entries with tree or flat view in the panel
585 ///
586 /// Default: false
587 pub tree_view: Option<bool>,
588
589 /// Whether to show the addition/deletion change count next to each file in the Git panel.
590 ///
591 /// Default: true
592 pub diff_stats: Option<bool>,
593
594 /// Whether to show a badge on the git panel icon with the count of uncommitted changes.
595 ///
596 /// Default: false
597 pub show_count_badge: Option<bool>,
598
599 /// Whether the git panel should open on startup.
600 ///
601 /// Default: false
602 pub starts_open: Option<bool>,
603}
604
605#[derive(
606 Default,
607 Copy,
608 Clone,
609 Debug,
610 Serialize,
611 Deserialize,
612 JsonSchema,
613 MergeFrom,
614 PartialEq,
615 Eq,
616 strum::VariantArray,
617 strum::VariantNames,
618)]
619#[serde(rename_all = "snake_case")]
620pub enum StatusStyle {
621 #[default]
622 Icon,
623 LabelColor,
624}
625
626#[with_fallible_options]
627#[derive(
628 Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq,
629)]
630pub struct ScrollbarSettings {
631 pub show: Option<ShowScrollbar>,
632}
633
634#[with_fallible_options]
635#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
636pub struct NotificationPanelSettingsContent {
637 /// Whether to show the panel button in the status bar.
638 ///
639 /// Default: true
640 pub button: Option<bool>,
641 /// Where to dock the panel.
642 ///
643 /// Default: right
644 pub dock: Option<DockPosition>,
645 /// Default width of the panel in pixels.
646 ///
647 /// Default: 300
648 #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
649 pub default_width: Option<f32>,
650 /// Whether to show a badge on the notification panel icon with the count of unread notifications.
651 ///
652 /// Default: false
653 pub show_count_badge: Option<bool>,
654}
655
656#[with_fallible_options]
657#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
658pub struct PanelSettingsContent {
659 /// Whether to show the panel button in the status bar.
660 ///
661 /// Default: true
662 pub button: Option<bool>,
663 /// Where to dock the panel.
664 ///
665 /// Default: left
666 pub dock: Option<DockPosition>,
667 /// Default width of the panel in pixels.
668 ///
669 /// Default: 240
670 #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
671 pub default_width: Option<f32>,
672}
673
674#[with_fallible_options]
675#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
676pub struct MessageEditorSettings {
677 /// Whether to automatically replace emoji shortcodes with emoji characters.
678 /// For example: typing `:wave:` gets replaced with `👋`.
679 ///
680 /// Default: false
681 pub auto_replace_emoji_shortcode: Option<bool>,
682}
683
684#[with_fallible_options]
685#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
686pub struct FileFinderSettingsContent {
687 /// Whether to show file icons in the file finder.
688 ///
689 /// Default: true
690 pub file_icons: Option<bool>,
691 /// Determines how much space the file finder can take up in relation to the available window width.
692 ///
693 /// Default: small
694 pub modal_max_width: Option<FileFinderWidthContent>,
695 /// Determines whether the file finder should skip focus for the active file in search results.
696 ///
697 /// Default: true
698 pub skip_focus_for_active_in_search: Option<bool>,
699 /// Whether to use gitignored files when searching.
700 /// Only the file Zed had indexed will be used, not necessary all the gitignored files.
701 ///
702 /// Default: Smart
703 pub include_ignored: Option<IncludeIgnoredContent>,
704 /// Whether to include text channels in file finder results.
705 ///
706 /// Default: false
707 pub include_channels: Option<bool>,
708}
709
710#[derive(
711 Debug,
712 PartialEq,
713 Eq,
714 Clone,
715 Copy,
716 Default,
717 Serialize,
718 Deserialize,
719 JsonSchema,
720 MergeFrom,
721 strum::VariantArray,
722 strum::VariantNames,
723)]
724#[serde(rename_all = "snake_case")]
725pub enum IncludeIgnoredContent {
726 /// Use all gitignored files
727 All,
728 /// Use only the files Zed had indexed
729 Indexed,
730 /// Be smart and search for ignored when called from a gitignored worktree
731 #[default]
732 Smart,
733}
734
735#[derive(
736 Debug,
737 PartialEq,
738 Eq,
739 Clone,
740 Copy,
741 Default,
742 Serialize,
743 Deserialize,
744 JsonSchema,
745 MergeFrom,
746 strum::VariantArray,
747 strum::VariantNames,
748)]
749#[serde(rename_all = "lowercase")]
750pub enum FileFinderWidthContent {
751 #[default]
752 Small,
753 Medium,
754 Large,
755 XLarge,
756 Full,
757}
758
759#[with_fallible_options]
760#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Debug, JsonSchema, MergeFrom)]
761pub struct VimSettingsContent {
762 pub default_mode: Option<ModeContent>,
763 pub toggle_relative_line_numbers: Option<bool>,
764 pub use_system_clipboard: Option<UseSystemClipboard>,
765 pub use_smartcase_find: Option<bool>,
766 pub use_regex_search: Option<bool>,
767 /// When enabled, the `:substitute` command replaces all matches in a line
768 /// by default. The 'g' flag then toggles this behavior.,
769 pub gdefault: Option<bool>,
770 pub custom_digraphs: Option<HashMap<String, Arc<str>>>,
771 pub highlight_on_yank_duration: Option<u64>,
772 pub cursor_shape: Option<CursorShapeSettings>,
773}
774
775#[derive(
776 Copy,
777 Clone,
778 Default,
779 Serialize,
780 Deserialize,
781 JsonSchema,
782 MergeFrom,
783 PartialEq,
784 Debug,
785 strum::VariantArray,
786 strum::VariantNames,
787)]
788#[serde(rename_all = "snake_case")]
789pub enum ModeContent {
790 #[default]
791 Normal,
792 Insert,
793}
794
795/// Controls when to use system clipboard.
796#[derive(
797 Copy,
798 Clone,
799 Debug,
800 Serialize,
801 Deserialize,
802 PartialEq,
803 Eq,
804 JsonSchema,
805 MergeFrom,
806 strum::VariantArray,
807 strum::VariantNames,
808)]
809#[serde(rename_all = "snake_case")]
810pub enum UseSystemClipboard {
811 /// Don't use system clipboard.
812 Never,
813 /// Use system clipboard.
814 Always,
815 /// Use system clipboard for yank operations.
816 OnYank,
817}
818
819/// Cursor shape configuration for insert mode in Vim.
820#[derive(
821 Copy,
822 Clone,
823 Debug,
824 Serialize,
825 Deserialize,
826 PartialEq,
827 Eq,
828 JsonSchema,
829 MergeFrom,
830 strum::VariantArray,
831 strum::VariantNames,
832)]
833#[serde(rename_all = "snake_case")]
834pub enum VimInsertModeCursorShape {
835 /// Inherit cursor shape from the editor's base cursor_shape setting.
836 Inherit,
837 /// Vertical bar cursor.
838 Bar,
839 /// Block cursor that surrounds the character.
840 Block,
841 /// Underline cursor.
842 Underline,
843 /// Hollow box cursor.
844 Hollow,
845}
846
847/// The settings for cursor shape.
848#[with_fallible_options]
849#[derive(
850 Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom,
851)]
852pub struct CursorShapeSettings {
853 /// Cursor shape for the normal mode.
854 ///
855 /// Default: block
856 pub normal: Option<CursorShape>,
857 /// Cursor shape for the replace mode.
858 ///
859 /// Default: underline
860 pub replace: Option<CursorShape>,
861 /// Cursor shape for the visual mode.
862 ///
863 /// Default: block
864 pub visual: Option<CursorShape>,
865 /// Cursor shape for the insert mode.
866 ///
867 /// The default value follows the primary cursor_shape.
868 pub insert: Option<VimInsertModeCursorShape>,
869}
870
871/// Settings specific to journaling
872#[with_fallible_options]
873#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
874pub struct JournalSettingsContent {
875 /// The path of the directory where journal entries are stored.
876 ///
877 /// Default: `~`
878 pub path: Option<String>,
879 /// What format to display the hours in.
880 ///
881 /// Default: hour12
882 pub hour_format: Option<HourFormat>,
883}
884
885#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
886#[serde(rename_all = "snake_case")]
887pub enum HourFormat {
888 #[default]
889 Hour12,
890 Hour24,
891}
892
893#[with_fallible_options]
894#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
895pub struct OutlinePanelSettingsContent {
896 /// Whether to show the outline panel button in the status bar.
897 ///
898 /// Default: true
899 pub button: Option<bool>,
900 /// Customize default width (in pixels) taken by outline panel
901 ///
902 /// Default: 240
903 #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
904 pub default_width: Option<f32>,
905 /// The position of outline panel
906 ///
907 /// Default: left
908 pub dock: Option<DockSide>,
909 /// Whether to show file icons in the outline panel.
910 ///
911 /// Default: true
912 pub file_icons: Option<bool>,
913 /// Whether to show folder icons or chevrons for directories in the outline panel.
914 ///
915 /// Default: true
916 pub folder_icons: Option<bool>,
917 /// Whether to show the git status in the outline panel.
918 ///
919 /// Default: true
920 pub git_status: Option<bool>,
921 /// Amount of indentation (in pixels) for nested items.
922 ///
923 /// Default: 20
924 #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
925 pub indent_size: Option<f32>,
926 /// Whether to reveal it in the outline panel automatically,
927 /// when a corresponding project entry becomes active.
928 /// Gitignored entries are never auto revealed.
929 ///
930 /// Default: true
931 pub auto_reveal_entries: Option<bool>,
932 /// Whether to fold directories automatically
933 /// when directory has only one directory inside.
934 ///
935 /// Default: true
936 pub auto_fold_dirs: Option<bool>,
937 /// Settings related to indent guides in the outline panel.
938 pub indent_guides: Option<IndentGuidesSettingsContent>,
939 /// Scrollbar-related settings
940 pub scrollbar: Option<ScrollbarSettingsContent>,
941 /// Default depth to expand outline items in the current file.
942 /// The default depth to which outline entries are expanded on reveal.
943 /// - Set to 0 to collapse all items that have children
944 /// - Set to 1 or higher to collapse items at that depth or deeper
945 ///
946 /// Default: 100
947 pub expand_outlines_with_depth: Option<usize>,
948}
949
950#[derive(
951 Clone,
952 Copy,
953 Debug,
954 PartialEq,
955 Eq,
956 Serialize,
957 Deserialize,
958 JsonSchema,
959 MergeFrom,
960 strum::VariantArray,
961 strum::VariantNames,
962)]
963#[serde(rename_all = "snake_case")]
964pub enum DockSide {
965 Left,
966 Right,
967}
968
969#[derive(
970 Copy,
971 Clone,
972 Debug,
973 PartialEq,
974 Eq,
975 Deserialize,
976 Serialize,
977 JsonSchema,
978 MergeFrom,
979 strum::VariantArray,
980 strum::VariantNames,
981)]
982#[serde(rename_all = "snake_case")]
983pub enum ShowIndentGuides {
984 Always,
985 Never,
986}
987
988#[with_fallible_options]
989#[derive(
990 Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq, Default,
991)]
992pub struct IndentGuidesSettingsContent {
993 /// When to show the scrollbar in the outline panel.
994 pub show: Option<ShowIndentGuides>,
995}
996
997#[derive(Clone, Copy, Default, PartialEq, Debug, JsonSchema, MergeFrom, Deserialize, Serialize)]
998#[serde(rename_all = "snake_case")]
999pub enum LineIndicatorFormat {
1000 Short,
1001 #[default]
1002 Long,
1003}
1004
1005/// The settings for the image viewer.
1006#[with_fallible_options]
1007#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, Default, PartialEq)]
1008pub struct ImageViewerSettingsContent {
1009 /// The unit to use for displaying image file sizes.
1010 ///
1011 /// Default: "binary"
1012 pub unit: Option<ImageFileSizeUnit>,
1013}
1014
1015#[with_fallible_options]
1016#[derive(
1017 Clone,
1018 Copy,
1019 Debug,
1020 Serialize,
1021 Deserialize,
1022 JsonSchema,
1023 MergeFrom,
1024 Default,
1025 PartialEq,
1026 strum::VariantArray,
1027 strum::VariantNames,
1028)]
1029#[serde(rename_all = "snake_case")]
1030pub enum ImageFileSizeUnit {
1031 /// Displays file size in binary units (e.g., KiB, MiB).
1032 #[default]
1033 Binary,
1034 /// Displays file size in decimal units (e.g., KB, MB).
1035 Decimal,
1036}
1037
1038#[with_fallible_options]
1039#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
1040pub struct RemoteSettingsContent {
1041 pub ssh_connections: Option<Vec<SshConnection>>,
1042 pub wsl_connections: Option<Vec<WslConnection>>,
1043 pub dev_container_connections: Option<Vec<DevContainerConnection>>,
1044 pub read_ssh_config: Option<bool>,
1045 pub use_podman: Option<bool>,
1046}
1047
1048#[with_fallible_options]
1049#[derive(
1050 Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash,
1051)]
1052pub struct DevContainerConnection {
1053 pub name: String,
1054 pub remote_user: String,
1055 pub container_id: String,
1056 pub use_podman: bool,
1057 pub extension_ids: Vec<String>,
1058 pub remote_env: BTreeMap<String, String>,
1059}
1060
1061#[with_fallible_options]
1062#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, JsonSchema, MergeFrom)]
1063pub struct SshConnection {
1064 pub host: String,
1065 pub username: Option<String>,
1066 pub port: Option<u16>,
1067 #[serde(default)]
1068 pub args: Vec<String>,
1069 #[serde(default)]
1070 pub projects: collections::BTreeSet<RemoteProject>,
1071 /// Name to use for this server in UI.
1072 pub nickname: Option<String>,
1073 // By default Zed will download the binary to the host directly.
1074 // If this is set to true, Zed will download the binary to your local machine,
1075 // and then upload it over the SSH connection. Useful if your SSH server has
1076 // limited outbound internet access.
1077 pub upload_binary_over_ssh: Option<bool>,
1078
1079 pub port_forwards: Option<Vec<SshPortForwardOption>>,
1080 /// Timeout in seconds for SSH connection and downloading the remote server binary.
1081 /// Defaults to 10 seconds if not specified.
1082 pub connection_timeout: Option<u16>,
1083}
1084
1085#[derive(Clone, Default, Serialize, Deserialize, PartialEq, JsonSchema, MergeFrom, Debug)]
1086pub struct WslConnection {
1087 pub distro_name: String,
1088 pub user: Option<String>,
1089 #[serde(default)]
1090 pub projects: BTreeSet<RemoteProject>,
1091}
1092
1093#[with_fallible_options]
1094#[derive(
1095 Clone, Debug, Default, Serialize, PartialEq, Eq, PartialOrd, Ord, Deserialize, JsonSchema,
1096)]
1097pub struct RemoteProject {
1098 pub paths: Vec<String>,
1099}
1100
1101#[with_fallible_options]
1102#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, JsonSchema, MergeFrom)]
1103pub struct SshPortForwardOption {
1104 pub local_host: Option<String>,
1105 pub local_port: u16,
1106 pub remote_host: Option<String>,
1107 pub remote_port: u16,
1108}
1109
1110/// Settings for configuring REPL display and behavior.
1111#[with_fallible_options]
1112#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
1113pub struct ReplSettingsContent {
1114 /// Maximum number of lines to keep in REPL's scrollback buffer.
1115 /// Clamped with [4, 256] range.
1116 ///
1117 /// Default: 32
1118 pub max_lines: Option<usize>,
1119 /// Maximum number of columns to keep in REPL's scrollback buffer.
1120 /// Clamped with [20, 512] range.
1121 ///
1122 /// Default: 128
1123 pub max_columns: Option<usize>,
1124 /// Whether to show small single-line outputs inline instead of in a block.
1125 ///
1126 /// Default: true
1127 pub inline_output: Option<bool>,
1128 /// Maximum number of characters for an output to be shown inline.
1129 /// Only applies when `inline_output` is true.
1130 ///
1131 /// Default: 50
1132 pub inline_output_max_length: Option<usize>,
1133 /// Maximum number of lines of output to display before scrolling.
1134 /// Set to 0 to disable output height limits.
1135 ///
1136 /// Default: 0
1137 pub output_max_height_lines: Option<usize>,
1138}
1139
1140/// Settings for configuring the which-key popup behaviour.
1141#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
1142pub struct WhichKeySettingsContent {
1143 /// Whether to show the which-key popup when holding down key combinations
1144 ///
1145 /// Default: false
1146 pub enabled: Option<bool>,
1147 /// Delay in milliseconds before showing the which-key popup.
1148 ///
1149 /// Default: 700
1150 pub delay_ms: Option<u64>,
1151}
1152
1153// An ExtendingVec in the settings can only accumulate new values.
1154//
1155// This is useful for things like private files where you only want
1156// to allow new values to be added.
1157//
1158// Consider using a HashMap<String, bool> instead of this type
1159// (like auto_install_extensions) so that user settings files can both add
1160// and remove values from the set.
1161#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
1162pub struct ExtendingVec<T>(pub Vec<T>);
1163
1164impl<T> Into<Vec<T>> for ExtendingVec<T> {
1165 fn into(self) -> Vec<T> {
1166 self.0
1167 }
1168}
1169impl<T> From<Vec<T>> for ExtendingVec<T> {
1170 fn from(vec: Vec<T>) -> Self {
1171 ExtendingVec(vec)
1172 }
1173}
1174
1175impl<T: Clone> merge_from::MergeFrom for ExtendingVec<T> {
1176 fn merge_from(&mut self, other: &Self) {
1177 self.0.extend_from_slice(other.0.as_slice());
1178 }
1179}
1180
1181// A SaturatingBool in the settings can only ever be set to true,
1182// later attempts to set it to false will be ignored.
1183//
1184// Used by `disable_ai`.
1185#[derive(Debug, Default, Copy, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
1186pub struct SaturatingBool(pub bool);
1187
1188impl From<bool> for SaturatingBool {
1189 fn from(value: bool) -> Self {
1190 SaturatingBool(value)
1191 }
1192}
1193
1194impl From<SaturatingBool> for bool {
1195 fn from(value: SaturatingBool) -> bool {
1196 value.0
1197 }
1198}
1199
1200impl merge_from::MergeFrom for SaturatingBool {
1201 fn merge_from(&mut self, other: &Self) {
1202 self.0 |= other.0
1203 }
1204}
1205
1206#[derive(
1207 Copy,
1208 Clone,
1209 Default,
1210 Debug,
1211 PartialEq,
1212 Eq,
1213 PartialOrd,
1214 Ord,
1215 Serialize,
1216 Deserialize,
1217 MergeFrom,
1218 JsonSchema,
1219 derive_more::FromStr,
1220)]
1221#[serde(transparent)]
1222pub struct DelayMs(pub u64);
1223
1224impl From<u64> for DelayMs {
1225 fn from(n: u64) -> Self {
1226 Self(n)
1227 }
1228}
1229
1230impl std::fmt::Display for DelayMs {
1231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1232 write!(f, "{}ms", self.0)
1233 }
1234}