diff --git a/docs/completion.md b/docs/completion.md index 4984eda..854ddde 100644 --- a/docs/completion.md +++ b/docs/completion.md @@ -1,8 +1,26 @@ # Command-Line Auto-Completion -This project uses [argcomplete](https://kislyuk.github.io/argcomplete/) to provide command-line auto-completion for the `struct` script. Follow these steps to enable auto-completion: +STRUCT provides intelligent auto-completion for commands, options, and **structure names** using [argcomplete](https://kislyuk.github.io/argcomplete/). This makes discovering and using available structures much faster and more user-friendly. -## Installation +!!! tip "New Feature: Structure Name Completion" + STRUCT now automatically completes structure names when using `struct generate`, showing all 47+ available structures from both built-in and custom paths! + +## Quick Setup + +For most users, this simple setup will enable full completion: + +```sh +# Install (if not already installed) +pip install argcomplete + +# Enable completion for current session +eval "$(register-python-argcomplete struct)" + +# Make permanent - add to your ~/.zshrc or ~/.bashrc +echo 'eval "$(register-python-argcomplete struct)"' >> ~/.zshrc +``` + +## Detailed Installation ### 1. Install argcomplete @@ -10,9 +28,9 @@ This project uses [argcomplete](https://kislyuk.github.io/argcomplete/) to provi pip install argcomplete ``` -### 2. Enable Global Completion +### 2. Enable Global Completion (Optional) -This step is usually done once per system: +This step is optional but can be done once per system: ```sh activate-global-python-argcomplete @@ -59,15 +77,41 @@ source ~/.config/fish/config.fish After completing the setup, you can use auto-completion by typing part of a command and pressing `Tab`: +### Command Completion ```sh struct # Shows: generate, generate-schema, validate, info, list +``` +### Structure Name Completion ✨ +```sh +# Complete structure names - shows all available structures! struct generate -# Shows available structure names and options +# Shows: ansible-playbook, docker-files, github/workflows/codeql, project/nodejs, etc. + +# Partial completion works too +struct generate git +# Shows: git-hooks, github/workflows/codeql, github/templates, etc. +# Works with nested structures +struct generate github/ +# Shows: github/workflows/codeql, github/templates, github/prompts/generic, etc. +``` + +### Custom Structure Paths +```sh +# Completion works with custom structure paths +struct generate --structures-path /custom/path +# Shows structures from both custom path and built-in structures +``` + +### Option Completion +```sh struct generate -- -# Shows: --log, --dry-run, --backup, --file-strategy, etc. +# Shows: --log, --dry-run, --backup, --file-strategy, --structures-path, etc. + +struct generate --log +# Shows: DEBUG, INFO, WARNING, ERROR, CRITICAL ``` ## Advanced Configuration @@ -180,32 +224,64 @@ eval "$(register-python-argcomplete struct-wrapper.sh)" ## Supported Completions -STRUCT provides completion for: +STRUCT provides intelligent completion for: -- **Commands**: `generate`, `validate`, `list`, etc. -- **Options**: `--log`, `--dry-run`, `--backup`, etc. -- **Structure names**: All available built-in and custom structures +- **Commands**: `generate`, `validate`, `list`, `info`, `generate-schema` +- **Options**: `--log`, `--dry-run`, `--backup`, `--file-strategy`, `--structures-path`, etc. +- **Structure names**: All 47+ available built-in and custom structures + - Built-in structures: `ansible-playbook`, `docker-files`, `helm-chart`, etc. + - Nested structures: `github/workflows/codeql`, `project/nodejs`, `terraform/apps/generic`, etc. + - Custom structures: From `--structures-path` directories - **File paths**: Local files and directories -- **Enum values**: Log levels, file strategies, etc. +- **Enum values**: Log levels (`DEBUG`, `INFO`, etc.), file strategies (`overwrite`, `skip`, etc.) + +## How Structure Completion Works + +The structure name completion feature: + +1. **Dynamically discovers** all available structure files (`.yaml` files) +2. **Scans multiple locations**: + - Built-in structures in `struct_module/contribs/` + - Custom structures from `--structures-path` if specified +3. **Returns clean names** without `.yaml` extensions +4. **Supports nested directories** like `github/workflows/codeql` +5. **Updates automatically** when new structures are added ## Example Session ```sh +# Command completion $ struct generate generate-schema info list validate +# Structure name completion (NEW!) $ struct generate -configs/ docker-files project/ terraform/ - -$ struct generate terraform/ -terraform/app terraform/module - +ansible-playbook configs/codeowners github/workflows/codeql project/nodejs +chef-cookbook docker-files helm-chart terraform/apps/generic +ci-cd-pipelines git-hooks kubernetes-manifests vagrant-files + +# Partial completion +$ struct generate proj +project/custom-structures project/go project/nodejs project/ruby +project/generic project/java project/python project/rust + +# Nested structure completion +$ struct generate github/ +github/chatmodes/plan github/prompts/react-form github/workflows/codeql +github/instructions/generic github/prompts/security-api github/workflows/labeler +github/prompts/generic github/workflows/pre-commit github/workflows/stale + +# Option completion $ struct generate -- --backup --dry-run --file-strategy --log ---log-file --mappings-file --structures-path +--log-file --mappings-file --structures-path --vars +# Enum value completion $ struct generate --log -DEBUG ERROR INFO WARNING +DEBUG ERROR INFO WARNING CRITICAL + +$ struct generate --file-strategy +append backup overwrite rename skip ``` This makes working with STRUCT much more efficient and user-friendly! diff --git a/docs/installation.md b/docs/installation.md index 413c6b5..8de341d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -8,6 +8,13 @@ Install STRUCT with pip: pip install git+https://github.com/httpdss/struct.git ``` +!!! tip "Enable Auto-Completion" + After installation, enable command-line auto-completion for better productivity: + ```sh + eval "$(register-python-argcomplete struct)" + ``` + For permanent setup, see the [Command-Line Completion](completion.md) guide. + ## From Source Clone the repository and install locally. See the [Development](development.md) page for details. diff --git a/docs/quickstart.md b/docs/quickstart.md index 5577fce..d89e062 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -45,16 +45,35 @@ struct generate structure.yaml . > **Note**: The `file://` protocol is automatically added for `.yaml` files, so `structure.yaml` and `file://structure.yaml` work identically. +## Discovering Available Structures + +Before generating, see what structures are available: + +```sh +struct list +``` + +This shows all built-in structures you can use. + +!!! tip "Auto-Completion" + If you've enabled [auto-completion](completion.md), you can press `Tab` after `struct generate ` to see all available structures! + ## First Example After installing STRUCT, try this simple example: ```sh -struct generate terraform-module ./my-terraform-module +struct generate terraform/modules/generic ./my-terraform-module ``` This will create a new terraform module structure in the `./my-terraform-module` directory. +Or try a simple project structure: + +```sh +struct generate project/nodejs ./my-node-app +``` + ## Next Steps - Learn about [YAML Configuration](configuration.md) diff --git a/docs/usage.md b/docs/usage.md index 4473596..e376d8c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -18,10 +18,25 @@ struct -h ## Generate Command +### Finding Available Structures + +Use the `list` command to see all available structures: + +```sh +struct list +``` + +Or if you have [auto-completion](completion.md) enabled, use `Tab` to see all options: + +```sh +struct generate +# Shows all available structures +``` + ### Simple Example ```sh -struct generate terraform-module ./my-terraform-module +struct generate terraform/modules/generic ./my-terraform-module ``` ### YAML File Usage diff --git a/struct_module/commands/generate.py b/struct_module/commands/generate.py index 4fb244f..e78b83d 100644 --- a/struct_module/commands/generate.py +++ b/struct_module/commands/generate.py @@ -3,7 +3,7 @@ import yaml import argparse from struct_module.file_item import FileItem -from struct_module.completers import file_strategy_completer +from struct_module.completers import file_strategy_completer, structures_completer from struct_module.template_renderer import TemplateRenderer import subprocess @@ -12,7 +12,8 @@ class GenerateCommand(Command): def __init__(self, parser): super().__init__(parser) - parser.add_argument('structure_definition', type=str, help='Path to the YAML configuration file') + structure_arg = parser.add_argument('structure_definition', type=str, help='Path to the YAML configuration file') + structure_arg.completer = structures_completer parser.add_argument('base_path', type=str, help='Base path where the structure will be created') parser.add_argument('-s', '--structures-path', type=str, help='Path to structure definitions') parser.add_argument('-n', '--input-store', type=str, help='Path to the input store', default='/tmp/struct/input.json') diff --git a/struct_module/completers.py b/struct_module/completers.py index e15ef27..b880844 100644 --- a/struct_module/completers.py +++ b/struct_module/completers.py @@ -1,3 +1,5 @@ +import os + class ChoicesCompleter(object): def __init__(self, choices): self.choices = choices @@ -6,5 +8,47 @@ def __call__(self, **kwargs): return self.choices +class StructuresCompleter(object): + """Dynamic completer for available structure names.""" + + def __init__(self, structures_path=None): + self.structures_path = structures_path + + def __call__(self, prefix, parsed_args, **kwargs): + """Return list of available structure names for completion.""" + return self._get_available_structures(parsed_args) + + def _get_available_structures(self, parsed_args): + """Get list of available structure names, similar to ListCommand logic.""" + # Get the directory where the commands are located + this_file = os.path.dirname(os.path.realpath(__file__)) + contribs_path = os.path.join(this_file, "contribs") + + # Check if custom structures path is provided via parsed_args + structures_path = getattr(parsed_args, 'structures_path', None) or self.structures_path + + if structures_path: + paths_to_list = [structures_path, contribs_path] + else: + paths_to_list = [contribs_path] + + all_structures = set() + for path in paths_to_list: + if not os.path.exists(path): + continue + + for root, _, files in os.walk(path): + for file in files: + if file.endswith(".yaml"): + file_path = os.path.join(root, file) + rel_path = os.path.relpath(file_path, path) + # Remove .yaml extension + structure_name = rel_path[:-5] + all_structures.add(structure_name) + + return sorted(list(all_structures)) + + log_level_completer = ChoicesCompleter(['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']) file_strategy_completer = ChoicesCompleter(['overwrite', 'skip', 'append', 'rename', 'backup']) +structures_completer = StructuresCompleter() diff --git a/tests/test_completers.py b/tests/test_completers.py index ae6ad71..66275bd 100644 --- a/tests/test_completers.py +++ b/tests/test_completers.py @@ -1,5 +1,7 @@ import pytest -from struct_module.completers import log_level_completer, file_strategy_completer +import os +import argparse +from struct_module.completers import log_level_completer, file_strategy_completer, structures_completer def test_log_level_completer(): completer = log_level_completer() @@ -16,3 +18,35 @@ def test_file_strategy_completer(): assert 'append' in completer assert 'rename' in completer assert 'backup' in completer + +def test_structures_completer(): + # Create a mock parsed_args + parsed_args = argparse.Namespace(structures_path=None) + + # Test the completer + completions = structures_completer(prefix="", parsed_args=parsed_args) + + # Should return a list + assert isinstance(completions, list) + + # Should contain some of the known structures from contribs + # (these are based on what we saw in the directory listing) + expected_structures = ['ansible-playbook', 'docker-files', 'helm-chart'] + + # Check if at least some expected structures are present + for expected in expected_structures: + assert expected in completions, f"Expected '{expected}' to be in completions: {completions}" + +def test_structures_completer_with_custom_path(tmp_path): + # Create a temporary structure file + custom_structure_file = tmp_path / "custom-structure.yaml" + custom_structure_file.write_text("files: []") + + # Create a parsed_args with custom structures_path + parsed_args = argparse.Namespace(structures_path=str(tmp_path)) + + # Test the completer + completions = structures_completer(prefix="", parsed_args=parsed_args) + + # Should contain the custom structure + assert 'custom-structure' in completions