Skip to content

Commit aa5505d

Browse files
committed
Release v0.1.6
* Update to passepartout v0.1.5 * Use async runtime from futures crate * Add command line option for use with TTY pinentry programs
1 parent de7f5fd commit aa5505d

File tree

8 files changed

+830
-108
lines changed

8 files changed

+830
-108
lines changed

Cargo.lock

+503-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "passepartui"
33
description = "A TUI for pass"
4-
version = "0.1.5"
4+
version = "0.1.6"
55
edition = "2021"
66
authors = ["Karl Felix Schewe"]
77
readme = "README.md"
@@ -12,7 +12,8 @@ categories = ["authentication", "command-line-utilities"]
1212

1313
[dependencies]
1414
anyhow = "1.0.93"
15-
passepartout = "0.1.4"
15+
futures = { version = "0.3.31", features = ["executor", "thread-pool"] }
16+
passepartout = "0.1.5"
1617
ratatui = { version = "0.29.0", features = ["palette"] }
1718

1819
[profile.dev]

src/actions.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ pub enum Action {
1111
},
1212
DisplayOneTimePassword {
1313
pass_id: String,
14-
one_time_password: String,
14+
otp: String,
1515
},
1616
NoOp,
17+
Redraw,
1718
}
1819

1920
#[derive(Debug, Clone, PartialEq)]
@@ -50,10 +51,10 @@ pub enum SearchAction {
5051

5152
#[derive(Debug, Clone, PartialEq)]
5253
pub enum PasswordAction {
53-
CopyPassId,
5454
Fetch,
55+
FetchOtp,
56+
CopyPassId,
5557
CopyPassword,
5658
CopyLogin,
57-
FetchOneTimePassword,
58-
CopyOneTimePassword,
59+
CopyOtp,
5960
}

src/app.rs

+41-27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use anyhow::Result;
2-
use passepartout::{PasswordError, PasswordEvent};
32
use ratatui::{
43
crossterm::event::{self, Event as TerminalEvent, KeyCode, KeyEvent, KeyEventKind, MouseEvent},
54
DefaultTerminal,
@@ -14,22 +13,25 @@ mod state;
1413
use crate::{
1514
actions::{Action, NavigationAction, PasswordAction, SearchAction},
1615
components::{Component, Dashboard, MouseSupport},
16+
event::PasswordEvent,
1717
};
1818
pub use state::{MainState, OverlayState, SearchState, State};
1919

2020
pub struct App<'a> {
2121
running: bool,
22+
complete_redraw: bool,
2223
tick_rate: Duration,
2324
event_rx: Receiver<PasswordEvent>,
2425
dashboard: Dashboard<'a>,
2526
}
2627

2728
impl<'a> App<'a> {
28-
pub fn new() -> Self {
29+
pub fn new(tty_pinentry: bool) -> Self {
2930
let (event_tx, event_rx) = mpsc::channel();
3031
Self {
31-
dashboard: Dashboard::new(event_tx),
32+
dashboard: Dashboard::new(tty_pinentry, event_tx),
3233
running: false,
34+
complete_redraw: false,
3335
tick_rate: Duration::from_millis(80),
3436
event_rx,
3537
}
@@ -39,6 +41,10 @@ impl<'a> App<'a> {
3941
self.running = true;
4042
// Application loop
4143
while self.running {
44+
if self.complete_redraw {
45+
let _ = terminal.clear();
46+
self.complete_redraw = false;
47+
}
4248
terminal.draw(|frame| frame.render_widget(&mut self.dashboard, frame.area()))?;
4349
self.handle_events()?;
4450
}
@@ -105,8 +111,8 @@ impl<'a> App<'a> {
105111
KeyCode::Char('/') => Some(Action::Navigation(NavigationAction::Search)),
106112
KeyCode::F(1) => Some(Action::Navigation(NavigationAction::Help)),
107113
KeyCode::Char('i') => Some(Action::Navigation(NavigationAction::File)),
108-
KeyCode::Char('r') => Some(Action::Password(PasswordAction::FetchOneTimePassword)),
109-
KeyCode::Char('x') => Some(Action::Password(PasswordAction::CopyOneTimePassword)),
114+
KeyCode::Char('r') => Some(Action::Password(PasswordAction::FetchOtp)),
115+
KeyCode::Char('x') => Some(Action::Password(PasswordAction::CopyOtp)),
110116
KeyCode::Char('c') => Some(Action::Password(PasswordAction::CopyPassId)),
111117
KeyCode::Char('v') => Some(Action::Password(PasswordAction::CopyLogin)),
112118
KeyCode::Esc => Some(Action::Navigation(NavigationAction::Leave)),
@@ -143,7 +149,7 @@ impl<'a> App<'a> {
143149
KeyCode::Char('/') => Some(Action::Navigation(NavigationAction::Search)),
144150
KeyCode::F(1) => Some(Action::Navigation(NavigationAction::Help)),
145151
KeyCode::Char('i') => Some(Action::Navigation(NavigationAction::File)),
146-
KeyCode::Char('x') => Some(Action::Password(PasswordAction::CopyOneTimePassword)),
152+
KeyCode::Char('x') => Some(Action::Password(PasswordAction::CopyOtp)),
147153
KeyCode::Char('c') => Some(Action::Password(PasswordAction::CopyPassId)),
148154
KeyCode::Char('v') => Some(Action::Password(PasswordAction::CopyLogin)),
149155
KeyCode::Esc => Some(Action::Navigation(NavigationAction::Leave)),
@@ -202,50 +208,58 @@ impl<'a> App<'a> {
202208
match event {
203209
PasswordEvent::Status(Ok(None)) => Some(Action::ResetStatus),
204210
PasswordEvent::Status(Ok(Some(message))) => Some(Action::SetStatus(message)),
205-
PasswordEvent::Status(Err(PasswordError::PassError(e))) => {
211+
PasswordEvent::Status(Err(passepartout::Error::Pass(e))) => {
206212
Some(Action::SetStatus(format!("✗ (pass) {e:?}")))
207213
}
208-
PasswordEvent::Status(Err(PasswordError::ClipboardUnavailable)) => {
209-
Some(Action::SetStatus("✗ Clipboard not available".to_string()))
210-
}
211-
PasswordEvent::Status(Err(PasswordError::ClipboardError(e))) => {
212-
Some(Action::SetStatus(format!("✗ {e:?}")))
214+
PasswordEvent::Status(Err(passepartout::Error::Clipboard(e))) => {
215+
Some(Action::SetStatus(format!("✗ Clipboard error: {e:?}")))
213216
}
214-
PasswordEvent::PasswordInfo {
217+
PasswordEvent::Status(Err(e)) => Some(Action::SetStatus(format!("✗ {e:?}"))),
218+
PasswordEvent::PasswordFile {
215219
pass_id,
216220
file_contents,
217221
} => Some(Action::DisplaySecrets {
218222
pass_id,
219223
file_contents,
220224
}),
221-
PasswordEvent::OneTimePassword {
222-
pass_id,
223-
one_time_password,
224-
} => Some(Action::DisplayOneTimePassword {
225-
pass_id,
226-
one_time_password,
227-
}),
225+
PasswordEvent::OneTimePassword { pass_id, otp } => {
226+
Some(Action::DisplayOneTimePassword { pass_id, otp })
227+
}
228228
}
229229
}
230230

231231
fn dispatch_action(&mut self, action: Action) -> Result<()> {
232-
let mut next_action = self.dashboard.update(action.clone())?;
233-
while let Some(action) = next_action {
234-
next_action = self.dashboard.update(action)?;
235-
}
232+
let mut current_action = action;
233+
loop {
234+
// Actions from App take precedence
235+
if let Some(next) = self.update(current_action.clone())? {
236+
current_action = next;
237+
continue;
238+
}
236239

237-
let _ = self.update(action)?;
240+
if let Some(next) = self.dashboard.update(current_action.clone())? {
241+
current_action = next;
242+
continue;
243+
}
238244

245+
break;
246+
}
239247
Ok(())
240248
}
241249

242250
fn update(&mut self, action: Action) -> Result<Option<Action>> {
243-
if let Action::Navigation(NavigationAction::Quit) = action {
244-
self.quit();
251+
match action {
252+
Action::Navigation(NavigationAction::Quit) => self.quit(),
253+
Action::Redraw => self.request_redraw(),
254+
_ => (),
245255
}
246256
Ok(None)
247257
}
248258

259+
fn request_redraw(&mut self) {
260+
self.complete_redraw = true;
261+
}
262+
249263
fn quit(&mut self) {
250264
self.running = false;
251265
}

0 commit comments

Comments
 (0)