mirror of
https://github.com/NotAShelf/stash.git
synced 2026-04-17 00:03:46 +00:00
treewide: format with rustfmt
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I6a6a69642c2865f41a4b141ddf39a198a3fc2e09
This commit is contained in:
parent
404990f928
commit
6a5cd9b95d
10 changed files with 1191 additions and 1132 deletions
|
|
@ -1,10 +1,9 @@
|
|||
use crate::db::{ClipboardDb, SqliteClipboardDb};
|
||||
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use crate::db::StashError;
|
||||
use wl_clipboard_rs::paste::{ClipboardType, MimeType, Seat, get_contents};
|
||||
|
||||
use crate::db::{ClipboardDb, SqliteClipboardDb, StashError};
|
||||
|
||||
pub trait DecodeCommand {
|
||||
fn decode(
|
||||
&self,
|
||||
|
|
@ -50,10 +49,14 @@ impl DecodeCommand for SqliteClipboardDb {
|
|||
}
|
||||
|
||||
// Try decode as usual
|
||||
match self.decode_entry(input_str.as_bytes(), &mut out, Some(input_str.clone())) {
|
||||
match self.decode_entry(
|
||||
input_str.as_bytes(),
|
||||
&mut out,
|
||||
Some(input_str.clone()),
|
||||
) {
|
||||
Ok(()) => {
|
||||
log::info!("Entry decoded");
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed to decode entry: {e}");
|
||||
if let Ok((mut reader, _mime)) =
|
||||
|
|
@ -68,7 +71,7 @@ impl DecodeCommand for SqliteClipboardDb {
|
|||
} else {
|
||||
log::error!("Failed to get clipboard contents for relay");
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::db::{ClipboardDb, SqliteClipboardDb, StashError};
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use crate::db::{ClipboardDb, SqliteClipboardDb, StashError};
|
||||
|
||||
pub trait DeleteCommand {
|
||||
fn delete(&self, input: impl Read) -> Result<usize, StashError>;
|
||||
}
|
||||
|
|
@ -12,11 +12,11 @@ impl DeleteCommand for SqliteClipboardDb {
|
|||
Ok(deleted) => {
|
||||
log::info!("Deleted {deleted} entries");
|
||||
Ok(deleted)
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed to delete entries: {e}");
|
||||
Err(e)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,21 @@
|
|||
use std::io::Write;
|
||||
|
||||
use crate::db::{ClipboardDb, SqliteClipboardDb, StashError};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::db::{ClipboardDb, SqliteClipboardDb, StashError};
|
||||
|
||||
pub trait ListCommand {
|
||||
fn list(&self, out: impl Write, preview_width: u32) -> Result<(), StashError>;
|
||||
fn list(&self, out: impl Write, preview_width: u32)
|
||||
-> Result<(), StashError>;
|
||||
}
|
||||
|
||||
impl ListCommand for SqliteClipboardDb {
|
||||
fn list(&self, out: impl Write, preview_width: u32) -> Result<(), StashError> {
|
||||
fn list(
|
||||
&self,
|
||||
out: impl Write,
|
||||
preview_width: u32,
|
||||
) -> Result<(), StashError> {
|
||||
self.list_entries(out, preview_width)?;
|
||||
log::info!("Listed clipboard entries");
|
||||
Ok(())
|
||||
|
|
@ -20,11 +26,16 @@ impl SqliteClipboardDb {
|
|||
/// Public TUI listing function for use in main.rs
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn list_tui(&self, preview_width: u32) -> Result<(), StashError> {
|
||||
use std::io::stdout;
|
||||
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
|
||||
execute,
|
||||
terminal::{
|
||||
EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
|
||||
EnterAlternateScreen,
|
||||
LeaveAlternateScreen,
|
||||
disable_raw_mode,
|
||||
enable_raw_mode,
|
||||
},
|
||||
};
|
||||
use ratatui::{
|
||||
|
|
@ -34,7 +45,6 @@ impl SqliteClipboardDb {
|
|||
text::{Line, Span},
|
||||
widgets::{Block, Borders, List, ListItem, ListState},
|
||||
};
|
||||
use std::io::stdout;
|
||||
|
||||
// Query entries from DB
|
||||
let mut stmt = self
|
||||
|
|
@ -61,7 +71,8 @@ impl SqliteClipboardDb {
|
|||
let mime: Option<String> = row
|
||||
.get(2)
|
||||
.map_err(|e| StashError::ListDecode(e.to_string()))?;
|
||||
let preview = crate::db::preview_entry(&contents, mime.as_deref(), preview_width);
|
||||
let preview =
|
||||
crate::db::preview_entry(&contents, mime.as_deref(), preview_width);
|
||||
let mime_str = mime.as_deref().unwrap_or("").to_string();
|
||||
let id_str = id.to_string();
|
||||
max_id_width = max_id_width.max(id_str.width());
|
||||
|
|
@ -74,8 +85,8 @@ impl SqliteClipboardDb {
|
|||
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)
|
||||
.map_err(|e| StashError::ListDecode(e.to_string()))?;
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let mut terminal =
|
||||
Terminal::new(backend).map_err(|e| StashError::ListDecode(e.to_string()))?;
|
||||
let mut terminal = Terminal::new(backend)
|
||||
.map_err(|e| StashError::ListDecode(e.to_string()))?;
|
||||
|
||||
let mut state = ListState::default();
|
||||
if !entries.is_empty() {
|
||||
|
|
@ -165,7 +176,8 @@ impl SqliteClipboardDb {
|
|||
mwidth += g_width;
|
||||
}
|
||||
|
||||
// Compose the row as highlight + id + space + preview + space + mimetype
|
||||
// Compose the row as highlight + id + space + preview + space +
|
||||
// mimetype
|
||||
let mut spans = Vec::new();
|
||||
let (id, preview, mime) = entry;
|
||||
if Some(i) == selected {
|
||||
|
|
@ -234,11 +246,11 @@ impl SqliteClipboardDb {
|
|||
} else {
|
||||
i + 1
|
||||
}
|
||||
}
|
||||
},
|
||||
None => 0,
|
||||
};
|
||||
state.select(Some(i));
|
||||
}
|
||||
},
|
||||
KeyCode::Up | KeyCode::Char('k') => {
|
||||
let i = match state.selected() {
|
||||
Some(i) => {
|
||||
|
|
@ -247,12 +259,12 @@ impl SqliteClipboardDb {
|
|||
} else {
|
||||
i - 1
|
||||
}
|
||||
}
|
||||
},
|
||||
None => 0,
|
||||
};
|
||||
state.select(Some(i));
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use crate::db::{ClipboardDb, SqliteClipboardDb};
|
||||
|
||||
use crate::db::StashError;
|
||||
use crate::db::{ClipboardDb, SqliteClipboardDb, StashError};
|
||||
|
||||
pub trait QueryCommand {
|
||||
fn query_delete(&self, query: &str) -> Result<usize, StashError>;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::db::{ClipboardDb, SqliteClipboardDb};
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use crate::db::{ClipboardDb, SqliteClipboardDb};
|
||||
|
||||
pub trait StoreCommand {
|
||||
fn store(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use crate::db::{ClipboardDb, Entry, SqliteClipboardDb};
|
||||
use std::{io::Read, time::Duration};
|
||||
|
||||
use smol::Timer;
|
||||
use std::io::Read;
|
||||
use std::time::Duration;
|
||||
use wl_clipboard_rs::paste::{ClipboardType, Seat, get_contents};
|
||||
|
||||
use crate::db::{ClipboardDb, Entry, SqliteClipboardDb};
|
||||
|
||||
pub trait WatchCommand {
|
||||
fn watch(&self, max_dedupe_search: u64, max_items: u64);
|
||||
}
|
||||
|
|
@ -64,13 +65,13 @@ impl WatchCommand for SqliteClipboardDb {
|
|||
// Drop clipboard contents after storing
|
||||
last_contents = None;
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
let error_msg = e.to_string();
|
||||
if !error_msg.contains("empty") {
|
||||
log::error!("Failed to get clipboard contents: {e}");
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Timer::after(Duration::from_millis(500)).await;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use crate::db::{ClipboardDb, SqliteClipboardDb};
|
||||
|
||||
use crate::db::StashError;
|
||||
use crate::db::{ClipboardDb, SqliteClipboardDb, StashError};
|
||||
|
||||
pub trait WipeCommand {
|
||||
fn wipe(&self) -> Result<(), StashError>;
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
use std::env;
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::io::{BufRead, BufReader, Read, Write};
|
||||
use std::str;
|
||||
use std::{
|
||||
env,
|
||||
fmt,
|
||||
fs,
|
||||
io::{BufRead, BufReader, Read, Write},
|
||||
str,
|
||||
};
|
||||
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
use imagesize::{ImageSize, ImageType};
|
||||
use log::{error, info, warn};
|
||||
use regex::Regex;
|
||||
|
||||
use rusqlite::{Connection, OptionalExtension, params};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use serde_json::json;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum StashError {
|
||||
|
|
@ -67,7 +66,11 @@ pub trait ClipboardDb {
|
|||
fn trim_db(&self, max: u64) -> Result<(), StashError>;
|
||||
fn delete_last(&self) -> Result<(), StashError>;
|
||||
fn wipe_db(&self) -> Result<(), StashError>;
|
||||
fn list_entries(&self, out: impl Write, preview_width: u32) -> Result<usize, StashError>;
|
||||
fn list_entries(
|
||||
&self,
|
||||
out: impl Write,
|
||||
preview_width: u32,
|
||||
) -> Result<usize, StashError>;
|
||||
fn decode_entry(
|
||||
&self,
|
||||
in_: impl Read,
|
||||
|
|
@ -98,7 +101,8 @@ pub struct SqliteClipboardDb {
|
|||
|
||||
impl SqliteClipboardDb {
|
||||
pub fn new(conn: Connection) -> Result<Self, StashError> {
|
||||
conn.execute_batch(
|
||||
conn
|
||||
.execute_batch(
|
||||
"CREATE TABLE IF NOT EXISTS clipboard (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
contents BLOB NOT NULL,
|
||||
|
|
@ -138,7 +142,7 @@ impl SqliteClipboardDb {
|
|||
let contents_str = match mime.as_deref() {
|
||||
Some(m) if m.starts_with("text/") || m == "application/json" => {
|
||||
String::from_utf8_lossy(&contents).to_string()
|
||||
}
|
||||
},
|
||||
_ => STANDARD.encode(&contents),
|
||||
};
|
||||
entries.push(json!({
|
||||
|
|
@ -148,7 +152,8 @@ impl SqliteClipboardDb {
|
|||
}));
|
||||
}
|
||||
|
||||
serde_json::to_string_pretty(&entries).map_err(|e| StashError::ListDecode(e.to_string()))
|
||||
serde_json::to_string_pretty(&entries)
|
||||
.map_err(|e| StashError::ListDecode(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +165,10 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
max_items: u64,
|
||||
) -> Result<u64, StashError> {
|
||||
let mut buf = Vec::new();
|
||||
if input.read_to_end(&mut buf).is_err() || buf.is_empty() || buf.len() > 5 * 1_000_000 {
|
||||
if input.read_to_end(&mut buf).is_err()
|
||||
|| buf.is_empty()
|
||||
|| buf.len() > 5 * 1_000_000
|
||||
{
|
||||
return Err(StashError::EmptyOrTooLarge);
|
||||
}
|
||||
if buf.iter().all(u8::is_ascii_whitespace) {
|
||||
|
|
@ -175,7 +183,7 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
},
|
||||
other => other,
|
||||
};
|
||||
|
||||
|
|
@ -186,14 +194,17 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
if let Ok(s) = std::str::from_utf8(&buf) {
|
||||
if re.is_match(s) {
|
||||
warn!("Clipboard entry matches sensitive regex, skipping store.");
|
||||
return Err(StashError::Store("Filtered by sensitive regex".to_string()));
|
||||
return Err(StashError::Store(
|
||||
"Filtered by sensitive regex".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.deduplicate(&buf, max_dedupe_search)?;
|
||||
|
||||
self.conn
|
||||
self
|
||||
.conn
|
||||
.execute(
|
||||
"INSERT INTO clipboard (contents, mime) VALUES (?1, ?2)",
|
||||
params![buf, mime],
|
||||
|
|
@ -224,7 +235,8 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
.get(1)
|
||||
.map_err(|e| StashError::DeduplicationDecode(e.to_string()))?;
|
||||
if contents == buf {
|
||||
self.conn
|
||||
self
|
||||
.conn
|
||||
.execute("DELETE FROM clipboard WHERE id = ?1", params![id])
|
||||
.map_err(|e| StashError::DeduplicationRemove(e.to_string()))?;
|
||||
deduped += 1;
|
||||
|
|
@ -240,10 +252,14 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
.map_err(|e| StashError::Trim(e.to_string()))?;
|
||||
if count > max {
|
||||
let to_delete = count - max;
|
||||
self.conn.execute(
|
||||
"DELETE FROM clipboard WHERE id IN (SELECT id FROM clipboard ORDER BY id ASC LIMIT ?1)",
|
||||
self
|
||||
.conn
|
||||
.execute(
|
||||
"DELETE FROM clipboard WHERE id IN (SELECT id FROM clipboard ORDER \
|
||||
BY id ASC LIMIT ?1)",
|
||||
params![i64::try_from(to_delete).unwrap_or(i64::MAX)],
|
||||
).map_err(|e| StashError::Trim(e.to_string()))?;
|
||||
)
|
||||
.map_err(|e| StashError::Trim(e.to_string()))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -259,7 +275,8 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
.optional()
|
||||
.map_err(|e| StashError::DeleteLast(e.to_string()))?;
|
||||
if let Some(id) = id {
|
||||
self.conn
|
||||
self
|
||||
.conn
|
||||
.execute("DELETE FROM clipboard WHERE id = ?1", params![id])
|
||||
.map_err(|e| StashError::DeleteLast(e.to_string()))?;
|
||||
Ok(())
|
||||
|
|
@ -269,13 +286,18 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
}
|
||||
|
||||
fn wipe_db(&self) -> Result<(), StashError> {
|
||||
self.conn
|
||||
self
|
||||
.conn
|
||||
.execute("DELETE FROM clipboard", [])
|
||||
.map_err(|e| StashError::Wipe(e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn list_entries(&self, mut out: impl Write, preview_width: u32) -> Result<usize, StashError> {
|
||||
fn list_entries(
|
||||
&self,
|
||||
mut out: impl Write,
|
||||
preview_width: u32,
|
||||
) -> Result<usize, StashError> {
|
||||
let mut stmt = self
|
||||
.conn
|
||||
.prepare("SELECT id, contents, mime FROM clipboard ORDER BY id DESC")
|
||||
|
|
@ -315,11 +337,13 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
input
|
||||
} else {
|
||||
let mut buf = String::new();
|
||||
in_.read_to_string(&mut buf)
|
||||
in_
|
||||
.read_to_string(&mut buf)
|
||||
.map_err(|e| StashError::DecodeRead(e.to_string()))?;
|
||||
buf
|
||||
};
|
||||
let id = extract_id(&s).map_err(|e| StashError::DecodeExtractId(e.to_string()))?;
|
||||
let id =
|
||||
extract_id(&s).map_err(|e| StashError::DecodeExtractId(e.to_string()))?;
|
||||
let (contents, _mime): (Vec<u8>, Option<String>) = self
|
||||
.conn
|
||||
.query_row(
|
||||
|
|
@ -328,7 +352,8 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
|row| Ok((row.get(0)?, row.get(1)?)),
|
||||
)
|
||||
.map_err(|e| StashError::DecodeGet(e.to_string()))?;
|
||||
out.write_all(&contents)
|
||||
out
|
||||
.write_all(&contents)
|
||||
.map_err(|e| StashError::DecodeWrite(e.to_string()))?;
|
||||
info!("Decoded entry with id {id}");
|
||||
Ok(())
|
||||
|
|
@ -354,7 +379,8 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
.get(1)
|
||||
.map_err(|e| StashError::QueryDelete(e.to_string()))?;
|
||||
if contents.windows(query.len()).any(|w| w == query.as_bytes()) {
|
||||
self.conn
|
||||
self
|
||||
.conn
|
||||
.execute("DELETE FROM clipboard WHERE id = ?1", params![id])
|
||||
.map_err(|e| StashError::QueryDelete(e.to_string()))?;
|
||||
deleted += 1;
|
||||
|
|
@ -368,7 +394,8 @@ impl ClipboardDb for SqliteClipboardDb {
|
|||
let mut deleted = 0;
|
||||
for line in reader.lines().map_while(Result::ok) {
|
||||
if let Ok(id) = extract_id(&line) {
|
||||
self.conn
|
||||
self
|
||||
.conn
|
||||
.execute("DELETE FROM clipboard WHERE id = ?1", params![id])
|
||||
.map_err(|e| StashError::DeleteEntry(id, e.to_string()))?;
|
||||
deleted += 1;
|
||||
|
|
@ -476,7 +503,7 @@ pub fn preview_entry(data: &[u8], mime: Option<&str>, width: u32) -> String {
|
|||
Err(e) => {
|
||||
error!("Failed to decode UTF-8 clipboard data: {e}");
|
||||
""
|
||||
}
|
||||
},
|
||||
};
|
||||
let s = s.trim().replace(|c: char| c.is_whitespace(), " ");
|
||||
return truncate(&s, width as usize, "…");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use crate::db::{Entry, SqliteClipboardDb, detect_mime};
|
||||
use log::{error, info};
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
use log::{error, info};
|
||||
|
||||
use crate::db::{Entry, SqliteClipboardDb, detect_mime};
|
||||
|
||||
pub trait ImportCommand {
|
||||
fn import_tsv(&self, input: impl io::Read);
|
||||
}
|
||||
|
|
@ -34,7 +36,7 @@ impl ImportCommand for SqliteClipboardDb {
|
|||
Ok(_) => {
|
||||
imported += 1;
|
||||
info!("Imported entry from TSV");
|
||||
}
|
||||
},
|
||||
Err(e) => error!("Failed to insert entry: {e}"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
92
src/main.rs
92
src/main.rs
|
|
@ -6,7 +6,6 @@ use std::{
|
|||
};
|
||||
|
||||
use atty::Stream;
|
||||
|
||||
use clap::{CommandFactory, Parser, Subcommand};
|
||||
use inquire::Confirm;
|
||||
|
||||
|
|
@ -14,14 +13,18 @@ mod commands;
|
|||
mod db;
|
||||
mod import;
|
||||
|
||||
use crate::commands::decode::DecodeCommand;
|
||||
use crate::commands::delete::DeleteCommand;
|
||||
use crate::commands::list::ListCommand;
|
||||
use crate::commands::query::QueryCommand;
|
||||
use crate::commands::store::StoreCommand;
|
||||
use crate::commands::watch::WatchCommand;
|
||||
use crate::commands::wipe::WipeCommand;
|
||||
use crate::import::ImportCommand;
|
||||
use crate::{
|
||||
commands::{
|
||||
decode::DecodeCommand,
|
||||
delete::DeleteCommand,
|
||||
list::ListCommand,
|
||||
query::QueryCommand,
|
||||
store::StoreCommand,
|
||||
watch::WatchCommand,
|
||||
wipe::WipeCommand,
|
||||
},
|
||||
import::ImportCommand,
|
||||
};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "stash")]
|
||||
|
|
@ -65,8 +68,9 @@ enum Command {
|
|||
/// Decode and output clipboard entry by id
|
||||
Decode { input: Option<String> },
|
||||
|
||||
/// Delete clipboard entry by id (if numeric), or entries matching a query (if not).
|
||||
/// Numeric arguments are treated as ids. Use --type to specify explicitly.
|
||||
/// Delete clipboard entry by id (if numeric), or entries matching a query (if
|
||||
/// not). Numeric arguments are treated as ids. Use --type to specify
|
||||
/// explicitly.
|
||||
Delete {
|
||||
/// Id or query string
|
||||
arg: Option<String>,
|
||||
|
|
@ -102,13 +106,16 @@ enum Command {
|
|||
Watch,
|
||||
}
|
||||
|
||||
fn report_error<T>(result: Result<T, impl std::fmt::Display>, context: &str) -> Option<T> {
|
||||
fn report_error<T>(
|
||||
result: Result<T, impl std::fmt::Display>,
|
||||
context: &str,
|
||||
) -> Option<T> {
|
||||
match result {
|
||||
Ok(val) => Some(val),
|
||||
Err(e) => {
|
||||
log::error!("{context}: {e}");
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +151,7 @@ fn main() {
|
|||
Err(e) => {
|
||||
log::error!("Failed to initialize SQLite database: {e}");
|
||||
process::exit(1);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
match cli.command {
|
||||
|
|
@ -154,25 +161,28 @@ fn main() {
|
|||
db.store(io::stdin(), cli.max_dedupe_search, cli.max_items, state),
|
||||
"Failed to store entry",
|
||||
);
|
||||
}
|
||||
Some(Command::List { format }) => match format.as_deref() {
|
||||
},
|
||||
Some(Command::List { format }) => {
|
||||
match format.as_deref() {
|
||||
Some("tsv") => {
|
||||
report_error(
|
||||
db.list(io::stdout(), cli.preview_width),
|
||||
"Failed to list entries",
|
||||
);
|
||||
}
|
||||
Some("json") => match db.list_json() {
|
||||
},
|
||||
Some("json") => {
|
||||
match db.list_json() {
|
||||
Ok(json) => {
|
||||
println!("{json}");
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Failed to list entries as JSON: {e}");
|
||||
},
|
||||
}
|
||||
},
|
||||
Some(other) => {
|
||||
log::error!("Unsupported format: {other}");
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if atty::is(Stream::Stdout) {
|
||||
report_error(
|
||||
|
|
@ -185,6 +195,7 @@ fn main() {
|
|||
"Failed to list entries",
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
Some(Command::Decode { input }) => {
|
||||
|
|
@ -192,7 +203,7 @@ fn main() {
|
|||
db.decode(io::stdin(), io::stdout(), input),
|
||||
"Failed to decode entry",
|
||||
);
|
||||
}
|
||||
},
|
||||
Some(Command::Delete { arg, r#type, ask }) => {
|
||||
let mut should_proceed = true;
|
||||
if ask {
|
||||
|
|
@ -218,10 +229,13 @@ fn main() {
|
|||
} else {
|
||||
log::error!("Argument is not a valid id");
|
||||
}
|
||||
}
|
||||
},
|
||||
(Some(s), Some("query")) => {
|
||||
report_error(db.query_delete(&s), "Failed to delete entry by query");
|
||||
}
|
||||
report_error(
|
||||
db.query_delete(&s),
|
||||
"Failed to delete entry by query",
|
||||
);
|
||||
},
|
||||
(Some(s), None) => {
|
||||
if let Ok(id) = s.parse::<u64>() {
|
||||
use std::io::Cursor;
|
||||
|
|
@ -235,24 +249,25 @@ fn main() {
|
|||
"Failed to delete entry by query",
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
(None, _) => {
|
||||
report_error(
|
||||
db.delete(io::stdin()),
|
||||
"Failed to delete entry from stdin",
|
||||
);
|
||||
}
|
||||
},
|
||||
(_, Some(_)) => {
|
||||
log::error!("Unknown type for --type. Use \"id\" or \"query\".");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(Command::Wipe { ask }) => {
|
||||
let mut should_proceed = true;
|
||||
if ask {
|
||||
should_proceed =
|
||||
Confirm::new("Are you sure you want to wipe all clipboard history?")
|
||||
should_proceed = Confirm::new(
|
||||
"Are you sure you want to wipe all clipboard history?",
|
||||
)
|
||||
.with_default(false)
|
||||
.prompt()
|
||||
.unwrap_or(false);
|
||||
|
|
@ -263,12 +278,15 @@ fn main() {
|
|||
if should_proceed {
|
||||
report_error(db.wipe(), "Failed to wipe database");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Some(Command::Import { r#type, ask }) => {
|
||||
let mut should_proceed = true;
|
||||
if ask {
|
||||
should_proceed = Confirm::new("Are you sure you want to import clipboard data? This may overwrite existing entries.")
|
||||
should_proceed = Confirm::new(
|
||||
"Are you sure you want to import clipboard data? This may \
|
||||
overwrite existing entries.",
|
||||
)
|
||||
.with_default(false)
|
||||
.prompt()
|
||||
.unwrap_or(false);
|
||||
|
|
@ -281,22 +299,22 @@ fn main() {
|
|||
match format {
|
||||
"tsv" => {
|
||||
db.import_tsv(io::stdin());
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
log::error!("Unsupported import format: {format}");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(Command::Watch) => {
|
||||
db.watch(cli.max_dedupe_search, cli.max_items);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if let Err(e) = Cli::command().print_help() {
|
||||
log::error!("Failed to print help: {e}");
|
||||
}
|
||||
println!();
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue