File search on the way
This commit is contained in:
parent
53e45fa232
commit
47dd0c752a
98
Cargo.lock
generated
98
Cargo.lock
generated
@ -89,6 +89,27 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "directories"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@ -583,6 +604,16 @@ version = "0.2.175"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.13"
|
||||
@ -658,6 +689,12 @@ version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.21.1"
|
||||
@ -727,6 +764,17 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "relm4"
|
||||
version = "0.10.0"
|
||||
@ -787,6 +835,15 @@ dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@ -879,6 +936,26 @@ version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.47.1"
|
||||
@ -990,6 +1067,16 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
@ -1057,6 +1144,7 @@ dependencies = [
|
||||
name = "waycast"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"directories",
|
||||
"gio",
|
||||
"glib",
|
||||
"gtk4",
|
||||
@ -1064,6 +1152,16 @@ dependencies = [
|
||||
"relm4",
|
||||
"relm4-components",
|
||||
"tracker",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22"
|
||||
dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
directories = "6.0.0"
|
||||
gio = "0.21.1"
|
||||
glib = "0.21.1"
|
||||
gtk = { version = "0.10.0", package = "gtk4" }
|
||||
@ -11,3 +12,4 @@ gtk4-layer-shell = "0.6.1"
|
||||
relm4 = "0.10.0"
|
||||
relm4-components = "0.10.0"
|
||||
tracker = "0.2.2"
|
||||
walkdir = "2.5.0"
|
||||
|
@ -15,6 +15,7 @@ pub trait LauncherListItem {
|
||||
}
|
||||
|
||||
pub trait LauncherPlugin {
|
||||
fn init(&self);
|
||||
fn name(&self) -> String;
|
||||
fn priority(&self) -> i32;
|
||||
fn description(&self) -> Option<String>;
|
||||
|
@ -1,8 +1,13 @@
|
||||
use gtk::Application;
|
||||
use gtk::prelude::*;
|
||||
use std::env;
|
||||
use waycast::plugins;
|
||||
use waycast::ui::WaycastLauncher;
|
||||
|
||||
// TODO: Add an init() function to the launcher plugin spec
|
||||
// that will get called when loaded. That way plugins like
|
||||
// file search can index the file system on init instead
|
||||
// of on the fly
|
||||
fn main() {
|
||||
let app = Application::builder()
|
||||
.application_id("dev.thegrind.waycast")
|
||||
@ -11,7 +16,7 @@ fn main() {
|
||||
app.connect_activate(|app| {
|
||||
let launcher = WaycastLauncher::new()
|
||||
.add_plugin(plugins::drun::DrunPlugin {})
|
||||
.add_plugin(plugins::file_search::FileSearchPlugin {})
|
||||
.add_plugin(plugins::file_search::FileSearchPlugin::new())
|
||||
.initialize(app);
|
||||
|
||||
launcher.borrow().show();
|
||||
|
@ -85,6 +85,10 @@ pub fn get_desktop_entries() -> Vec<DesktopEntry> {
|
||||
pub struct DrunPlugin {}
|
||||
|
||||
impl LauncherPlugin for DrunPlugin {
|
||||
fn init(&self) {
|
||||
// TODO: Load apps into memory
|
||||
// TODO: Find and cache Icons
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
return String::from("drun");
|
||||
}
|
||||
|
@ -1,28 +1,128 @@
|
||||
use directories::UserDirs;
|
||||
use gio::prelude::FileExt;
|
||||
use glib::object::Cast;
|
||||
use std::path::PathBuf;
|
||||
use std::{cell::RefCell, env};
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
use crate::{LaunchError, LauncherListItem, LauncherPlugin};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FileEntry {
|
||||
title: String,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl LauncherListItem for ExampleEntry {
|
||||
impl FileEntry {
|
||||
fn from(entry: DirEntry) -> Self {
|
||||
return FileEntry {
|
||||
path: entry.into_path(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl LauncherListItem for FileEntry {
|
||||
fn title(&self) -> String {
|
||||
return self.title.to_string();
|
||||
return String::from(self.path.file_name().unwrap().to_string_lossy());
|
||||
}
|
||||
fn description(&self) -> Option<String> {
|
||||
return None;
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), LaunchError> {
|
||||
println!("Sample item clicked: {}", self.title);
|
||||
Ok(())
|
||||
let file_uri = gio::File::for_path(&self.path);
|
||||
match gio::AppInfo::launch_default_for_uri(
|
||||
file_uri.uri().as_str(),
|
||||
None::<&gio::AppLaunchContext>,
|
||||
) {
|
||||
Err(_) => Err(LaunchError::CouldNotLaunch(
|
||||
"Error opening file".to_string(),
|
||||
)),
|
||||
Ok(()) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn icon(&self) -> String {
|
||||
return String::from("vscode");
|
||||
let (content_type, _) = gio::content_type_guess(Some(&self.path), None);
|
||||
|
||||
let icon = gio::content_type_get_icon(&content_type);
|
||||
|
||||
if let Some(themed_icon) = icon.downcast_ref::<gio::ThemedIcon>() {
|
||||
if let Some(icon_name) = themed_icon.names().first() {
|
||||
return icon_name.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
String::from("text-x-generic")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FileSearchPlugin {}
|
||||
pub struct FileSearchPlugin {
|
||||
search_paths: Vec<PathBuf>,
|
||||
skip_dirs: Vec<String>,
|
||||
// Running list of files in memory
|
||||
files: RefCell<Vec<FileEntry>>,
|
||||
}
|
||||
|
||||
impl FileSearchPlugin {
|
||||
pub fn new() -> Self {
|
||||
return FileSearchPlugin {
|
||||
search_paths: Vec::new(),
|
||||
skip_dirs: vec![
|
||||
String::from("vendor"),
|
||||
String::from("node_modules"),
|
||||
String::from("cache"),
|
||||
String::from("zig-cache"),
|
||||
],
|
||||
files: RefCell::new(Vec::new()),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn skip_hidden(entry: &DirEntry) -> bool {
|
||||
entry
|
||||
.file_name()
|
||||
.to_str()
|
||||
.map(|s| s.starts_with("."))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn skip_dir(entry: &DirEntry, dirs: &Vec<String>) -> bool {
|
||||
entry
|
||||
.file_name()
|
||||
.to_str()
|
||||
.map(|n| dirs.contains(&String::from(n)))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
impl LauncherPlugin for FileSearchPlugin {
|
||||
fn init(&self) {
|
||||
// let home = env::home_dir().unwrap();
|
||||
if let Some(ud) = UserDirs::new() {
|
||||
let scan = [
|
||||
ud.document_dir(),
|
||||
ud.picture_dir(),
|
||||
ud.audio_dir(),
|
||||
ud.video_dir(),
|
||||
];
|
||||
|
||||
for p in scan {
|
||||
match p {
|
||||
Some(path) => {
|
||||
let walker = WalkDir::new(path).into_iter();
|
||||
for entry in walker
|
||||
.filter_entry(|e| !skip_hidden(e) && !skip_dir(e, &self.skip_dirs))
|
||||
.filter_map(|e| e.ok())
|
||||
{
|
||||
if entry.path().is_file() {
|
||||
self.files.borrow_mut().push(FileEntry::from(entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
return String::from("File search");
|
||||
}
|
||||
@ -48,6 +148,21 @@ impl LauncherPlugin for FileSearchPlugin {
|
||||
}
|
||||
|
||||
fn filter(&self, query: &str) -> Vec<Box<dyn LauncherListItem>> {
|
||||
self.default_list()
|
||||
if query.is_empty() {
|
||||
return self.default_list();
|
||||
}
|
||||
|
||||
let mut entries: Vec<Box<dyn LauncherListItem>> = Vec::new();
|
||||
let files = self.files.borrow();
|
||||
for f in files.iter() {
|
||||
if let Some(file_name) = f.path.file_name() {
|
||||
let cmp = file_name.to_string_lossy().to_lowercase();
|
||||
if cmp.contains(&query.to_lowercase()) {
|
||||
entries.push(Box::new(f.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entries
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use gtk4_layer_shell as layerShell;
|
||||
use layerShell::LayerShell;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
mod launcher_builder;
|
||||
@ -155,6 +156,7 @@ impl WaycastLauncher {
|
||||
plugins_by_prefix,
|
||||
}));
|
||||
|
||||
model.borrow().init_plugins();
|
||||
// Populate the list
|
||||
model.borrow_mut().populate_list();
|
||||
|
||||
@ -165,7 +167,6 @@ impl WaycastLauncher {
|
||||
let model_clone = model.clone();
|
||||
search_input.connect_changed(move |entry| {
|
||||
let query = entry.text().to_string();
|
||||
println!("query: {query}");
|
||||
model_clone.borrow_mut().filter_list(&query);
|
||||
});
|
||||
|
||||
@ -263,6 +264,12 @@ impl WaycastLauncher {
|
||||
model
|
||||
}
|
||||
|
||||
fn init_plugins(&self) {
|
||||
for plugin in &self.plugins {
|
||||
plugin.init();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_list_ui(&self) {
|
||||
while let Some(child) = self.list_box.first_child() {
|
||||
self.list_box.remove(&child);
|
||||
|
Loading…
x
Reference in New Issue
Block a user