Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 94 additions & 18 deletions docs/completion.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
# 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

```sh
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
Expand Down Expand Up @@ -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 <Tab>
# Shows: generate, generate-schema, validate, info, list
```

### Structure Name Completion ✨
```sh
# Complete structure names - shows all available structures!
struct generate <Tab>
# Shows available structure names and options
# Shows: ansible-playbook, docker-files, github/workflows/codeql, project/nodejs, etc.

# Partial completion works too
struct generate git<Tab>
# Shows: git-hooks, github/workflows/codeql, github/templates, etc.

# Works with nested structures
struct generate github/<Tab>
# 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 <Tab>
# Shows structures from both custom path and built-in structures
```

### Option Completion
```sh
struct generate --<Tab>
# Shows: --log, --dry-run, --backup, --file-strategy, etc.
# Shows: --log, --dry-run, --backup, --file-strategy, --structures-path, etc.

struct generate --log <Tab>
# Shows: DEBUG, INFO, WARNING, ERROR, CRITICAL
```

## Advanced Configuration
Expand Down Expand Up @@ -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 <Tab>
generate generate-schema info list validate

# Structure name completion (NEW!)
$ struct generate <Tab>
configs/ docker-files project/ terraform/

$ struct generate terraform/<Tab>
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<Tab>
project/custom-structures project/go project/nodejs project/ruby
project/generic project/java project/python project/rust

# Nested structure completion
$ struct generate github/<Tab>
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 --<Tab>
--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 <Tab>
DEBUG ERROR INFO WARNING
DEBUG ERROR INFO WARNING CRITICAL

$ struct generate --file-strategy <Tab>
append backup overwrite rename skip
```

This makes working with STRUCT much more efficient and user-friendly!
7 changes: 7 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
21 changes: 20 additions & 1 deletion docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
17 changes: 16 additions & 1 deletion docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <Tab>
# 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
Expand Down
5 changes: 3 additions & 2 deletions struct_module/commands/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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')
Expand Down
44 changes: 44 additions & 0 deletions struct_module/completers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

class ChoicesCompleter(object):
def __init__(self, choices):
self.choices = choices
Expand All @@ -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()
36 changes: 35 additions & 1 deletion tests/test_completers.py
Original file line number Diff line number Diff line change
@@ -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()
Expand All @@ -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
Loading