summaryrefslogtreecommitdiffstats
path: root/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.rs')
-rw-r--r--src/config.rs107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..4463479
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,107 @@
1use anyhow::{anyhow, Context, Result};
2use codemap::CodeMap;
3use codemap_diagnostic::Diagnostic;
4use serde_derive::{Deserialize, Serialize};
5use structopt::StructOpt;
6use thiserror::Error;
7
8use std::path::{Path, PathBuf};
9use std::sync::Arc;
10
11pub(super) const DEFAULT_PROJECT_CONFIGURATION_FILE_NAME: &str = "poseidoc.toml";
12
13#[derive(Debug, Clone, StructOpt, Deserialize, Serialize)]
14#[structopt(rename_all = "kebab-case")]
15#[serde(rename_all = "kebab-case", default)]
16pub(crate) struct Config {
17 #[structopt(skip)]
18 pub(crate) name: String,
19 #[structopt(long, default_value = ".")]
20 pub(crate) compile_commands_location: PathBuf,
21 #[structopt(skip = vec![])]
22 pub(crate) extra_clang_args: Vec<String>,
23}
24
25impl Default for Config {
26 fn default() -> Self {
27 Config {
28 name: "My Project".into(),
29 compile_commands_location: PathBuf::from(r"."),
30 extra_clang_args: Vec::new(),
31 }
32 }
33}
34
35pub(super) fn load_config(location: impl AsRef<Path>, codemap: &mut CodeMap) -> Result<Config> {
36 let location = location.as_ref();
37
38 let final_path = if location.is_dir() {
39 location.join(DEFAULT_PROJECT_CONFIGURATION_FILE_NAME)
40 } else if !location.exists() {
41 return Err(anyhow!("File {:?} does not exists", location))
42 .with_context(|| format!("Failed to open project configuration: {:?}", location));
43 } else {
44 location.to_owned()
45 };
46
47 let config_str =
48 std::fs::read_to_string(&final_path).map_err(|err| ConfigLoadError::IoError {
49 file_name: final_path.clone(),
50 source: err,
51 })?;
52 Ok(
53 toml::from_str(&config_str).map_err(|err| ConfigLoadError::TomlDeserialzation {
54 file: codemap.add_file(final_path.to_string_lossy().into(), config_str),
55 source: err,
56 })?,
57 )
58}
59
60#[derive(Debug, Error)]
61#[error("Error loading project configuration")]
62pub(crate) enum ConfigLoadError {
63 #[error("Failed to read project configuration: {:?}", file_name)]
64 IoError {
65 file_name: PathBuf,
66 source: std::io::Error,
67 },
68 #[error("Failed to parse project configuration: {:?}", file.name())]
69 TomlDeserialzation {
70 file: Arc<codemap::File>,
71 source: toml::de::Error,
72 },
73}
74
75impl From<&ConfigLoadError> for Diagnostic {
76 fn from(err: &ConfigLoadError) -> Diagnostic {
77 use codemap_diagnostic::{Level, SpanLabel, SpanStyle};
78 use std::convert::TryInto;
79
80 let message = err.to_string();
81
82 let spans = match err {
83 ConfigLoadError::IoError { .. } => vec![],
84 ConfigLoadError::TomlDeserialzation { file, source, .. } => {
85 if let Some((line, col)) = source.line_col() {
86 let line_span = file.line_span(line);
87 let col = col.try_into().unwrap();
88 let span = line_span.subspan(col, col);
89 vec![SpanLabel {
90 span,
91 label: None,
92 style: SpanStyle::Primary,
93 }]
94 } else {
95 vec![]
96 }
97 }
98 };
99
100 Diagnostic {
101 level: Level::Error,
102 message,
103 code: None,
104 spans,
105 }
106 }
107}