feat: update README and add documentation for installation, configuration, usage, and plugin development
This commit is contained in:
81
README.md
81
README.md
@@ -1,56 +1,41 @@
|
|||||||
# K-Launcher
|
# k-launcher
|
||||||
|
|
||||||
K-Launcher is a lightweight, GPU-accelerated command palette for Linux (Wayland/X11), macOS, and Windows. It reimagines the "Spotlight" experience through the lens of Frutiger Aero—focusing on gloss, glass, and skeuomorphism—powered by a non-blocking, multi-threaded Rust kernel.
|
A lightweight, GPU-accelerated command palette for Linux (Wayland/X11). Zero Electron — every pixel rendered via WGPU. Async search that never blocks the UI.
|
||||||
|
|
||||||
## Core Philosophy
|
|
||||||
|
|
||||||
- Zero Webview: No Chromium, no Electron. Every pixel is rendered via WGPU (Iced) for sub-5ms input-to-render latency.
|
|
||||||
|
|
||||||
- Async-First: Search queries never block the UI. If the file-searcher is indexing, the calculator still feels instant.
|
|
||||||
|
|
||||||
- The "Aero" Standard: Deep support for Gaussian blur (via Layer Shell), linear gradients, and high-gloss textures.
|
|
||||||
|
|
||||||
## High-Level Architecture
|
|
||||||
|
|
||||||
We are utilizing a "Hub-and-Spoke" model within a Cargo Workspace. The k-launcher-kernel acts as the central hub, dispatching user input to various "Spokes" (Plugins).
|
|
||||||
|
|
||||||
### The Crate Hierarchy
|
|
||||||
|
|
||||||
| Crate | Responsibility | Key Dependencies |
|
|
||||||
| -------------------------- | --------------------------------------------------------- | -------------------------------------- |
|
|
||||||
| **`k-launcher`** | The entry-point binary. Glues everything together. | `k-launcher-ui`, `k-launcher-kernel` |
|
|
||||||
| **`k-launcher-ui`** | The Iced-based view layer. Handles animations/theming. | `iced`, `lyon` (for vector paths) |
|
|
||||||
| **`k-launcher-kernel`** | The "Brain." Manages state, history, and plugin dispatch. | `tokio`, `tracing` |
|
|
||||||
| **`k-launcher-os-bridge`** | OS-specific windowing (Layer Shell for Wayland, Win32). | `iced_layershell`, `raw-window-handle` |
|
|
||||||
| **`plugins/*`** | Individual features (Calc, Files, Apps, Web). | `plugin-api` (Shared traits) |
|
|
||||||
|
|
||||||
## Data & Communication Flow
|
|
||||||
|
|
||||||
K-Launcher operates on an Event loop.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
sequenceDiagram
|
[screenshot placeholder]
|
||||||
participant User
|
|
||||||
participant UI as k-launcher-ui
|
|
||||||
participant Kernel as k-launcher-kernel
|
|
||||||
participant Plugins as plugin-file-search
|
|
||||||
|
|
||||||
User->>UI: Types "p"
|
|
||||||
UI->>Kernel: QueryUpdate("p")
|
|
||||||
par Parallel Search
|
|
||||||
Kernel->>Plugins: async search("p")
|
|
||||||
Plugins-->>Kernel: List<SearchResult>
|
|
||||||
end
|
|
||||||
Kernel->>UI: NewResults(Vec)
|
|
||||||
UI-->>User: Render Glass Result List
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Technical Specifications
|
## Quick Start
|
||||||
|
|
||||||
To ensure "Plug and Play" capability, all features must implement the `Plugin` trait. This allows the user to swap the default `file-searcher` for something like `fzf` or `plocate` without recompiling the UI.
|
```bash
|
||||||
|
git clone https://github.com/GKaszewski/k-launcher
|
||||||
|
cd k-launcher
|
||||||
|
cargo build --release
|
||||||
|
./target/release/k-launcher
|
||||||
|
```
|
||||||
|
|
||||||
To achieve the 2000s aesthetic without a browser:
|
## Keybinds
|
||||||
|
|
||||||
- Background Blur: On Wayland, we request blur through the org_kde_kwin_blur or fractional-scale protocols.
|
| Key | Action |
|
||||||
- Shaders: We will use Iced’s canvas to draw glossy "shine" overlays that respond to mouse hovering.
|
| --------- | --------------- |
|
||||||
- Icons: We will prefer .svg and .png with high-depth shadows over flat icon fonts.
|
| Type | Filter results |
|
||||||
|
| `↑` / `↓` | Navigate |
|
||||||
|
| `Enter` | Launch selected |
|
||||||
|
| `Escape` | Close |
|
||||||
|
|
||||||
|
## Built-in Plugins
|
||||||
|
|
||||||
|
| Trigger | Plugin | Example |
|
||||||
|
| ----------------- | ------ | -------------- |
|
||||||
|
| (any text) | Apps | `firefox` |
|
||||||
|
| number/expression | Calc | `2^10 + 5` |
|
||||||
|
| `>` prefix | Shell | `> echo hello` |
|
||||||
|
| `/` or `~/` | Files | `~/Documents` |
|
||||||
|
|
||||||
|
## Docs
|
||||||
|
|
||||||
|
- [Installation](docs/install.md)
|
||||||
|
- [Usage & Keybinds](docs/usage.md)
|
||||||
|
- [Configuration & Theming](docs/configuration.md)
|
||||||
|
- [Plugin Development](docs/plugin-development.md)
|
||||||
|
|||||||
45
docs/configuration.md
Normal file
45
docs/configuration.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Configuration
|
||||||
|
|
||||||
|
Config file: `~/.config/k-launcher/config.toml`
|
||||||
|
|
||||||
|
The file is optional — all fields have defaults and missing sections fall back to defaults automatically. Create it manually if you want to customize behavior.
|
||||||
|
|
||||||
|
## Full Annotated Example
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[window]
|
||||||
|
width = 600.0 # window width in logical pixels
|
||||||
|
height = 400.0 # window height in logical pixels
|
||||||
|
decorations = false # show window title bar / frame
|
||||||
|
transparent = true # allow background transparency
|
||||||
|
resizable = false # allow manual resizing
|
||||||
|
|
||||||
|
[appearance]
|
||||||
|
# RGBA: r/g/b are 0–255 as floats, a is 0.0–1.0
|
||||||
|
background_rgba = [20.0, 20.0, 30.0, 0.9] # main background
|
||||||
|
border_rgba = [229.0, 125.0, 33.0, 1.0] # accent/border color
|
||||||
|
border_width = 1.0 # border thickness in pixels
|
||||||
|
border_radius = 8.0 # corner radius of the window
|
||||||
|
search_font_size = 18.0 # font size of the search input
|
||||||
|
title_size = 15.0 # font size of result titles
|
||||||
|
desc_size = 12.0 # font size of result descriptions
|
||||||
|
row_radius = 4.0 # corner radius of result rows
|
||||||
|
placeholder = "Search..." # search input placeholder text
|
||||||
|
|
||||||
|
[search]
|
||||||
|
max_results = 8 # maximum results shown at once
|
||||||
|
|
||||||
|
[plugins]
|
||||||
|
calc = true # math expression evaluator
|
||||||
|
cmd = true # shell command runner (> prefix)
|
||||||
|
files = true # filesystem browser (/ or ~/ prefix)
|
||||||
|
apps = true # XDG application launcher
|
||||||
|
```
|
||||||
|
|
||||||
|
## RGBA Format
|
||||||
|
|
||||||
|
Colors use `[r, g, b, a]` arrays where:
|
||||||
|
- `r`, `g`, `b` — red, green, blue channels as floats **0.0–255.0**
|
||||||
|
- `a` — alpha (opacity) as a float **0.0–1.0**
|
||||||
|
|
||||||
|
Example — semi-transparent white: `[255.0, 255.0, 255.0, 0.5]`
|
||||||
57
docs/install.md
Normal file
57
docs/install.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Installation
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Rust** stable toolchain — install via [rustup](https://rustup.rs)
|
||||||
|
- **git**
|
||||||
|
- A **Wayland** or **X11** compositor (Linux)
|
||||||
|
|
||||||
|
## Build from Source
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/GKaszewski/k-launcher
|
||||||
|
cd k-launcher
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
Binary location: `target/release/k-launcher`
|
||||||
|
|
||||||
|
### Optional: install to PATH
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp target/release/k-launcher ~/.local/bin/
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensure `~/.local/bin` is in your `$PATH`.
|
||||||
|
|
||||||
|
## Autostart
|
||||||
|
|
||||||
|
### Hyprland
|
||||||
|
|
||||||
|
Add to `~/.config/hypr/hyprland.conf`:
|
||||||
|
|
||||||
|
```
|
||||||
|
exec-once = k-launcher
|
||||||
|
```
|
||||||
|
|
||||||
|
### systemd user service
|
||||||
|
|
||||||
|
Create `~/.config/systemd/user/k-launcher.service`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=k-launcher command palette
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=%h/.local/bin/k-launcher
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
|
```
|
||||||
|
|
||||||
|
Then enable it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl --user enable --now k-launcher
|
||||||
|
```
|
||||||
132
docs/plugin-development.md
Normal file
132
docs/plugin-development.md
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# Plugin Development
|
||||||
|
|
||||||
|
Plugins are Rust crates that implement the `Plugin` trait from `k-launcher-kernel`. They run concurrently — the kernel fans out every query to all enabled plugins and merges results by score.
|
||||||
|
|
||||||
|
> Note: plugins are compiled into the binary at build time. There is no dynamic loading support yet.
|
||||||
|
|
||||||
|
## Step-by-Step
|
||||||
|
|
||||||
|
### 1. Create a new crate in the workspace
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo new --lib crates/plugins/plugin-hello
|
||||||
|
```
|
||||||
|
|
||||||
|
Add it to the workspace root `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
# ...existing members...
|
||||||
|
"crates/plugins/plugin-hello",
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Add dependencies
|
||||||
|
|
||||||
|
`crates/plugins/plugin-hello/Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
k-launcher-kernel = { path = "../../k-launcher-kernel" }
|
||||||
|
async-trait = "0.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Implement the `Plugin` trait
|
||||||
|
|
||||||
|
`crates/plugins/plugin-hello/src/lib.rs`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use k_launcher_kernel::{
|
||||||
|
LaunchAction, Plugin, PluginName, ResultId, ResultTitle, Score, SearchResult,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct HelloPlugin;
|
||||||
|
|
||||||
|
impl HelloPlugin {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Plugin for HelloPlugin {
|
||||||
|
fn name(&self) -> PluginName {
|
||||||
|
"hello"
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn search(&self, query: &str) -> Vec<SearchResult> {
|
||||||
|
if !query.starts_with("hello") {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
vec![SearchResult {
|
||||||
|
id: ResultId::new("hello:world"),
|
||||||
|
title: ResultTitle::new("Hello, World!"),
|
||||||
|
description: Some("A greeting from the hello plugin".to_string()),
|
||||||
|
icon: None,
|
||||||
|
score: Score::new(80),
|
||||||
|
action: LaunchAction::CopyToClipboard("Hello, World!".to_string()),
|
||||||
|
on_select: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Wire up in main.rs
|
||||||
|
|
||||||
|
`crates/k-launcher/src/main.rs` — add alongside the existing plugins:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use plugin_hello::HelloPlugin;
|
||||||
|
|
||||||
|
// inside main():
|
||||||
|
plugins.push(Arc::new(HelloPlugin::new()));
|
||||||
|
```
|
||||||
|
|
||||||
|
Also add the dependency to `crates/k-launcher/Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
plugin-hello = { path = "../plugins/plugin-hello" }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
### `SearchResult` Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | `ResultId` | Unique stable ID (e.g. `"apps:firefox"`) |
|
||||||
|
| `title` | `ResultTitle` | Primary display text |
|
||||||
|
| `description` | `Option<String>` | Secondary line shown below title |
|
||||||
|
| `icon` | `Option<String>` | Icon name or path (currently unused in renderer) |
|
||||||
|
| `score` | `Score(u32)` | Sort priority — higher wins |
|
||||||
|
| `action` | `LaunchAction` | What happens on `Enter` |
|
||||||
|
| `on_select` | `Option<Arc<dyn Fn()>>` | Optional side-effect on selection (e.g. frecency bump) |
|
||||||
|
|
||||||
|
### `LaunchAction` Variants
|
||||||
|
|
||||||
|
| Variant | Behavior |
|
||||||
|
|---------|----------|
|
||||||
|
| `SpawnProcess(String)` | Launch a process directly (e.g. app exec string) |
|
||||||
|
| `SpawnInTerminal(String)` | Run command inside a terminal emulator |
|
||||||
|
| `OpenPath(String)` | Open a file or directory with `xdg-open` |
|
||||||
|
| `CopyToClipboard(String)` | Copy text to clipboard |
|
||||||
|
| `Custom(Arc<dyn Fn()>)` | Arbitrary closure |
|
||||||
|
|
||||||
|
### Scoring Guidance
|
||||||
|
|
||||||
|
| Score range | Match type |
|
||||||
|
|-------------|-----------|
|
||||||
|
| 100 | Exact match |
|
||||||
|
| 90–99 | Calc/command result (always relevant) |
|
||||||
|
| 80 | Prefix match |
|
||||||
|
| 70 | Abbreviation match |
|
||||||
|
| 60 | Substring match |
|
||||||
|
| 50 | Keyword / loose match |
|
||||||
|
|
||||||
|
The kernel sorts all results from all plugins by score descending and truncates to `max_results` (default: 8).
|
||||||
50
docs/usage.md
Normal file
50
docs/usage.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Usage
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
k-launcher
|
||||||
|
```
|
||||||
|
|
||||||
|
## Keybinds
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| Type | Filter results |
|
||||||
|
| `↑` / `↓` | Navigate list |
|
||||||
|
| `Enter` | Launch selected result |
|
||||||
|
| `Escape` | Close launcher |
|
||||||
|
|
||||||
|
## Built-in Plugins
|
||||||
|
|
||||||
|
### Apps
|
||||||
|
|
||||||
|
Type any app name to search installed applications. An empty query shows your most frequently launched apps (frecency-ranked top results).
|
||||||
|
|
||||||
|
### Calc
|
||||||
|
|
||||||
|
Type a math expression — the result appears instantly and is copied to clipboard on `Enter`.
|
||||||
|
|
||||||
|
```
|
||||||
|
2^10 + 5 → 1029
|
||||||
|
sqrt(144) → 12
|
||||||
|
sin(pi / 2) → 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shell Command
|
||||||
|
|
||||||
|
Prefix your input with `>` to run a shell command in a terminal:
|
||||||
|
|
||||||
|
```
|
||||||
|
> echo hello
|
||||||
|
> htop
|
||||||
|
```
|
||||||
|
|
||||||
|
### Files
|
||||||
|
|
||||||
|
Start your query with `/` or `~/` to browse the filesystem:
|
||||||
|
|
||||||
|
```
|
||||||
|
/etc/hosts
|
||||||
|
~/Documents/report.pdf
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user