project.rs

  1use std::{path::PathBuf, sync::Arc};
  2
  3use collections::{BTreeMap, HashMap};
  4use gpui::Rgba;
  5use schemars::JsonSchema;
  6use serde::{Deserialize, Serialize};
  7use settings_json::parse_json_with_comments;
  8use settings_macros::{MergeFrom, with_fallible_options};
  9use util::serde::default_true;
 10
 11use crate::{
 12    AllLanguageSettingsContent, DelayMs, ExtendingVec, ParseStatus, ProjectTerminalSettingsContent,
 13    RootUserSettings, SlashCommandSettings, fallible_options,
 14};
 15
 16#[with_fallible_options]
 17#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
 18pub struct LspSettingsMap(pub HashMap<Arc<str>, LspSettings>);
 19
 20impl IntoIterator for LspSettingsMap {
 21    type Item = (Arc<str>, LspSettings);
 22    type IntoIter = std::collections::hash_map::IntoIter<Arc<str>, LspSettings>;
 23
 24    fn into_iter(self) -> Self::IntoIter {
 25        self.0.into_iter()
 26    }
 27}
 28
 29impl RootUserSettings for ProjectSettingsContent {
 30    fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
 31        fallible_options::parse_json(json)
 32    }
 33    fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
 34        parse_json_with_comments(json)
 35    }
 36}
 37
 38#[with_fallible_options]
 39#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
 40pub struct ProjectSettingsContent {
 41    #[serde(flatten)]
 42    pub all_languages: AllLanguageSettingsContent,
 43
 44    #[serde(flatten)]
 45    pub worktree: WorktreeSettingsContent,
 46
 47    /// Configuration for language servers.
 48    ///
 49    /// The following settings can be overridden for specific language servers:
 50    /// - initialization_options
 51    ///
 52    /// To override settings for a language, add an entry for that language server's
 53    /// name to the lsp value.
 54    /// Default: null
 55    #[serde(default)]
 56    pub lsp: LspSettingsMap,
 57
 58    pub terminal: Option<ProjectTerminalSettingsContent>,
 59
 60    /// Configuration for Debugger-related features
 61    #[serde(default)]
 62    pub dap: HashMap<Arc<str>, DapSettingsContent>,
 63
 64    /// Settings for context servers used for AI-related features.
 65    #[serde(default)]
 66    pub context_servers: HashMap<Arc<str>, ContextServerSettingsContent>,
 67
 68    /// Default timeout in seconds for context server tool calls.
 69    /// Can be overridden per-server in context_servers configuration.
 70    ///
 71    /// Default: 60
 72    pub context_server_timeout: Option<u64>,
 73
 74    /// Configuration for how direnv configuration should be loaded
 75    pub load_direnv: Option<DirenvSettings>,
 76
 77    /// Settings for slash commands.
 78    pub slash_commands: Option<SlashCommandSettings>,
 79
 80    /// The list of custom Git hosting providers.
 81    pub git_hosting_providers: Option<ExtendingVec<GitHostingProviderConfig>>,
 82}
 83
 84#[with_fallible_options]
 85#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
 86pub struct WorktreeSettingsContent {
 87    /// The displayed name of this project. If not set or null, the root directory name
 88    /// will be displayed.
 89    ///
 90    /// Default: null
 91    pub project_name: Option<String>,
 92
 93    /// Whether to prevent this project from being shared in public channels.
 94    ///
 95    /// Default: false
 96    #[serde(default)]
 97    pub prevent_sharing_in_public_channels: bool,
 98
 99    /// Completely ignore files matching globs from `file_scan_exclusions`. Overrides
100    /// `file_scan_inclusions`.
101    ///
102    /// Default: [
103    ///   "**/.git",
104    ///   "**/.svn",
105    ///   "**/.hg",
106    ///   "**/.jj",
107    ///   "**/CVS",
108    ///   "**/.DS_Store",
109    ///   "**/Thumbs.db",
110    ///   "**/.classpath",
111    ///   "**/.settings"
112    /// ]
113    pub file_scan_exclusions: Option<Vec<String>>,
114
115    /// Always include files that match these globs when scanning for files, even if they're
116    /// ignored by git. This setting is overridden by `file_scan_exclusions`.
117    /// Default: [
118    ///  ".env*",
119    ///  "docker-compose.*.yml",
120    /// ]
121    pub file_scan_inclusions: Option<Vec<String>>,
122
123    /// Treat the files matching these globs as `.env` files.
124    /// Default: ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"]
125    pub private_files: Option<ExtendingVec<String>>,
126
127    /// Treat the files matching these globs as hidden files. You can hide hidden files in the project panel.
128    /// Default: ["**/.*"]
129    pub hidden_files: Option<Vec<String>>,
130
131    /// Treat the files matching these globs as read-only. These files can be opened and viewed,
132    /// but cannot be edited. This is useful for generated files, build outputs, or files from
133    /// external dependencies that should not be modified directly.
134    /// Default: []
135    pub read_only_files: Option<Vec<String>>,
136}
137
138#[with_fallible_options]
139#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash)]
140#[serde(rename_all = "snake_case")]
141pub struct LspSettings {
142    pub binary: Option<BinarySettings>,
143    /// Options passed to the language server at startup.
144    ///
145    /// Ref: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize
146    ///
147    /// Consult the documentation for the specific language server to see which settings are supported.
148    pub initialization_options: Option<serde_json::Value>,
149    /// Language server settings.
150    ///
151    /// Ref: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration
152    ///
153    /// Consult the documentation for the specific language server to see which settings are supported.
154    pub settings: Option<serde_json::Value>,
155    /// If the server supports sending tasks over LSP extensions,
156    /// this setting can be used to enable or disable them in Zed.
157    /// Default: true
158    #[serde(default = "default_true")]
159    pub enable_lsp_tasks: bool,
160    pub fetch: Option<FetchSettings>,
161}
162
163impl Default for LspSettings {
164    fn default() -> Self {
165        Self {
166            binary: None,
167            initialization_options: None,
168            settings: None,
169            enable_lsp_tasks: true,
170            fetch: None,
171        }
172    }
173}
174
175#[with_fallible_options]
176#[derive(
177    Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash,
178)]
179pub struct BinarySettings {
180    pub path: Option<String>,
181    pub arguments: Option<Vec<String>>,
182    pub env: Option<BTreeMap<String, String>>,
183    pub ignore_system_version: Option<bool>,
184}
185
186#[with_fallible_options]
187#[derive(
188    Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash,
189)]
190pub struct FetchSettings {
191    // Whether to consider pre-releases for fetching
192    pub pre_release: Option<bool>,
193}
194
195/// Common language server settings.
196#[with_fallible_options]
197#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
198pub struct GlobalLspSettingsContent {
199    /// Whether to show the LSP servers button in the status bar.
200    ///
201    /// Default: `true`
202    pub button: Option<bool>,
203    /// The maximum amount of time to wait for responses from language servers, in seconds.
204    /// A value of `0` will result in no timeout being applied (causing all LSP responses to wait indefinitely until completed).
205    ///
206    /// Default: `120`
207    pub request_timeout: Option<u64>,
208    /// Settings for language server notifications
209    pub notifications: Option<LspNotificationSettingsContent>,
210    /// Rules for rendering LSP semantic tokens.
211    pub semantic_token_rules: Option<SemanticTokenRules>,
212}
213
214#[with_fallible_options]
215#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
216pub struct LspNotificationSettingsContent {
217    /// Timeout in milliseconds for automatically dismissing language server notifications.
218    /// Set to 0 to disable auto-dismiss.
219    ///
220    /// Default: 5000
221    pub dismiss_timeout_ms: Option<u64>,
222}
223
224/// Custom rules for rendering LSP semantic tokens.
225#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, JsonSchema)]
226#[serde(transparent)]
227pub struct SemanticTokenRules {
228    pub rules: Vec<SemanticTokenRule>,
229}
230
231impl crate::merge_from::MergeFrom for SemanticTokenRules {
232    fn merge_from(&mut self, other: &Self) {
233        self.rules.splice(0..0, other.rules.iter().cloned());
234    }
235}
236
237#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, JsonSchema)]
238#[serde(rename_all = "snake_case")]
239pub struct SemanticTokenRule {
240    pub token_type: Option<String>,
241    #[serde(default)]
242    pub token_modifiers: Vec<String>,
243    #[serde(default)]
244    pub style: Vec<String>,
245    pub foreground_color: Option<Rgba>,
246    pub background_color: Option<Rgba>,
247    pub underline: Option<SemanticTokenColorOverride>,
248    pub strikethrough: Option<SemanticTokenColorOverride>,
249    pub font_weight: Option<SemanticTokenFontWeight>,
250    pub font_style: Option<SemanticTokenFontStyle>,
251}
252
253#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, MergeFrom)]
254#[serde(untagged)]
255pub enum SemanticTokenColorOverride {
256    InheritForeground(bool),
257    Replace(Rgba),
258}
259
260#[derive(
261    Copy,
262    Clone,
263    Debug,
264    Default,
265    Serialize,
266    Deserialize,
267    PartialEq,
268    Eq,
269    JsonSchema,
270    MergeFrom,
271    strum::VariantArray,
272    strum::VariantNames,
273)]
274#[serde(rename_all = "snake_case")]
275pub enum SemanticTokenFontWeight {
276    #[default]
277    Normal,
278    Bold,
279}
280
281#[derive(
282    Copy,
283    Clone,
284    Debug,
285    Default,
286    Serialize,
287    Deserialize,
288    PartialEq,
289    Eq,
290    JsonSchema,
291    MergeFrom,
292    strum::VariantArray,
293    strum::VariantNames,
294)]
295#[serde(rename_all = "snake_case")]
296pub enum SemanticTokenFontStyle {
297    #[default]
298    Normal,
299    Italic,
300}
301
302#[with_fallible_options]
303#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
304#[serde(rename_all = "snake_case")]
305pub struct DapSettingsContent {
306    pub binary: Option<String>,
307    pub args: Option<Vec<String>>,
308    pub env: Option<HashMap<String, String>>,
309}
310
311#[with_fallible_options]
312#[derive(
313    Default, Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, JsonSchema, MergeFrom,
314)]
315pub struct SessionSettingsContent {
316    /// Whether or not to restore unsaved buffers on restart.
317    ///
318    /// If this is true, user won't be prompted whether to save/discard
319    /// dirty files when closing the application.
320    ///
321    /// Default: true
322    pub restore_unsaved_buffers: Option<bool>,
323    /// Whether or not to skip worktree trust checks.
324    /// When trusted, project settings are synchronized automatically,
325    /// language and MCP servers are downloaded and started automatically.
326    ///
327    /// Default: false
328    pub trust_all_worktrees: Option<bool>,
329}
330
331#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, MergeFrom, Debug)]
332#[serde(untagged, rename_all = "snake_case")]
333pub enum ContextServerSettingsContent {
334    Stdio {
335        /// Whether the context server is enabled.
336        #[serde(default = "default_true")]
337        enabled: bool,
338        /// Whether to run the context server on the remote server when using remote development.
339        ///
340        /// If this is false, the context server will always run on the local machine.
341        ///
342        /// Default: false
343        #[serde(default)]
344        remote: bool,
345        #[serde(flatten)]
346        command: ContextServerCommand,
347    },
348    Http {
349        /// Whether the context server is enabled.
350        #[serde(default = "default_true")]
351        enabled: bool,
352        /// The URL of the remote context server.
353        url: String,
354        /// Optional headers to send.
355        #[serde(skip_serializing_if = "HashMap::is_empty", default)]
356        headers: HashMap<String, String>,
357        /// Timeout for tool calls in seconds. Defaults to global context_server_timeout if not specified.
358        timeout: Option<u64>,
359    },
360    Extension {
361        /// Whether the context server is enabled.
362        #[serde(default = "default_true")]
363        enabled: bool,
364        /// Whether to run the context server on the remote server when using remote development.
365        ///
366        /// If this is false, the context server will always run on the local machine.
367        ///
368        /// Default: false
369        #[serde(default)]
370        remote: bool,
371        /// The settings for this context server specified by the extension.
372        ///
373        /// Consult the documentation for the context server to see what settings
374        /// are supported.
375        settings: serde_json::Value,
376    },
377}
378
379impl ContextServerSettingsContent {
380    pub fn set_enabled(&mut self, enabled: bool) {
381        match self {
382            ContextServerSettingsContent::Stdio {
383                enabled: custom_enabled,
384                ..
385            } => {
386                *custom_enabled = enabled;
387            }
388            ContextServerSettingsContent::Extension {
389                enabled: ext_enabled,
390                ..
391            } => *ext_enabled = enabled,
392            ContextServerSettingsContent::Http {
393                enabled: remote_enabled,
394                ..
395            } => *remote_enabled = enabled,
396        }
397    }
398}
399
400#[with_fallible_options]
401#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, MergeFrom)]
402pub struct ContextServerCommand {
403    #[serde(rename = "command")]
404    pub path: PathBuf,
405    pub args: Vec<String>,
406    pub env: Option<HashMap<String, String>>,
407    /// Timeout for tool calls in seconds. Defaults to 60 if not specified.
408    pub timeout: Option<u64>,
409}
410
411impl std::fmt::Debug for ContextServerCommand {
412    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413        let filtered_env = self.env.as_ref().map(|env| {
414            env.iter()
415                .map(|(k, v)| {
416                    (
417                        k,
418                        if util::redact::should_redact(k) {
419                            "[REDACTED]"
420                        } else {
421                            v
422                        },
423                    )
424                })
425                .collect::<Vec<_>>()
426        });
427
428        f.debug_struct("ContextServerCommand")
429            .field("path", &self.path)
430            .field("args", &self.args)
431            .field("env", &filtered_env)
432            .finish()
433    }
434}
435
436#[with_fallible_options]
437#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
438pub struct GitSettings {
439    /// Whether or not to enable git integration.
440    ///
441    /// Default: true
442    #[serde(flatten)]
443    pub enabled: Option<GitEnabledSettings>,
444    /// Whether or not to show the git gutter.
445    ///
446    /// Default: tracked_files
447    pub git_gutter: Option<GitGutterSetting>,
448    /// Sets the debounce threshold (in milliseconds) after which changes are reflected in the git gutter.
449    ///
450    /// Default: 0
451    pub gutter_debounce: Option<u64>,
452    /// Whether or not to show git blame data inline in
453    /// the currently focused line.
454    ///
455    /// Default: on
456    pub inline_blame: Option<InlineBlameSettings>,
457    /// Git blame settings.
458    pub blame: Option<BlameSettings>,
459    /// Which information to show in the branch picker.
460    ///
461    /// Default: on
462    pub branch_picker: Option<BranchPickerSettingsContent>,
463    /// How hunks are displayed visually in the editor.
464    ///
465    /// Default: staged_hollow
466    pub hunk_style: Option<GitHunkStyleSetting>,
467    /// How file paths are displayed in the git gutter.
468    ///
469    /// Default: file_name_first
470    pub path_style: Option<GitPathStyle>,
471}
472
473#[with_fallible_options]
474#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
475#[serde(rename_all = "snake_case")]
476pub struct GitEnabledSettings {
477    pub disable_git: Option<bool>,
478    pub enable_status: Option<bool>,
479    pub enable_diff: Option<bool>,
480}
481
482impl GitEnabledSettings {
483    pub fn is_git_status_enabled(&self) -> bool {
484        !self.disable_git.unwrap_or(false) && self.enable_status.unwrap_or(true)
485    }
486
487    pub fn is_git_diff_enabled(&self) -> bool {
488        !self.disable_git.unwrap_or(false) && self.enable_diff.unwrap_or(true)
489    }
490}
491
492#[derive(
493    Clone,
494    Copy,
495    Debug,
496    PartialEq,
497    Default,
498    Serialize,
499    Deserialize,
500    JsonSchema,
501    MergeFrom,
502    strum::VariantArray,
503    strum::VariantNames,
504)]
505#[serde(rename_all = "snake_case")]
506pub enum GitGutterSetting {
507    /// Show git gutter in tracked files.
508    #[default]
509    TrackedFiles,
510    /// Hide git gutter
511    Hide,
512}
513
514#[with_fallible_options]
515#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
516#[serde(rename_all = "snake_case")]
517pub struct InlineBlameSettings {
518    /// Whether or not to show git blame data inline in
519    /// the currently focused line.
520    ///
521    /// Default: true
522    pub enabled: Option<bool>,
523    /// Whether to only show the inline blame information
524    /// after a delay once the cursor stops moving.
525    ///
526    /// Default: 0
527    pub delay_ms: Option<DelayMs>,
528    /// The amount of padding between the end of the source line and the start
529    /// of the inline blame in units of columns.
530    ///
531    /// Default: 7
532    pub padding: Option<u32>,
533    /// The minimum column number to show the inline blame information at
534    ///
535    /// Default: 0
536    pub min_column: Option<u32>,
537    /// Whether to show commit summary as part of the inline blame.
538    ///
539    /// Default: false
540    pub show_commit_summary: Option<bool>,
541}
542
543#[with_fallible_options]
544#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
545#[serde(rename_all = "snake_case")]
546pub struct BlameSettings {
547    /// Whether to show the avatar of the author of the commit.
548    ///
549    /// Default: true
550    pub show_avatar: Option<bool>,
551}
552
553#[with_fallible_options]
554#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
555#[serde(rename_all = "snake_case")]
556pub struct BranchPickerSettingsContent {
557    /// Whether to show author name as part of the commit information.
558    ///
559    /// Default: false
560    pub show_author_name: Option<bool>,
561}
562
563#[derive(
564    Clone,
565    Copy,
566    PartialEq,
567    Debug,
568    Default,
569    Serialize,
570    Deserialize,
571    JsonSchema,
572    MergeFrom,
573    strum::VariantArray,
574    strum::VariantNames,
575)]
576#[serde(rename_all = "snake_case")]
577pub enum GitHunkStyleSetting {
578    /// Show unstaged hunks with a filled background and staged hunks hollow.
579    #[default]
580    StagedHollow,
581    /// Show unstaged hunks hollow and staged hunks with a filled background.
582    UnstagedHollow,
583}
584
585#[with_fallible_options]
586#[derive(
587    Copy,
588    Clone,
589    Debug,
590    PartialEq,
591    Default,
592    Serialize,
593    Deserialize,
594    JsonSchema,
595    MergeFrom,
596    strum::VariantArray,
597    strum::VariantNames,
598)]
599#[serde(rename_all = "snake_case")]
600pub enum GitPathStyle {
601    /// Show file name first, then path
602    #[default]
603    FileNameFirst,
604    /// Show full path first
605    FilePathFirst,
606}
607
608#[with_fallible_options]
609#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
610pub struct DiagnosticsSettingsContent {
611    /// Whether to show the project diagnostics button in the status bar.
612    pub button: Option<bool>,
613
614    /// Whether or not to include warning diagnostics.
615    ///
616    /// Default: true
617    pub include_warnings: Option<bool>,
618
619    /// Settings for using LSP pull diagnostics mechanism in Zed.
620    pub lsp_pull_diagnostics: Option<LspPullDiagnosticsSettingsContent>,
621
622    /// Settings for showing inline diagnostics.
623    pub inline: Option<InlineDiagnosticsSettingsContent>,
624}
625
626#[with_fallible_options]
627#[derive(
628    Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq,
629)]
630pub struct LspPullDiagnosticsSettingsContent {
631    /// Whether to pull for diagnostics or not.
632    ///
633    /// Default: true
634    pub enabled: Option<bool>,
635    /// Minimum time to wait before pulling diagnostics from the language server(s).
636    /// 0 turns the debounce off.
637    ///
638    /// Default: 50
639    pub debounce_ms: Option<DelayMs>,
640}
641
642#[with_fallible_options]
643#[derive(
644    Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Eq,
645)]
646pub struct InlineDiagnosticsSettingsContent {
647    /// Whether or not to show inline diagnostics
648    ///
649    /// Default: false
650    pub enabled: Option<bool>,
651    /// Whether to only show the inline diagnostics after a delay after the
652    /// last editor event.
653    ///
654    /// Default: 150
655    pub update_debounce_ms: Option<DelayMs>,
656    /// The amount of padding between the end of the source line and the start
657    /// of the inline diagnostic in units of columns.
658    ///
659    /// Default: 4
660    pub padding: Option<u32>,
661    /// The minimum column to display inline diagnostics. This setting can be
662    /// used to horizontally align inline diagnostics at some position. Lines
663    /// longer than this value will still push diagnostics further to the right.
664    ///
665    /// Default: 0
666    pub min_column: Option<u32>,
667
668    pub max_severity: Option<DiagnosticSeverityContent>,
669}
670
671#[with_fallible_options]
672#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
673pub struct NodeBinarySettings {
674    /// The path to the Node binary.
675    pub path: Option<String>,
676    /// The path to the npm binary Zed should use (defaults to `.path/../npm`).
677    pub npm_path: Option<String>,
678    /// If enabled, Zed will download its own copy of Node.
679    pub ignore_system_version: Option<bool>,
680}
681
682#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
683#[serde(rename_all = "snake_case")]
684pub enum DirenvSettings {
685    /// Load direnv configuration through a shell hook
686    ShellHook,
687    /// Load direnv configuration directly using `direnv export json`
688    #[default]
689    Direct,
690    /// Do not load direnv configuration
691    Disabled,
692}
693
694#[derive(
695    Clone,
696    Copy,
697    Debug,
698    Eq,
699    PartialEq,
700    Ord,
701    PartialOrd,
702    Serialize,
703    Deserialize,
704    JsonSchema,
705    MergeFrom,
706    strum::VariantArray,
707    strum::VariantNames,
708)]
709#[serde(rename_all = "snake_case")]
710pub enum DiagnosticSeverityContent {
711    // No diagnostics are shown.
712    Off,
713    Error,
714    Warning,
715    Info,
716    Hint,
717    All,
718}
719
720/// A custom Git hosting provider.
721#[with_fallible_options]
722#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
723pub struct GitHostingProviderConfig {
724    /// The type of the provider.
725    ///
726    /// Must be one of `github`, `gitlab`, `bitbucket`, `gitea`, `forgejo`, or `source_hut`.
727    pub provider: GitHostingProviderKind,
728
729    /// The base URL for the provider (e.g., "https://code.corp.big.com").
730    pub base_url: String,
731
732    /// The display name for the provider (e.g., "BigCorp GitHub").
733    pub name: String,
734}
735
736#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
737#[serde(rename_all = "snake_case")]
738pub enum GitHostingProviderKind {
739    Github,
740    Gitlab,
741    Bitbucket,
742    Gitea,
743    Forgejo,
744    SourceHut,
745}