use crate::shell::Result;
use crate::shell::completer::ReplCompleter;
use rsql_core::Configuration;
use rsql_drivers::{Connection, Metadata};
use rsql_formatters::Highlighter;
use rustyline::completion::Completer;
use rustyline::hint::{Hinter, HistoryHinter};
use rustyline::validate::{ValidationContext, ValidationResult, Validator};
use rustyline::{Context, Helper};
pub(crate) struct ReplHelper {
pub(crate) highlighter: Highlighter,
pub(crate) completer: ReplCompleter,
}
impl ReplHelper {
#[cfg(test)]
pub(crate) fn new(configuration: &Configuration) -> Self {
Self::new_with_metadata(configuration, Metadata::default())
}
pub(crate) async fn with_connection(
configuration: &Configuration,
connection: &mut dyn Connection,
) -> Result<Self> {
Ok(Self::new_with_metadata(
configuration,
connection.metadata().await?,
))
}
pub(crate) fn new_with_metadata(configuration: &Configuration, metadata: Metadata) -> Self {
let options = configuration.get_formatter_options();
let highlighter = Highlighter::new(&options, "sql");
let completer = ReplCompleter::with_config(configuration, metadata);
Self {
highlighter,
completer,
}
}
}
impl Helper for ReplHelper {}
impl Completer for ReplHelper {
type Candidate = <ReplCompleter as Completer>::Candidate;
fn complete(
&self,
line: &str,
pos: usize,
ctx: &Context<'_>,
) -> rustyline::Result<(usize, Vec<Self::Candidate>)> {
self.completer.complete(line, pos, ctx)
}
}
impl Hinter for ReplHelper {
type Hint = String;
fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<Self::Hint> {
let hinter = HistoryHinter {};
hinter.hint(line, pos, ctx)
}
}
impl Validator for ReplHelper {
fn validate(&self, _ctx: &mut ValidationContext) -> rustyline::Result<ValidationResult> {
Ok(ValidationResult::Valid(None))
}
}
#[cfg(test)]
mod test {
use super::*;
use rustyline::history::DefaultHistory;
#[test]
fn test_new() {
let configuration = Configuration::default();
let _ = ReplHelper::new(&configuration);
}
#[test]
fn test_hinter() {
let configuration = Configuration::default();
let helper = ReplHelper::new(&configuration);
let history = &DefaultHistory::new();
let ctx = Context::new(history);
let hint = helper.hint("SELECT", 0, &ctx);
assert!(hint.is_none());
}
}