tokei/
config.rs

1use std::{env, fs, path::PathBuf};
2
3use etcetera::BaseStrategy;
4
5use crate::language::LanguageType;
6use crate::sort::Sort;
7use crate::stats::Report;
8
9/// A configuration struct for how [`Languages::get_statistics`] searches and
10/// counts languages.
11///
12/// ```
13/// use tokei::Config;
14///
15/// let config = Config {
16///     treat_doc_strings_as_comments: Some(true),
17///     ..Config::default()
18/// };
19/// ```
20///
21/// [`Languages::get_statistics`]: struct.Languages.html#method.get_statistics
22#[derive(Debug, Default, Deserialize)]
23pub struct Config {
24    /// Width of columns to be printed to the terminal. _This option is ignored
25    /// in the library._ *Default:* Auto detected width of the terminal.
26    pub columns: Option<usize>,
27    /// Count hidden files and directories. *Default:* `false`.
28    pub hidden: Option<bool>,
29    /// Don't respect ignore files (.gitignore, .ignore, etc.). This implies --no-ignore-parent,
30    /// --no-ignore-dot, and --no-ignore-vcs. *Default:* `false`.
31    pub no_ignore: Option<bool>,
32    /// Don't respect ignore files (.gitignore, .ignore, etc.) in parent directories.
33    /// *Default:* `false`.
34    pub no_ignore_parent: Option<bool>,
35    /// Don't respect .ignore and .tokeignore files, including those in parent directories.
36    /// *Default:* `false`.
37    pub no_ignore_dot: Option<bool>,
38    /// Don't respect VCS ignore files (.gitignore, .hgignore, etc.), including those in
39    /// parent directories. *Default:* `false`.
40    pub no_ignore_vcs: Option<bool>,
41    /// Whether to treat doc strings in languages as comments.  *Default:*
42    /// `false`.
43    pub treat_doc_strings_as_comments: Option<bool>,
44    /// Sort languages. *Default:* `None`.
45    pub sort: Option<Sort>,
46    /// Filters languages searched to just those provided. E.g. A directory
47    /// containing `C`, `Cpp`, and `Rust` with a `Config.types` of `[Cpp, Rust]`
48    /// will count only `Cpp` and `Rust`. *Default:* `None`.
49    pub types: Option<Vec<LanguageType>>,
50    // /// A map of individual language configuration.
51    // pub languages: Option<HashMap<LanguageType, LanguageConfig>>,
52    /// Whether to output only the paths for downstream batch processing
53    /// *Default:* false
54    #[serde(skip)]
55    /// Adds a closure for each function, e.g., print the result
56    pub for_each_fn: Option<fn(LanguageType, Report)>,
57}
58
59impl Config {
60    /// Constructs a new `Config` from either `$base/tokei.toml` or
61    /// `$base/.tokeirc`. `tokei.toml` takes precedence over `.tokeirc`
62    /// as the latter is a hidden file on Unix and not an idiomatic
63    /// filename on Windows.
64    fn get_config(base: PathBuf) -> Option<Self> {
65        fs::read_to_string(base.join("tokei.toml"))
66            .ok()
67            .or_else(|| fs::read_to_string(base.join(".tokeirc")).ok())
68            .and_then(|s| toml::from_str(&s).ok())
69    }
70
71    /// Creates a `Config` from three configuration files if they are available.
72    /// Files can have two different names `tokei.toml` and `.tokeirc`.
73    /// Firstly it will attempt to find a config in the configuration directory
74    /// (see below), secondly from the home directory, `$HOME/`,
75    /// and thirdly from the current directory, `./`.
76    /// The current directory's configuration will take priority over the configuration
77    /// directory.
78    ///
79    /// |Platform | Value                                 | Example                        |
80    /// | ------- | ------------------------------------- | ------------------------------ |
81    /// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config            |
82    /// | macOS   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /Users/alice/.config           |
83    /// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming |
84    ///
85    /// # Example
86    /// ```toml
87    /// columns = 80
88    /// types = ["Python"]
89    /// treat_doc_strings_as_comments = true
90    // ///
91    // /// [[languages.Python]]
92    // /// extensions = ["py3"]
93    /// ```
94    pub fn from_config_files() -> Self {
95        let conf_dir = etcetera::choose_base_strategy()
96            .ok()
97            .map(|basedirs| basedirs.config_dir())
98            .and_then(Self::get_config)
99            .unwrap_or_default();
100
101        let home_dir = etcetera::home_dir()
102            .ok()
103            .and_then(Self::get_config)
104            .unwrap_or_default();
105
106        let current_dir = env::current_dir()
107            .ok()
108            .and_then(Self::get_config)
109            .unwrap_or_default();
110
111        #[allow(clippy::or_fun_call)]
112        Config {
113            columns: current_dir
114                .columns
115                .or(home_dir.columns.or(conf_dir.columns)),
116            hidden: current_dir.hidden.or(home_dir.hidden.or(conf_dir.hidden)),
117            //languages: current_dir.languages.or(conf_dir.languages),
118            treat_doc_strings_as_comments: current_dir.treat_doc_strings_as_comments.or(home_dir
119                .treat_doc_strings_as_comments
120                .or(conf_dir.treat_doc_strings_as_comments)),
121            sort: current_dir.sort.or(home_dir.sort.or(conf_dir.sort)),
122            types: current_dir.types.or(home_dir.types.or(conf_dir.types)),
123            for_each_fn: current_dir
124                .for_each_fn
125                .or(home_dir.for_each_fn.or(conf_dir.for_each_fn)),
126            no_ignore: current_dir
127                .no_ignore
128                .or(home_dir.no_ignore.or(conf_dir.no_ignore)),
129            no_ignore_parent: current_dir
130                .no_ignore_parent
131                .or(home_dir.no_ignore_parent.or(conf_dir.no_ignore_parent)),
132            no_ignore_dot: current_dir
133                .no_ignore_dot
134                .or(home_dir.no_ignore_dot.or(conf_dir.no_ignore_dot)),
135            no_ignore_vcs: current_dir
136                .no_ignore_vcs
137                .or(home_dir.no_ignore_vcs.or(conf_dir.no_ignore_vcs)),
138        }
139    }
140}
141
142/*
143/// Configuration for an individual [`LanguageType`].
144///
145/// ```
146/// use std::collections::HashMap;
147/// use tokei::{Config, LanguageConfig, LanguageType};
148///
149/// let config = Config {
150///     languages: {
151///         let cpp_conf = LanguageConfig {
152///             extensions: vec![String::from("c")],
153///         };
154///
155///         let mut languages_config = HashMap::new();
156///         languages_config.insert(LanguageType::Cpp, cpp_conf);
157///
158///         Some(languages_config)
159///     },
160///
161///     ..Config::default()
162/// };
163///
164/// ```
165///
166/// [`LanguageType`]: enum.LanguageType.html
167#[derive(Debug, Default, Deserialize)]
168pub struct LanguageConfig {
169    /// Additional extensions for a language. Any extensions that overlap with
170    /// already defined extensions from `tokei` will be ignored.
171    pub extensions: Vec<String>,
172}
173
174impl LanguageConfig {
175    /// Creates a new empty configuration. By default this will not change
176    /// anything from the default.
177    pub fn new() -> Self {
178        Self::default()
179    }
180
181    /// Accepts a `Vec<String>` representing additional extensions for a
182    /// language. Any extensions that overlap with already defined extensions
183    /// from `tokei` will be ignored.
184    pub fn extensions(&mut self, extensions: Vec<String>) {
185        self.extensions = extensions;
186    }
187}
188*/