diff --git a/cli/app.rs b/cli/app.rs index f82c587bd..40e187d43 100644 --- a/cli/app.rs +++ b/cli/app.rs @@ -467,7 +467,8 @@ impl<'a> Limbo<'a> { } match CommandParser::try_parse_from(args) { Err(err) => { - let _ = self.write_fmt(format_args!("{err}")); + // Let clap print with Styled Colors instead + let _ = err.print(); } Ok(cmd) => match cmd.command { Command::Exit(args) => { diff --git a/cli/commands/args.rs b/cli/commands/args.rs index e0fd10994..3bb78d0b8 100644 --- a/cli/commands/args.rs +++ b/cli/commands/args.rs @@ -1,6 +1,7 @@ use clap::{Args, ValueEnum}; +use clap_complete::{ArgValueCompleter, CompletionCandidate, PathCompleter}; -use crate::input::OutputMode; +use crate::{input::OutputMode, opcodes_dictionary::OPCODE_DESCRIPTIONS}; #[derive(Debug, Clone, Args)] pub struct ExitArgs { @@ -12,13 +13,17 @@ pub struct ExitArgs { #[derive(Debug, Clone, Args)] pub struct OpenArgs { /// Path to open database + #[arg(add = ArgValueCompleter::new(PathCompleter::file()))] pub path: String, + // TODO see how to have this completed with the output of List Vfs function + // Currently not possible to pass arbitrary /// Name of VFS pub vfs_name: Option, } #[derive(Debug, Clone, Args)] pub struct SchemaArgs { + // TODO depends on PRAGMA table_list for completions /// Table name to visualize schema pub table_name: Option, } @@ -26,6 +31,7 @@ pub struct SchemaArgs { #[derive(Debug, Clone, Args)] pub struct SetOutputArgs { /// File path to send output to + #[arg(add = ArgValueCompleter::new(PathCompleter::file()))] pub path: Option, } @@ -35,15 +41,40 @@ pub struct OutputModeArgs { pub mode: OutputMode, } +fn opcodes_completer(current: &std::ffi::OsStr) -> Vec { + let mut completions = vec![]; + + let Some(current) = current.to_str() else { + return completions; + }; + + let current = current.to_lowercase(); + + let opcodes = &OPCODE_DESCRIPTIONS; + + for op in opcodes { + // TODO if someone know how to do prefix_match with case insensitve in Rust + // without converting the String to lowercase first, please fix this. + let op_name = op.name.to_ascii_lowercase(); + if op_name.starts_with(¤t) { + completions.push(CompletionCandidate::new(op.name).help(Some(op.description.into()))); + } + } + + completions +} + #[derive(Debug, Clone, Args)] pub struct OpcodesArgs { /// Opcode to display description + #[arg(add = ArgValueCompleter::new(opcodes_completer))] pub opcode: Option, } #[derive(Debug, Clone, Args)] pub struct CwdArgs { /// Target directory + #[arg(add = ArgValueCompleter::new(PathCompleter::dir()))] pub directory: String, } @@ -72,11 +103,6 @@ pub struct TablesArgs { #[derive(Debug, Clone, Args)] pub struct LoadExtensionArgs { /// Path to extension file - pub path: String, -} - -#[derive(Debug, Clone, Args)] -pub struct ListVfsArgs { - /// Path to extension file + #[arg(add = ArgValueCompleter::new(PathCompleter::file()))] pub path: String, } diff --git a/cli/commands/mod.rs b/cli/commands/mod.rs index 33261a860..757cee530 100644 --- a/cli/commands/mod.rs +++ b/cli/commands/mod.rs @@ -35,9 +35,6 @@ pub enum Command { /// Open a database file #[command(display_name = ".open")] Open(OpenArgs), - /// Print this message or the help of the given subcommand(s) - // #[command(display_name = ".help")] - // Help, /// Display schema for a table #[command(display_name = ".schema")] Schema(SchemaArgs), diff --git a/cli/helper.rs b/cli/helper.rs index a464c3515..f0d396ae0 100644 --- a/cli/helper.rs +++ b/cli/helper.rs @@ -107,6 +107,7 @@ impl SqlCompleter { mut line: &str, mut pos: usize, ) -> rustyline::Result<(usize, Vec)> { + // TODO maybe check to see if the line is empty and then just output the command names line = &line[1..]; pos = pos - 1;