feat: add configurable Space leader bindings
This commit is contained in:
+53
-2
@@ -13,10 +13,21 @@ const MAX_FRAME: usize = 4 * 1024 * 1024;
|
||||
const STARTUP_TIMEOUT: Duration = Duration::from_secs(2);
|
||||
const INVOKE_TIMEOUT: Duration = Duration::from_millis(500);
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
pub plugins: Vec<PathBuf>,
|
||||
pub bindings: Vec<Binding>,
|
||||
pub leader: String,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
plugins: Vec::new(),
|
||||
bindings: Vec::new(),
|
||||
leader: "space".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Relative plugin paths are resolved against the configuration file's directory.
|
||||
@@ -27,7 +38,10 @@ pub fn load_config(path: &Path) -> Result<Config, String> {
|
||||
let response = host.receive(deadline)?;
|
||||
match response {
|
||||
Response::Config {
|
||||
plugins, bindings, ..
|
||||
plugins,
|
||||
bindings,
|
||||
leader,
|
||||
..
|
||||
} => {
|
||||
let mut config = Config::default();
|
||||
let directory = path.parent().expect("absolute file has a parent");
|
||||
@@ -38,6 +52,7 @@ pub fn load_config(path: &Path) -> Result<Config, String> {
|
||||
config.plugins.push(directory.join(plugin));
|
||||
}
|
||||
config.bindings = bindings;
|
||||
config.leader = leader;
|
||||
Ok(config)
|
||||
}
|
||||
Response::Error {
|
||||
@@ -182,6 +197,7 @@ enum Response {
|
||||
version: u8,
|
||||
plugins: Vec<String>,
|
||||
bindings: Vec<Binding>,
|
||||
leader: String,
|
||||
},
|
||||
#[serde(rename = "result")]
|
||||
Result {
|
||||
@@ -550,6 +566,41 @@ end
|
||||
assert!(RubyPlugin::start(&invalid).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_leader_defaults_custom_keys_validation_and_required_wire_field() {
|
||||
let fixture = Fixture::new();
|
||||
let defaults = Config::default();
|
||||
assert_eq!(defaults.leader, "space");
|
||||
assert!(defaults.plugins.is_empty() && defaults.bindings.is_empty());
|
||||
let path = fixture.file("config.rb", "Vamp.configure { |_| }");
|
||||
assert_eq!(load_config(&path).unwrap().leader, "space");
|
||||
for (source, key) in [
|
||||
(r#"Vamp.configure { |config| config.leader = "," }"#, ","),
|
||||
(r#"Vamp.configure { |config| config.leader = "\\" }"#, "\\"),
|
||||
] {
|
||||
let path = fixture.file("config.rb", source);
|
||||
assert_eq!(load_config(&path).unwrap().leader, key);
|
||||
}
|
||||
for (value, error) in [
|
||||
("7", "leader key must be a String"),
|
||||
("nil", "leader key must be a String"),
|
||||
(r#""""#, "leader key must not be empty"),
|
||||
] {
|
||||
let path = fixture.file(
|
||||
"config.rb",
|
||||
&format!("Vamp.configure {{ |config| config.leader = {value} }}"),
|
||||
);
|
||||
assert!(load_config(&path).unwrap_err().contains(error), "{value}");
|
||||
}
|
||||
for frame in [
|
||||
r#"{"type":"config","version":1,"plugins":[],"bindings":[]}"#,
|
||||
r#"{"type":"config","version":1,"plugins":[],"bindings":[],"leader":null}"#,
|
||||
r#"{"type":"config","version":1,"plugins":[],"bindings":[],"leader":7}"#,
|
||||
] {
|
||||
assert!(serde_json::from_str::<Response>(frame).is_err(), "{frame}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn crash_hang_callback_failure_and_fresh_host_recovery() {
|
||||
let fixture = Fixture::new();
|
||||
|
||||
Reference in New Issue
Block a user