fix(review): bugs, arch violations, design smells
P1 bugs: - unix_launcher: shell_split respects quoted args (was split_whitespace) - plugin-host: 5s timeout on external plugin search - ui: handle engine init panic, wire error state - ui-egui: read window config instead of always using defaults - plugin-url: use OpenPath action instead of SpawnProcess+xdg-open Architecture: - remove WindowConfig (mirror of WindowCfg); use WindowCfg directly - remove on_select closure from SearchResult (domain leakage) - remove LaunchAction::Custom; add Plugin::on_selected + SearchEngine::on_selected - apps: record frecency via on_selected instead of embedded closure Design smells: - frecency: extract decay_factor helper, write outside mutex - apps: remove cfg(test) cache_path hack; add new_for_test ctor - apps: stable ResultId using name+exec to prevent collision - files: stable ResultId using full path instead of index - plugin-host: remove k-launcher-os-bridge dep (WindowConfig gone)
This commit is contained in:
@@ -4,6 +4,5 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
k-launcher-config = { path = "../k-launcher-config" }
|
||||
k-launcher-kernel = { path = "../k-launcher-kernel" }
|
||||
libc = "0.2"
|
||||
|
||||
@@ -1,23 +1,2 @@
|
||||
mod unix_launcher;
|
||||
|
||||
pub use unix_launcher::UnixAppLauncher;
|
||||
|
||||
pub struct WindowConfig {
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
pub decorations: bool,
|
||||
pub transparent: bool,
|
||||
pub resizable: bool,
|
||||
}
|
||||
|
||||
impl WindowConfig {
|
||||
pub fn from_cfg(w: &k_launcher_config::WindowCfg) -> Self {
|
||||
Self {
|
||||
width: w.width,
|
||||
height: w.height,
|
||||
decorations: w.decorations,
|
||||
transparent: w.transparent,
|
||||
resizable: w.resizable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,29 @@ use std::process::{Command, Stdio};
|
||||
|
||||
use k_launcher_kernel::{AppLauncher, LaunchAction};
|
||||
|
||||
fn shell_split(cmd: &str) -> Vec<String> {
|
||||
let mut tokens = Vec::new();
|
||||
let mut current = String::new();
|
||||
let mut in_quotes = false;
|
||||
|
||||
for ch in cmd.chars() {
|
||||
match ch {
|
||||
'"' => in_quotes = !in_quotes,
|
||||
' ' | '\t' if !in_quotes => {
|
||||
if !current.is_empty() {
|
||||
tokens.push(current.clone());
|
||||
current.clear();
|
||||
}
|
||||
}
|
||||
_ => current.push(ch),
|
||||
}
|
||||
}
|
||||
if !current.is_empty() {
|
||||
tokens.push(current);
|
||||
}
|
||||
tokens
|
||||
}
|
||||
|
||||
fn parse_term_cmd(s: &str) -> (String, Vec<String>) {
|
||||
let mut parts = s.split_whitespace();
|
||||
let bin = parts.next().unwrap_or("").to_string();
|
||||
@@ -69,7 +92,7 @@ impl AppLauncher for UnixAppLauncher {
|
||||
fn execute(&self, action: &LaunchAction) {
|
||||
match action {
|
||||
LaunchAction::SpawnProcess(cmd) => {
|
||||
let parts: Vec<&str> = cmd.split_whitespace().collect();
|
||||
let parts = shell_split(cmd);
|
||||
if let Some((bin, args)) = parts.split_first() {
|
||||
let _ = unsafe {
|
||||
Command::new(bin)
|
||||
@@ -121,7 +144,50 @@ impl AppLauncher for UnixAppLauncher {
|
||||
}
|
||||
}
|
||||
}
|
||||
LaunchAction::Custom(f) => f(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::shell_split;
|
||||
|
||||
#[test]
|
||||
fn split_simple() {
|
||||
assert_eq!(shell_split("firefox"), vec!["firefox"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_with_args() {
|
||||
assert_eq!(
|
||||
shell_split("firefox --new-window"),
|
||||
vec!["firefox", "--new-window"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_quoted_path() {
|
||||
assert_eq!(
|
||||
shell_split(r#""My App" --flag"#),
|
||||
vec!["My App", "--flag"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_quoted_with_spaces() {
|
||||
assert_eq!(
|
||||
shell_split(r#"env "FOO BAR" baz"#),
|
||||
vec!["env", "FOO BAR", "baz"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_empty() {
|
||||
assert!(shell_split("").is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_extra_whitespace() {
|
||||
assert_eq!(shell_split(" a b "), vec!["a", "b"]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user