refactor: centralize editor plugin lifecycle ownership

This commit is contained in:
Valdemar Lorenzen
2026-10-05 14:22:32 +02:00
parent 396ffc4f3a
commit 73b15f5134
6 changed files with 402 additions and 75 deletions
+5 -55
View File
@@ -1,10 +1,6 @@
use std::{collections::BTreeMap, env, path::PathBuf};
use std::{env, path::PathBuf};
use vamp::{
editor::Editor,
ruby::{Config, RubyPlugin, load_config},
tui,
};
use vamp::{session::EditorSession, tui};
const HELP: &str = "vamp — modal editor with isolated Ruby plugins
@@ -69,59 +65,13 @@ fn run() -> Result<(), String> {
let Some(options) = options()? else {
return Ok(());
};
let mut editor = Editor::open(
let mut session = EditorSession::open(
options.file,
tui::CAPABILITIES.iter().map(|s| (*s).to_owned()).collect(),
options.config.as_deref(),
)
.map_err(|error| format!("cannot open file: {error}"))?;
let mut notices = Vec::new();
let config = match options.config {
Some(path) => load_config(&path).unwrap_or_else(|error| {
notices.push(format!("config disabled: {error}"));
Config::default()
}),
None => Config::default(),
};
let mut plugins = BTreeMap::new();
for path in config.plugins {
match RubyPlugin::start(&path) {
Ok((plugin, feature)) => {
let name = feature.name.clone();
match editor.register(feature) {
Ok(()) => {
plugins.insert(name, plugin);
}
Err(error) => notices.push(format!("{}: {error}", path.display())),
}
}
Err(error) => notices.push(format!("{}: {error}", path.display())),
}
}
for (key, command) in config.bindings {
if let Err(error) = editor.bind(key, command) {
notices.push(format!("binding {key:?}: {error}"));
}
}
if notices.is_empty() {
editor.set_message("i: insert • Esc: normal • :w save • :q quit • :plugins");
} else {
editor.set_message(notices.join(" | "));
}
tui::run(&mut editor, |editor, invocation| {
let result = match plugins.get_mut(&invocation.plugin) {
Some(plugin) => plugin
.invoke(&invocation.command, &invocation.args, &editor.context())
.and_then(|effects| editor.apply(effects)),
None => Err("plugin host is unavailable".into()),
};
if let Err(error) = result {
if let Some(mut plugin) = plugins.remove(&invocation.plugin) {
plugin.disable();
}
editor.disable_plugin(&invocation.plugin, &error);
}
})
.map_err(|error| format!("terminal error: {error}"))
tui::run(&mut session).map_err(|error| format!("terminal error: {error}"))
}
fn main() {