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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use std::{collections::HashMap, path};
use crate::{data, error, ui};
/// The file format a viewer expects.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub(crate) enum ViewerType {
/// A viewer that displays HTML files and thus needs to be given paths to an HTML file.
#[default]
Html,
/// A viewer that displays markdown files and thus needs to be given paths to an markdown file.
Markdown,
}
/// Groups data passed by the user in the config file.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(default)]
pub struct Config {
/// Path to the vault to index.
pub(crate) vault_path: Option<path::PathBuf>,
/// File types to consider notes
/// See the [default list](https://docs.rs/ignore/latest/src/ignore/default_types.rs.html) of the ignore crate for possible options.
/// The "all" option matches all files.
pub(crate) file_types: Vec<String>,
/// Default file ending for newly created notes
pub(crate) default_extension: String,
/// Whether to create a cache file of the index to reload on program start.
pub(crate) cache_index: bool,
/// Selected theme
pub(crate) theme: String,
/// When to show the global stats area on the select screen.
pub(crate) stats_show: ui::screen::StatsShow,
/// What columns to display on the select screen.
pub(crate) select_columns: Vec<(String, data::NoteColumn)>,
/// Whether tags have to match exactly or only by prefix when filtering.
pub(crate) tag_match: data::TagMatch,
/// Default column to sort notes by.
pub(crate) default_sorting: data::NoteColumn,
/// Default sorting direction (true for ascending, false for descending).
pub(crate) default_sorting_asc: bool,
/// The editor to use for notes.
pub(crate) editor: Option<Vec<String>>,
/// Main viewer to inspect rendered notes.
pub(crate) viewer: Option<Vec<String>>,
/// Preferred file type of the main viewer.
pub(crate) viewer_type: Option<ViewerType>,
/// Alternative viewer to inspect rendered notes.
pub(crate) secondary_viewer: Option<Vec<String>>,
/// Preferred file type of the alternative viewer.
pub(crate) secondary_viewer_type: Option<ViewerType>,
/// When set to true, HTML files are mass-created on start and continuously kept up to date with file changes instead of being created on-demand.
pub(crate) enable_html: bool,
/// Path to .css file to style htmls with.
pub(crate) css: Option<String>,
/// String to prepend to all generated html documents (e.g. for MathJax)
pub(crate) html_prepend: Option<String>,
/// Whether or not to insert a MathJax preamble in notes containing math code.
pub(crate) katex: bool,
/// A list of strings to replace in math mode to mimic latex commands
pub(crate) math_replacements: HashMap<String, String>,
}
impl Default for Config {
fn default() -> Self {
Self {
vault_path: None,
file_types: vec![String::from("markdown")],
default_extension: String::from("md"),
cache_index: false,
theme: "default_dark".to_string(),
stats_show: ui::screen::StatsShow::Both,
select_columns: vec![
("Name".to_string(), data::NoteColumn::Name),
(" Words".to_string(), data::NoteColumn::Words),
(" Chars".to_string(), data::NoteColumn::Chars),
("GlobalOut".to_string(), data::NoteColumn::GlobalOutLinks),
("LocalOut".to_string(), data::NoteColumn::LocalOutLinks),
("GlobalIn".to_string(), data::NoteColumn::GlobalInLinks),
("LocalIn".to_string(), data::NoteColumn::LocalInLinks),
],
tag_match: data::TagMatch::Exact,
default_sorting: data::NoteColumn::Name,
default_sorting_asc: true,
editor: None,
viewer_type: Some(ViewerType::Html),
viewer: Some(vec![String::from("firefox"), String::from("%p")]),
secondary_viewer_type: None,
secondary_viewer: None,
enable_html: true,
css: Some("default_dark".to_string()),
html_prepend: None,
katex: true,
math_replacements: HashMap::from_iter(vec![(
"\\field".to_string(),
"\\mathbb".to_string(),
)]),
}
}
}
impl Config {
/// Ensures the vault path in this configuration struct is set and not `None`.
/// If a vault path is given in a command line argument, that one takes precedent over one given in the configuration file.
/// If neither the configuration file nor the command line arguments specify a vault path, the current directory is used instead.
pub fn fix_vault_path(&mut self, args: crate::Arguments) -> error::Result<()> {
let mut full_vault_path = Self::vault_path(std::env::current_dir()?, args, self);
// make sure path is absolute
if !full_vault_path.is_absolute() {
full_vault_path = std::env::current_dir()?.join(full_vault_path);
}
self.vault_path = Some(full_vault_path);
Ok(())
}
/// Not expansion on windows
#[cfg(not(target_family = "unix"))]
fn vault_path(
pwd: path::PathBuf,
args: crate::Arguments,
config: &mut Config,
) -> path::PathBuf {
args.target_folder
.map(|folder_string| path::PathBuf::from(folder_string))
.or(config.vault_path.take())
.unwrap_or_else(|| pwd.clone())
}
/// Expanduser expands `~` to the correct user home directory and similar, on unix systems.
#[cfg(target_family = "unix")]
fn vault_path(
pwd: path::PathBuf,
args: crate::Arguments,
config: &mut Config,
) -> path::PathBuf {
args.target_folder
// first attempt to extend the command line given path if one was passed
.and_then(|arg_string| expanduser::expanduser(arg_string).ok())
// if none was given, expand the path given from the config file
.or_else(|| {
config.vault_path.take().and_then(|conf_path_buf| {
expanduser::expanduser(conf_path_buf.to_string_lossy()).ok()
})
})
.unwrap_or_else(|| pwd.clone())
}
}