style: formatting

This commit is contained in:
ByteAtATime 2025-06-19 20:49:39 -07:00
parent 41c880f9d5
commit 00eb6d6e18
No known key found for this signature in database
6 changed files with 253 additions and 236 deletions

View file

@ -56,7 +56,8 @@ enum IncomingMessage {
pub struct WsState {
pub connection: Arc<Mutex<Option<tokio::sync::mpsc::Sender<String>>>>,
pub is_connected: Arc<Mutex<bool>>,
pub pending_requests: Arc<Mutex<HashMap<u64, oneshot::Sender<Result<serde_json::Value, String>>>>>,
pub pending_requests:
Arc<Mutex<HashMap<u64, oneshot::Sender<Result<serde_json::Value, String>>>>>,
pub request_id_counter: Arc<Mutex<u64>>,
}
@ -90,7 +91,11 @@ async fn handle_connection(stream: TcpStream, app_handle: AppHandle) {
let sender_task = tokio::spawn(async move {
while let Some(msg_to_send) = rx.recv().await {
if ws_sender.send(Message::Binary(msg_to_send.into())).await.is_err() {
if ws_sender
.send(Message::Binary(msg_to_send.into()))
.await
.is_err()
{
break;
}
}
@ -113,14 +118,24 @@ async fn handle_connection(stream: TcpStream, app_handle: AppHandle) {
"result": null,
"id": id
});
let tx = app_clone_for_receiver.state::<WsState>().connection.lock().unwrap().clone();
let tx = app_clone_for_receiver
.state::<WsState>()
.connection
.lock()
.unwrap()
.clone();
if let Some(tx) = tx {
let _ = tx.send(response.to_string()).await;
}
}
}
Ok(IncomingMessage::Response { id, result, error }) => {
let sender = app_clone_for_receiver.state::<WsState>().pending_requests.lock().unwrap().remove(&id);
let sender = app_clone_for_receiver
.state::<WsState>()
.pending_requests
.lock()
.unwrap()
.remove(&id);
if let Some(sender) = sender {
if !error.is_null() {
let _ = sender.send(Err(error.to_string()));
@ -161,7 +176,9 @@ pub async fn run_server(app_handle: AppHandle) {
}
#[tauri::command]
pub async fn browser_extension_check_connection(state: tauri::State<'_, WsState>) -> Result<bool, String> {
pub async fn browser_extension_check_connection(
state: tauri::State<'_, WsState>,
) -> Result<bool, String> {
Ok(*state.is_connected.lock().unwrap())
}
@ -212,4 +229,3 @@ pub async fn browser_extension_request(
Err("Browser extension not connected".into())
}
}

View file

@ -5,119 +5,121 @@ use tauri_plugin_clipboard_manager::ClipboardExt;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ReadResult {
text: Option<String>,
html: Option<String>,
file: Option<String>,
text: Option<String>,
html: Option<String>,
file: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ClipboardContent {
text: Option<String>,
html: Option<String>,
file: Option<String>,
text: Option<String>,
html: Option<String>,
file: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub struct CopyOptions {
concealed: Option<bool>,
concealed: Option<bool>,
}
#[tauri::command]
pub async fn clipboard_read_text(app: tauri::AppHandle) -> Result<ReadResult, String> {
let clipboard = app.clipboard();
let text = clipboard.read_text().ok();
Ok(ReadResult {
text,
html: None,
file: None
})
let clipboard = app.clipboard();
let text = clipboard.read_text().ok();
Ok(ReadResult {
text,
html: None,
file: None,
})
}
#[tauri::command]
pub async fn clipboard_read(app: tauri::AppHandle) -> Result<ReadResult, String> {
let clipboard = app.clipboard();
let text = clipboard.read_text().ok();
let html = None; // read_html is not supported by the plugin
let clipboard = app.clipboard();
let text = clipboard.read_text().ok();
let html = None; // read_html is not supported by the plugin
let file = if let Some(ref text_content) = text {
if text_content.lines().count() == 1
&& (text_content.starts_with('/') || text_content.starts_with("file://"))
{
Some(text_content.clone())
} else {
None
}
} else {
None
};
let file = if let Some(ref text_content) = text {
if text_content.lines().count() == 1
&& (text_content.starts_with('/') || text_content.starts_with("file://"))
{
Some(text_content.clone())
} else {
None
}
} else {
None
};
Ok(ReadResult { text, html, file })
Ok(ReadResult { text, html, file })
}
#[tauri::command]
pub async fn clipboard_copy(
app: tauri::AppHandle,
content: ClipboardContent,
_options: Option<CopyOptions>
app: tauri::AppHandle,
content: ClipboardContent,
_options: Option<CopyOptions>,
) -> Result<(), String> {
let clipboard = app.clipboard();
let clipboard = app.clipboard();
if let Some(file_path) = &content.file {
clipboard
.write_text(file_path.clone())
.map_err(|e| e.to_string())?;
} else if let Some(html) = &content.html {
clipboard
.write_html(html.clone(), content.text)
.map_err(|e| e.to_string())?;
} else if let Some(text) = &content.text {
clipboard.write_text(text.clone()).map_err(|e| e.to_string())?;
}
if let Some(file_path) = &content.file {
clipboard
.write_text(file_path.clone())
.map_err(|e| e.to_string())?;
} else if let Some(html) = &content.html {
clipboard
.write_html(html.clone(), content.text)
.map_err(|e| e.to_string())?;
} else if let Some(text) = &content.text {
clipboard
.write_text(text.clone())
.map_err(|e| e.to_string())?;
}
Ok(())
Ok(())
}
#[tauri::command]
pub async fn clipboard_paste(
app: tauri::AppHandle,
content: ClipboardContent
app: tauri::AppHandle,
content: ClipboardContent,
) -> Result<(), String> {
let clipboard = app.clipboard();
let original_text = clipboard.read_text().ok();
let clipboard = app.clipboard();
let original_text = clipboard.read_text().ok();
clipboard_copy(app.clone(), content, None).await?;
clipboard_copy(app.clone(), content, None).await?;
thread::sleep(Duration::from_millis(100));
thread::sleep(Duration::from_millis(100));
let mut enigo = Enigo::new(&Settings::default()).map_err(|e| e.to_string())?;
let mut enigo = Enigo::new(&Settings::default()).map_err(|e| e.to_string())?;
#[cfg(target_os = "macos")]
{
enigo.key(Key::Meta, enigo::Direction::Press).ok();
enigo.key(Key::Unicode('v'), enigo::Direction::Click).ok();
enigo.key(Key::Meta, enigo::Direction::Release).ok();
}
#[cfg(not(target_os = "macos"))]
{
enigo.key(Key::Control, enigo::Direction::Press).ok();
enigo.key(Key::Unicode('v'), enigo::Direction::Click).ok();
enigo.key(Key::Control, enigo::Direction::Release).ok();
}
#[cfg(target_os = "macos")]
{
enigo.key(Key::Meta, enigo::Direction::Press).ok();
enigo.key(Key::Unicode('v'), enigo::Direction::Click).ok();
enigo.key(Key::Meta, enigo::Direction::Release).ok();
}
#[cfg(not(target_os = "macos"))]
{
enigo.key(Key::Control, enigo::Direction::Press).ok();
enigo.key(Key::Unicode('v'), enigo::Direction::Click).ok();
enigo.key(Key::Control, enigo::Direction::Release).ok();
}
thread::sleep(Duration::from_millis(100));
thread::sleep(Duration::from_millis(100));
if let Some(text) = original_text {
clipboard.write_text(text).map_err(|e| e.to_string())?;
} else {
clipboard.clear().map_err(|e| e.to_string())?;
}
if let Some(text) = original_text {
clipboard.write_text(text).map_err(|e| e.to_string())?;
} else {
clipboard.clear().map_err(|e| e.to_string())?;
}
Ok(())
Ok(())
}
#[tauri::command]
pub async fn clipboard_clear(app: tauri::AppHandle) -> Result<(), String> {
app.clipboard().clear().map_err(|e| e.to_string())
app.clipboard().clear().map_err(|e| e.to_string())
}

View file

@ -14,142 +14,142 @@ use selection::get_text;
use std::process::Command;
use std::thread;
use std::time::Duration;
use tauri::{Manager, Emitter};
use tauri::{Emitter, Manager};
use tauri_plugin_deep_link::DeepLinkExt;
#[tauri::command]
fn get_installed_apps() -> Vec<App> {
match AppCache::get_apps() {
Ok(apps) => apps,
Err(e) => {
eprintln!("Failed to get apps: {:?}", e);
Vec::new()
}
}
match AppCache::get_apps() {
Ok(apps) => apps,
Err(e) => {
eprintln!("Failed to get apps: {:?}", e);
Vec::new()
}
}
}
#[tauri::command]
fn launch_app(exec: String) -> Result<(), String> {
let exec_parts: Vec<&str> = exec.split_whitespace().collect();
if exec_parts.is_empty() {
return Err("Empty exec command".to_string());
}
let exec_parts: Vec<&str> = exec.split_whitespace().collect();
if exec_parts.is_empty() {
return Err("Empty exec command".to_string());
}
let mut command = Command::new(exec_parts[0]);
for arg in &exec_parts[1..] {
if !arg.starts_with('%') {
command.arg(arg);
}
}
let mut command = Command::new(exec_parts[0]);
for arg in &exec_parts[1..] {
if !arg.starts_with('%') {
command.arg(arg);
}
}
command
.spawn()
.map_err(|e| format!("Failed to launch app: {}", e))?;
command
.spawn()
.map_err(|e| format!("Failed to launch app: {}", e))?;
Ok(())
Ok(())
}
#[tauri::command]
fn get_selected_text() -> String {
get_text()
get_text()
}
fn setup_background_refresh() {
thread::spawn(|| {
thread::sleep(Duration::from_secs(60));
loop {
AppCache::refresh_background();
thread::sleep(Duration::from_secs(300));
}
});
thread::spawn(|| {
thread::sleep(Duration::from_secs(60));
loop {
AppCache::refresh_background();
thread::sleep(Duration::from_secs(300));
}
});
}
fn setup_global_shortcut(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
use tauri_plugin_global_shortcut::{
Code, GlobalShortcutExt, Modifiers, Shortcut, ShortcutState
};
use tauri_plugin_global_shortcut::{
Code, GlobalShortcutExt, Modifiers, Shortcut, ShortcutState,
};
let spotlight_shortcut = Shortcut::new(Some(Modifiers::ALT), Code::Space);
let handle = app.handle().clone();
let spotlight_shortcut = Shortcut::new(Some(Modifiers::ALT), Code::Space);
let handle = app.handle().clone();
println!("Spotlight shortcut: {:?}", spotlight_shortcut);
println!("Spotlight shortcut: {:?}", spotlight_shortcut);
app.handle().plugin(
tauri_plugin_global_shortcut::Builder::new()
.with_handler(move |_app, shortcut, event| {
println!("Shortcut: {:?}, Event: {:?}", shortcut, event);
if shortcut == &spotlight_shortcut && event.state() == ShortcutState::Pressed {
let spotlight_window = handle.get_webview_window("raycast-linux").unwrap();
println!("Spotlight window: {:?}", spotlight_window);
if spotlight_window.is_visible().unwrap_or(false) {
spotlight_window.hide().unwrap();
} else {
spotlight_window.show().unwrap();
spotlight_window.set_focus().unwrap();
}
}
})
.build()
)?;
app.handle().plugin(
tauri_plugin_global_shortcut::Builder::new()
.with_handler(move |_app, shortcut, event| {
println!("Shortcut: {:?}, Event: {:?}", shortcut, event);
if shortcut == &spotlight_shortcut && event.state() == ShortcutState::Pressed {
let spotlight_window = handle.get_webview_window("raycast-linux").unwrap();
println!("Spotlight window: {:?}", spotlight_window);
if spotlight_window.is_visible().unwrap_or(false) {
spotlight_window.hide().unwrap();
} else {
spotlight_window.show().unwrap();
spotlight_window.set_focus().unwrap();
}
}
})
.build(),
)?;
app.global_shortcut().register(spotlight_shortcut)?;
Ok(())
app.global_shortcut().register(spotlight_shortcut)?;
Ok(())
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.manage(WsState::default())
.plugin(tauri_plugin_single_instance::init(|app, args, _cwd| {
if args.len() > 1 && args[1].starts_with("raycast://") {
if let Some(window) = app.get_webview_window("main") {
let _ = window.emit("deep-link", args[1].to_string());
window.show().unwrap();
}
tauri::Builder::default()
.manage(WsState::default())
.plugin(tauri_plugin_single_instance::init(|app, args, _cwd| {
if args.len() > 1 && args[1].starts_with("raycast://") {
if let Some(window) = app.get_webview_window("main") {
let _ = window.emit("deep-link", args[1].to_string());
window.show().unwrap();
}
return;
}
return;
}
if let Some(window) = app.get_webview_window("main") {
if let Ok(true) = window.is_visible() {
let _ = window.hide();
} else {
let _ = window.show();
let _ = window.set_focus();
}
}
}))
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_global_shortcut::Builder::new().build())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_clipboard_manager::init())
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![
get_installed_apps,
launch_app,
get_selected_text,
filesystem::get_selected_finder_items,
extensions::install_extension,
browser_extension::browser_extension_check_connection,
browser_extension::browser_extension_request,
clipboard::clipboard_read_text,
clipboard::clipboard_read,
clipboard::clipboard_copy,
clipboard::clipboard_paste,
clipboard::clipboard_clear,
oauth::oauth_set_tokens,
oauth::oauth_get_tokens,
oauth::oauth_remove_tokens
])
.setup(|app| {
let app_handle = app.handle().clone();
tauri::async_runtime::spawn(browser_extension::run_server(app_handle));
if let Some(window) = app.get_webview_window("main") {
if let Ok(true) = window.is_visible() {
let _ = window.hide();
} else {
let _ = window.show();
let _ = window.set_focus();
}
}
}))
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_global_shortcut::Builder::new().build())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_clipboard_manager::init())
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![
get_installed_apps,
launch_app,
get_selected_text,
filesystem::get_selected_finder_items,
extensions::install_extension,
browser_extension::browser_extension_check_connection,
browser_extension::browser_extension_request,
clipboard::clipboard_read_text,
clipboard::clipboard_read,
clipboard::clipboard_copy,
clipboard::clipboard_paste,
clipboard::clipboard_clear,
oauth::oauth_set_tokens,
oauth::oauth_get_tokens,
oauth::oauth_remove_tokens
])
.setup(|app| {
let app_handle = app.handle().clone();
tauri::async_runtime::spawn(browser_extension::run_server(app_handle));
setup_background_refresh();
setup_global_shortcut(app)?;
setup_background_refresh();
setup_global_shortcut(app)?;
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View file

@ -8,80 +8,79 @@ use tauri::Manager;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
struct StoredTokenSet {
access_token: String,
refresh_token: Option<String>,
expires_in: Option<u64>,
scope: Option<String>,
id_token: Option<String>,
updated_at: String,
access_token: String,
refresh_token: Option<String>,
expires_in: Option<u64>,
scope: Option<String>,
id_token: Option<String>,
updated_at: String,
}
type TokenStore = HashMap<String, StoredTokenSet>;
fn get_storage_path(app: &tauri::AppHandle) -> Result<PathBuf, String> {
let data_dir = app
.path()
.app_local_data_dir()
.map_err(|_| "Failed to get app local data dir".to_string())?;
let data_dir = app
.path()
.app_local_data_dir()
.map_err(|_| "Failed to get app local data dir".to_string())?;
if !data_dir.exists() {
fs::create_dir_all(&data_dir).map_err(|e| e.to_string())?;
}
if !data_dir.exists() {
fs::create_dir_all(&data_dir).map_err(|e| e.to_string())?;
}
Ok(data_dir.join("oauth_tokens.json"))
Ok(data_dir.join("oauth_tokens.json"))
}
fn read_store(path: &Path) -> Result<TokenStore, String> {
if !path.exists() {
return Ok(HashMap::new());
}
let content = fs::read_to_string(path).map_err(|e| e.to_string())?;
if content.trim().is_empty() {
return Ok(HashMap::new());
}
serde_json::from_str(&content).map_err(|e| e.to_string())
if !path.exists() {
return Ok(HashMap::new());
}
let content = fs::read_to_string(path).map_err(|e| e.to_string())?;
if content.trim().is_empty() {
return Ok(HashMap::new());
}
serde_json::from_str(&content).map_err(|e| e.to_string())
}
fn write_store(path: &Path, store: &TokenStore) -> Result<(), String> {
let content = serde_json::to_string_pretty(store).map_err(|e| e.to_string())?;
fs::write(path, content).map_err(|e| e.to_string())
let content = serde_json::to_string_pretty(store).map_err(|e| e.to_string())?;
fs::write(path, content).map_err(|e| e.to_string())
}
#[tauri::command]
pub fn oauth_set_tokens(
app: tauri::AppHandle,
provider_id: String,
tokens: serde_json::Value,
app: tauri::AppHandle,
provider_id: String,
tokens: serde_json::Value,
) -> Result<(), String> {
let path = get_storage_path(&app)?;
let mut store = read_store(&path)?;
let path = get_storage_path(&app)?;
let mut store = read_store(&path)?;
let token_set: StoredTokenSet =
serde_json::from_value(tokens).map_err(|e| e.to_string())?;
let token_set: StoredTokenSet = serde_json::from_value(tokens).map_err(|e| e.to_string())?;
store.insert(provider_id, token_set);
write_store(&path, &store)
store.insert(provider_id, token_set);
write_store(&path, &store)
}
#[tauri::command]
pub fn oauth_get_tokens(
app: tauri::AppHandle,
provider_id: String,
app: tauri::AppHandle,
provider_id: String,
) -> Result<Option<serde_json::Value>, String> {
let path = get_storage_path(&app)?;
let store = read_store(&path)?;
if let Some(token_set) = store.get(&provider_id) {
let value = serde_json::to_value(token_set).map_err(|e| e.to_string())?;
Ok(Some(value))
} else {
Ok(None)
}
let path = get_storage_path(&app)?;
let store = read_store(&path)?;
if let Some(token_set) = store.get(&provider_id) {
let value = serde_json::to_value(token_set).map_err(|e| e.to_string())?;
Ok(Some(value))
} else {
Ok(None)
}
}
#[tauri::command]
pub fn oauth_remove_tokens(app: tauri::AppHandle, provider_id: String) -> Result<(), String> {
let path = get_storage_path(&app)?;
let mut store = read_store(&path)?;
store.remove(&provider_id);
write_store(&path, &store)
let path = get_storage_path(&app)?;
let mut store = read_store(&path)?;
store.remove(&provider_id);
write_store(&path, &store)
}