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