Master Domain Interaction Mode in Rust CLI with interactcli-rs
This article explains how interactcli-rs implements a domain‑specific interactive mode for command‑line programs, detailing the run function, the main parsing loop, prompt handling, history management, and configuration of rustyline, with full Rust code examples.
Basic Principle
interactcli-rs implements a domain interaction mode by continuously parsing each input line using rustyline, then delegating the line to a command‑parsing function for response logic.
Activating Domain Mode
When the -i flag is supplied, the library executes interact::run() (i.e., interact → cli → run).
pub fn run() {
let config = Config::builder()
.history_ignore_space(true)
.completion_type(CompletionType::List)
.output_stream(OutputStreamType::Stdout)
.build();
let h = MyHelper {
completer: get_command_completer(),
highlighter: MatchingBracketHighlighter::new(),
hinter: HistoryHinter {},
colored_prompt: "".to_owned(),
validator: MatchingBracketValidator::new(),
};
let mut rl = Editor::with_config(config);
rl.set_helper(Some(h));
if rl.load_history("/tmp/history").is_err() {
println!("No previous history.");
}
loop {
let p = format!("{}> ", "interact-rs");
rl.helper_mut().expect("No helper").colored_prompt =
format!("\x1b[1;32m{}\x1b[0m", p);
let readline = rl.readline(&p);
match readline {
Ok(line) => {
if line.trim_start().is_empty() { continue; }
rl.add_history_entry(line.as_str());
match split(line.as_str()).as_mut() {
Ok(arg) => {
if arg[0] == "exit" {
println!("bye!");
break;
}
arg.insert(0, "clisample".to_string());
run_from(arg.to_vec())
}
Err(err) => {
println!("{}", err)
}
}
}
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
break;
}
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break;
}
Err(err) => {
println!("Error: {:?}", err);
break;
}
}
}
rl.append_history("/tmp/history")
.map_err(|err| error!("{}", err))
.ok();
}Parsing Main Logic
Define a prompt (e.g., mysql>) to indicate the active program.
Read each input line and parse it.
Add the command to the history file so previous commands can be recalled with arrow keys.
Convert the line into an argument vector and pass it to cmd::run_from for execution.
Handle interruptions (Ctrl‑C, Ctrl‑D) by exiting gracefully.
Other Code in run
The function first builds a
rustyline Configthat controls history behavior, completion type, and output stream.
let config = Config::builder()
.history_ignore_space(true)
.completion_type(CompletionType::List)
.output_stream(OutputStreamType::Stdout)
.build();A MyHelper instance is created to provide autocomplete, bracket highlighting, and validation.
let h = MyHelper {
completer: get_command_completer(),
highlighter: MatchingBracketHighlighter::new(),
hinter: HistoryHinter {},
colored_prompt: "".to_owned(),
validator: MatchingBracketValidator::new(),
};Finally, the program configures a history file ( /tmp/history) so that command history persists across sessions.
rl.append_history("/tmp/history")
.map_err(|err| error!("{}", err))
.ok();The article concludes by promising a future deep dive into the autocomplete implementation.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JD Cloud Developers
JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
