Add support for configuration files
With this patch, we load defaults for the command-line arguments from the configuration file located in the user configuration directory according to the XDG Base Directory Specification.
This commit is contained in:
parent
3a20d662c5
commit
e5ee4df73b
@ -12,6 +12,12 @@ SPDX-License-Identifier: MIT
|
||||
the rich text viewer.
|
||||
- Add the `--no-syntax-highlight` option to disable syntax highlighting.
|
||||
- Add the `--theme [theme]` option to select the syntax highlighting theme.
|
||||
- Add support for configuration files:
|
||||
- Load the `config.toml` file from the config directory according to the XDG
|
||||
Base Directory Specification `${XDG_CONFIG_HOME}/rusty-man/config.toml`,
|
||||
where `${XDG_CONFIG_HOME}` defaults to `${HOME}/.config`. The
|
||||
configuration file can be used to set defaults for the command-line
|
||||
options.
|
||||
|
||||
## v0.1.3 (2020-07-28)
|
||||
|
||||
|
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -726,6 +726,8 @@ dependencies = [
|
||||
"serde_tuple 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntect 4.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -998,6 +1000,14 @@ dependencies = [
|
||||
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.6.0"
|
||||
@ -1065,6 +1075,11 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "xdg"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.3"
|
||||
@ -1197,6 +1212,7 @@ dependencies = [
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
||||
"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
|
||||
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
@ -1208,5 +1224,6 @@ dependencies = [
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
||||
"checksum xml-rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
|
||||
"checksum xml5ever 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b1b52e6e8614d4a58b8e70cf51ec0cc21b256ad8206708bcff8139b5bbd6a59"
|
||||
|
@ -26,6 +26,8 @@ pager = "0.15.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_repr = "0.1.6"
|
||||
serde_tuple = "0.5.0"
|
||||
toml = "0.5.6"
|
||||
xdg = "2.2.0"
|
||||
|
||||
[dependencies.env_logger]
|
||||
version = "0.7.1"
|
||||
|
74
src/args.rs
74
src/args.rs
@ -1,6 +1,9 @@
|
||||
// SPDX-FileCopyrightText: 2020 Robin Krahl <robin.krahl@ireas.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::fs;
|
||||
|
||||
use serde::Deserialize;
|
||||
use structopt::StructOpt;
|
||||
|
||||
use crate::doc;
|
||||
@ -18,9 +21,11 @@ use crate::viewer;
|
||||
/// rusty-man tries to find an item that exactly matches the given keyword. If it doesn’t find an
|
||||
/// exact match, it reads the search indexes of all available sources and tries to find a partial
|
||||
/// match.
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[derive(Debug, Default, Deserialize, StructOpt)]
|
||||
#[serde(default)]
|
||||
pub struct Args {
|
||||
/// The keyword to open the documentation for, e. g. `rand_core::RngCore`
|
||||
#[serde(skip)]
|
||||
pub keyword: doc::Name,
|
||||
|
||||
/// The sources to check for documentation generated by rustdoc
|
||||
@ -32,6 +37,7 @@ pub struct Args {
|
||||
|
||||
/// The viewer for the rustdoc documentation (one of: plain, rich)
|
||||
#[structopt(long, parse(try_from_str = viewer::get_viewer))]
|
||||
#[serde(deserialize_with = "deserialize_viewer")]
|
||||
pub viewer: Option<Box<dyn viewer::Viewer>>,
|
||||
|
||||
/// Do not search the default documentation sources
|
||||
@ -55,10 +61,12 @@ pub struct Args {
|
||||
pub examples: bool,
|
||||
|
||||
#[structopt(flatten)]
|
||||
#[serde(flatten)]
|
||||
pub viewer_args: ViewerArgs,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[derive(Debug, Default, Deserialize, StructOpt)]
|
||||
#[serde(default)]
|
||||
pub struct ViewerArgs {
|
||||
/// Disable syntax highlighting.
|
||||
///
|
||||
@ -71,12 +79,66 @@ pub struct ViewerArgs {
|
||||
///
|
||||
/// rusty-man includes these color themes: base16-ocean.dark, base16-eighties.dark,
|
||||
/// base16-mocha.dark, base16-ocean.light, InspiredGitHub, Solarized (dark), Solarized (light).
|
||||
#[structopt(long, default_value = "base16-eighties.dark")]
|
||||
pub theme: String,
|
||||
/// Default value: base16-eighties.dark.
|
||||
#[structopt(long)]
|
||||
pub theme: Option<String>,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn load() -> Args {
|
||||
Args::from_args()
|
||||
pub fn load() -> anyhow::Result<Args> {
|
||||
let mut args = Args::from_args();
|
||||
|
||||
if let Some(config) = Args::load_config()? {
|
||||
args.merge(config);
|
||||
}
|
||||
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
fn load_config() -> anyhow::Result<Option<Args>> {
|
||||
let dirs = xdg::BaseDirectories::with_prefix("rusty-man")?;
|
||||
if let Some(path) = dirs.find_config_file("config.toml") {
|
||||
log::info!("Loading configuration file '{}'", path.display());
|
||||
let s = fs::read_to_string(path)?;
|
||||
toml::from_str(&s).map(Some).map_err(From::from)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn merge(&mut self, mut args: Args) {
|
||||
if !args.source_paths.is_empty() {
|
||||
args.source_paths.append(&mut self.source_paths);
|
||||
self.source_paths = args.source_paths;
|
||||
}
|
||||
if self.viewer.is_none() {
|
||||
self.viewer = args.viewer;
|
||||
}
|
||||
if !self.no_default_sources {
|
||||
self.no_default_sources = args.no_default_sources;
|
||||
}
|
||||
if !self.no_search {
|
||||
self.no_search = args.no_search;
|
||||
}
|
||||
if !self.examples {
|
||||
self.examples = args.examples;
|
||||
}
|
||||
if !self.viewer_args.no_syntax_highlight {
|
||||
self.viewer_args.no_syntax_highlight = args.viewer_args.no_syntax_highlight;
|
||||
}
|
||||
if self.viewer_args.theme.is_none() {
|
||||
self.viewer_args.theme = args.viewer_args.theme;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_viewer<'de, D>(d: D) -> Result<Option<Box<dyn viewer::Viewer>>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
use serde::de::Error;
|
||||
|
||||
let s: Option<&str> = Deserialize::deserialize(d)?;
|
||||
s.map(|s| viewer::get_viewer(s).map_err(D::Error::custom))
|
||||
.transpose()
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ use std::path;
|
||||
fn main() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
let args = args::Args::load();
|
||||
let args = args::Args::load()?;
|
||||
let sources = load_sources(&args.source_paths, !args.no_default_sources)?;
|
||||
let doc = if let Some(doc) = find_doc(&sources, &args.keyword)? {
|
||||
Some(doc)
|
||||
|
@ -59,10 +59,11 @@ impl super::Printer for RichTextRenderer {
|
||||
use anyhow::Context;
|
||||
|
||||
let mut theme_set = syntect::highlighting::ThemeSet::load_defaults();
|
||||
let theme_name = args.theme.as_deref().unwrap_or("base16-eighties.dark");
|
||||
let theme = theme_set
|
||||
.themes
|
||||
.remove(&args.theme)
|
||||
.with_context(|| format!("Could not find theme {}", &args.theme))?;
|
||||
.remove(theme_name)
|
||||
.with_context(|| format!("Could not find theme {}", theme_name))?;
|
||||
Ok(Self {
|
||||
line_length: viewer::get_line_length(),
|
||||
highlight: !args.no_syntax_highlight,
|
||||
|
Loading…
Reference in New Issue
Block a user