Skip to repository content921 lines · 28.9 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T02:35:04.981Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
project.rs
1use std::{
2 path::{Path, PathBuf},
3 sync::Arc,
4};
5
6use anyhow::Context;
7use collections::{BTreeMap, HashMap};
8use gpui::Rgba;
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11use settings_json::parse_json_with_comments;
12use settings_macros::{MergeFrom, with_fallible_options};
13use util::serde::default_true;
14
15use crate::{
16 AllLanguageSettingsContent, DelayMs, ExtendingVec, ParseStatus, ProjectTerminalSettingsContent,
17 RootUserSettings, SaturatingBool, fallible_options,
18};
19
20#[with_fallible_options]
21#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
22pub struct LspSettingsMap(pub HashMap<Arc<str>, LspSettings>);
23
24impl IntoIterator for LspSettingsMap {
25 type Item = (Arc<str>, LspSettings);
26 type IntoIter = std::collections::hash_map::IntoIter<Arc<str>, LspSettings>;
27
28 fn into_iter(self) -> Self::IntoIter {
29 self.0.into_iter()
30 }
31}
32
33impl RootUserSettings for ProjectSettingsContent {
34 fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
35 fallible_options::parse_json(json)
36 }
37 fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
38 parse_json_with_comments(json)
39 }
40}
41
42#[with_fallible_options]
43#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
44pub struct ProjectSettingsContent {
45 #[serde(flatten)]
46 pub all_languages: AllLanguageSettingsContent,
47
48 #[serde(flatten)]
49 pub worktree: WorktreeSettingsContent,
50
51 /// Configuration for language servers.
52 ///
53 /// The following settings can be overridden for specific language servers:
54 /// - initialization_options
55 ///
56 /// To override settings for a language, add an entry for that language server's
57 /// name to the lsp value.
58 /// Default: null
59 #[serde(default)]
60 pub lsp: LspSettingsMap,
61
62 pub terminal: Option<ProjectTerminalSettingsContent>,
63
64 /// Configuration for Debugger-related features
65 #[serde(default)]
66 pub dap: HashMap<Arc<str>, DapSettingsContent>,
67
68 /// Settings for context servers used for AI-related features.
69 #[serde(default)]
70 pub context_servers: HashMap<Arc<str>, ContextServerSettingsContent>,
71
72 /// Default timeout in seconds for context server tool calls.
73 /// Can be overridden per-server in context_servers configuration.
74 ///
75 /// Default: 60
76 pub context_server_timeout: Option<u64>,
77
78 /// Configuration for how direnv configuration should be loaded
79 pub load_direnv: Option<DirenvSettings>,
80
81 /// The list of custom Git hosting providers.
82 pub git_hosting_providers: Option<ExtendingVec<GitHostingProviderConfig>>,
83
84 /// Whether to disable all AI features in Omega.
85 ///
86 /// Default: false
87 pub disable_ai: Option<SaturatingBool>,
88}
89
90/// When to scan content of linked directories.
91#[derive(
92 Copy,
93 Clone,
94 Default,
95 Debug,
96 Serialize,
97 Deserialize,
98 PartialEq,
99 Eq,
100 JsonSchema,
101 MergeFrom,
102 strum::VariantArray,
103 strum::VariantNames,
104)]
105#[serde(rename_all = "snake_case")]
106pub enum ScanSymlinksSetting {
107 /// Always scan symlinked directories
108 Always,
109 /// Only scan symlinked directories when they've been expanded in the workspace
110 #[default]
111 Expanded,
112}
113
114#[with_fallible_options]
115#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
116pub struct WorktreeSettingsContent {
117 /// Whether to prevent this project from being shared in public channels.
118 ///
119 /// Default: false
120 #[serde(default)]
121 pub prevent_sharing_in_public_channels: bool,
122
123 /// Completely ignore files matching globs from `file_scan_exclusions`. Overrides
124 /// `file_scan_inclusions`.
125 ///
126 /// Default: [
127 /// "**/.git",
128 /// "**/.svn",
129 /// "**/.hg",
130 /// "**/.jj",
131 /// "**/CVS",
132 /// "**/.DS_Store",
133 /// "**/Thumbs.db",
134 /// "**/.classpath",
135 /// "**/.settings"
136 /// ]
137 pub file_scan_exclusions: Option<Vec<String>>,
138
139 /// Always include files that match these globs when scanning for files, even if they're
140 /// ignored by git. This setting is overridden by `file_scan_exclusions`.
141 /// Default: [
142 /// ".env*",
143 /// "docker-compose.*.yml",
144 /// ]
145 pub file_scan_inclusions: Option<Vec<String>>,
146
147 /// When to scan content of linked directories.
148 ///
149 /// Default: expanded
150 pub scan_symlinks: Option<ScanSymlinksSetting>,
151
152 /// Treat the files matching these globs as `.env` files.
153 /// Default: ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"]
154 pub private_files: Option<ExtendingVec<String>>,
155
156 /// Treat the files matching these globs as hidden files. You can hide hidden files in the project panel.
157 /// Default: ["**/.*"]
158 pub hidden_files: Option<Vec<String>>,
159
160 /// Treat the files matching these globs as read-only. These files can be opened and viewed,
161 /// but cannot be edited. This is useful for generated files, build outputs, or files from
162 /// external dependencies that should not be modified directly.
163 /// Default: []
164 pub read_only_files: Option<Vec<String>>,
165}
166
167#[with_fallible_options]
168#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash)]
169#[serde(rename_all = "snake_case")]
170pub struct LspSettings {
171 pub binary: Option<BinarySettings>,
172 /// Options passed to the language server at startup.
173 ///
174 /// Ref: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize
175 ///
176 /// Consult the documentation for the specific language server to see which settings are supported.
177 pub initialization_options: Option<serde_json::Value>,
178 /// Language server settings.
179 ///
180 /// Ref: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration
181 ///
182 /// Consult the documentation for the specific language server to see which settings are supported.
183 pub settings: Option<serde_json::Value>,
184 /// If the server supports sending tasks over LSP extensions,
185 /// this setting can be used to enable or disable them in Omega.
186 /// Default: true
187 #[serde(default = "default_true")]
188 pub enable_lsp_tasks: bool,
189 pub fetch: Option<FetchSettings>,
190}
191
192impl Default for LspSettings {
193 fn default() -> Self {
194 Self {
195 binary: None,
196 initialization_options: None,
197 settings: None,
198 enable_lsp_tasks: true,
199 fetch: None,
200 }
201 }
202}
203
204#[with_fallible_options]
205#[derive(
206 Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash,
207)]
208pub struct BinarySettings {
209 pub path: Option<String>,
210 pub arguments: Option<Vec<String>>,
211 pub env: Option<BTreeMap<String, String>>,
212 pub ignore_system_version: Option<bool>,
213}
214
215#[with_fallible_options]
216#[derive(
217 Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash,
218)]
219pub struct FetchSettings {
220 // Whether to consider pre-releases for fetching
221 pub pre_release: Option<bool>,
222}
223
224/// Common language server settings.
225#[with_fallible_options]
226#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
227pub struct GlobalLspSettingsContent {
228 /// Whether to show the LSP servers button in the status bar.
229 ///
230 /// Default: `true`
231 pub button: Option<bool>,
232 /// The maximum amount of time to wait for responses from language servers, in seconds.
233 /// A value of `0` will result in no timeout being applied (causing all LSP responses to wait indefinitely until completed).
234 ///
235 /// Default: `120`
236 pub request_timeout: Option<u64>,
237 /// The maximum line length a buffer may contain before language server features are disabled for the entire buffer.
238 ///
239 /// Default: `20000`
240 #[schemars(range(min = 1))]
241 pub max_buffer_line_length: Option<u32>,
242 /// Settings for language server notifications
243 pub notifications: Option<LspNotificationSettingsContent>,
244 /// Rules for rendering LSP semantic tokens.
245 pub semantic_token_rules: Option<SemanticTokenRules>,
246}
247
248#[with_fallible_options]
249#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
250pub struct LspNotificationSettingsContent {
251 /// Timeout in milliseconds for automatically dismissing language server notifications.
252 /// Set to 0 to disable auto-dismiss.
253 ///
254 /// Default: 5000
255 pub dismiss_timeout_ms: Option<u64>,
256}
257
258/// Custom rules for rendering LSP semantic tokens.
259#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, JsonSchema)]
260#[serde(transparent)]
261pub struct SemanticTokenRules {
262 pub rules: Vec<SemanticTokenRule>,
263}
264
265impl SemanticTokenRules {
266 pub const FILE_NAME: &'static str = "semantic_token_rules.json";
267
268 pub fn load(file_path: &Path) -> anyhow::Result<Self> {
269 let rules_content = std::fs::read(file_path).with_context(|| {
270 anyhow::anyhow!(
271 "Could not read semantic token rules from {}",
272 file_path.display()
273 )
274 })?;
275
276 serde_json_lenient::from_slice::<SemanticTokenRules>(&rules_content).with_context(|| {
277 anyhow::anyhow!(
278 "Failed to parse semantic token rules from {}",
279 file_path.display()
280 )
281 })
282 }
283}
284
285impl crate::merge_from::MergeFrom for SemanticTokenRules {
286 fn merge_from(&mut self, other: &Self) {
287 self.rules.splice(0..0, other.rules.iter().cloned());
288 }
289}
290
291#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, JsonSchema)]
292#[serde(rename_all = "snake_case")]
293pub struct SemanticTokenRule {
294 pub token_type: Option<String>,
295 #[serde(default)]
296 pub token_modifiers: Vec<String>,
297 #[serde(default)]
298 pub style: Vec<String>,
299 pub foreground_color: Option<Rgba>,
300 pub background_color: Option<Rgba>,
301 pub underline: Option<SemanticTokenColorOverride>,
302 pub strikethrough: Option<SemanticTokenColorOverride>,
303 pub font_weight: Option<SemanticTokenFontWeight>,
304 pub font_style: Option<SemanticTokenFontStyle>,
305}
306
307impl SemanticTokenRule {
308 pub fn no_style_defined(&self) -> bool {
309 self.style.is_empty()
310 && self.foreground_color.is_none()
311 && self.background_color.is_none()
312 && self.underline.is_none()
313 && self.strikethrough.is_none()
314 && self.font_weight.is_none()
315 && self.font_style.is_none()
316 }
317}
318
319#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, MergeFrom)]
320#[serde(untagged)]
321pub enum SemanticTokenColorOverride {
322 InheritForeground(bool),
323 Replace(Rgba),
324}
325
326#[derive(
327 Copy,
328 Clone,
329 Debug,
330 Default,
331 Serialize,
332 Deserialize,
333 PartialEq,
334 Eq,
335 JsonSchema,
336 MergeFrom,
337 strum::VariantArray,
338 strum::VariantNames,
339)]
340#[serde(rename_all = "snake_case")]
341pub enum SemanticTokenFontWeight {
342 #[default]
343 Normal,
344 Bold,
345}
346
347#[derive(
348 Copy,
349 Clone,
350 Debug,
351 Default,
352 Serialize,
353 Deserialize,
354 PartialEq,
355 Eq,
356 JsonSchema,
357 MergeFrom,
358 strum::VariantArray,
359 strum::VariantNames,
360)]
361#[serde(rename_all = "snake_case")]
362pub enum SemanticTokenFontStyle {
363 #[default]
364 Normal,
365 Italic,
366}
367
368#[with_fallible_options]
369#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
370#[serde(rename_all = "snake_case")]
371pub struct DapSettingsContent {
372 pub binary: Option<String>,
373 pub args: Option<Vec<String>>,
374 pub env: Option<HashMap<String, String>>,
375}
376
377#[with_fallible_options]
378#[derive(
379 Default, Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, JsonSchema, MergeFrom,
380)]
381pub struct SessionSettingsContent {
382 /// Whether or not to restore unsaved buffers on restart.
383 ///
384 /// If this is true, user won't be prompted whether to save/discard
385 /// dirty files when closing the application.
386 ///
387 /// Default: true
388 pub restore_unsaved_buffers: Option<bool>,
389 /// Whether or not to skip worktree trust checks.
390 /// When trusted, project settings are synchronized automatically,
391 /// language and MCP servers are downloaded and started automatically.
392 ///
393 /// Omega defaults this to true; upstream Zed defaults it to false.
394 /// See OMEGA-DELTA-0001.
395 ///
396 /// Default: true
397 pub trust_all_worktrees: Option<bool>,
398}
399
400#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, MergeFrom, Debug)]
401#[serde(untagged, rename_all = "snake_case")]
402pub enum ContextServerSettingsContent {
403 Stdio {
404 /// Whether the context server is enabled.
405 #[serde(default = "default_true")]
406 enabled: bool,
407 /// Whether to run the context server on the remote server when using remote development.
408 ///
409 /// If this is false, the context server will always run on the local machine.
410 ///
411 /// Default: false
412 #[serde(default)]
413 remote: bool,
414 #[serde(flatten)]
415 command: ContextServerCommand,
416 },
417 Http {
418 /// Whether the context server is enabled.
419 #[serde(default = "default_true")]
420 enabled: bool,
421 /// The URL of the remote context server.
422 url: String,
423 /// Optional headers to send.
424 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
425 headers: HashMap<String, String>,
426 /// Timeout for tool calls in seconds. Defaults to global context_server_timeout if not specified.
427 timeout: Option<u64>,
428 /// Pre-registered OAuth client credentials for authorization servers that
429 /// require out-of-band client registration.
430 #[serde(default, skip_serializing_if = "Option::is_none")]
431 oauth: Option<OAuthClientSettings>,
432 },
433 Extension {
434 /// Whether the context server is enabled.
435 #[serde(default = "default_true")]
436 enabled: bool,
437 /// Whether to run the context server on the remote server when using remote development.
438 ///
439 /// If this is false, the context server will always run on the local machine.
440 ///
441 /// Default: false
442 #[serde(default)]
443 remote: bool,
444 /// The settings for this context server specified by the extension.
445 ///
446 /// Consult the documentation for the context server to see what settings
447 /// are supported.
448 settings: serde_json::Value,
449 },
450}
451
452impl ContextServerSettingsContent {
453 pub fn set_enabled(&mut self, enabled: bool) {
454 match self {
455 ContextServerSettingsContent::Stdio {
456 enabled: custom_enabled,
457 ..
458 } => {
459 *custom_enabled = enabled;
460 }
461 ContextServerSettingsContent::Extension {
462 enabled: ext_enabled,
463 ..
464 } => *ext_enabled = enabled,
465 ContextServerSettingsContent::Http {
466 enabled: remote_enabled,
467 ..
468 } => *remote_enabled = enabled,
469 }
470 }
471}
472
473/// Pre-registered OAuth client credentials for MCP servers that don't support
474/// Dynamic Client Registration.
475#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, MergeFrom, Debug)]
476pub struct OAuthClientSettings {
477 /// The OAuth client ID obtained from out-of-band registration with the
478 /// authorization server.
479 pub client_id: String,
480 /// The OAuth client secret, if this is a confidential client. For security,
481 /// prefer providing this interactively; we will prompt and store it in
482 /// the system keychain.
483 #[serde(default, skip_serializing_if = "Option::is_none")]
484 pub client_secret: Option<String>,
485}
486
487#[with_fallible_options]
488#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, MergeFrom)]
489pub struct ContextServerCommand {
490 #[serde(rename = "command")]
491 pub path: PathBuf,
492 #[serde(default)]
493 pub args: Vec<String>,
494 pub env: Option<HashMap<String, String>>,
495 /// Timeout for tool calls in seconds. Defaults to 60 if not specified.
496 pub timeout: Option<u64>,
497}
498
499impl std::fmt::Debug for ContextServerCommand {
500 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
501 let filtered_env = self.env.as_ref().map(|env| {
502 env.iter()
503 .map(|(k, v)| {
504 (
505 k,
506 if util::redact::should_redact(k) {
507 "[REDACTED]"
508 } else {
509 v
510 },
511 )
512 })
513 .collect::<Vec<_>>()
514 });
515
516 f.debug_struct("ContextServerCommand")
517 .field("path", &self.path)
518 .field("args", &self.args)
519 .field("env", &filtered_env)
520 .finish()
521 }
522}
523
524#[with_fallible_options]
525#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
526pub struct GitSettings {
527 /// Whether or not to enable git integration.
528 ///
529 /// Default: true
530 #[serde(flatten)]
531 pub enabled: Option<GitEnabledSettings>,
532 /// Whether or not to show the git gutter.
533 ///
534 /// Default: tracked_files
535 pub git_gutter: Option<GitGutterSetting>,
536 /// Sets the debounce threshold (in milliseconds) after which changes are reflected in the git gutter.
537 ///
538 /// Default: 0
539 pub gutter_debounce: Option<u64>,
540 /// Whether or not to show git blame data inline in
541 /// the currently focused line.
542 ///
543 /// Default: on
544 pub inline_blame: Option<InlineBlameSettings>,
545 /// Git blame settings.
546 pub blame: Option<BlameSettings>,
547 /// Which information to show in the branch picker.
548 ///
549 /// Default: on
550 pub branch_picker: Option<BranchPickerSettingsContent>,
551 /// File diff settings.
552 pub file_diff: Option<FileDiffSettingsContent>,
553 /// How hunks are displayed visually in the editor.
554 ///
555 /// Default: staged_hollow
556 pub hunk_style: Option<GitHunkStyleSetting>,
557 /// How file paths are displayed in the git gutter.
558 ///
559 /// Default: file_name_first
560 pub path_style: Option<GitPathStyle>,
561 /// Whether to show the stage and restore buttons on diff hunks.
562 ///
563 /// Default: true
564 pub show_stage_restore_buttons: Option<bool>,
565 /// Directory where git worktrees are created, relative to the repository
566 /// working directory.
567 ///
568 /// When the resolved directory is outside the project root, the
569 /// project's directory name is automatically appended so that
570 /// sibling repos don't collide. For example, with the default
571 /// `"../worktrees"` and a project at `~/code/omega`, worktrees are
572 /// created under `~/code/worktrees/omega/`.
573 ///
574 /// When the resolved directory is inside the project root, no
575 /// extra component is added (it's already project-scoped).
576 ///
577 /// Examples:
578 /// - `"../worktrees"` — `~/code/worktrees/<project>/` (default)
579 /// - `".git/zed-worktrees"` — `<project>/.git/zed-worktrees/`
580 /// - `"my-worktrees"` — `<project>/my-worktrees/`
581 ///
582 /// Trailing slashes are ignored.
583 ///
584 /// Default: ../worktrees
585 pub worktree_directory: Option<String>,
586}
587
588#[with_fallible_options]
589#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
590#[serde(rename_all = "snake_case")]
591pub struct GitEnabledSettings {
592 pub disable_git: Option<bool>,
593 pub enable_status: Option<bool>,
594 pub enable_diff: Option<bool>,
595}
596
597impl GitEnabledSettings {
598 pub fn is_git_status_enabled(&self) -> bool {
599 !self.disable_git.unwrap_or(false) && self.enable_status.unwrap_or(true)
600 }
601
602 pub fn is_git_diff_enabled(&self) -> bool {
603 !self.disable_git.unwrap_or(false) && self.enable_diff.unwrap_or(true)
604 }
605}
606
607#[derive(
608 Clone,
609 Copy,
610 Debug,
611 PartialEq,
612 Default,
613 Serialize,
614 Deserialize,
615 JsonSchema,
616 MergeFrom,
617 strum::VariantArray,
618 strum::VariantNames,
619)]
620#[serde(rename_all = "snake_case")]
621pub enum GitGutterSetting {
622 /// Show git gutter in tracked files.
623 #[default]
624 TrackedFiles,
625 /// Hide git gutter
626 Hide,
627}
628
629#[derive(
630 Clone,
631 Copy,
632 Debug,
633 PartialEq,
634 Default,
635 Serialize,
636 Deserialize,
637 JsonSchema,
638 MergeFrom,
639 strum::VariantArray,
640 strum::VariantNames,
641)]
642#[serde(rename_all = "snake_case")]
643pub enum InlineBlameLocation {
644 /// Show git blame inline at the current line.
645 #[default]
646 Inline,
647 /// Show git blame in the status bar at the bottom of the window.
648 StatusBar,
649}
650
651#[with_fallible_options]
652#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
653#[serde(rename_all = "snake_case")]
654pub struct InlineBlameSettings {
655 /// Whether or not to show git blame data inline in
656 /// the currently focused line.
657 ///
658 /// Default: true
659 pub enabled: Option<bool>,
660 /// Whether to only show the inline blame information
661 /// after a delay once the cursor stops moving.
662 ///
663 /// Default: 0
664 pub delay_ms: Option<DelayMs>,
665 /// Where to render the blame information when enabled.
666 ///
667 /// Default: inline
668 pub location: Option<InlineBlameLocation>,
669 /// The amount of padding between the end of the source line and the start
670 /// of the inline blame in units of columns.
671 ///
672 /// Default: 7
673 pub padding: Option<u32>,
674 /// The minimum column number to show the inline blame information at
675 ///
676 /// Default: 0
677 pub min_column: Option<u32>,
678 /// Whether to show commit summary as part of the inline blame.
679 ///
680 /// Default: false
681 pub show_commit_summary: Option<bool>,
682}
683
684#[with_fallible_options]
685#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
686#[serde(rename_all = "snake_case")]
687pub struct BlameSettings {
688 /// Whether to show the avatar of the author of the commit.
689 ///
690 /// Default: true
691 pub show_avatar: Option<bool>,
692}
693
694#[with_fallible_options]
695#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
696#[serde(rename_all = "snake_case")]
697pub struct BranchPickerSettingsContent {
698 /// Whether to show author name as part of the commit information.
699 ///
700 /// Default: false
701 pub show_author_name: Option<bool>,
702}
703
704#[with_fallible_options]
705#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
706#[serde(rename_all = "snake_case")]
707pub struct FileDiffSettingsContent {
708 /// Whether newly opened file diffs show the full file instead of changes only.
709 ///
710 /// Default: true
711 pub show_full_file: Option<bool>,
712}
713
714#[derive(
715 Clone,
716 Copy,
717 PartialEq,
718 Debug,
719 Default,
720 Serialize,
721 Deserialize,
722 JsonSchema,
723 MergeFrom,
724 strum::VariantArray,
725 strum::VariantNames,
726)]
727#[serde(rename_all = "snake_case")]
728pub enum GitHunkStyleSetting {
729 /// Show unstaged hunks with a filled background and staged hunks hollow.
730 #[default]
731 StagedHollow,
732 /// Show unstaged hunks hollow and staged hunks with a filled background.
733 UnstagedHollow,
734}
735
736#[with_fallible_options]
737#[derive(
738 Copy,
739 Clone,
740 Debug,
741 PartialEq,
742 Default,
743 Serialize,
744 Deserialize,
745 JsonSchema,
746 MergeFrom,
747 strum::VariantArray,
748 strum::VariantNames,
749)]
750#[serde(rename_all = "snake_case")]
751pub enum GitPathStyle {
752 /// Show file name first, then path
753 #[default]
754 FileNameFirst,
755 /// Show full path first
756 FilePathFirst,
757}
758
759#[with_fallible_options]
760#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
761pub struct DiagnosticsSettingsContent {
762 /// Whether to show the project diagnostics button in the status bar.
763 pub button: Option<bool>,
764
765 /// Whether or not to include warning diagnostics.
766 ///
767 /// Default: true
768 pub include_warnings: Option<bool>,
769
770 /// Settings for using LSP pull diagnostics mechanism in Omega.
771 pub lsp_pull_diagnostics: Option<LspPullDiagnosticsSettingsContent>,
772
773 /// Settings for showing inline diagnostics.
774 pub inline: Option<InlineDiagnosticsSettingsContent>,
775}
776
777#[with_fallible_options]
778#[derive(
779 Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq,
780)]
781pub struct LspPullDiagnosticsSettingsContent {
782 /// Whether to pull for diagnostics or not.
783 ///
784 /// Default: true
785 pub enabled: Option<bool>,
786 /// Minimum time to wait before pulling diagnostics from the language server(s).
787 /// 0 turns the debounce off.
788 ///
789 /// Default: 50
790 pub debounce_ms: Option<DelayMs>,
791}
792
793#[with_fallible_options]
794#[derive(
795 Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Eq,
796)]
797pub struct InlineDiagnosticsSettingsContent {
798 /// Whether or not to show inline diagnostics
799 ///
800 /// Default: false
801 pub enabled: Option<bool>,
802 /// Whether to only show the inline diagnostics after a delay after the
803 /// last editor event.
804 ///
805 /// Default: 150
806 pub update_debounce_ms: Option<DelayMs>,
807 /// The amount of padding between the end of the source line and the start
808 /// of the inline diagnostic in units of columns.
809 ///
810 /// Default: 4
811 pub padding: Option<u32>,
812 /// The minimum column to display inline diagnostics. This setting can be
813 /// used to horizontally align inline diagnostics at some position. Lines
814 /// longer than this value will still push diagnostics further to the right.
815 ///
816 /// Default: 0
817 pub min_column: Option<u32>,
818
819 pub max_severity: Option<DiagnosticSeverityContent>,
820}
821
822#[with_fallible_options]
823#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
824pub struct NodeBinarySettings {
825 /// The path to the Node binary.
826 pub path: Option<String>,
827 /// The path to the npm binary Omega should use (defaults to `.path/../npm`).
828 pub npm_path: Option<String>,
829 /// If enabled, Omega will download its own copy of Node.
830 pub ignore_system_version: Option<bool>,
831}
832
833#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
834#[serde(rename_all = "snake_case")]
835pub enum DirenvSettings {
836 /// Load direnv configuration through a shell hook
837 ShellHook,
838 /// Load direnv configuration directly using `direnv export json`
839 #[default]
840 Direct,
841 /// Do not load direnv configuration
842 Disabled,
843}
844
845#[derive(
846 Clone,
847 Copy,
848 Debug,
849 Eq,
850 PartialEq,
851 Ord,
852 PartialOrd,
853 Serialize,
854 Deserialize,
855 JsonSchema,
856 MergeFrom,
857 strum::VariantArray,
858 strum::VariantNames,
859)]
860#[serde(rename_all = "snake_case")]
861pub enum DiagnosticSeverityContent {
862 // No diagnostics are shown.
863 Off,
864 Error,
865 Warning,
866 Info,
867 Hint,
868 All,
869}
870
871/// A custom Git hosting provider.
872#[with_fallible_options]
873#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
874pub struct GitHostingProviderConfig {
875 /// The type of the provider.
876 ///
877 /// Must be one of `github`, `gitlab`, `bitbucket`, `gitea`, `forgejo`, or `source_hut`.
878 pub provider: GitHostingProviderKind,
879
880 /// The base URL for the provider (e.g., "https://code.corp.big.com").
881 pub base_url: String,
882
883 /// The display name for the provider (e.g., "BigCorp GitHub").
884 pub name: String,
885}
886
887#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
888#[serde(rename_all = "snake_case")]
889pub enum GitHostingProviderKind {
890 Github,
891 Gitlab,
892 Bitbucket,
893 Gitea,
894 Forgejo,
895 SourceHut,
896}
897
898#[cfg(test)]
899mod tests {
900 use super::*;
901
902 #[test]
903 fn test_stdio_context_server_without_args() {
904 let settings: ContextServerSettingsContent =
905 serde_json::from_str(r#"{ "command": "echo" }"#)
906 .expect("stdio context server without `args` should parse");
907 let ContextServerSettingsContent::Stdio { command, .. } = settings else {
908 panic!("expected Stdio variant, got {settings:?}");
909 };
910 assert_eq!(command.path, PathBuf::from("echo"));
911 assert!(command.args.is_empty());
912
913 let settings: ContextServerSettingsContent =
914 serde_json::from_str(r#"{ "command": "echo", "args": ["hello"] }"#).unwrap();
915 let ContextServerSettingsContent::Stdio { command, .. } = settings else {
916 panic!("expected Stdio variant, got {settings:?}");
917 };
918 assert_eq!(command.args, vec!["hello".to_string()]);
919 }
920}
921