# cxr

`cxr` is a Rust CLI that generates directory structures and files from YAML templates.

[日本語版](./README-ja.md)

## What it does

- Lists available templates
- Creates a starter template file
- Generates files by replacing variables in a template

## Build

```bash
cargo build
```

## Usage

```bash
cargo run -- list
cargo run -- list --tag web
cargo run -- list --search starter
cargo run -- new <name>
cargo run -- remove <name>
cargo run -- fzf
cargo run -- lint <template> [--all]
cargo run -- <template> [-v VAR=VALUE ...] [-o OUTPUT] [--dry-run] [--force|--backup|--skip]
```

If installed, you can use `cxr` instead of `cargo run --`.

### Commands

- `list`: show available templates (`--tag` / `--search` supported)
- `new <name>`: create `<name>.yaml` under `~/.config/cxr/` or `$XDG_CONFIG_HOME/cxr/`
- `remove <name>` (`delete <name>`): remove an existing template file
- `fzf`: select a template via fzf and generate
- `lint <template>` (`--all`): validate a template (or all templates) without generating files
- `<template>`: generate files from the specified template

## Template location

Templates are stored in one of these locations:

- `$XDG_CONFIG_HOME/cxr/`
- `~/.config/cxr/`

Each template file must be named `<template>.yaml`.

## Template format

Templates are defined in YAML.

```yaml
name: "default template"
description: "A default template generated by cxr"
tags:
  - starter
variables:
  - project_name
  - author: "John Doe"
pre_hook: "echo pre {{ project_name }}"
post_hook: "echo post {{ project_name }}"
items:
  - type: "directory"
    name: "src"
    when: "project_name"
    items:
      - type: "file"
        name: "main.py"
        content: |
          def main():
              print("Hello, {{ project_name }}!")
```

### Variables

- Use `- project_name` to prompt for a value during generation
- Use `- author: "John Doe"` to provide a default value
- Placeholders such as `{{ project_name }}` are replaced in file names, directory names, and file contents
- `when` skips an item when the condition is false. Supported forms: `flag`, `!flag`, `name == value`, `name != value`
- `extends` lets a template inherit variables, tags, hooks, and items from another template
- `tags` can be used to filter templates with `cxr list --tag <tag>`

### Items

- `type: directory`: create a directory
- `type: file`: create a file

## Existing files

If a file or directory already exists, cxr asks before overwriting it.

## Overwrite strategies

- `--force`: overwrite existing files without prompting
- `--backup`: rename existing files to `.bak` before writing (overwrites existing `.bak`)
- `--skip`: skip existing files without prompting

Directories are reused; overwrite strategies apply to files only. `--backup` will rename existing directories to `.bak` before creating a new directory.

## Dry run

Use `--dry-run` (`-n`) to preview the generated items without writing files. It still checks existing paths and reports when it would overwrite them.

## Hooks

Use `pre_hook` and `post_hook` in the template YAML to run a command before and after generation. Hooks run in the output directory and support `{{ var }}` substitution. If a hook fails, generation stops.

```yaml
pre_hook: "echo pre {{ project_name }}"
post_hook: "echo post {{ project_name }}"
```

Hooks are executed with `/bin/sh -c`. Dry run does not execute hooks.
Hooks also receive `CX_OUTPUT_DIR`, `CX_TEMPLATE_NAME`, `CX_TEMPLATE_DESCRIPTION`, and the resolved variables as environment variables.

## Non-interactive variables

Use `--vars-file` to supply variables from a YAML or JSON file. The file should contain a mapping of variable names to string values, for example:

```yaml
project_name: myproject
author: Jane
```

Precedence: command-line `-v VAR=VALUE` entries override values from `--vars-file`. Values from `--vars-file` override interactive prompts and template defaults. Variables provided by `--vars-file` will not be prompted interactively. Example:

```bash
cargo run -- mytemplate --vars-file vars.yaml --dry-run
```


## fzf selection

`cxr fzf` uses [fzf](https://github.com/junegunn/fzf) to select a template and then generates files. If fzf is not installed or the selection is cancelled, cxr exits with an error.

`cxr list --search <query>` matches against the template name, description, and tags.
