feat: add plugin-url for URL handling and open in browser functionality
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -3352,6 +3352,14 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plugin-url"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.16"
|
version = "0.17.16"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ members = [
|
|||||||
"crates/plugins/plugin-cmd",
|
"crates/plugins/plugin-cmd",
|
||||||
"crates/plugins/plugin-files",
|
"crates/plugins/plugin-files",
|
||||||
"crates/k-launcher-ui-egui",
|
"crates/k-launcher-ui-egui",
|
||||||
|
"crates/plugins/plugin-url",
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
default-run = "k-launcher"
|
default-run = "k-launcher"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
strip = true
|
||||||
|
codegen-units = 1
|
||||||
|
opt-level = 3
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "k-launcher"
|
name = "k-launcher"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|||||||
12
crates/plugins/plugin-url/Cargo.toml
Normal file
12
crates/plugins/plugin-url/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "plugin-url"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "k-launcher-plugin-url"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
130
crates/plugins/plugin-url/src/main.rs
Normal file
130
crates/plugins/plugin-url/src/main.rs
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
use std::io::{self, BufRead, Write};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Query {
|
||||||
|
query: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Action {
|
||||||
|
r#type: &'static str,
|
||||||
|
cmd: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Result {
|
||||||
|
id: &'static str,
|
||||||
|
title: &'static str,
|
||||||
|
description: String,
|
||||||
|
score: u32,
|
||||||
|
action: Action,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_url(query: &str) -> bool {
|
||||||
|
query.starts_with("http://") || query.starts_with("https://") || query.starts_with("www.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize(query: &str) -> String {
|
||||||
|
if query.starts_with("www.") {
|
||||||
|
format!("https://{query}")
|
||||||
|
} else {
|
||||||
|
query.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search(query: &str) -> Vec<Result> {
|
||||||
|
if !is_url(query) {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
let url = normalize(query);
|
||||||
|
vec![Result {
|
||||||
|
id: "url-open",
|
||||||
|
title: "Open in Browser",
|
||||||
|
description: url.clone(),
|
||||||
|
score: 95,
|
||||||
|
action: Action {
|
||||||
|
r#type: "SpawnProcess",
|
||||||
|
cmd: format!("xdg-open {url}"),
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let stdin = io::stdin();
|
||||||
|
let stdout = io::stdout();
|
||||||
|
let mut out = stdout.lock();
|
||||||
|
|
||||||
|
for line in stdin.lock().lines() {
|
||||||
|
let line = line?;
|
||||||
|
let q: Query = match serde_json::from_str(&line) {
|
||||||
|
Ok(q) => q,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
let results = search(&q.query);
|
||||||
|
writeln!(out, "{}", serde_json::to_string(&results).unwrap())?;
|
||||||
|
out.flush()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_url_https() {
|
||||||
|
assert!(is_url("https://example.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_url_http() {
|
||||||
|
assert!(is_url("http://example.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_url_www() {
|
||||||
|
assert!(is_url("www.foo.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_url_plain() {
|
||||||
|
assert!(!is_url("firefox"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_url_empty() {
|
||||||
|
assert!(!is_url(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalize_www() {
|
||||||
|
assert_eq!(normalize("www.foo.com"), "https://www.foo.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalize_https() {
|
||||||
|
assert_eq!(normalize("https://example.com"), "https://example.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn search_returns_result() {
|
||||||
|
let results = search("https://example.com");
|
||||||
|
assert_eq!(results.len(), 1);
|
||||||
|
assert_eq!(results[0].action.cmd, "xdg-open https://example.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn search_returns_empty() {
|
||||||
|
assert!(search("firefox").is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn result_serializes() {
|
||||||
|
let results = search("https://example.com");
|
||||||
|
let json = serde_json::to_string(&results).unwrap();
|
||||||
|
assert!(json.contains("SpawnProcess"));
|
||||||
|
assert!(json.contains("xdg-open"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user