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