proper prompt coloring and password masking
This commit is contained in:
parent
9703d984bb
commit
a3c8ef9f74
@ -6,7 +6,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustyline = "11"
|
rustyline = {version = "11", features = ["derive"]}
|
||||||
color-eyre = "0.6"
|
color-eyre = "0.6"
|
||||||
tokio = { version = "1.0", default-features = false, features = ["macros"] }
|
tokio = { version = "1.0", default-features = false, features = ["macros"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
@ -15,5 +15,5 @@ clap = { version = "4.2", default-features = false, features = ["suggestions", "
|
|||||||
dirs = "5.0"
|
dirs = "5.0"
|
||||||
connectbox = { path = "../connectbox" }
|
connectbox = { path = "../connectbox" }
|
||||||
color-print = "0.3"
|
color-print = "0.3"
|
||||||
ascii_table = { version = "4.0", features = ["auto_table_width"] }
|
ascii_table = "4.0"
|
||||||
once_cell = "1.17"
|
once_cell = "1.17"
|
||||||
|
@ -54,8 +54,8 @@ pub(crate) enum PortForwardsCommand {
|
|||||||
/// ID of the port. You can use `pfw show` to find it
|
/// ID of the port. You can use `pfw show` to find it
|
||||||
id: u32,
|
id: u32,
|
||||||
/// Action to perform with the port. Can be either enable, disable or delete.
|
/// Action to perform with the port. Can be either enable, disable or delete.
|
||||||
action: String
|
action: String,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn shell_cmd() -> Command {
|
pub(crate) fn shell_cmd() -> Command {
|
||||||
|
@ -3,7 +3,10 @@ use std::vec;
|
|||||||
use ascii_table::{Align::Right, AsciiTable};
|
use ascii_table::{Align::Right, AsciiTable};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use color_print::cprintln;
|
use color_print::cprintln;
|
||||||
use connectbox::{models::{PortForwardEntry, PortForwardProtocol}, PortForwardAction};
|
use connectbox::{
|
||||||
|
models::{PortForwardEntry, PortForwardProtocol},
|
||||||
|
PortForwardAction,
|
||||||
|
};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
use crate::{cli::PortForwardsCommand, AppState};
|
use crate::{cli::PortForwardsCommand, AppState};
|
||||||
@ -101,24 +104,27 @@ pub(crate) async fn run(cmd: PortForwardsCommand, state: &AppState) -> Result<()
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cprintln!("<red!>Invalid action {action:?}");
|
cprintln!("<red!>Invalid action {action:?}");
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut modified = false;
|
let mut modified = false;
|
||||||
state.connect_box.edit_port_forwards(|p| {
|
state
|
||||||
|
.connect_box
|
||||||
|
.edit_port_forwards(|p| {
|
||||||
if p.id == id {
|
if p.id == id {
|
||||||
modified = true;
|
modified = true;
|
||||||
action
|
action
|
||||||
} else {
|
} else {
|
||||||
PortForwardAction::Keep
|
PortForwardAction::Keep
|
||||||
}
|
}
|
||||||
}).await?;
|
})
|
||||||
|
.await?;
|
||||||
if !modified {
|
if !modified {
|
||||||
cprintln!("<red!>No port with id {id} exists");
|
cprintln!("<red!>No port with id {id} exists");
|
||||||
} else {
|
} else {
|
||||||
cprintln!("<green!>Done!")
|
cprintln!("<green!>Done!")
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
use color_print::{cprintln, cstr};
|
use crate::{cli::ShellCommand, utils::QuotableArgs};
|
||||||
|
|
||||||
use clap::{FromArgMatches, Parser};
|
use clap::{FromArgMatches, Parser};
|
||||||
use cli::Args;
|
use cli::Args;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
|
use color_print::{cformat, cprintln, cstr};
|
||||||
use connectbox::ConnectBox;
|
use connectbox::ConnectBox;
|
||||||
use rustyline::{error::ReadlineError, DefaultEditor};
|
use rustyline::{
|
||||||
|
error::ReadlineError,
|
||||||
use crate::{cli::ShellCommand, utils::QuotableArgs};
|
highlight::Highlighter,
|
||||||
|
history::{DefaultHistory, FileHistory, MemHistory},
|
||||||
|
Completer, DefaultEditor, Editor, Helper, Hinter, Validator,
|
||||||
|
};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod commands;
|
mod commands;
|
||||||
@ -16,6 +20,40 @@ pub(crate) struct AppState {
|
|||||||
connect_box: ConnectBox,
|
connect_box: ConnectBox,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Completer, Helper, Hinter, Validator)]
|
||||||
|
struct GreenPrompt;
|
||||||
|
|
||||||
|
impl Highlighter for GreenPrompt {
|
||||||
|
fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
|
||||||
|
&'s self,
|
||||||
|
prompt: &'p str,
|
||||||
|
_default: bool,
|
||||||
|
) -> std::borrow::Cow<'b, str> {
|
||||||
|
cformat!("<green!>{prompt}").into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Completer, Helper, Hinter, Validator)]
|
||||||
|
struct PasswordPrompt;
|
||||||
|
|
||||||
|
impl Highlighter for PasswordPrompt {
|
||||||
|
fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
|
||||||
|
&'s self,
|
||||||
|
prompt: &'p str,
|
||||||
|
_default: bool,
|
||||||
|
) -> std::borrow::Cow<'b, str> {
|
||||||
|
cformat!("<red!>{prompt}").into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> {
|
||||||
|
"*".repeat(line.len()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight_char(&self, _line: &str, _pos: usize) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
@ -26,10 +64,14 @@ async fn main() -> Result<()> {
|
|||||||
.with_max_level(args.log_level)
|
.with_max_level(args.log_level)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let mut rl = DefaultEditor::new()?;
|
let mut rl = Editor::new()?;
|
||||||
|
rl.set_helper(Some(GreenPrompt));
|
||||||
|
|
||||||
let password = if let Some(password) = args.password {
|
let password = if let Some(password) = args.password {
|
||||||
password
|
password
|
||||||
} else {
|
} else {
|
||||||
|
let mut rl = Editor::new()?;
|
||||||
|
rl.set_helper(Some(PasswordPrompt));
|
||||||
rl.readline("Password: ")?
|
rl.readline("Password: ")?
|
||||||
};
|
};
|
||||||
let history_path = dirs::data_dir()
|
let history_path = dirs::data_dir()
|
||||||
@ -43,7 +85,7 @@ async fn main() -> Result<()> {
|
|||||||
let state = AppState { connect_box };
|
let state = AppState { connect_box };
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match rl.readline(cstr!("\n<green!> > ")) {
|
match rl.readline("\n >> ") {
|
||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
if line.chars().all(char::is_whitespace) {
|
if line.chars().all(char::is_whitespace) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use std::fmt::Display;
|
use std::{fmt::Display, net::Ipv4Addr, time::Duration};
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use serde::de::{self, Error, Unexpected};
|
use serde::{
|
||||||
use serde::{Deserialize, Deserializer};
|
de::{self, Error, Unexpected},
|
||||||
|
Deserialize, Deserializer,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct LanUserTable {
|
pub struct LanUserTable {
|
||||||
|
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
unstable_features = true
|
||||||
|
imports_granularity = "Crate"
|
Loading…
x
Reference in New Issue
Block a user