Skip to content

Commit 0bf67fc

Browse files
More updates to the cli
1 parent cf4cc25 commit 0bf67fc

3 files changed

Lines changed: 53 additions & 6 deletions

File tree

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ sqllogictest = "0.28"
3636
indicatif = "0.18"
3737
env_logger = "0.11"
3838
insta = "1.43.2"
39-
rustyline = "14.0"
39+
rustyline = { version = "14.0", features = ["derive"] }

examples/cli.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,45 @@ use datafusion_variant::{
99
VariantToJsonUdf,
1010
};
1111
use flate2::read::GzDecoder;
12-
use rustyline::DefaultEditor;
1312
use rustyline::error::ReadlineError;
13+
use rustyline::validate::{ValidationContext, ValidationResult, Validator};
14+
use rustyline::{Completer, Config, Editor, Helper, Highlighter, Hinter};
1415
use std::fs::File;
1516
use std::io::{self, BufRead, BufReader, Write};
1617
use std::sync::Arc;
1718
use std::time::Instant;
1819

20+
/// Helper for rustyline that provides multi-line SQL query support
21+
#[derive(Helper, Completer, Highlighter, Hinter, Default)]
22+
struct SqlHelper;
23+
24+
impl Validator for SqlHelper {
25+
fn validate(&self, ctx: &mut ValidationContext) -> rustyline::Result<ValidationResult> {
26+
let input = ctx.input();
27+
28+
// Check if query is complete (ends with semicolon)
29+
if is_complete_query(input) {
30+
Ok(ValidationResult::Valid(None))
31+
} else {
32+
Ok(ValidationResult::Incomplete)
33+
}
34+
}
35+
}
36+
37+
fn is_complete_query(input: &str) -> bool {
38+
let trimmed = input.trim();
39+
40+
if trimmed.is_empty() {
41+
return true;
42+
}
43+
44+
if trimmed == "quit" || trimmed == "q" {
45+
return true;
46+
}
47+
48+
trimmed.ends_with(';')
49+
}
50+
1951
#[tokio::main]
2052
async fn main() -> Result<()> {
2153
// todo: we can let users pass in arbitrary files to load
@@ -97,9 +129,14 @@ async fn main() -> Result<()> {
97129
};
98130

99131
println!("interactive query mode. type 'q' or 'quit' or ctrl+c to exit");
100-
println!("Available table: bsky (json_data: Utf8)\n");
132+
println!("Available table: bsky (json_data: Utf8)");
133+
println!("Tip: Press Enter without ';' to continue query on next line\n");
134+
135+
let config = Config::builder().auto_add_history(true).build();
136+
let helper = SqlHelper::default();
101137

102-
let mut rl = DefaultEditor::new()?;
138+
let mut rl = Editor::with_config(config)?;
139+
rl.set_helper(Some(helper));
103140

104141
loop {
105142
let readline = rl.readline("> ");
@@ -117,8 +154,6 @@ async fn main() -> Result<()> {
117154
break;
118155
}
119156

120-
rl.add_history_entry(&line)?;
121-
122157
if let Err(e) = run_query(&ctx, query).await {
123158
eprintln!("\x1b[31;1merror:\x1b[0m {}", e);
124159
}

0 commit comments

Comments
 (0)