pub struct ReplInterface { /* private fields */ }Expand description
REPL (Read-Eval-Print Loop) interface
Provides an interactive command-line interface with:
- Line editing and history
- Per-application persistent command history
- Tab completion (commands, aliases, option flags)
- Graceful error handling
- Special commands (exit, quit, –help)
§Architecture
User input → rustyline (DcliHelper) → ReplParser → CommandExecutor → Handler
↓ ↓
Tab completion ExecutionContext
(commands + flags)§Special Commands
The REPL recognizes these built-in commands:
exit,quit— Exit the REPL--help,-h— Show application-level help (if a formatter is attached)<cmd> --help,--help <cmd>— Show per-command help
§History
Command history is stored per application under the XDG data directory:
- Linux/macOS:
~/.local/share/<app_name>/history - Windows:
%LOCALAPPDATA%\<app_name>\history
Lines containing a secure: true argument are never written to history.
Lines that fail to parse are discarded silently.
Implementations§
Source§impl ReplInterface
impl ReplInterface
Sourcepub fn new(
registry: CommandRegistry,
context: Box<dyn ExecutionContext>,
prompt: String,
config: Option<CommandsConfig>,
help_formatter: Option<Box<dyn HelpFormatter>>,
) -> Result<Self>
pub fn new( registry: CommandRegistry, context: Box<dyn ExecutionContext>, prompt: String, config: Option<CommandsConfig>, help_formatter: Option<Box<dyn HelpFormatter>>, ) -> Result<Self>
Create a new REPL interface.
All configuration is supplied at construction time so that the tab-completion engine and the help formatter share the same data without duplication.
§Arguments
registry— Command registry with all registered commands.context— Execution context passed to handlers.prompt— Prompt prefix (e.g.,"myapp"). The displayed prompt ispromptfollowed byconfig.metadata.prompt_suffix(e.g.,"myapp > ") whenconfigis supplied, or by [crate::config::schema::default_prompt_suffix] ("myapp > ") otherwise — the suffix is never hardcoded independently of the config.config— Application configuration for completion, help, and the prompt suffix. PassNoneto disable all three.help_formatter— Help formatter implementation. PassNoneto use [DefaultHelpFormatter] lazily, or supply a custom implementation.
§Errors
Returns an error if rustyline initialisation fails (rare).
§Example
use dynamic_cli::interface::ReplInterface;
use dynamic_cli::prelude::*;
let registry = CommandRegistry::new();
let context = Box::new(MyContext::default());
// Without completion or help:
let repl = ReplInterface::new(registry, context, "myapp".to_string(), None, None)?;Sourcepub fn with_prompt_multiline(self, prompt: String) -> Self
pub fn with_prompt_multiline(self, prompt: String) -> Self
Override the base segment of the continuation prompt shown while a
\-continued command is being accumulated (DD-027, #67).
prompt here plays the same role as the app-name segment passed to
ReplInterface::new for the main prompt: only the base is
supplied, prompt_suffix (from the config, or the default) is
always appended after it by effective_prompt_multiline.
When this setter is never called, the base defaults to "...".
Purely additive — consuming self and returning Self like every
other fluent setter in this crate; no existing ReplInterface::new()
call site changes.
§Example
use dynamic_cli::interface::ReplInterface;
use dynamic_cli::prelude::*;
let registry = CommandRegistry::new();
let context = Box::new(MyContext::default());
let repl = ReplInterface::new(registry, context, "rpn".to_string(), None, None)?
.with_prompt_multiline("_ _ _".to_string());Sourcepub fn run(self) -> Result<()>
pub fn run(self) -> Result<()>
Run the REPL loop.
Enters an interactive loop that:
- Displays the prompt (or the continuation prompt while
accumulating a
\-continued command, DD-027/#69) - Reads user input (with tab completion)
- Parses and executes the command
- Displays results or errors
- Repeats until the user exits
§Multi-line option accumulation (DD-027, #69)
A line ending in a trailing \ is not dispatched: the marker is
stripped and the fragment is buffered, the prompt switches to
effective_prompt_multiline,
and another line is read. The first line that does not end in \
completes the buffer — every fragment plus this final one are
joined with a single space and dispatched through
execute_line exactly once, with the normal
prompt restored. Only this fully reconstructed line (no \
markers) can ever reach REPL history — execute_line() never sees
a raw partial fragment.
A Ctrl+C while accumulating discards the buffer and returns to
the normal prompt, mirroring the familiar shell convention of
abandoning a continued line on interrupt.
This mechanism is entirely local to this loop: Self::execute_line,
ReplParser, and CliParser are untouched, and non-interactive
paths (run_script(), :load) never go through it — see DD-027’s
abort-by-construction rule for contexts without a live operator.
§Returns
Ok(())when the user exits normally (viaexitorquit)Err(_)on critical errors (I/O failures, etc.)
§Example
use dynamic_cli::interface::ReplInterface;
use dynamic_cli::prelude::*;
let registry = CommandRegistry::new();
let context = Box::new(MyContext::default());
let repl = ReplInterface::new(registry, context, "myapp".to_string(), None, None)?;
repl.run()?;Trait Implementations§
Source§impl Drop for ReplInterface
impl Drop for ReplInterface
Auto Trait Implementations§
impl !RefUnwindSafe for ReplInterface
impl !Send for ReplInterface
impl !Sync for ReplInterface
impl !UnwindSafe for ReplInterface
impl Freeze for ReplInterface
impl Unpin for ReplInterface
impl UnsafeUnpin for ReplInterface
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more