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
150
151
152
153
154
use std::{path::PathBuf, str::FromStr};
use clap::{Parser, Subcommand, ValueHint};
use regex::Regex;
use crate::defaults;
#[derive(Parser, Debug)]
#[command(version, about)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
/// Path to the SQLite database.
///
/// Automatically created if it does not exist at the given path.
#[arg(
short,
long,
default_value = defaults::DB_PATH.to_str(),
value_hint = ValueHint::FilePath,
env = "CLIPVAULT_DB",
global = true
)]
pub database: PathBuf,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
/// List the currently stored entries.
#[command()]
List(ListArgs),
/// Store an entry. Only accepts STDIN.
#[command()]
Store(StoreArgs),
/// Get the content of an entry.
#[command()]
Get(GetDelArgs),
/// Delete an entry.
#[command()]
Delete(GetDelArgs),
/// Delete all entries.
#[command()]
Clear,
}
#[derive(Debug, clap::Args)]
pub struct StoreArgs {
/// Maximum number of entries to store.
///
/// Setting this value to 0 disables the limit.
#[arg(long, default_value_t = defaults::MAX_ENTRIES, env = "CLIPVAULT_MAX_ENTRIES")]
pub max_entries: usize,
/// Entries older than this value will be deleted. Only accurate to the
/// second.
///
/// Setting this value to 0s or less disables the limit.
#[arg(long, default_value = defaults::MAX_ENTRY_AGE, env = "CLIPVAULT_MAX_AGE")]
pub max_entry_age: humantime::Duration,
/// Entries that are larger than this value in bytes will not be stored.
///
/// Setting this value to 0 disables the limit.
#[arg(long, default_value_t = defaults::MAX_ENTRY_LEN, env = "CLIPVAULT_MAX_LENGTH")]
pub max_entry_length: usize,
/// Entries that are smaller than this value in bytes will not be stored.
///
/// This value must be less than `max_entry_length`.
#[arg(long, default_value_t = defaults::MIN_ENTRY_LEN, env = "CLIPVAULT_MIN_LENGTH")]
pub min_entry_length: usize,
/// Store sensitive values, ignoring e.g. CLIPBOARD_STATE="sensitive" set by
/// wl-clipboard.
#[arg(long, action, env = "CLIPVAULT_STORE_SENSITIVE")]
pub store_sensitive: bool,
/// Entries which include any match for the given regex pattern will not be
/// stored.
///
/// To specify multiple patterns, simply call the argument again with a new
/// pattern. Be mindful of the fact that every regex pattern given will
/// be tested against every text input.
///
/// e.g. clipvault --store --ignore-pattern '^<meta http-equiv='
/// --ignore-pattern 'ignore\n$'
///
/// Note that look-around and backreferences are not supported, as the Rust
/// implementation of a regex engine used does not support those
/// features.
#[arg(long, action, env = "CLIPVAULT_IGNORE_PATTERN", num_args = 1)]
pub ignore_pattern: Option<Vec<Regex>>,
}
impl Default for StoreArgs {
fn default() -> Self {
Self {
max_entries: defaults::MAX_ENTRIES,
max_entry_age: humantime::Duration::from_str(defaults::MAX_ENTRY_AGE)
.expect("default max entry age should be valid"),
max_entry_length: defaults::MAX_ENTRY_LEN,
min_entry_length: defaults::MIN_ENTRY_LEN,
store_sensitive: false,
ignore_pattern: None,
}
}
}
#[derive(Debug, clap::Args)]
pub struct ListArgs {
/// Maximum width in characters for the previews.
///
/// Setting this value to 0 disables the limit.
#[arg(
short,
long,
default_value_t = defaults::MAX_PREVIEW_WIDTH,
env = "CLIPVAULT_MAX_PREVIEW_WIDTH"
)]
pub max_preview_width: usize,
/// Reverse the order of the list of returned entries (oldest first).
#[arg(short, long, action, env = "CLIPVAULT_REVERSE_LIST")]
pub reverse: bool,
}
impl Default for ListArgs {
fn default() -> Self {
Self {
max_preview_width: defaults::MAX_PREVIEW_WIDTH,
reverse: false,
}
}
}
#[derive(Debug, Default, clap::Args)]
pub struct GetDelArgs {
/// The selected row from `clipvault list`, or just the ID of the entry.
///
/// Can also be provided through STDIN.
#[arg(default_value(""))]
pub input: String,
/// The relative index of the desired entry (starting at 0). Negative
/// values are interpreted as starting from the oldest entries first.
/// For example, 0 represents the newest entry, 1 the entry just before
/// that, and -1 represents the oldest entry.
///
/// *NOTE*: conflicts with positional input, and will ignore
/// STDIN in the case where input is not provided.
// TODO: return error instead of ignore STDIN?
#[arg(long, conflicts_with("input"), allow_hyphen_values(true))]
pub index: Option<isize>,
}