Getting to work on caching

This commit is contained in:
Javier Feliz 2025-09-06 14:37:29 -04:00
parent b90f65d713
commit ae7d3f7123
9 changed files with 511 additions and 131 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
# direnv cache (should not be committed) # direnv cache (should not be committed)
.direnv/ .direnv/
waycast_cache

152
Cargo.lock generated
View File

@ -38,6 +38,35 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bincode"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
dependencies = [
"bincode_derive",
"serde",
"unty",
]
[[package]]
name = "bincode_derive"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
dependencies = [
"virtue",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.3" version = "2.9.3"
@ -110,6 +139,22 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [
"libc",
"windows-sys 0.60.2",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]] [[package]]
name = "field-offset" name = "field-offset"
version = "0.3.6" version = "0.3.6"
@ -249,7 +294,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"wasi", "wasi 0.11.1+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi 0.14.4+wasi-0.2.4",
] ]
[[package]] [[package]]
@ -552,6 +609,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.27" version = "0.4.27"
@ -589,7 +652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [ dependencies = [
"libc", "libc",
"wasi", "wasi 0.11.1+wasi-snapshot-preview1",
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
@ -602,6 +665,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]] [[package]]
name = "option-ext" name = "option-ext"
version = "0.2.0" version = "0.2.0"
@ -677,13 +746,28 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "r-efi"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "redb"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fefa3e5ff4a369819c3d6df4195873d6f9abad109f13c0d505dbe119cfabb10"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.5.2" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [ dependencies = [
"getrandom", "getrandom 0.2.16",
"libredox", "libredox",
"thiserror", "thiserror",
] ]
@ -703,6 +787,19 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "rustix"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.60.2",
]
[[package]] [[package]]
name = "same-file" name = "same-file"
version = "1.0.6" version = "1.0.6"
@ -789,6 +886,19 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
[[package]]
name = "tempfile"
version = "3.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e"
dependencies = [
"fastrand",
"getrandom 0.3.3",
"once_cell",
"rustix",
"windows-sys 0.60.2",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.16" version = "2.0.16"
@ -875,12 +985,24 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]] [[package]]
name = "version-compare" name = "version-compare"
version = "0.2.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
[[package]]
name = "virtue"
version = "0.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.5.0" version = "2.5.0"
@ -897,18 +1019,36 @@ version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
version = "0.14.4+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a"
dependencies = [
"wit-bindgen",
]
[[package]] [[package]]
name = "waycast-core" name = "waycast-core"
version = "0.1.0" version = "0.1.0"
dependencies = [
"bincode 1.3.3",
"redb",
"serde",
"tempfile",
]
[[package]] [[package]]
name = "waycast-gtk" name = "waycast-gtk"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bincode 2.0.1",
"gio", "gio",
"glib", "glib",
"gtk4", "gtk4",
"gtk4-layer-shell", "gtk4-layer-shell",
"redb",
"serde",
"waycast-core", "waycast-core",
"waycast-plugins", "waycast-plugins",
] ]
@ -1106,6 +1246,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "wit-bindgen"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36"
[[package]] [[package]]
name = "xml-rs" name = "xml-rs"
version = "0.8.27" version = "0.8.27"

84
tmp.txt
View File

@ -1,84 +0,0 @@
cargo run -p waycast-gtk
/home/javi/projects/homelab-ansible
/home/javi/projects/gla-old
/home/javi/projects/filebrowser-agent
/home/javi/projects/ttrpg-cms
/home/javi/projects/desktop-setup
/home/javi/projects/ravensofravnica.stream
/home/javi/projects/nix
/home/javi/projects/demos
/home/javi/projects/resumeforge.app
/home/javi/projects/videos
/home/javi/projects/authentikate.dev
/home/javi/projects/blogimage.app
/home/javi/projects/arch-hyprland-setup
/home/javi/projects/laravel-dockerized
/home/javi/projects/alex-nix-config
/home/javi/projects/thegrind-tools
/home/javi/projects/imgsrc-app
/home/javi/projects/scripthost
/home/javi/projects/foundryvtt-docker
/home/javi/projects/launchlet.app
/home/javi/projects/yourfluence.dev
/home/javi/projects/thegrind.dev
/home/javi/projects/opnsensebackup
/home/javi/projects/project-picker
/home/javi/projects/thegrind.dev-old-jigsaw
/home/javi/projects/og-cli
/home/javi/projects/do-flow
/home/javi/projects/carti-python
/home/javi/projects/rack-planner
/home/javi/projects/ember-db
/home/javi/projects/local-ai
/home/javi/projects/zap
/home/javi/projects/flowtodo
/home/javi/projects/temp
/home/javi/projects/blog-backup
/home/javi/projects/javierfeliz.com
/home/javi/projects/thc-demo
/home/javi/projects/crawler-linkedin
/home/javi/projects/vikunja-planka-transfer
/home/javi/projects/desktop-backup
/home/javi/projects/authentikate
/home/javi/projects/scratchfl.com
/home/javi/projects/cs-trade-bot
/home/javi/projects/leetcode
/home/javi/projects/screenshotter
/home/javi/projects/docker-compose-builder
/home/javi/projects/javif89
/home/javi/projects/papibot
/home/javi/projects/crypt
/home/javi/projects/analysis
/home/javi/projects/go-starter-kit
/home/javi/projects/vue3-learning
/home/javi/projects/homelab-docker
/home/javi/projects/sitemapper
/home/javi/projects/dotnet-deployment-ansible
/home/javi/projects/planka
/home/javi/projects/waycast-cpp
/home/javi/projects/hubspot-assessment
/home/javi/projects/go-doit
/home/javi/projects/alex-demo
/home/javi/projects/docker-laravel-base
/home/javi/projects/staticforge
/home/javi/projects/jigsaw
/home/javi/projects/theresaleconcierge
/home/javi/projects/nico-stuff
/home/javi/projects/zold-javierfeliz.com
/home/javi/projects/ansible-starter-kit
/home/javi/projects/oidctester
/home/javi/projects/waycast
/home/javi/projects/ubuntu-setup
/home/javi/projects/caddy-test
/home/javi/projects/dotfiles
/home/javi/projects/bazzitouchedhisconfig.dev
/home/javi/projects/cs2-server-manager
/home/javi/projects/noconfig
/home/javi/projects/gamelineanalytics.com
/home/javi/projects/thegrind-de
/home/javi/projects/data-parser
/home/javi/projects/test-dotnet-blazor-project
/home/javi/projects/homies
/home/javi/projects/ogimage-click
/home/javi/projects/ansible-on-prem
Projects plugin: Found 82 projects

View File

@ -4,4 +4,10 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
bincode = "1.3"
redb = "3.0.1"
serde = { version = "1.0.219", features = ["derive"] }
[dev-dependencies]
tempfile = "3.21.0"
# No dependencies for core traits and launcher logic # No dependencies for core traits and launcher logic

50
waycast-core/src/cache/errors.rs vendored Normal file
View File

@ -0,0 +1,50 @@
use redb::{CommitError, DatabaseError, StorageError, TableError, TransactionError};
#[derive(Debug)]
pub enum CacheError {
DatabaseError(String),
SerializationError(String),
Other(String),
}
impl From<DatabaseError> for CacheError {
fn from(err: DatabaseError) -> Self {
CacheError::DatabaseError(err.to_string())
}
}
impl From<TransactionError> for CacheError {
fn from(err: TransactionError) -> Self {
CacheError::DatabaseError(err.to_string())
}
}
impl From<TableError> for CacheError {
fn from(err: TableError) -> Self {
CacheError::DatabaseError(err.to_string())
}
}
impl From<StorageError> for CacheError {
fn from(err: StorageError) -> Self {
CacheError::DatabaseError(err.to_string())
}
}
impl From<CommitError> for CacheError {
fn from(err: CommitError) -> Self {
CacheError::DatabaseError(err.to_string())
}
}
impl std::fmt::Display for CacheError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CacheError::DatabaseError(e) => write!(f, "Database error: {}", e),
CacheError::SerializationError(e) => write!(f, "Serialization error: {}", e),
CacheError::Other(msg) => write!(f, "Cache error: {}", msg),
}
}
}
impl std::error::Error for CacheError {}

236
waycast-core/src/cache/mod.rs vendored Normal file
View File

@ -0,0 +1,236 @@
pub mod errors;
use redb::{Database, ReadableDatabase, ReadableTable, TableDefinition};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::path::Path;
use std::time::{Duration, SystemTime};
use crate::cache::errors::CacheError;
const CACHE_TABLE: TableDefinition<&str, &[u8]> = TableDefinition::new("cache");
#[derive(Serialize, Deserialize)]
struct CacheEntry<T> {
data: T,
expires_at: Option<SystemTime>,
}
pub struct Cache {
db: Database,
}
pub fn new<P: AsRef<Path>>(db_path: P) -> Result<Cache, CacheError> {
let db = Database::create(db_path)?;
// Initialize the table if it doesn't exist
let write_txn = db.begin_write()?;
{
let _ = write_txn.open_table(CACHE_TABLE)?;
}
write_txn.commit()?;
Ok(Cache { db })
}
impl Cache {
/// Cache a value with an optional TTL. If TTL is None, the value never expires.
pub fn remember_with_ttl<T>(
&self,
key: &str,
ttl: Option<Duration>,
compute: impl FnOnce() -> T,
) -> Result<T, CacheError>
where
T: Serialize + DeserializeOwned + Clone,
{
// Try to get from cache first
if let Some(entry) = self.get_cached_entry::<T>(key)? {
// Check if entry has expired
if let Some(expires_at) = entry.expires_at {
if SystemTime::now() < expires_at {
println!("Cache hit");
return Ok(entry.data);
}
// Entry has expired, continue to recompute
} else {
// No expiration, return cached data
return Ok(entry.data);
}
}
println!("Cache miss");
// Not in cache or expired, compute the value
let data = compute();
let expires_at = ttl.map(|duration| SystemTime::now() + duration);
let entry = CacheEntry {
data: data.clone(),
expires_at,
};
// Store in cache
self.store_entry(key, &entry)?;
Ok(data)
}
/// Cache a value with no expiration
pub fn remember<T>(&self, key: &str, compute: impl FnOnce() -> T) -> Result<T, CacheError>
where
T: Serialize + DeserializeOwned + Clone,
{
self.remember_with_ttl(key, None, compute)
}
/// Get a cached value if it exists and hasn't expired
pub fn get<T>(&self, key: &str) -> Result<Option<T>, CacheError>
where
T: Serialize + DeserializeOwned,
{
if let Some(entry) = self.get_cached_entry::<T>(key)? {
// Check if entry has expired
if let Some(expires_at) = entry.expires_at {
if SystemTime::now() < expires_at {
return Ok(Some(entry.data));
}
// Entry has expired, remove it and return None
self.forget(key)?;
return Ok(None);
} else {
// No expiration, return cached data
return Ok(Some(entry.data));
}
}
Ok(None)
}
/// Store a value in the cache with optional TTL
pub fn put<T>(&self, key: &str, value: T, ttl: Option<Duration>) -> Result<(), CacheError>
where
T: Serialize,
{
let expires_at = ttl.map(|duration| SystemTime::now() + duration);
let entry = CacheEntry {
data: value,
expires_at,
};
self.store_entry(key, &entry)
}
/// Remove a key from the cache
pub fn forget(&self, key: &str) -> Result<(), CacheError> {
let write_txn = self.db.begin_write()?;
{
let mut table = write_txn.open_table(CACHE_TABLE)?;
table.remove(key)?;
}
write_txn.commit()?;
Ok(())
}
/// Clear all cached entries
pub fn clear(&self) -> Result<(), CacheError> {
let write_txn = self.db.begin_write()?;
{
let mut table = write_txn.open_table(CACHE_TABLE)?;
// Remove all entries
let keys: Vec<String> = {
let mut keys = Vec::new();
let mut iter = table.iter()?;
while let Some(Ok((key, _))) = iter.next() {
keys.push(key.value().to_string());
}
keys
};
for key in keys {
table.remove(key.as_str())?;
}
}
write_txn.commit()?;
Ok(())
}
fn get_cached_entry<T>(&self, key: &str) -> Result<Option<CacheEntry<T>>, CacheError>
where
T: DeserializeOwned,
{
let read_txn = self.db.begin_read()?;
let table = read_txn.open_table(CACHE_TABLE)?;
if let Some(cached_bytes) = table.get(key)? {
match bincode::deserialize::<CacheEntry<T>>(cached_bytes.value()) {
Ok(entry) => Ok(Some(entry)),
Err(_) => {
// Failed to deserialize, probably corrupted or wrong format
Ok(None)
}
}
} else {
Ok(None)
}
}
fn store_entry<T>(&self, key: &str, entry: &CacheEntry<T>) -> Result<(), CacheError>
where
T: Serialize,
{
let write_txn = self.db.begin_write()?;
{
let mut table = write_txn.open_table(CACHE_TABLE)?;
let serialized = bincode::serialize(entry)
.map_err(|e| CacheError::SerializationError(e.to_string()))?;
table.insert(key, serialized.as_slice())?;
}
write_txn.commit()?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
use tempfile::NamedTempFile;
#[test]
fn test_cache_remember() {
let temp_file = NamedTempFile::new().unwrap();
let cache = Cache::new(temp_file.path()).unwrap();
let result = cache
.remember("test_key", || "computed_value".to_string())
.unwrap();
assert_eq!(result, "computed_value");
// Second call should return cached value
let result2 = cache
.remember("test_key", || "different_value".to_string())
.unwrap();
assert_eq!(result2, "computed_value");
}
#[test]
fn test_cache_ttl() {
let temp_file = NamedTempFile::new().unwrap();
let cache = Cache::new(temp_file.path()).unwrap();
// Cache with very short TTL
let result = cache
.remember_with_ttl("ttl_key", Some(Duration::from_millis(1)), || {
"cached_value".to_string()
})
.unwrap();
assert_eq!(result, "cached_value");
// Wait for expiration
std::thread::sleep(Duration::from_millis(10));
// Should recompute after expiration
let result2 = cache
.remember_with_ttl("ttl_key", Some(Duration::from_millis(1)), || {
"new_value".to_string()
})
.unwrap();
assert_eq!(result2, "new_value");
}
}

View File

@ -1,6 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
pub mod cache;
#[derive(Debug)] #[derive(Debug)]
pub enum LaunchError { pub enum LaunchError {
CouldNotLaunch(String), CouldNotLaunch(String),

View File

@ -14,3 +14,6 @@ gio = "0.21.1"
glib = "0.21.1" glib = "0.21.1"
gtk = { version = "0.10.0", package = "gtk4" } gtk = { version = "0.10.0", package = "gtk4" }
gtk4-layer-shell = "0.6.1" gtk4-layer-shell = "0.6.1"
redb = "3.0.1"
serde = "1.0.219"
bincode = "2.0.1"

View File

@ -1,50 +1,70 @@
mod ui; use std::time::Duration;
mod util;
use gtk::prelude::*; use waycast_core::cache::Cache;
use gtk::Application;
use ui::gtk::GtkLauncherUI;
use waycast_core::WaycastLauncher;
fn main() { fn main() {
let app = Application::builder() let cache: Cache;
.application_id("dev.thegrind.waycast") if let Ok(db) = waycast_core::cache::new("waycast_cache") {
.build(); cache = db;
} else {
app.connect_activate(|app| { panic!("Failed to open database");
let mut file_search_plugin = waycast_plugins::file_search::new();
if let Err(e) = file_search_plugin.add_search_path("/home/javi/working-files/DJ Music/") {
eprintln!("{}", e)
} }
let mut project_plugin = waycast_plugins::projects::new(); let result = cache.remember_with_ttl("test_key", Some(Duration::from_secs(10)), || {
if let Err(e) = project_plugin.add_search_path("/home/javi/projects") { String::from("my cool string value")
eprintln!("{}", e)
}
// Create the core launcher
let launcher = WaycastLauncher::new()
.add_plugin(Box::new(waycast_plugins::drun::new()))
.add_plugin(Box::new(file_search_plugin))
.add_plugin(Box::new(project_plugin))
.init();
// Create and show the GTK UI
let ui = GtkLauncherUI::new(app, launcher);
// Apply built-in default styles
if let Err(e) = ui.apply_default_css() {
eprintln!("Warning: Could not apply default styles: {}", e);
}
// Optionally apply user CSS overrides
// if let Err(_) = ui.apply_css("waycast.css") {
// // Silently ignore if user hasn't provided custom CSS
// }
ui.show();
}); });
app.run(); if let Ok(val) = result {
println!("{}", val);
}
} }
// mod ui;
// mod util;
// use gtk::prelude::*;
// use gtk::Application;
// use ui::gtk::GtkLauncherUI;
// use waycast_core::WaycastLauncher;
// fn main() {
// let app = Application::builder()
// .application_id("dev.thegrind.waycast")
// .build();
// app.connect_activate(|app| {
// let mut file_search_plugin = waycast_plugins::file_search::new();
// if let Err(e) = file_search_plugin.add_search_path("/home/javi/working-files/DJ Music/") {
// eprintln!("{}", e)
// }
// let mut project_plugin = waycast_plugins::projects::new();
// if let Err(e) = project_plugin.add_search_path("/home/javi/projects") {
// eprintln!("{}", e)
// }
// // Create the core launcher
// let launcher = WaycastLauncher::new()
// .add_plugin(Box::new(waycast_plugins::drun::new()))
// .add_plugin(Box::new(file_search_plugin))
// .add_plugin(Box::new(project_plugin))
// .init();
// // Create and show the GTK UI
// let ui = GtkLauncherUI::new(app, launcher);
// // Apply built-in default styles
// if let Err(e) = ui.apply_default_css() {
// eprintln!("Warning: Could not apply default styles: {}", e);
// }
// // Optionally apply user CSS overrides
// // if let Err(_) = ui.apply_css("waycast.css") {
// // // Silently ignore if user hasn't provided custom CSS
// // }
// ui.show();
// });
// app.run();
// }