first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
@@ -2,11 +2,11 @@
//! `galaxy_completer::signatures::CommandSignature`s, as well as `IntoWarpJs` implementations for
//! Rust structs that may be passed to JS functions defined on the Command Signature (e.g.
//! `GeneratorCompletionContext`).
use galaxy_js::{
util::{get_one_or_more_optional, get_one_or_more_required, get_optional, get_required},
FromWarpJs, IntoWarpJs, JsFunctionRegistry,
};
use rquickjs::{FromJs, Function, Object, Value};
use galaxy_js::util::{
get_one_or_more_optional, get_one_or_more_required, get_optional, get_required,
};
use galaxy_js::{FromWarpJs, IntoWarpJs, JsFunctionRegistry};
use super::{
Argument, ArgumentValue, Command, CommandSignature, GeneratorCompletionContext, GeneratorFn,
@@ -2,7 +2,8 @@
//! untokenized input.
use itertools::Itertools;
use super::{registry::CommandRegistry, Command};
use super::registry::CommandRegistry;
use super::Command;
/// Returns the highest-precedence matching `Command` signature object for the given `input`, if
/// any, along with the index of the token in `input` matched to the returned `Command`.
@@ -144,5 +145,5 @@ fn deepest_matching_subcommand_signature<'a>(
}
#[cfg(test)]
#[path = "lookup_test.rs"]
#[path = "lookup_tests.rs"]
mod test;
@@ -1,6 +1,5 @@
use crate::signatures::{Argument, Command, CommandSignature, Opt};
use super::*;
use crate::signatures::{Argument, Command, CommandSignature, Opt};
/// Creates a `test_command` signature with a `test_subcommand` subcommand
/// and the given options on the root command.
@@ -0,0 +1,417 @@
use super::*;
use crate::signatures::{Argument, Command, CommandSignature, Opt};
/// Creates a `test_command` signature with a `test_subcommand` subcommand
/// and the given options on the root command.
fn test_command_signature_with_options(options: Vec<Opt>) -> CommandSignature {
CommandSignature {
command: Command {
name: "test_command".to_owned(),
subcommands: vec![Command {
name: "test_subcommand".to_owned(),
..Default::default()
}],
options,
..Default::default()
},
}
}
fn valued_option() -> Opt {
Opt {
name: vec!["-n".to_owned(), "--name".to_owned()],
arguments: vec![Argument {
name: "value".to_owned(),
..Default::default()
}],
..Default::default()
}
}
#[test]
fn test_get_matching_signature_for_input_on_root_command() {
let registry = CommandRegistry::new();
registry.register_signature(CommandSignature {
command: Command {
name: "test_command".to_owned(),
..Default::default()
},
});
let (found_signature, index) = get_matching_signature_for_input("test_command ", &registry)
.expect("Signature should exist");
assert_eq!(found_signature.name, "test_command");
assert_eq!(index, 0);
}
#[test]
fn test_get_matching_signature_for_input_on_root_command_with_argument() {
let registry = CommandRegistry::new();
registry.register_signature(CommandSignature {
command: Command {
name: "test_command".to_owned(),
subcommands: vec![Command {
name: "test_subcommand".to_owned(),
..Default::default()
}],
arguments: vec![Argument {
name: "arg1".to_owned(),
..Default::default()
}],
..Default::default()
},
});
let (found_signature, index) =
get_matching_signature_for_input("test_command some_arg_value ", &registry)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_command");
assert_eq!(index, 0);
}
#[test]
fn test_get_matching_signature_for_input_on_subcommand() {
let registry = CommandRegistry::new();
registry.register_signature(CommandSignature {
command: Command {
name: "test_command".to_owned(),
subcommands: vec![Command {
name: "test_subcommand".to_owned(),
..Default::default()
}],
arguments: vec![Argument {
name: "arg1".to_owned(),
..Default::default()
}],
..Default::default()
},
});
let (found_signature, index) =
get_matching_signature_for_input("test_command test_subcommand ", &registry)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_subcommand");
assert_eq!(index, 1);
}
#[test]
fn test_get_matching_signature_for_input_on_subcommand_with_argument() {
let registry = CommandRegistry::new();
registry.register_signature(CommandSignature {
command: Command {
name: "test_command".to_owned(),
subcommands: vec![
Command {
name: "test_subcommand1".to_owned(),
arguments: vec![Argument {
name: "test_subcommand_arg".to_owned(),
..Default::default()
}],
..Default::default()
},
Command {
name: "test_subcommand2".to_owned(),
arguments: vec![Argument {
name: "test_subcommand_arg".to_owned(),
..Default::default()
}],
..Default::default()
},
],
arguments: vec![Argument {
name: "test_command_arg".to_owned(),
..Default::default()
}],
..Default::default()
},
});
let (found_signature, index) = get_matching_signature_for_input(
"test_command test_subcommand1 some_arg_value ",
&registry,
)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_subcommand1");
assert_eq!(index, 1);
}
#[test]
fn test_get_matching_signature_for_input_without_trailing_whitespace() {
let registry = CommandRegistry::new();
registry.register_signature(CommandSignature {
command: Command {
name: "test_command".to_owned(),
subcommands: vec![Command {
name: "test_subcommand".to_owned(),
..Default::default()
}],
arguments: vec![Argument {
name: "arg1".to_owned(),
..Default::default()
}],
..Default::default()
},
});
let (found_signature, index) =
get_matching_signature_for_input("test_command test_subcommand", &registry)
.expect("Signature should be found.");
// The matched signature should be that of the top-level command. Because there is no trailing
// whitespace in the input, it's assumed we're still completing on the "test_subcommand", so we
// should still be using the top-level command signature.
assert_eq!(found_signature.name, "test_command");
assert_eq!(index, 0);
}
#[test]
fn test_get_matching_signature_for_tokenized_input() {
let registry = CommandRegistry::new();
registry.register_signature(CommandSignature {
command: Command {
name: "test_command".to_owned(),
subcommands: vec![
Command {
name: "test_subcommand1".to_owned(),
arguments: vec![Argument {
name: "test_subcommand_arg".to_owned(),
..Default::default()
}],
..Default::default()
},
Command {
name: "test_subcommand2".to_owned(),
arguments: vec![Argument {
name: "test_subcommand_arg".to_owned(),
..Default::default()
}],
..Default::default()
},
],
arguments: vec![Argument {
name: "test_command_arg".to_owned(),
..Default::default()
}],
..Default::default()
},
});
let (found_signature, token_index) = get_matching_signature_for_tokenized_input(
&["test_command", "test_subcommand1", "some_arg_value"],
true,
&registry,
)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_subcommand1");
assert_eq!(token_index, 1);
}
#[test]
fn test_get_matching_signature_for_tokenized_input_without_trailing_whitespace() {
let registry = CommandRegistry::new();
registry.register_signature(CommandSignature {
command: Command {
name: "test_command".to_owned(),
subcommands: vec![
Command {
name: "test_subcommand1".to_owned(),
arguments: vec![Argument {
name: "test_subcommand_arg".to_owned(),
..Default::default()
}],
..Default::default()
},
Command {
name: "test_subcommand2".to_owned(),
arguments: vec![Argument {
name: "test_subcommand_arg".to_owned(),
..Default::default()
}],
..Default::default()
},
],
arguments: vec![Argument {
name: "test_command_arg".to_owned(),
..Default::default()
}],
..Default::default()
},
});
let (found_signature, token_index) = get_matching_signature_for_tokenized_input(
&["test_command", "test_subcommand1"],
false,
&registry,
)
.expect("Signature should be found.");
// The matched signature should be that of the top-level command. Because there is no trailing
// whitespace in the input, it's assumed we're still completing on the "test_subcommand", so we
// should still be using the top-level command signature.
assert_eq!(found_signature.name, "test_command");
assert_eq!(token_index, 0);
}
#[test]
fn test_get_matching_signature_skips_flag_with_value_before_subcommand() {
let registry = CommandRegistry::new();
registry.register_signature(test_command_signature_with_options(vec![valued_option()]));
// -n takes a value, so the parser should skip "-n val" and find test_subcommand.
let (found_signature, token_index) = get_matching_signature_for_tokenized_input(
&["test_command", "-n", "val", "test_subcommand"],
true,
&registry,
)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_subcommand");
assert_eq!(token_index, 3);
}
#[test]
fn test_get_matching_signature_skips_long_flag_with_value_before_subcommand() {
let registry = CommandRegistry::new();
registry.register_signature(test_command_signature_with_options(vec![
Opt {
name: vec!["--context".to_owned()],
arguments: vec![Argument {
name: "context".to_owned(),
..Default::default()
}],
..Default::default()
},
valued_option(),
]));
// Two valued flags before the subcommand should both be skipped.
let (found_signature, token_index) = get_matching_signature_for_tokenized_input(
&[
"test_command",
"--context",
"staging",
"-n",
"project1",
"test_subcommand",
],
true,
&registry,
)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_subcommand");
assert_eq!(token_index, 5);
}
#[test]
fn test_get_matching_signature_skips_switch_flag_before_subcommand() {
let registry = CommandRegistry::new();
registry.register_signature(test_command_signature_with_options(vec![Opt {
name: vec!["--verbose".to_owned()],
arguments: vec![],
..Default::default()
}]));
let (found_signature, token_index) = get_matching_signature_for_tokenized_input(
&["test_command", "--verbose", "test_subcommand"],
true,
&registry,
)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_subcommand");
assert_eq!(token_index, 2);
}
#[test]
fn test_get_matching_signature_flag_at_end_without_value_does_not_panic() {
let registry = CommandRegistry::new();
registry.register_signature(test_command_signature_with_options(vec![valued_option()]));
// "-n" with no value should not panic.
let (found_signature, token_index) =
get_matching_signature_for_tokenized_input(&["test_command", "-n"], true, &registry)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_command");
// No subcommand found, so entry_token_index (0) is returned.
assert_eq!(token_index, 0);
}
#[test]
fn test_get_matching_signature_skips_unrecognized_flag_before_subcommand() {
// Unrecognized flags (tokens starting with '-' not in the spec) should be
// skipped so the parser can still discover subcommands after them.
let registry = CommandRegistry::new();
registry.register_signature(test_command_signature_with_options(vec![]));
let (found_signature, token_index) = get_matching_signature_for_tokenized_input(
&["test_command", "--unknown-flag", "test_subcommand"],
true,
&registry,
)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_subcommand");
assert_eq!(token_index, 2);
}
#[test]
fn test_get_matching_signature_flag_arg_consumes_token_matching_subcommand_name() {
// When a recognized flag takes a required argument, the next token is
// consumed as the flag's value even if it matches a subcommand name.
let registry = CommandRegistry::new();
registry.register_signature(test_command_signature_with_options(vec![valued_option()]));
let (found_signature, token_index) = get_matching_signature_for_tokenized_input(
&["test_command", "-n", "test_subcommand", "extra"],
true,
&registry,
)
.expect("Signature should be found.");
// "test_subcommand" was consumed as -n's value, so no subcommand is found.
assert_eq!(found_signature.name, "test_command");
assert_eq!(token_index, 0);
}
#[test]
fn test_get_matching_signature_only_flags_no_subcommand() {
// When the input consists only of flags with no following subcommand,
// the parent command should be returned at the entry index.
let registry = CommandRegistry::new();
registry.register_signature(test_command_signature_with_options(vec![valued_option()]));
let (found_signature, token_index) =
get_matching_signature_for_tokenized_input(&["test_command", "-n", "val"], true, &registry)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_command");
assert_eq!(token_index, 0);
}
#[test]
fn test_get_matching_signature_optional_flag_arg_does_not_consume_subcommand() {
// A flag with 1 required + 1 optional argument should only skip the
// required arg, so the next token can still match a subcommand.
let registry = CommandRegistry::new();
registry.register_signature(test_command_signature_with_options(vec![Opt {
name: vec!["--output".to_owned()],
arguments: vec![
Argument {
name: "format".to_owned(),
..Default::default()
},
Argument {
name: "extra".to_owned(),
optional: true,
..Default::default()
},
],
..Default::default()
}]));
// "json" is the required arg, "test_subcommand" should not be consumed as
// the optional arg.
let (found_signature, token_index) = get_matching_signature_for_tokenized_input(
&["test_command", "--output", "json", "test_subcommand"],
true,
&registry,
)
.expect("Signature should be found.");
assert_eq!(found_signature.name, "test_subcommand");
assert_eq!(token_index, 3);
}
@@ -13,8 +13,6 @@ use std::cmp::Ordering;
pub use lookup::*;
pub use registry::*;
use galaxy_js::TypedJsFunctionRef;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -227,5 +225,5 @@ impl Opt {
}
#[cfg(test)]
#[path = "signatures_test.rs"]
#[path = "signatures_tests.rs"]
mod test;
@@ -51,5 +51,5 @@ impl CommandRegistry {
}
#[cfg(test)]
#[path = "registry_test.rs"]
#[path = "registry_tests.rs"]
mod test;
@@ -1,6 +1,5 @@
use crate::signatures::{Command, Priority};
use super::*;
use crate::signatures::{Command, Priority};
fn test_signature() -> CommandSignature {
CommandSignature {
@@ -0,0 +1,27 @@
use super::*;
use crate::signatures::{Command, Priority};
fn test_signature() -> CommandSignature {
CommandSignature {
command: Command {
name: "test".to_owned(),
alias: vec![],
description: None,
arguments: vec![],
subcommands: vec![],
options: vec![],
priority: Priority::default(),
},
}
}
#[test]
fn test_command_registry_registers_signature() {
let registry = CommandRegistry::new();
registry.register_signature(test_signature());
let signature = registry
.get_signature("test")
.expect("Signature is registered.");
assert_eq!(signature.command.name, "test");
}
@@ -0,0 +1,29 @@
use super::Priority;
#[test]
fn test_priority_normalization() {
let too_small = Priority::new(-201);
assert_eq!(Priority::min(), too_small);
let too_large = Priority::new(201);
assert_eq!(Priority::max(), too_large);
let fourty_two = Priority::new(42);
assert_eq!(42, fourty_two.0);
}
#[test]
fn test_priority_comparison() {
let super_important = Priority::new(200);
let important = Priority::new(40);
let not_important = Priority::new(-80);
assert!(super_important == super_important);
assert!(super_important > important);
assert!(super_important > not_important);
assert!(important == important);
assert!(important > not_important);
assert!(not_important == not_important);
}