Skip to content

Lightweight and extensible Java REPL (Read-Eval-Print Loop), library for building interactive command handling. Supports typed argument parsing, quotes/escaping, aliases, async calls, and REPL lifecycle control.

License

Notifications You must be signed in to change notification settings

Anc3vt/replines-core

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

74 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Replines Core Library

Maven Central License Java Build

A lightweight but powerful Java library for building CLI tools and REPL (Read-Eval-Print Loop) applications. It combines simple argument parsing, a flexible command registry, and a built-in interactive shell, giving you a production-ready CLI in just a few lines.

This library is perfect for developer tools, admin consoles, embedded CLIs, or even educational projects where you want to experiment with command interpreters.

Note on terminology:
This project uses the term REPL (Read–Eval–Print Loop) in the shell-style sense:
each line of input is read, matched against registered commands, executed,
and the result is printed back to the user.

It does not try to be a general-purpose language interpreter like Python or JavaScript REPLs.
Instead, it’s closer to tools such as bash, redis-cli, or psql
interactive command environments built around a registry of commands.

Contents


Why not just Picocli or JLine?

Feature Replines Picocli JLine
Lightweight ✅ Yes ❌ Heavy ⚠️ Medium
Async execution ✅ Built-in
Annotation-based commands ✅ Yes ✅ Yes
Command builder API ✅ Yes
Built-in REPL loop ✅ Yes ⚠️ Only input
Colorized output (ANSI) ✅ Yes

With Replines, you don’t need to glue together multiple libraries — everything you need for a functional REPL/CLI is already here.


Features

  • Argument parsing with support for:

    • Quoted strings ("hello world")
    • Escaped characters (line\ breakline break)
    • --key value and --key=value syntax
    • Flags (--debugtrue)
  • Command registry with fluent builder API

  • Annotation-based commands with @ReplCommand and @ReplExecute

  • Async command execution with configurable Executor

  • Simple REPL runner (ReplRunner) with pluggable input/output

  • Output filters, including a built-in colorizer (<r>, <g>, <bold> → ANSI)

  • Helpful error messages for unknown commands or parse errors

  • Unit-tested with JUnit 5


Installation

<dependency>
  <groupId>com.ancevt.replines</groupId>
  <artifactId>replines-core</artifactId>
  <version>1.3.0</version>
</dependency>

Quick Start

Before: the old way

Scanner sc = new Scanner(System.in);
while (true) {
    String line = sc.nextLine();
    if (line.equals("ping")) {
        System.out.println("pong");
    }
}

After: with Replines

ReplRunner repl = new ReplRunner();
repl.getRegistry().command("ping")
    .description("Replies with pong")
    .action((r, a) -> r.println("pong"))
    .build();

repl.start();

Run it:

> ping
pong

Command Registration

Builder API

registry.command("greet", "hello") // multiple aliases
    .description("Greets a user")
    .action((r, a) -> {
        String name = a.hasNext() ? a.next() : "stranger";
        r.println("Hello, " + name + "!");
    })
    .build();

// Usage:
// > greet Alice
// Hello, Alice!
// > hello
// Hello, stranger!

Annotation-based

@ReplCommand(name = "sum", description = "Adds two integers")
public class SumCommand {
    @ReplExecute
    public Object run(ReplRunner repl, Arguments args) {
        int a = args.next(Integer.class, 0);
        int b = args.next(Integer.class, 0);
        int result = a + b;
        repl.println("Result: " + result);
        return result;
    }
}

CommandRegistry registry = new CommandRegistry();
registry.register(SumCommand.class);
new ReplRunner(registry).start();

Argument Parsing

Basic usage

Arguments args = Arguments.parse("--port=8080 --debug true");

int port = args.get(Integer.class, "--port"); // 8080
boolean debug = args.get(Boolean.class, "--debug"); // true

Supported forms

  • --key value
  • --key=value
  • --flag

Quoted strings

Arguments args = Arguments.parse("--message \"Hello World\"");
System.out.println(args.get("--message")); // Hello World

Iteration

Arguments args = Arguments.parse("one two three");
while (args.hasNext()) {
    System.out.println(args.next());
}

Async Execution

registry.command("download")
    .description("Simulates a background task")
    .action((r, a) -> {
        try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
        return "done";
    })
    .async()
    .build();

// > download
// (done appears asynchronously)

You can also provide a result handler:

registry.command("compute")
    .action((r, a) -> 42)
    .result((r, result) -> r.println("Answer: " + result))
    .async()
    .build();

Colorized Output

The built-in ColorizeFilter lets you add ANSI tags:

repl.addOutputFilter(new ColorizeFilter()::colorize);
repl.println("<g>Success!<reset>");

Available tags:

  • <r>, <g>, <y>, <b>, <c>, <w> (colors)
  • <bold>, <underline>, <blink>
  • <reset> or <>

Default Commands

When using the builder API:

ReplRunner repl = ReplRunner.builder()
    .withDefaultCommands()
    .withColorizer()
    .build();

🪄 Reflection-based Argument Binding

Replines allows you to bind parsed arguments directly into Java objects using annotations and reflection. This eliminates boilerplate parsing code and gives you strongly typed arguments for your commands.

Defining Argument Classes

You can mark fields in a class with @CommandArgument (for positional args) and @OptionArgument (for named options):

class MyArgs {
    @CommandArgument
    String name;

    @OptionArgument(names = {"-c", "--count"}, required = true)
    int count;

    @OptionArgument(names = {"-f", "--flag"})
    boolean flag;
}

Using with the Builder API

The command builder integrates seamlessly with argument binding:

registry.command("greet")
    .description("Greets a user with options")
    .action(MyArgs.class, (repl, args) -> {
        repl.println("Hello, " + args.name + "!");
        repl.println("Count: " + args.count);
        repl.println("Flag: " + args.flag);
    })
    .build();

Now you can run:

> greet Alice --count 5 --flag
Hello, Alice!
Count: 5
Flag: true

With Return Values

You can also return values from commands when binding arguments:

static class SumArgs {
    @CommandArgument String a;
    @CommandArgument String b;
}

registry.command("sum")
    .description("Adds two numbers")
    .action(SumArgs.class, (repl, parsed) -> {
        int result = Integer.parseInt(parsed.a) + Integer.parseInt(parsed.b);
        repl.println("Result: " + result);
        return result;
    })
    .result((repl, result) -> repl.println("Returned: " + result))
    .build();

Output:

> sum 7 8
Result: 15
Returned: 15

Comparison with Picocli

Unlike Picocli, where argument binding is typically used for parsing command-line options of standalone applications, Replines integrates reflection-based argument binding directly into its REPL command model. This means:

  • You don’t need to manually wire up argument parsers inside your REPL.
  • Each command can have its own DTO with annotated fields.
  • Binding works seamlessly both in sync and async commands.

This makes Replines particularly well-suited for interactive shells and embedded admin consoles, where commands are invoked repeatedly and need clean, strongly typed argument handling.

You get:

  • help → shows available commands
  • exit or /q → stops the REPL

Use Cases

  • Interactive REPL shells for developer tools
  • Admin consoles for applications
  • Embeddable CLI for microservices
  • Educational projects (argument parsing, REPL design, DSLs)
  • Replacement for ad-hoc Scanner.nextLine() loops
  • Test harnesses for experiments and simulations

License

Licensed under the Apache License, Version 2.0.

See LICENSE and notice.md for details.


Contact

me@ancevt.com

About

Lightweight and extensible Java REPL (Read-Eval-Print Loop), library for building interactive command handling. Supports typed argument parsing, quotes/escaping, aliases, async calls, and REPL lifecycle control.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages