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