Skip to content

REPL API

The REPL (Read-Eval-Print Loop) module provides the interactive terminal interface.

Main Function

run_repl

Starts the interactive REPL session.

rust
pub async fn run_repl(client: MoonrakerClient) -> Result<()>

Parameters:

  • client - Connected MoonrakerClient instance

Returns:

  • Result<()> - Success when user exits, or error

Features:

  • Command history (saved to ~/.moonriver_history)
  • Tab completion for G-code and macros
  • Syntax highlighting
  • Arrow key navigation
  • Ctrl+R history search

Example:

rust
use moonriver::moonraker::MoonrakerClient;
use moonriver::repl::run_repl;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = MoonrakerClient::connect("ws://localhost:7125/websocket").await?;
    run_repl(client).await?;
    Ok(())
}

Internal Components

MoonriverHelper

Internal struct that implements rustyline traits for enhanced functionality.

rust
struct MoonriverHelper {
    macros: HashSet<String>,
    gcode_commands: HashSet<String>,
}

Implements:

  • Completer - Tab completion
  • Highlighter - Syntax highlighting
  • Hinter - Command hints (future)
  • Validator - Input validation (future)
  • Helper - Combines all traits

Completion

The REPL provides intelligent tab completion:

G-code Commands

Pre-populated with common G-code commands:

  • Movement: G0, G1, G2, G3, G28, etc.
  • Temperature: M104, M105, M109, M140, M190, etc.
  • Configuration: M500, M501, M502, M503, etc.
  • And many more...

Klipper Macros

Dynamically loaded from the connected printer:

  • Custom user macros
  • Built-in Klipper commands
  • Configuration-specific commands

Case Insensitive

Completion works regardless of input case:

> g28<Tab>  → G28
> m105<Tab> → M105

Syntax Highlighting

Commands are highlighted as you type:

  • Bright Green: Recognized G-code commands
  • Bright Cyan: Klipper macros
  • White: Unrecognized commands

Command History

Storage

History is automatically saved to:

~/.moonriver_history
  • / Ctrl+P - Previous command
  • / Ctrl+N - Next command
  • Ctrl+R - Search history backward

Persistence

  • History loaded on startup
  • Saved on exit
  • Survives across sessions

Input Handling

Special Commands

Exit

> exit
> quit

Or press Ctrl+D

Emergency Stop

> M112

Immediately sends emergency stop

Multiple Commands

Separate commands with commas:

> G28, M105, GET_POSITION

Command Processing

  1. User input captured via rustyline
  2. Input trimmed and validated
  3. Commands split by comma
  4. Each command sent via MoonrakerClient
  5. Responses processed and displayed

Error Handling

The REPL handles various errors gracefully:

Connection Errors

rust
Err(ReadlineError::Interrupted) => {
    // Ctrl+C pressed, continue
}

Err(ReadlineError::Eof) => {
    // Ctrl+D pressed, exit
    break;
}

Command Errors

Errors are displayed in red but don't crash the REPL:

rust
if let Err(e) = client.send_gcode(cmd).await {
    eprintln!("{}", format!("Error: {}", e).red());
}

Message Processing

The REPL continuously checks for messages:

rust
loop {
    // Check for incoming messages
    while let Some(msg) = client.try_receive_message() {
        format_response(&msg);
    }
    
    // Get user input
    let line = rl.readline("> ")?;
    
    // Process command...
}

Customization

Prompt

The prompt is customizable:

rust
let prompt = format!("{} ", ">".bright_blue().bold());
rl.readline(&prompt)?;

Welcome Message

Displayed on startup:

rust
println!("🌙 Moonriver - Klipper Console 🌙");
println!("Type commands or 'exit' to quit.");

Integration Example

Complete example showing REPL integration:

rust
use moonriver::moonraker::MoonrakerClient;
use moonriver::repl::run_repl;
use anyhow::Result;

#[tokio::main]
async fn main() -> Result<()> {
    // Parse CLI args (not shown)
    let host = "192.168.1.100";
    let port = 7125;
    
    // Build URL
    let url = format!("ws://{}:{}/websocket", host, port);
    
    // Connect
    let client = MoonrakerClient::connect(&url).await?;
    
    // Start REPL
    run_repl(client).await?;
    
    Ok(())
}

Dependencies

The REPL module uses:

  • rustyline - Line editing and history
  • colored - Terminal colors
  • tokio - Async runtime

Future Enhancements

Planned features:

  • Command hints as you type
  • Custom color schemes
  • Configurable keybindings
  • Multi-line command support
  • Command aliases

Next Steps

Released under the MIT License.