1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use toml;
pub trait ConfigType {
fn get_variant_names() -> String;
}
impl ConfigType for bool {
fn get_variant_names() -> String {
String::from("<boolean>")
}
}
impl ConfigType for usize {
fn get_variant_names() -> String {
String::from("<unsigned integer>")
}
}
impl ConfigType for String {
fn get_variant_names() -> String {
String::from("<string>")
}
}
impl<T: ConfigType> ConfigType for Option<T> {
fn get_variant_names() -> String {
String::from("<string> | null")
}
}
macro_rules! create_config {
($($i:ident: $ty:ty, $def:expr, $unstable:expr, $( $dstring:expr ),+ );+ $(;)*) => (
#[derive(Serialize, Deserialize, Clone)]
pub struct Config {
$(pub $i: $ty),+
}
#[derive(Deserialize, Clone)]
pub struct ParsedConfig {
$(pub $i: Option<$ty>),+
}
impl Config {
fn fill_from_parsed_config(mut self, parsed: ParsedConfig) -> Config {
$(
if let Some(val) = parsed.$i {
self.$i = val;
}
)+
self
}
pub fn from_toml(s: &str) -> Config {
let parsed_config: ParsedConfig = toml::from_str(s).expect("Could not parse TOML");
Config::default().fill_from_parsed_config(parsed_config)
}
pub fn print_docs() {
use std::cmp;
let max = 0;
$( let max = cmp::max(max, stringify!($i).len()+1); )+
let mut space_str = String::with_capacity(max);
for _ in 0..max {
space_str.push(' ');
}
println!("Configuration Options:");
$(
if !$unstable {
let name_raw = stringify!($i);
let mut name_out = String::with_capacity(max);
for _ in name_raw.len()..max-1 {
name_out.push(' ')
}
name_out.push_str(name_raw);
name_out.push(' ');
println!("{}{} Default: {:?}",
name_out,
<$ty>::get_variant_names(),
$def);
$(
println!("{}{}", space_str, $dstring);
)+
println!("");
}
)+
}
}
impl Default for Config {
fn default() -> Config {
Config {
$(
$i: $def,
)+
}
}
}
)
}
create_config! {
build_command: String, "cargo check".to_owned(), false, "command to call to build";
edit_command: String, String::new(), false,
"command to call to edit; can use $file, $line, and $col.";
unstable_features: bool, false, false, "Enable unstable features";
ip: String, "127.0.0.1".to_owned(), false, "ip address to launch server";
port: usize, 7878, false, "port to run rustw on";
demo_mode: bool, false, true, "run in demo mode";
demo_mode_root_path: String, String::new(), true, "path to use in URLs in demo mode";
context_lines: usize, 2, false, "lines of context to show before and after code snippets";
build_on_load: bool, true, false, "build on page load and refresh";
workspace_root: Option<String>, None: Option<String>, false, "root of the project workspace";
vcs_link: String, String::new(), false, "link to use for VCS; should use $file and $line.";
}