feat(snippets): add import snippet feature

Currently, our application does not support snippets without keywords. We will have to figure out why it's possible to have a text replacement item without the text to replace.
This commit is contained in:
ByteAtATime 2025-06-25 08:38:14 -07:00
parent 15dbf0692a
commit 56813684e1
No known key found for this signature in database
16 changed files with 433 additions and 114 deletions

View file

@ -20,10 +20,7 @@ pub struct ExpansionEngine {
}
impl ExpansionEngine {
pub fn new(
snippet_manager: Arc<SnippetManager>,
input_manager: Arc<dyn InputManager>,
) -> Self {
pub fn new(snippet_manager: Arc<SnippetManager>, input_manager: Arc<dyn InputManager>) -> Self {
Self {
buffer: Arc::new(Mutex::new(String::with_capacity(BUFFER_SIZE))),
snippet_manager,
@ -33,8 +30,7 @@ impl ExpansionEngine {
pub fn start_listening(&self) -> anyhow::Result<()> {
let engine = Arc::new(self.clone_for_thread());
self.input_manager
.start_listening(Box::new(move |event| {
self.input_manager.start_listening(Box::new(move |event| {
engine.handle_key_press(event);
}))?;
Ok(())

View file

@ -47,8 +47,7 @@ impl InputManager for RdevInputManager {
let callback_clone = callback.clone();
thread::spawn(move || {
let cb = move |event: rdev::Event| {
match event.event_type {
let cb = move |event: rdev::Event| match event.event_type {
rdev::EventType::KeyPress(key) => {
if key == Key::ShiftLeft || key == Key::ShiftRight {
*shift_clone_press.lock().unwrap() = true;
@ -64,7 +63,6 @@ impl InputManager for RdevInputManager {
}
}
_ => (),
}
};
if let Err(error) = rdev::listen(cb) {
eprintln!("rdev error: {:?}", error)
@ -387,7 +385,7 @@ impl InputManager for EvdevInputManager {
}
_ => {
xkb_state.update_key(keycode.into(), direction);
},
}
}
}
}

View file

@ -71,7 +71,9 @@ impl SnippetManager {
})
})?;
snippets_iter.collect::<Result<Vec<_>, _>>().map_err(|e| e.into())
snippets_iter
.collect::<Result<Vec<_>, _>>()
.map_err(|e| e.into())
}
pub fn update_snippet(

View file

@ -3,9 +3,26 @@ pub mod input_manager;
pub mod manager;
pub mod types;
use crate::error::AppError;
use serde::{Deserialize, Serialize};
use tauri::{AppHandle, Manager};
use types::Snippet;
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct ImportSnippet {
name: String,
text: String,
keyword: String,
}
#[derive(Serialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ImportResult {
snippets_added: u32,
duplicates_skipped: u32,
}
#[tauri::command]
pub fn create_snippet(
app: AppHandle,
@ -43,4 +60,33 @@ pub fn delete_snippet(app: AppHandle, id: i64) -> Result<(), String> {
app.state::<manager::SnippetManager>()
.delete_snippet(id)
.map_err(|e| e.to_string())
}
}
#[tauri::command]
pub fn import_snippets(app: AppHandle, json_content: String) -> Result<ImportResult, String> {
let snippets: Vec<ImportSnippet> =
serde_json::from_str(&json_content).map_err(|e| e.to_string())?;
let manager = app.state::<manager::SnippetManager>();
let mut snippets_added = 0;
let mut duplicates_skipped = 0;
for snippet in snippets {
let keyword = snippet.keyword;
match manager.create_snippet(snippet.name, keyword, snippet.text) {
Ok(_) => snippets_added += 1,
Err(AppError::Rusqlite(rusqlite::Error::SqliteFailure(e, Some(msg))))
if e.code == rusqlite::ErrorCode::ConstraintViolation
&& msg.contains("UNIQUE constraint failed: snippets.keyword") =>
{
duplicates_skipped += 1;
}
Err(e) => return Err(e.to_string()),
}
}
Ok(ImportResult {
snippets_added,
duplicates_skipped,
})
}