manage readline autocomplete for bespoke cli
Project description
pyrl-complete
Python readline completer and command line parser
What is pyrl-complete?
pyrl-complete is a Python library for building powerful, context-aware command-line autocompletion. It allows developers to define the grammar of a command-line interface (CLI) using a simple, human-readable syntax.
The library parses this grammar to understand all possible command structures, including commands, sub-commands, options, and arguments. It then uses this understanding to provide intelligent autocompletion suggestions and predictions as a user types.
Key Features
- Custom Grammar: Define your CLI structure in a simple
.prlfile. The syntax supports:- Simple command sequences (
get status) - Alternatives using
|(get (one | two)) - Optional groups using
[](command [optional_part]) - Options with placeholder arguments (
-d ?)
- Simple command sequences (
- Completion Engine: A prefix-tree-based engine that provides:
- Suggestions: A list of all possible valid commands that match the current input.
- Predictions: The most likely next word or token based on the current input.
- Tester GUI: A bundled Tkinter application that provides a live development environment. You can write your grammar, parse it, and test the completion behavior in real-time, making development and debugging fast and easy.
Rules Syntax
The grammar for defining your command-line interface is designed to be simple and flexible. Rules are typically defined in a .prl file.
Statements
Each complete command path is a statement. Statements can be separated by a newline or a semicolon (;).
# Separated by newline
get status
set user
# Separated by semicolon
get status; set user;
Alternatives (|) and Grouping (())
The pipe character | is used to define a set of alternative tokens. Parentheses ( ... ) are used to group these alternatives, which is necessary when they appear in the middle of a command.
# Creates two valid paths: 'set user name ?' and 'set group name ?'
set (user | group) name ?;
Optional Groups ([])
Square brackets [ ... ] define an optional part of a command. The command is valid with or without the tokens inside the brackets.
# Creates three valid paths: 'show config', 'show interfaces', and just 'show'
show [config | interfaces];
Options and Arguments (- and ?)
Tokens starting with a hyphen - are treated as options. An option can be followed by a ? to indicate that it takes an argument. The ? acts as a placeholder for the completion engine.
# An option without an argument
get -h
# An option that requires an argument
set user -name ?
How it Works
- Define Rules: You write your command structure in a text file (e.g.,
rules.prl).# Example Rules get status; set (user | group) name ?; show [config | interfaces]; - Parse: The library's parser (built with
ply) reads your rules and generates a list of all valid command paths. - Complete: As a user types a command, the completion engine queries a tree built from these paths to find and suggest the next valid tokens.
This library provides the core components to build a rich autocompletion experience for any Python-based CLI application.
Usage with a Python CLI
To integrate pyrl-complete into a Python CLI application, you need to connect its completion engine to Python's built-in readline library. readline handles the user input loop and allows you to register a custom completer function.
Here's a basic example of how to set it up:
1. Your Rules (my_cli.prl)
First, define your command grammar in a .prl file.
# my_cli.prl
get (status | version);
set user -name ?;
exit;
2. Your Python Application (my_cli.py)
Next, write the Python code to load these rules and hook them into readline.
import readline
from pyrl_complete.parser import Parser
from pyrl_complete.parser.tree import Tree
# --- 1. Load and Parse Rules ---
with open("my_cli.prl", "r") as f:
rules_text = f.read()
parser = Parser()
parser.parse(rules_text)
completion_tree = Tree(parser.paths)
# --- 2. Create a Completer Class ---
class PyrlCompleter:
def __init__(self, tree):
self.tree = tree
self.predictions = []
def complete(self, text, state):
# On the first Tab press, generate new predictions
if state == 0:
line_buffer = readline.get_line_buffer()
self.predictions = self.tree.get_predictions(line_buffer)
# Return the next prediction, or None if there are no more
return self.predictions[state] if state < len(self.predictions) else None
# --- 3. Setup Readline ---
completer = PyrlCompleter(completion_tree)
readline.set_completer(completer.complete)
readline.parse_and_bind("tab: complete")
# --- 4. Main Application Loop ---
print("Welcome to the CLI. Type 'exit' to quit.")
while True:
try:
line = input(">> ")
if line.strip() == 'exit':
break
print(f"You entered: {line}")
except (EOFError, KeyboardInterrupt):
break
print("\nGoodbye!")
How the Example Works
- Load and Parse Rules: We load the rule file, create a
Parser, and then aTreewhich holds our completion logic. - Create a Completer Class: The
PyrlCompleterclass holds the state for our completion.readlinecalls itscompletemethod every time the user hits Tab.- When
stateis0(the first Tab press for the current input), we get the full line fromreadline.get_line_buffer()and ask ourcompletion_treefor new predictions. - For subsequent Tab presses (
state > 0), we simply return the next prediction from the list we already generated.
- When
- Setup Readline: We instantiate our completer and tell
readlineto use it.readline.parse_and_bind("tab: complete")is crucial for making the Tab key trigger the completion function. - Main Loop: A standard
input()loop lets the user interact with the CLI, andreadlineautomatically handles the autocompletion in the background.
Using the Tester GUI
The library includes a graphical tester application built with Tkinter that provides a complete environment for writing, parsing, and testing your completion rules in real-time.
To run it, execute the tester.py script:
python pyrl_complete/apps/tester.py
Workflow
-
Write or Load Rules:
- Navigate to the Write Rules tab to write your grammar from scratch in the text editor.
- Alternatively, in the Test Rules tab, click Load Rules to open a
.prlfile from your computer. This will load its content into the editor and switch you to the Write Rules tab.
-
Parse Rules:
- In the Write Rules tab, click the Parse Rules button.
- This will process the grammar in the editor, build the completion tree, and update the path count (e.g., "12 paths generated").
- The application will automatically switch you to the Test Rules tab.
-
Test Completion:
- In the Test Rules tab, start typing a command in the Command line input field.
- As you type, the Predictions list on the right will update with all possible next tokens.
- Press the Tab key to cycle through the predictions and auto-populate the input field.
Interface Overview
The application is organized into two main tabs and a log panel.
-
Write Rules Tab: This is your editor. It contains a large text area for writing rules and two primary buttons:
Save Rules: Saves the content of the editor to a.prlfile.Parse Rules: Processes the rules and prepares them for testing.
-
Test Rules Tab: This is your testing ground.
- Rules View (Left): A read-only view of the currently parsed rules.
- Predictions (Right): A list that shows potential completions for the current input.
- Command line input: The field where you type commands and use Tab completion.
-
Log Activity Panel: Located at the bottom of the window, this panel shows a running log of actions like loading files, parsing rules, and which completion was selected, which is useful for debugging.
Dependencies
pyrl-complete has one core external dependency:
- ply: Used for the Lex/Yacc-style parsing of the custom grammar rules.
The included Tester GUI application uses Tkinter, which is part of the Python standard library and should not require a separate installation. However on some linux systems a separate installation is required via the package mager, for example
sudo apt install python3-tk
for Debian/Ubuntu.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyrl_complete-0.1.3.tar.gz.
File metadata
- Download URL: pyrl_complete-0.1.3.tar.gz
- Upload date:
- Size: 26.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.1 CPython/3.11.2 Linux/6.1.0-37-amd64
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b14f30aaad2ab8963c9273e56c892c7bfab27e02af980138489cc2644def48b
|
|
| MD5 |
6428c7f125bfa731e3b5faed1c90301f
|
|
| BLAKE2b-256 |
ce4edec0bd003378c00563d90fa09eb3d3ecc903fe24fc8fee73949c65015b2a
|
File details
Details for the file pyrl_complete-0.1.3-py3-none-any.whl.
File metadata
- Download URL: pyrl_complete-0.1.3-py3-none-any.whl
- Upload date:
- Size: 27.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.1 CPython/3.11.2 Linux/6.1.0-37-amd64
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fff640d57d2a170e7d74d1e5d749cfac9efb38c0741c75bd7783985ee6d17c1b
|
|
| MD5 |
2ed1e70d44bc91c26da19e45d0cca0e3
|
|
| BLAKE2b-256 |
1ec33f9bae372d0f7e18087dcb3f946eaec12a7a5ec4c7141771d8367f370d66
|