uds ipc working
This commit is contained in:
@ -7,10 +7,10 @@ use std::os::unix::net::UnixListener;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
// --- LE CONTRAT (Protocole) ---
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub enum IpcRequest {
|
pub enum IpcRequest {
|
||||||
GetHistory { limit: usize },
|
GetHistory { limit: usize },
|
||||||
|
SetClipboard { content: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@ -63,6 +63,33 @@ pub fn start_server(db: Arc<Mutex<Database>>, socket_path: &Path) {
|
|||||||
let response_json = serde_json::to_string(&response).unwrap();
|
let response_json = serde_json::to_string(&response).unwrap();
|
||||||
let _ = stream.write_all(response_json.as_bytes());
|
let _ = stream.write_all(response_json.as_bytes());
|
||||||
}
|
}
|
||||||
|
IpcRequest::SetClipboard { content } => {
|
||||||
|
if let Ok(mut clipboard) = arboard::Clipboard::new() {
|
||||||
|
if content.ends_with(".jpg") || content.ends_with(".png") {
|
||||||
|
if let Some(proj_dirs) = directories::ProjectDirs::from(
|
||||||
|
"com", "zefad", "rklipd",
|
||||||
|
) {
|
||||||
|
let img_path = proj_dirs
|
||||||
|
.data_dir()
|
||||||
|
.join("images")
|
||||||
|
.join(&content);
|
||||||
|
if let Ok(img) = image::open(&img_path) {
|
||||||
|
let rgba = img.into_rgba8();
|
||||||
|
let img_data = arboard::ImageData {
|
||||||
|
width: rgba.width() as usize,
|
||||||
|
height: rgba.height() as usize,
|
||||||
|
bytes: std::borrow::Cow::Borrowed(
|
||||||
|
rgba.as_raw(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let _ = clipboard.set_image(img_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = clipboard.set_text(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/app.rs
23
src/app.rs
@ -28,8 +28,14 @@ impl App {
|
|||||||
let mut list_state = ListState::default();
|
let mut list_state = ListState::default();
|
||||||
list_state.select(Some(0));
|
list_state.select(Some(0));
|
||||||
|
|
||||||
let items = ipc::fetch_history(100)
|
let items = ipc::fetch_history(100).unwrap_or_default();
|
||||||
.unwrap_or_else(|| vec!["rklipd deamon unaccessible".to_string()]);
|
|
||||||
|
let mut list_state = ListState::default();
|
||||||
|
if items.is_empty() {
|
||||||
|
list_state.select(None);
|
||||||
|
} else {
|
||||||
|
list_state.select(Some(0));
|
||||||
|
}
|
||||||
|
|
||||||
let picker = Picker::from_query_stdio().unwrap_or_else(|_| Picker::halfblocks());
|
let picker = Picker::from_query_stdio().unwrap_or_else(|_| Picker::halfblocks());
|
||||||
|
|
||||||
@ -175,6 +181,17 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_selected_item(&self) -> Option<&String> {
|
pub fn get_selected_item(&self) -> Option<&String> {
|
||||||
self.list_state.selected().map(|i| &self.filtered_items[i])
|
self.list_state
|
||||||
|
.selected()
|
||||||
|
.and_then(|i| self.filtered_items.get(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sync_with_daemon(&mut self) {
|
||||||
|
if let Some(new_history) = crate::ipc::fetch_history(100) {
|
||||||
|
if self.all_items != new_history {
|
||||||
|
self.all_items = new_history;
|
||||||
|
self.update_search();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/ipc.rs
14
src/ipc.rs
@ -5,6 +5,7 @@ use std::os::unix::net::UnixStream;
|
|||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub enum IpcRequest {
|
pub enum IpcRequest {
|
||||||
GetHistory { limit: usize },
|
GetHistory { limit: usize },
|
||||||
|
SetClipboard { content: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@ -35,3 +36,16 @@ pub fn fetch_history(limit: usize) -> Option<Vec<String>> {
|
|||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_clipboard(content: String) {
|
||||||
|
if let Some(base_dir) = directories::ProjectDirs::from("com", "zefad", "rklipd") {
|
||||||
|
let socket_path = base_dir.data_dir().join("rklip.sock");
|
||||||
|
if let Ok(mut stream) = UnixStream::connect(&socket_path) {
|
||||||
|
let req = IpcRequest::SetClipboard { content };
|
||||||
|
if let Ok(req_json) = serde_json::to_string(&req) {
|
||||||
|
let _ = stream.write_all(req_json.as_bytes());
|
||||||
|
let _ = stream.shutdown(std::net::Shutdown::Write);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
196
src/main.rs
196
src/main.rs
@ -11,6 +11,7 @@ use crossterm::{
|
|||||||
};
|
};
|
||||||
use ratatui::{Terminal, backend::CrosstermBackend};
|
use ratatui::{Terminal, backend::CrosstermBackend};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
enable_raw_mode()?;
|
enable_raw_mode()?;
|
||||||
@ -39,105 +40,120 @@ fn run_app(terminal: &mut Terminal<CrosstermBackend<io::Stdout>>, app: &mut App)
|
|||||||
loop {
|
loop {
|
||||||
terminal.draw(|f| ui::render(f, app))?;
|
terminal.draw(|f| ui::render(f, app))?;
|
||||||
|
|
||||||
if let Event::Key(key) = event::read()? {
|
if event::poll(Duration::from_millis(500))? {
|
||||||
match app.mode {
|
if let Event::Key(key) = event::read()? {
|
||||||
Mode::Normal => match key.code {
|
match app.mode {
|
||||||
KeyCode::Char('j') => {
|
Mode::Normal => match key.code {
|
||||||
app.next();
|
KeyCode::Enter => {
|
||||||
last_key_was_d = false;
|
if let Some(selected) = app.get_selected_item() {
|
||||||
}
|
crate::ipc::set_clipboard(selected.clone());
|
||||||
KeyCode::Char('k') => {
|
app.should_quit = true;
|
||||||
app.previous();
|
}
|
||||||
last_key_was_d = false;
|
|
||||||
}
|
|
||||||
KeyCode::Char('d') => {
|
|
||||||
if last_key_was_d {
|
|
||||||
app.delete_selected();
|
|
||||||
last_key_was_d = false;
|
|
||||||
} else {
|
|
||||||
last_key_was_d = true;
|
|
||||||
}
|
}
|
||||||
last_key_was_g = false;
|
KeyCode::Char('j') => {
|
||||||
}
|
app.next();
|
||||||
KeyCode::Char('u') => {
|
last_key_was_d = false;
|
||||||
app.undo_delete();
|
}
|
||||||
last_key_was_d = false;
|
KeyCode::Char('k') => {
|
||||||
}
|
app.previous();
|
||||||
KeyCode::Char('g') => {
|
last_key_was_d = false;
|
||||||
if last_key_was_g {
|
}
|
||||||
if !app.filtered_items.is_empty() {
|
KeyCode::Char('d') => {
|
||||||
app.list_state.select(Some(0));
|
if last_key_was_d {
|
||||||
|
app.delete_selected();
|
||||||
|
last_key_was_d = false;
|
||||||
|
} else {
|
||||||
|
last_key_was_d = true;
|
||||||
}
|
}
|
||||||
last_key_was_g = false;
|
last_key_was_g = false;
|
||||||
} else {
|
|
||||||
last_key_was_g = true;
|
|
||||||
}
|
}
|
||||||
last_key_was_d = false;
|
KeyCode::Char('u') => {
|
||||||
}
|
app.undo_delete();
|
||||||
KeyCode::Char('G') => {
|
last_key_was_d = false;
|
||||||
if !app.filtered_items.is_empty() {
|
|
||||||
app.list_state.select(Some(app.filtered_items.len() - 1));
|
|
||||||
}
|
}
|
||||||
last_key_was_d = false;
|
KeyCode::Char('g') => {
|
||||||
}
|
if last_key_was_g {
|
||||||
KeyCode::Char(':') => {
|
if !app.filtered_items.is_empty() {
|
||||||
app.mode = Mode::Command;
|
app.list_state.select(Some(0));
|
||||||
app.input_buffer.clear();
|
}
|
||||||
last_key_was_d = false;
|
last_key_was_g = false;
|
||||||
}
|
} else {
|
||||||
KeyCode::Char('/') => {
|
last_key_was_g = true;
|
||||||
app.mode = Mode::Search;
|
}
|
||||||
app.input_buffer.clear();
|
last_key_was_d = false;
|
||||||
app.update_search();
|
}
|
||||||
last_key_was_d = false;
|
KeyCode::Char('G') => {
|
||||||
}
|
if !app.filtered_items.is_empty() {
|
||||||
KeyCode::Char('q') => {
|
app.list_state.select(Some(app.filtered_items.len() - 1));
|
||||||
app.should_quit = true;
|
}
|
||||||
}
|
last_key_was_d = false;
|
||||||
_ => {
|
}
|
||||||
last_key_was_d = false;
|
KeyCode::Char(':') => {
|
||||||
}
|
app.mode = Mode::Command;
|
||||||
},
|
app.input_buffer.clear();
|
||||||
|
last_key_was_d = false;
|
||||||
Mode::Command => match key.code {
|
}
|
||||||
KeyCode::Esc => {
|
KeyCode::Char('/') => {
|
||||||
app.mode = Mode::Normal;
|
app.mode = Mode::Search;
|
||||||
app.input_buffer.clear();
|
app.input_buffer.clear();
|
||||||
app.update_search();
|
app.update_search();
|
||||||
}
|
last_key_was_d = false;
|
||||||
KeyCode::Char(c) => app.input_buffer.push(c),
|
}
|
||||||
KeyCode::Backspace => {
|
KeyCode::Char('q') => {
|
||||||
app.input_buffer.pop();
|
|
||||||
}
|
|
||||||
KeyCode::Enter => {
|
|
||||||
if app.input_buffer == "q" {
|
|
||||||
app.should_quit = true;
|
app.should_quit = true;
|
||||||
}
|
}
|
||||||
app.mode = Mode::Normal;
|
_ => {
|
||||||
app.input_buffer.clear();
|
last_key_was_d = false;
|
||||||
app.update_search();
|
}
|
||||||
}
|
},
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
|
|
||||||
Mode::Search => match key.code {
|
Mode::Command => match key.code {
|
||||||
// ... ton code de recherche ...
|
KeyCode::Esc => {
|
||||||
KeyCode::Esc | KeyCode::Enter => {
|
app.mode = Mode::Normal;
|
||||||
app.mode = Mode::Normal;
|
app.input_buffer.clear();
|
||||||
app.input_buffer.clear();
|
app.update_search();
|
||||||
app.update_search();
|
}
|
||||||
}
|
KeyCode::Char(c) => app.input_buffer.push(c),
|
||||||
KeyCode::Char(c) => {
|
KeyCode::Backspace => {
|
||||||
app.input_buffer.push(c);
|
app.input_buffer.pop();
|
||||||
app.update_search();
|
}
|
||||||
}
|
KeyCode::Enter => {
|
||||||
KeyCode::Backspace => {
|
if app.input_buffer == "q" {
|
||||||
app.input_buffer.pop();
|
app.should_quit = true;
|
||||||
app.update_search();
|
}
|
||||||
}
|
app.mode = Mode::Normal;
|
||||||
_ => {}
|
app.input_buffer.clear();
|
||||||
},
|
app.update_search();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
|
||||||
|
Mode::Search => match key.code {
|
||||||
|
KeyCode::Esc => {
|
||||||
|
app.mode = Mode::Normal;
|
||||||
|
app.input_buffer.clear();
|
||||||
|
app.update_search();
|
||||||
|
}
|
||||||
|
KeyCode::Enter => {
|
||||||
|
if let Some(selected) = app.get_selected_item() {
|
||||||
|
crate::ipc::set_clipboard(selected.clone());
|
||||||
|
app.should_quit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyCode::Char(c) => {
|
||||||
|
app.input_buffer.push(c);
|
||||||
|
app.update_search();
|
||||||
|
}
|
||||||
|
KeyCode::Backspace => {
|
||||||
|
app.input_buffer.pop();
|
||||||
|
app.update_search();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
app.sync_with_daemon();
|
||||||
}
|
}
|
||||||
|
|
||||||
if app.should_quit {
|
if app.should_quit {
|
||||||
|
|||||||
Reference in New Issue
Block a user