-
Notifications
You must be signed in to change notification settings - Fork 427
Expand file tree
/
Copy pathmod.rs
More file actions
119 lines (103 loc) · 2.98 KB
/
mod.rs
File metadata and controls
119 lines (103 loc) · 2.98 KB
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
pub mod consts;
pub mod directories;
pub mod editor;
pub mod knowledge_store;
pub mod open;
pub mod pattern_matching;
pub mod spinner;
pub mod system_info;
#[cfg(test)]
pub mod test;
pub mod tool_permission_checker;
pub mod ui;
use std::fmt::Display;
use std::io;
use std::io::{
ErrorKind,
Write,
stdout,
};
use anstream::stream::IsTerminal;
pub use consts::*;
use dialoguer::Select;
use dialoguer::theme::ColorfulTheme;
use eyre::{
Context,
Result,
bail,
};
use thiserror::Error;
use tracing::warn;
#[derive(Debug, Error)]
pub enum UtilError {
#[error("io operation error")]
IoError(#[from] std::io::Error),
#[error(transparent)]
Directory(#[from] directories::DirectoryError),
#[error(transparent)]
StrUtf8Error(#[from] std::str::Utf8Error),
#[error(transparent)]
Json(#[from] serde_json::Error),
}
#[derive(Debug, Clone)]
pub struct UnknownDesktopErrContext {
xdg_current_desktop: String,
xdg_session_desktop: String,
gdm_session: String,
}
impl std::fmt::Display for UnknownDesktopErrContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "XDG_CURRENT_DESKTOP: `{}`, ", self.xdg_current_desktop)?;
write!(f, "XDG_SESSION_DESKTOP: `{}`, ", self.xdg_session_desktop)?;
write!(f, "GDMSESSION: `{}`", self.gdm_session)
}
}
pub fn choose(prompt: impl Display, options: &[impl ToString]) -> Result<Option<usize>> {
if options.is_empty() {
bail!("no options passed to choose")
}
if !stdout().is_terminal() {
warn!("called choose while stdout is not a terminal");
return Ok(Some(0));
}
match Select::with_theme(&dialoguer_theme())
.items(options)
.default(0)
.with_prompt(prompt.to_string())
.interact_opt()
{
Ok(ok) => Ok(ok),
Err(dialoguer::Error::IO(io)) if io.kind() == ErrorKind::Interrupted => Ok(None),
Err(e) => Err(e).wrap_err("Failed to choose"),
}
}
pub fn input(prompt: &str, initial_text: Option<&str>) -> Result<String> {
if !stdout().is_terminal() {
warn!("called input while stdout is not a terminal");
return Ok(String::new());
}
let theme = dialoguer_theme();
let mut input = dialoguer::Input::with_theme(&theme).with_prompt(prompt);
if let Some(initial_text) = initial_text {
input = input.with_initial_text(initial_text);
}
Ok(input.interact_text()?)
}
pub fn dialoguer_theme() -> ColorfulTheme {
ColorfulTheme {
prompt_prefix: dialoguer::console::style("?".into()).for_stderr().magenta(),
..ColorfulTheme::default()
}
}
/// A writer that discards all data written to it.
pub struct NullWriter;
impl Write for NullWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// Report that all bytes were successfully "written" (i.e., discarded).
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
// Flushing a null writer does nothing.
Ok(())
}
}