Only initialize Rustyline if we are in a tty

This commit is contained in:
pedrocarlo
2025-04-20 17:03:43 -03:00
parent 53061f5642
commit b550fbb3e4
4 changed files with 82 additions and 22 deletions

6
Cargo.lock generated
View File

@@ -1575,9 +1575,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.171"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libgit2-sys"
@@ -1702,8 +1702,10 @@ dependencies = [
"ctrlc",
"dirs 5.0.1",
"env_logger 0.10.2",
"libc",
"limbo_core",
"miette",
"nix 0.29.0",
"nu-ansi-term 0.50.1",
"rustyline",
"shlex",

View File

@@ -28,10 +28,12 @@ csv = "1.3.1"
ctrlc = "3.4.4"
dirs = "5.0.1"
env_logger = "0.10.1"
libc = "0.2.172"
limbo_core = { path = "../core", default-features = true, features = [
"completion",
] }
miette = { version = "7.4.0", features = ["fancy"] }
nix = "0.29.0"
nu-ansi-term = "0.50.1"
rustyline = { version = "15.0.0", default-features = true, features = [
"derive",

View File

@@ -7,6 +7,7 @@ use crate::{
helper::LimboHelper,
input::{get_io, get_writer, DbLocation, OutputMode, Settings},
opcodes_dictionary::OPCODE_DESCRIPTIONS,
HISTORY_FILE,
};
use comfy_table::{Attribute, Cell, CellAlignment, Color, ContentArrangement, Row, Table};
use limbo_core::{Database, LimboError, OwnedValue, Statement, StepResult};
@@ -14,10 +15,10 @@ use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
use clap::Parser;
use rustyline::{history::DefaultHistory, Editor};
use rustyline::{error::ReadlineError, history::DefaultHistory, Editor};
use std::{
fmt,
io::{self, Write},
io::{self, BufRead as _, Write},
path::PathBuf,
rc::Rc,
sync::{
@@ -62,7 +63,7 @@ pub struct Opts {
const PROMPT: &str = "limbo> ";
pub struct Limbo<'a> {
pub struct Limbo {
pub prompt: String,
io: Arc<dyn limbo_core::IO>,
writer: Box<dyn Write>,
@@ -70,7 +71,7 @@ pub struct Limbo<'a> {
pub interrupt_count: Arc<AtomicUsize>,
input_buff: String,
opts: Settings,
pub rl: &'a mut Editor<LimboHelper, DefaultHistory>,
pub rl: Option<Editor<LimboHelper, DefaultHistory>>,
}
struct QueryStatistics {
@@ -105,8 +106,8 @@ macro_rules! query_internal {
static COLORS: &[Color] = &[Color::Green, Color::Black, Color::Grey];
impl<'a> Limbo<'a> {
pub fn new(rl: &'a mut rustyline::Editor<LimboHelper, DefaultHistory>) -> anyhow::Result<Self> {
impl Limbo {
pub fn new() -> anyhow::Result<Self> {
let opts = Opts::parse();
let db_file = opts
.database
@@ -133,8 +134,6 @@ impl<'a> Limbo<'a> {
)
};
let conn = db.connect()?;
let h = LimboHelper::new(conn.clone(), io.clone());
rl.set_helper(Some(h));
let interrupt_count = Arc::new(AtomicUsize::new(0));
{
let interrupt_count: Arc<AtomicUsize> = Arc::clone(&interrupt_count);
@@ -154,12 +153,19 @@ impl<'a> Limbo<'a> {
interrupt_count,
input_buff: String::new(),
opts: Settings::from(opts),
rl,
rl: None,
};
app.first_run(sql, quiet)?;
Ok(app)
}
pub fn with_readline(mut self, mut rl: Editor<LimboHelper, DefaultHistory>) -> Self {
let h = LimboHelper::new(self.conn.clone(), self.io.clone());
rl.set_helper(Some(h));
self.rl = Some(rl);
self
}
fn first_run(&mut self, sql: Option<String>, quiet: bool) -> io::Result<()> {
if let Some(sql) = sql {
self.handle_first_input(&sql);
@@ -470,8 +476,9 @@ impl<'a> Limbo<'a> {
}
}
fn reset_line(&mut self, line: &str) -> rustyline::Result<()> {
self.rl.add_history_entry(line.to_owned())?;
fn reset_line(&mut self, _line: &str) -> rustyline::Result<()> {
// Entry is auto added to history
// self.rl.add_history_entry(line.to_owned())?;
self.interrupt_count.store(0, Ordering::SeqCst);
Ok(())
}
@@ -973,4 +980,34 @@ impl<'a> Limbo<'a> {
self.run_query(buff.as_str());
self.reset_input();
}
pub fn readline(&mut self) -> Result<String, ReadlineError> {
if let Some(rl) = &mut self.rl {
Ok(rl.readline(&self.prompt)?)
} else {
let mut input = String::new();
println!("");
let mut reader = std::io::stdin().lock();
if reader.read_line(&mut input)? == 0 {
return Err(ReadlineError::Eof.into());
}
// Remove trailing newline
if input.ends_with('\n') {
input.pop();
if input.ends_with('\r') {
input.pop();
}
}
Ok(input)
}
}
}
impl Drop for Limbo {
fn drop(&mut self) {
if let Some(rl) = &mut self.rl {
let _ = rl.save_history(HISTORY_FILE.as_path());
}
}
}

View File

@@ -5,26 +5,41 @@ mod helper;
mod input;
mod opcodes_dictionary;
use nix::unistd::isatty;
use rustyline::{error::ReadlineError, Config, Editor};
use std::sync::atomic::Ordering;
use std::{
path::PathBuf,
sync::{atomic::Ordering, LazyLock},
};
fn rustyline_config() -> Config {
Config::builder()
.completion_type(rustyline::CompletionType::List)
.auto_add_history(true)
.build()
}
pub static HOME_DIR: LazyLock<PathBuf> =
LazyLock::new(|| dirs::home_dir().expect("Could not determine home directory"));
pub static HISTORY_FILE: LazyLock<PathBuf> = LazyLock::new(|| HOME_DIR.join(".limbo_history"));
fn main() -> anyhow::Result<()> {
let mut rl = Editor::with_config(rustyline_config())?;
let mut app = app::Limbo::new(&mut rl)?;
let mut app = app::Limbo::new()?;
let _guard = app.init_tracing()?;
let home = dirs::home_dir().expect("Could not determine home directory");
let history_file = home.join(".limbo_history");
if history_file.exists() {
app.rl.load_history(history_file.as_path())?;
if is_a_tty() {
let mut rl = Editor::with_config(rustyline_config())?;
if HISTORY_FILE.exists() {
rl.load_history(HISTORY_FILE.as_path())?;
}
app = app.with_readline(rl);
} else {
tracing::debug!("not in tty");
}
loop {
let readline = app.rl.readline(&app.prompt);
let readline = app.readline();
match readline {
Ok(line) => match app.handle_input_line(line.trim()) {
Ok(_) => {}
@@ -54,6 +69,10 @@ fn main() -> anyhow::Result<()> {
}
}
}
rl.save_history(history_file.as_path())?;
Ok(())
}
/// Return whether or not STDIN is a TTY
fn is_a_tty() -> bool {
isatty(libc::STDIN_FILENO).unwrap_or(false)
}