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
155
156
157
158
159
|
use std::collections::BTreeSet;
/// A completion suggestion that tells the shell how to perform completion.
/// This can be either a set of specific suggestion items or a request for file completion.
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
pub enum Suggest {
/// A set of specific suggestion items for the shell to display.
Suggest(BTreeSet<SuggestItem>),
/// A request for the shell to perform file‑path completion.
#[default]
FileCompletion,
}
impl Suggest {
/// Creates a new Suggest variant containing a BTreeSet of suggestions.
pub fn new() -> Self {
Self::Suggest(BTreeSet::new())
}
/// Creates a FileCompletion variant.
pub fn file_comp() -> Self {
Self::FileCompletion
}
}
impl<T> From<T> for Suggest
where
T: IntoIterator,
T::Item: Into<String>,
{
fn from(items: T) -> Self {
let suggests = items
.into_iter()
.map(|item| SuggestItem::new(item.into()))
.collect();
Suggest::Suggest(suggests)
}
}
impl std::ops::Deref for Suggest {
type Target = BTreeSet<SuggestItem>;
fn deref(&self) -> &Self::Target {
match self {
Self::Suggest(suggests) => suggests,
Self::FileCompletion => panic!("Cannot deref FileCompletion variant"),
}
}
}
impl std::ops::DerefMut for Suggest {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Self::Suggest(suggests) => suggests,
Self::FileCompletion => panic!("Cannot deref_mut FileCompletion variant"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SuggestItem {
Simple(String),
WithDescription(String, String),
}
impl Default for SuggestItem {
fn default() -> Self {
SuggestItem::Simple(String::new())
}
}
impl PartialOrd for SuggestItem {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for SuggestItem {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.suggest().cmp(&other.suggest())
}
}
impl SuggestItem {
/// Creates a new simple suggestion without description.
pub fn new(suggest: String) -> Self {
Self::Simple(suggest)
}
/// Creates a new suggestion with a description.
pub fn new_with_desc(suggest: String, description: String) -> Self {
Self::WithDescription(suggest, description)
}
/// Adds a description to this suggestion, replacing any existing description.
pub fn with_desc(self, description: String) -> Self {
match self {
Self::Simple(suggest) => Self::WithDescription(suggest, description),
Self::WithDescription(suggest, _) => Self::WithDescription(suggest, description),
}
}
/// Returns the suggestion text.
pub fn suggest(&self) -> &String {
match self {
Self::Simple(suggest) => suggest,
Self::WithDescription(suggest, _) => suggest,
}
}
/// Updates the suggestion text.
pub fn set_suggest(&mut self, new_suggest: String) {
match self {
Self::Simple(suggest) => *suggest = new_suggest,
Self::WithDescription(suggest, _) => *suggest = new_suggest,
}
}
/// Returns the description if present.
pub fn description(&self) -> Option<&String> {
match self {
Self::Simple(_) => None,
Self::WithDescription(_, description) => Some(description),
}
}
/// Sets or replaces the description.
pub fn set_description(&mut self, description: String) {
match self {
Self::Simple(suggest) => *self = Self::WithDescription(suggest.clone(), description),
Self::WithDescription(_, desc) => *desc = description,
}
}
/// Removes and returns the description if present.
pub fn remove_desc(&mut self) -> Option<String> {
match self {
Self::Simple(_) => None,
Self::WithDescription(suggest, description) => {
let desc = std::mem::take(description);
*self = Self::Simple(std::mem::take(suggest));
Some(desc)
}
}
}
}
impl From<String> for SuggestItem {
fn from(suggest: String) -> Self {
Self::new(suggest)
}
}
impl From<(String, String)> for SuggestItem {
fn from((suggest, description): (String, String)) -> Self {
Self::new_with_desc(suggest, description)
}
}
|