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, directives, option flags)
- Graceful error handling
:-prefixed directives and--helpinterception
§Architecture
User input → rustyline (DcliHelper) → ReplParser → CommandExecutor → Handler
↓ ↓
Tab completion ExecutionContext
(commands, directives, flags)§Directives
A line starting with : is a framework directive; any other line is an
application command, so a directive never shadows a command. With the
default names:
| Directive | Aliases | Effect |
|---|---|---|
:help [command] | :h, :? | Application help, or the help of one command |
:load <path> | Run every line of a script file | |
:quit | :q | Save the session history, then leave |
:exit | Leave without saving the session history |
Names, aliases and descriptions come from the configuration’s
directives: section when present (see crate::config::directive);
a renamed directive no longer answers to its default name. exit or
quit typed without : is an ordinary command; when the application
has no such command, the error suggests the matching directive.
--help, -h, --help <command> and <command> --help are also
intercepted and rendered like :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
The history file is read when the REPL starts. During the session, new
entries are kept in memory; the file is written only when the session
ends with :quit or end of input (Ctrl-D). Leaving with :exit, an
input error, a handler that exits the process, a panic or a signal
leaves the file as it was at startup.
Lines containing a secure: true argument are never added to history.
Lines that fail to parse and directive lines are not added either.
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 bydefault_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 useDefaultHelpFormatterlazily, 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 (#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, #69) - Reads user input (with tab completion)
- Parses and executes the command
- Displays results or errors
- Repeats until
:quit,:exitor end of input
§Multi-line option accumulation (#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 exactly once, with the
normal prompt restored. Only this fully reconstructed line (no \
markers) can ever reach REPL history — the dispatch 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: execute_line(),
ReplParser, and CliParser are untouched, and non-interactive
paths (run_script(), :load) never go through it: without a live
operator, nothing can answer a continuation prompt, so an incomplete
command there fails instead of waiting for more input.
§Returns
Ok(())when the session ends::quitor end of input (Ctrl-D), which save the session history,:exit, which does not, or an input error, reported on stderr, which does not eitherErr(_)is reserved for critical errors; command and directive errors are displayed and the loop goes on
§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()?;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