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
|
use clap::{App, AppSettings, Arg};
use crate::config;
use crate::config::Config;
use crate::error::Result;
// TODO --sites plural
// TODO --add-site (in addition to defaults)
pub struct Opts {
pub list_sites: bool,
pub update_sites: bool,
pub set_api_key: Option<String>,
pub query: Option<String>,
pub config: Config,
}
pub fn get_opts() -> Result<Opts> {
let config = config::user_config()?;
let limit = &config.limit.to_string();
let matches = App::new("so")
.setting(AppSettings::ColoredHelp)
.version(clap::crate_version!())
.author(clap::crate_authors!())
.about(clap::crate_description!())
.arg(
Arg::with_name("list-sites")
.long("list-sites")
.help("Print available StackExchange sites"),
)
.arg(
Arg::with_name("update-sites")
.long("update-sites")
.help("Update cache of StackExchange sites"),
)
.arg(
Arg::with_name("set-api-key")
.long("set-api-key")
.number_of_values(1)
.takes_value(true)
.help("Set StackExchange API key"),
)
.arg(
Arg::with_name("site")
.long("site")
.short("s")
.multiple(false) // TODO sites plural
.number_of_values(1)
.takes_value(true)
.default_value(&config.site)
.help("StackExchange site code to search"), // TODO sites plural
)
.arg(
Arg::with_name("limit")
.long("limit")
.short("l")
.number_of_values(1)
.takes_value(true)
.default_value(limit)
.validator(|s| s.parse::<u32>().map_err(|e| e.to_string()).map(|_| ()))
.help("Question limit per site query")
.hidden(true), // TODO unhide once more than just --lucky
)
.arg(
Arg::with_name("lucky")
.long("lucky")
.help("Print the top-voted answer of the most relevant question")
.hidden(true), // TODO unhide
)
.arg(
Arg::with_name("query")
.multiple(true)
.index(1)
.required_unless_one(&["list-sites", "update-sites", "set-api-key"]),
)
.get_matches();
Ok(Opts {
list_sites: matches.is_present("list-sites"),
update_sites: matches.is_present("update-sites"),
set_api_key: matches.value_of("set-api-key").map(String::from),
query: matches
.values_of("query")
.map(|q| q.collect::<Vec<_>>().join(" ")),
config: Config {
// these unwraps are safe via clap default values & validators
limit: matches.value_of("limit").unwrap().parse::<u16>().unwrap(),
site: matches.value_of("site").unwrap().to_string(), // TODO values_of
api_key: matches
.value_of("set-api-key")
.map(String::from)
.or(config.api_key),
},
})
}
// TODO how can I test this App given https://users.rust-lang.org/t/help-with-idiomatic-rust-and-ownership-semantics/43880
|