pyrl-complete


Namepyrl-complete JSON
Version 0.1.1 PyPI version JSON
download
home_pagehttps://github.com/codimoc/pyrl-complete
Summarymanage readline autocomplete for bespoke cli
upload_time2025-08-06 19:35:49
maintainerNone
docs_urlNone
authorcodimoc
requires_python>=3.9
licenseGNU AFFERO GENERAL PUBLIC LICENSE Version 3
keywords readline autocomplete cli ply
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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 `.prl` file. The syntax supports:
    - Simple command sequences (`get status`)
    - Alternatives using `|` (`get (one | two)`)
    - Optional groups using `[]` (`command [optional_part]`)
    - Options with placeholder arguments (`-d ?`)
- **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

1.  **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];
    ```
2.  **Parse**: The library's parser (built with `ply`) reads your rules and generates a list of all valid command paths.
3.  **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`.

```python
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

1.  **Load and Parse Rules**: We load the rule file, create a `Parser`, and then a `Tree` which holds our completion logic.
2.  **Create a Completer Class**: The `PyrlCompleter` class holds the state for our completion. `readline` calls its `complete` method every time the user hits Tab.
    *   When `state` is `0` (the first Tab press for the current input), we get the full line from `readline.get_line_buffer()` and ask our `completion_tree` for new predictions.
    *   For subsequent Tab presses (`state > 0`), we simply return the next prediction from the list we already generated.
3.  **Setup Readline**: We instantiate our completer and tell `readline` to use it. `readline.parse_and_bind("tab: complete")` is crucial for making the Tab key trigger the completion function.
4.  **Main Loop**: A standard `input()` loop lets the user interact with the CLI, and `readline` automatically 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:
```bash
python pyrl_complete/apps/tester.py
```

### Workflow

1.  **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 `.prl` file from your computer. This will load its content into the editor and switch you to the **Write Rules** tab.

2.  **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.

3.  **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 `.prl` file.
    *   `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 does not require a separate installation.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/codimoc/pyrl-complete",
    "name": "pyrl-complete",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "readline, autocomplete, cli, ply",
    "author": "codimoc",
    "author_email": "codimoc@prismoid.uk",
    "download_url": "https://files.pythonhosted.org/packages/15/12/693d48d685b7b21e79a93140af18c1276d1ac51ff9760da7a0a35abf9efd/pyrl_complete-0.1.1.tar.gz",
    "platform": null,
    "description": "# pyrl-complete\nPython readline completer and command line parser\n\n## What is pyrl-complete?\n\n`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.\n\nThe 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.\n\n## Key Features\n\n- **Custom Grammar**: Define your CLI structure in a simple `.prl` file. The syntax supports:\n    - Simple command sequences (`get status`)\n    - Alternatives using `|` (`get (one | two)`)\n    - Optional groups using `[]` (`command [optional_part]`)\n    - Options with placeholder arguments (`-d ?`)\n- **Completion Engine**: A prefix-tree-based engine that provides:\n    - **Suggestions**: A list of all possible valid commands that match the current input.\n    - **Predictions**: The most likely next word or token based on the current input.\n- **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.\n\n## Rules Syntax\n\nThe grammar for defining your command-line interface is designed to be simple and flexible. Rules are typically defined in a `.prl` file.\n\n#### Statements\n\nEach complete command path is a statement. Statements can be separated by a **newline** or a **semicolon (`;`)**.\n\n```\n# Separated by newline\nget status\nset user\n\n# Separated by semicolon\nget status; set user;\n```\n\n#### Alternatives (`|`) and Grouping (`()`)\n\nThe 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.\n\n```\n# Creates two valid paths: 'set user name ?' and 'set group name ?'\nset (user | group) name ?;\n```\n\n#### Optional Groups (`[]`)\n\nSquare brackets **`[ ... ]`** define an optional part of a command. The command is valid with or without the tokens inside the brackets.\n\n```\n# Creates three valid paths: 'show config', 'show interfaces', and just 'show'\nshow [config | interfaces];\n```\n\n#### Options and Arguments (`-` and `?`)\n\nTokens 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.\n\n```\n# An option without an argument\nget -h\n\n# An option that requires an argument\nset user -name ?\n```\n\n## How it Works\n\n1.  **Define Rules**: You write your command structure in a text file (e.g., `rules.prl`).\n    ```\n    # Example Rules\n    get status;\n    set (user | group) name ?;\n    show [config | interfaces];\n    ```\n2.  **Parse**: The library's parser (built with `ply`) reads your rules and generates a list of all valid command paths.\n3.  **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.\n\nThis library provides the core components to build a rich autocompletion experience for any Python-based CLI application.\n\n## Usage with a Python CLI\n\nTo 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.\n\nHere's a basic example of how to set it up:\n\n#### 1. Your Rules (`my_cli.prl`)\n\nFirst, define your command grammar in a `.prl` file.\n\n```\n# my_cli.prl\nget (status | version);\nset user -name ?;\nexit;\n```\n\n#### 2. Your Python Application (`my_cli.py`)\n\nNext, write the Python code to load these rules and hook them into `readline`.\n\n```python\nimport readline\nfrom pyrl_complete.parser import Parser\nfrom pyrl_complete.parser.tree import Tree\n\n# --- 1. Load and Parse Rules ---\nwith open(\"my_cli.prl\", \"r\") as f:\n    rules_text = f.read()\n\nparser = Parser()\nparser.parse(rules_text)\ncompletion_tree = Tree(parser.paths)\n\n# --- 2. Create a Completer Class ---\nclass PyrlCompleter:\n    def __init__(self, tree):\n        self.tree = tree\n        self.predictions = []\n\n    def complete(self, text, state):\n        # On the first Tab press, generate new predictions\n        if state == 0:\n            line_buffer = readline.get_line_buffer()\n            self.predictions = self.tree.get_predictions(line_buffer)\n\n        # Return the next prediction, or None if there are no more\n        return self.predictions[state] if state < len(self.predictions) else None\n\n# --- 3. Setup Readline ---\ncompleter = PyrlCompleter(completion_tree)\nreadline.set_completer(completer.complete)\nreadline.parse_and_bind(\"tab: complete\")\n\n# --- 4. Main Application Loop ---\nprint(\"Welcome to the CLI. Type 'exit' to quit.\")\nwhile True:\n    try:\n        line = input(\">> \")\n        if line.strip() == 'exit':\n            break\n        print(f\"You entered: {line}\")\n    except (EOFError, KeyboardInterrupt):\n        break\nprint(\"\\nGoodbye!\")\n```\n\n### How the Example Works\n\n1.  **Load and Parse Rules**: We load the rule file, create a `Parser`, and then a `Tree` which holds our completion logic.\n2.  **Create a Completer Class**: The `PyrlCompleter` class holds the state for our completion. `readline` calls its `complete` method every time the user hits Tab.\n    *   When `state` is `0` (the first Tab press for the current input), we get the full line from `readline.get_line_buffer()` and ask our `completion_tree` for new predictions.\n    *   For subsequent Tab presses (`state > 0`), we simply return the next prediction from the list we already generated.\n3.  **Setup Readline**: We instantiate our completer and tell `readline` to use it. `readline.parse_and_bind(\"tab: complete\")` is crucial for making the Tab key trigger the completion function.\n4.  **Main Loop**: A standard `input()` loop lets the user interact with the CLI, and `readline` automatically handles the autocompletion in the background.\n\n## Using the Tester GUI\n\nThe 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.\n\nTo run it, execute the `tester.py` script:\n```bash\npython pyrl_complete/apps/tester.py\n```\n\n### Workflow\n\n1.  **Write or Load Rules**:\n    *   Navigate to the **Write Rules** tab to write your grammar from scratch in the text editor.\n    *   Alternatively, in the **Test Rules** tab, click **Load Rules** to open a `.prl` file from your computer. This will load its content into the editor and switch you to the **Write Rules** tab.\n\n2.  **Parse Rules**:\n    *   In the **Write Rules** tab, click the **Parse Rules** button.\n    *   This will process the grammar in the editor, build the completion tree, and update the path count (e.g., \"12 paths generated\").\n    *   The application will automatically switch you to the **Test Rules** tab.\n\n3.  **Test Completion**:\n    *   In the **Test Rules** tab, start typing a command in the **Command line input** field.\n    *   As you type, the **Predictions** list on the right will update with all possible next tokens.\n    *   Press the **Tab** key to cycle through the predictions and auto-populate the input field.\n\n### Interface Overview\n\nThe application is organized into two main tabs and a log panel.\n\n*   **Write Rules Tab**: This is your editor. It contains a large text area for writing rules and two primary buttons:\n    *   `Save Rules`: Saves the content of the editor to a `.prl` file.\n    *   `Parse Rules`: Processes the rules and prepares them for testing.\n\n*   **Test Rules Tab**: This is your testing ground.\n    *   **Rules View (Left)**: A read-only view of the currently parsed rules.\n    *   **Predictions (Right)**: A list that shows potential completions for the current input.\n    *   **Command line input**: The field where you type commands and use Tab completion.\n\n*   **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.\n\n## Dependencies\n\n`pyrl-complete` has one core external dependency:\n\n-   **ply**: Used for the Lex/Yacc-style parsing of the custom grammar rules.\n\nThe included Tester GUI application uses **Tkinter**, which is part of the Python standard library and does not require a separate installation.\n",
    "bugtrack_url": null,
    "license": "GNU AFFERO GENERAL PUBLIC LICENSE Version 3",
    "summary": "manage readline autocomplete for bespoke cli",
    "version": "0.1.1",
    "project_urls": {
        "Homepage": "https://github.com/codimoc/pyrl-complete",
        "Repository": "https://github.com/codimoc/pyrl-complete"
    },
    "split_keywords": [
        "readline",
        " autocomplete",
        " cli",
        " ply"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6797f8d5ba5274cd49155dc236070ce402c562a4945dcccb9f29e6d8f6c10d54",
                "md5": "cd8e14881eb50aa071b32eda8ba417a8",
                "sha256": "5eec02f9b057a001d087424457c22527f214b2607f69a2cd03072a6697d1caf4"
            },
            "downloads": -1,
            "filename": "pyrl_complete-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "cd8e14881eb50aa071b32eda8ba417a8",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 26890,
            "upload_time": "2025-08-06T19:35:48",
            "upload_time_iso_8601": "2025-08-06T19:35:48.398837Z",
            "url": "https://files.pythonhosted.org/packages/67/97/f8d5ba5274cd49155dc236070ce402c562a4945dcccb9f29e6d8f6c10d54/pyrl_complete-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1512693d48d685b7b21e79a93140af18c1276d1ac51ff9760da7a0a35abf9efd",
                "md5": "9783e43d63c851fa9c9fc0b337be0db2",
                "sha256": "427cbeeaf0b2d74a886a1de58625f17c51ed257c0a4d1ad09bed3057acf46e97"
            },
            "downloads": -1,
            "filename": "pyrl_complete-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "9783e43d63c851fa9c9fc0b337be0db2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 26234,
            "upload_time": "2025-08-06T19:35:49",
            "upload_time_iso_8601": "2025-08-06T19:35:49.606797Z",
            "url": "https://files.pythonhosted.org/packages/15/12/693d48d685b7b21e79a93140af18c1276d1ac51ff9760da7a0a35abf9efd/pyrl_complete-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-06 19:35:49",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "codimoc",
    "github_project": "pyrl-complete",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "pyrl-complete"
}
        
Elapsed time: 0.63471s