feat: add configuration management and panel rendering
- Introduced a new `Config` struct for loading application configuration from a TOML file. - Added support for keybindings and panel configurations, including status widgets. - Implemented `PtyTerminal` for handling pseudo-terminal interactions. - Created a rendering module to manage the display of application windows, panels, and dropdowns. - Refactored the main application loop to utilize the new configuration and rendering logic. - Removed legacy code related to event handling and rendering from `main.rs`.
This commit is contained in:
143
src/config.rs
Normal file
143
src/config.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use serde::Deserialize;
|
||||
use std::fs;
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Default)]
|
||||
pub struct Config {
|
||||
#[serde(default, rename = "panel")]
|
||||
pub panels: Vec<PanelConfig>,
|
||||
#[serde(default, rename = "keybind")]
|
||||
pub keybinds: Vec<KeybindConfig>,
|
||||
}
|
||||
|
||||
/// En tangentbords-genväg definierad i config
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct KeybindConfig {
|
||||
/// T.ex. "ctrl+space", "alt+f2", "ctrl+t"
|
||||
pub key: String,
|
||||
/// "global" = alltid, "wm" = bara när ingen terminal är fokuserad
|
||||
#[serde(default)]
|
||||
pub scope: KeybindScope,
|
||||
pub action: MenuAction,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum KeybindScope {
|
||||
/// Aktiveras alltid, oavsett fokus
|
||||
Global,
|
||||
/// Aktiveras bara när ingen terminal-ruta är fokuserad
|
||||
#[default]
|
||||
Wm,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct PanelConfig {
|
||||
pub position: PanelPosition,
|
||||
#[serde(default, rename = "item")]
|
||||
pub items: Vec<MenuItem>,
|
||||
#[serde(default, rename = "status")]
|
||||
pub status_widgets: Vec<StatusWidget>,
|
||||
/// Länk till extern fil med panel-definition
|
||||
pub file: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum PanelPosition {
|
||||
Top,
|
||||
Bottom,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct MenuItem {
|
||||
pub label: String,
|
||||
pub action: MenuAction,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum MenuAction {
|
||||
Exit,
|
||||
SpawnTerminal {
|
||||
shell: Option<String>,
|
||||
},
|
||||
RunScript {
|
||||
path: String,
|
||||
},
|
||||
RunProgram {
|
||||
command: String,
|
||||
#[serde(default)]
|
||||
args: Vec<String>,
|
||||
},
|
||||
Submenu {
|
||||
#[serde(default, rename = "item")]
|
||||
items: Vec<MenuItem>,
|
||||
},
|
||||
/// Öppnar Tui-run kommandodialog
|
||||
SpawnRunDialog,
|
||||
}
|
||||
|
||||
/// En status-widget i panelen: kör ett kommando periodiskt och renderar output
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct StatusWidget {
|
||||
/// Shell-kommando som producerar en sträng (t.ex. `date '+%H:%M:%S'`)
|
||||
pub command: String,
|
||||
/// Hur ofta kommandot körs, i sekunder
|
||||
#[serde(default = "default_interval")]
|
||||
pub interval: u64,
|
||||
/// Hur många tecken brett blocket är
|
||||
pub width: u16,
|
||||
/// Dockas mot höger eller vänster i panelen
|
||||
#[serde(default)]
|
||||
pub align: StatusAlign,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Default, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum StatusAlign {
|
||||
Left,
|
||||
#[default]
|
||||
Right,
|
||||
}
|
||||
|
||||
fn default_interval() -> u64 {
|
||||
10
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load(path: &str) -> anyhow::Result<Config> {
|
||||
let content = fs::read_to_string(path)?;
|
||||
let mut config: Config = toml::from_str(&content)?;
|
||||
for panel in &mut config.panels {
|
||||
if let Some(file) = panel.file.clone() {
|
||||
let c = fs::read_to_string(&file)
|
||||
.map_err(|e| anyhow::anyhow!("Kunde inte läsa {}: {}", file, e))?;
|
||||
let ext: ExternalPanelConfig = toml::from_str(&c)
|
||||
.map_err(|e| anyhow::anyhow!("Parse-fel i {}: {}", file, e))?;
|
||||
panel.items = ext.items;
|
||||
panel.status_widgets = ext.status_widgets;
|
||||
}
|
||||
}
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn load_or_default(path: &str) -> Config {
|
||||
match Config::load(path) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
eprintln!("Varning: kunde inte ladda {}: {}", path, e);
|
||||
Config::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ExternalPanelConfig {
|
||||
#[serde(default, rename = "item")]
|
||||
items: Vec<MenuItem>,
|
||||
#[serde(default, rename = "status")]
|
||||
status_widgets: Vec<StatusWidget>,
|
||||
}
|
||||
Reference in New Issue
Block a user