swls_core/components/
config.rs1use std::{collections::HashSet, path::PathBuf};
2
3use bevy_ecs::prelude::*;
4use serde::Deserialize;
5
6use crate::{
7 lsp_types::{Url, WorkspaceFolder},
8 util::fs::Fs,
9};
10
11#[derive(Debug, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub enum Disabled {
13 #[serde(alias = "SHAPES", alias = "shapes")]
14 Shapes,
15}
16
17#[derive(Resource, Debug, Default)]
18pub struct ServerConfig {
19 pub workspaces: Vec<WorkspaceFolder>,
20 pub config: Config,
21}
22
23#[derive(Debug, Deserialize)]
24pub struct Config {
25 #[serde(default = "debug")]
27 pub log: String,
28 pub turtle: Option<bool>,
30 pub trig: Option<bool>,
32 pub jsonld: Option<bool>,
34 pub sparql: Option<bool>,
36 #[serde(flatten)]
38 pub local: LocalConfig,
39}
40
41#[derive(Debug, Deserialize, Default)]
42#[serde(default)]
43pub struct LocalConfig {
44 pub ontologies: HashSet<String>,
46 pub shapes: HashSet<String>,
48 pub disabled: HashSet<Disabled>,
50 pub prefix_disabled: HashSet<String>,
52 pub completion: CompletionConfig,
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
70#[serde(untagged)]
71pub enum CompletionConfig {
72 Mode(CompletionMode),
74
75 Except(ExceptRules),
77
78 Strict(StrictRules),
80}
81
82impl Default for CompletionConfig {
83 fn default() -> Self {
84 Self::Mode(CompletionMode::None)
85 }
86}
87
88impl CompletionConfig {
89 fn combine(&mut self, other: CompletionConfig) {
90 use CompletionConfig::*;
91
92 if matches!(other, Mode(CompletionMode::None)) {
93 return;
94 }
95
96 if matches!(self, Mode(CompletionMode::None)) {
97 *self = other;
98 return;
99 }
100
101 if let Strict(r) = self {
102 if let Strict(r2) = other {
103 r.strict.extend(r2.strict);
104 return;
105 }
106 }
107
108 if let Except(r) = self {
109 if let Except(r2) = other {
110 r.loose.extend(r2.loose);
111 return;
112 }
113 }
114
115 *self = other;
116 }
117 pub fn correct_domain_required(&self, property: &str) -> bool {
118 match self {
119 CompletionConfig::Mode(CompletionMode::Loose)
120 | CompletionConfig::Mode(CompletionMode::None) => false,
121 CompletionConfig::Mode(CompletionMode::Strict) => true,
122 CompletionConfig::Except(completion_rules) => !completion_rules
123 .loose
124 .iter()
125 .any(|x| property.starts_with(x)),
126 CompletionConfig::Strict(completion_rules) => completion_rules
127 .strict
128 .iter()
129 .any(|x| property.starts_with(x)),
130 }
131 }
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, Default, Deserialize)]
135#[serde(rename_all = "lowercase")]
136pub enum CompletionMode {
137 #[default]
138 None,
139 Loose,
140 Strict,
141}
142
143#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Default)]
144#[serde(deny_unknown_fields)]
145pub struct ExceptRules {
146 #[serde(default)]
147 pub loose: Vec<String>,
148}
149#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Default)]
150#[serde(deny_unknown_fields)]
151pub struct StrictRules {
152 #[serde(default)]
153 pub strict: Vec<String>,
154}
155
156impl LocalConfig {
157 pub fn combine(&mut self, other: LocalConfig) {
159 self.ontologies.extend(other.ontologies);
160 self.shapes.extend(other.shapes);
161 self.disabled.extend(other.disabled);
162 self.prefix_disabled.extend(other.prefix_disabled);
163 self.completion.combine(other.completion);
164 }
165 #[cfg(target_arch = "wasm32")]
166 pub async fn global(_: &Fs) -> Option<Self> {
167 None
168 }
169
170 #[cfg(not(target_arch = "wasm32"))]
171 pub async fn global(fs: &Fs) -> Option<Self> {
172 let global_path = dirs::config_dir()
173 .unwrap_or_else(|| PathBuf::from("."))
174 .join("swls/config.json");
175 let url = crate::lsp_types::Url::from_file_path(global_path).ok()?;
176
177 tracing::debug!("Found global config url {}", url.as_str());
178 let content = fs.0.read_file(&url).await?;
179 tracing::debug!("Read global config content");
180
181 match serde_json::from_str(&content) {
182 Ok(x) => Some(x),
183 Err(e) => {
184 tracing::error!("Deserialize failed\n{:?}", e);
185 None
186 }
187 }
188 }
189
190 pub async fn local(fs: &Fs, url: &Url) -> Option<Self> {
191 let url = Url::parse(&format!("{}/.swls/config.json", url.as_str())).ok()?;
192 tracing::debug!("Found local config url {}", url.as_str());
193 let content = fs.0.read_file(&url).await?;
194 tracing::debug!("Read local config content");
195 match serde_json::from_str(&content) {
196 Ok(x) => Some(x),
197 Err(e) => {
198 tracing::error!("Deserialize failed\n{:?}", e);
199 None
200 }
201 }
202 }
203}
204
205impl Default for Config {
206 fn default() -> Self {
207 Self {
208 log: "debug".to_string(),
209 turtle: None,
210 trig: None,
211 jsonld: None,
212 sparql: None,
213 local: LocalConfig::default(),
214 }
215 }
216}
217
218fn debug() -> String {
219 String::from("debug")
220}