Added projects plugin
This commit is contained in:
parent
8c5b9f9295
commit
bf443a27fd
84
tmp.txt
Normal file
84
tmp.txt
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
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
|
@ -20,10 +20,17 @@ fn main() {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut project_plugin = waycast_plugins::projects::new();
|
||||||
|
match project_plugin.add_search_path("/home/javi/projects") {
|
||||||
|
Err(e) => eprintln!("{}", e),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
// Create the core launcher
|
// Create the core launcher
|
||||||
let launcher = WaycastLauncher::new()
|
let launcher = WaycastLauncher::new()
|
||||||
.add_plugin(Box::new(waycast_plugins::drun::new()))
|
.add_plugin(Box::new(waycast_plugins::drun::new()))
|
||||||
.add_plugin(Box::new(file_search_plugin))
|
.add_plugin(Box::new(file_search_plugin))
|
||||||
|
.add_plugin(Box::new(project_plugin))
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
// Create and show the GTK UI
|
// Create and show the GTK UI
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
pub mod drun;
|
pub mod drun;
|
||||||
pub mod file_search;
|
pub mod file_search;
|
||||||
|
pub mod projects;
|
||||||
|
|
||||||
// Re-export the macros for external use
|
// Re-export the macros for external use
|
||||||
pub use waycast_macros::{plugin, launcher_entry};
|
pub use waycast_macros::{launcher_entry, plugin};
|
||||||
|
182
waycast-plugins/src/projects.rs
Normal file
182
waycast-plugins/src/projects.rs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
// TODO: Use the user's preferred editor.
|
||||||
|
// This should just be in the config when I implement
|
||||||
|
// that eventually since figuring out every editor's
|
||||||
|
// launch option would be a pain. The user can just
|
||||||
|
// configure launch_command and pass a parameter.
|
||||||
|
// Example: code -n {path}
|
||||||
|
// and I'll just regex in the path.
|
||||||
|
// TODO: Project type detection and icon
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
process::Command,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use waycast_core::{LaunchError, LauncherListItem, LauncherPlugin};
|
||||||
|
use waycast_macros::{launcher_entry, plugin};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ProjectEntry {
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LauncherListItem for ProjectEntry {
|
||||||
|
launcher_entry! {
|
||||||
|
id: self.path.to_string_lossy().to_string(),
|
||||||
|
title: String::from(self.path.file_name().unwrap().to_string_lossy()),
|
||||||
|
description: Some(self.path.to_string_lossy().to_string()),
|
||||||
|
icon: {
|
||||||
|
String::from("vscode")
|
||||||
|
},
|
||||||
|
execute: {
|
||||||
|
println!("Executing: {}", self.path.display());
|
||||||
|
|
||||||
|
// Use xdg-open directly since it works properly with music files
|
||||||
|
match Command::new("code").arg("-n").arg(&self.path).spawn() {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("Successfully opened with code");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(_) => Err(LaunchError::CouldNotLaunch("Failed to open project folder".into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProjectsPlugin {
|
||||||
|
search_paths: Vec<PathBuf>,
|
||||||
|
skip_dirs: Vec<String>,
|
||||||
|
// Running list of files in memory
|
||||||
|
files: Arc<Mutex<Vec<ProjectEntry>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProjectsPlugin {
|
||||||
|
pub fn add_search_path<P: AsRef<Path>>(&mut self, path: P) -> Result<(), String> {
|
||||||
|
let p = path.as_ref();
|
||||||
|
|
||||||
|
if !p.exists() {
|
||||||
|
return Err(format!("Path does not exist: {}", p.display()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.is_dir() {
|
||||||
|
return Err(format!("Path is not a directory: {}", p.display()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.search_paths.push(p.to_path_buf());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_skip_dir(&mut self, directory_name: String) -> Result<(), String> {
|
||||||
|
self.skip_dirs.push(directory_name);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_skip_dir(dir_name: &str, skip_dirs: &[String]) -> bool {
|
||||||
|
skip_dirs.iter().any(|skip| skip == dir_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LauncherPlugin for ProjectsPlugin {
|
||||||
|
plugin! {
|
||||||
|
name: "Projects",
|
||||||
|
priority: 800,
|
||||||
|
description: "Search and open code projects",
|
||||||
|
prefix: "proj",
|
||||||
|
init: projects_init,
|
||||||
|
default_list: projects_default_list,
|
||||||
|
filter: projects_filter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn projects_default_list(_plugin: &ProjectsPlugin) -> Vec<Box<dyn LauncherListItem>> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn projects_filter(plugin: &ProjectsPlugin, query: &str) -> Vec<Box<dyn LauncherListItem>> {
|
||||||
|
if query.is_empty() {
|
||||||
|
return projects_default_list(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut entries: Vec<Box<dyn LauncherListItem>> = Vec::new();
|
||||||
|
|
||||||
|
// Try to get files without blocking - if indexing is still in progress, return empty
|
||||||
|
if let Ok(files) = plugin.files.try_lock() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
fn projects_init(plugin: &ProjectsPlugin) {
|
||||||
|
let files_clone = Arc::clone(&plugin.files);
|
||||||
|
let search_paths = plugin.search_paths.clone();
|
||||||
|
let skip_dirs = plugin.skip_dirs.clone();
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
rt.block_on(async {
|
||||||
|
let mut project_entries = Vec::new();
|
||||||
|
|
||||||
|
for search_path in &search_paths {
|
||||||
|
if let Ok(entries) = fs::read_dir(search_path) {
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
if let Ok(file_type) = entry.file_type() {
|
||||||
|
if file_type.is_dir() {
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
// Skip hidden directories (starting with .)
|
||||||
|
if let Some(file_name) = path.file_name() {
|
||||||
|
if let Some(name_str) = file_name.to_str() {
|
||||||
|
// Skip hidden directories
|
||||||
|
if name_str.starts_with('.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip directories in skip list
|
||||||
|
if should_skip_dir(name_str, &skip_dirs) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{}", path.display());
|
||||||
|
|
||||||
|
project_entries.push(ProjectEntry { path });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the shared files collection
|
||||||
|
let mut files_guard = files_clone.lock().await;
|
||||||
|
*files_guard = project_entries;
|
||||||
|
|
||||||
|
println!("Projects plugin: Found {} projects", files_guard.len());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> ProjectsPlugin {
|
||||||
|
ProjectsPlugin {
|
||||||
|
search_paths: Vec::new(),
|
||||||
|
skip_dirs: vec![
|
||||||
|
String::from("vendor"),
|
||||||
|
String::from("node_modules"),
|
||||||
|
String::from("cache"),
|
||||||
|
String::from("zig-cache"),
|
||||||
|
String::from(".git"),
|
||||||
|
String::from(".svn"),
|
||||||
|
],
|
||||||
|
files: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user