Metadata-Version: 2.5
Name: ro-cli
Version: 0.1.0
Summary: Reorder sequentially numbered files
Project-URL: Homepage, https://gitlab.com/joseph8th/ro-cli
Project-URL: Issues, https://gitlab.com/joseph8th/ro-cli/-/issues
Author-email: Joseph Edwards VIII <jedwards8th@gmail.com>
License: MIT
License-File: LICENSE
Keywords: cli,files,migrations,rename,reorder,utilities
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# ro

Think of your sequentially numbered files as a deck of cards. `ro` moves a
card to any slot and the cards between the old and new positions slide to
fill the gap. Or spread the deck: push a card and everything above it up to
leave space for new files to land nearby.

```sh
pip install ro-cli
```

## Usage

```
ro FILE N [options]
```

Move `FILE` to slot `N`, shifting siblings to keep the sequence dense.

| Flag             | Description                                                                                          |
|------------------|------------------------------------------------------------------------------------------------------|
| `-m, --move`     | Block-shift `FILE` and everything above by `N − current` (opens a gap when up, closes one when down) |
| `-s, --suffix`   | Force suffix mode (`name_NNN.ext`). By default the position is auto-detected from `FILE`             |
| `-z W, --zpad W` | Digit-field width. By default auto-detected from `FILE`                                              |
| `-d, --dry-run`  | Print the plan without executing                                                                     |
| `-n, --no-git`   | Use `shutil.move` even inside a git repo                                                             |

Exit codes: `0` success · `1` user error · `2` internal failure / partial rollback.

## Examples

```sh
# Move migration 005 back to slot 3. Files 003 and 004 shift up one each.
ro 005_create_users.sql 3

# Preview the plan first
ro 005_create_users.sql 3 --dry-run

# Create space at slots 4–6 before adding three new migrations
ro 003_create_users.sql 7 --move

# Changed your mind. Pull 007 back down to 3 and close the gap.
ro 007_create_users.sql 3 --move

# DAW stems numbered at the end. Suffix detected automatically.
ro kick_005.wav 2

# Five-digit sequences. Zpad detected automatically from the filename.
ro 00005_chapter.md 2
```

## The two primitives

**Slide** (`ro FILE N`) moves `FILE` to position `N`. Every file between
the old and new slot shifts one step to close the gap. The deck stays dense,
no holes.

**Block-shift** (`ro FILE N -m`) moves `FILE` and every file above it as a
block by `N − current`. Moving up opens a gap below for new files. Moving
down closes a gap that was previously opened. If the destination range is
already occupied, `ro` errors out. Use slide instead.

## How it works

- Builds the complete rename plan before touching any file.
- Preflights the directory and the plan. Any of these halts before any
  filesystem change:
  - A destination filename already on disk.
  - A destination index already occupied by a file the plan isn't moving.
  - A sibling file that looks numbered but uses a different mode or
    digit width than `FILE`.
  - A duplicate index in the directory.
- Executes atomically: moves the source to a temp name first, shifts siblings,
  then moves the temp to the final destination.
- Rolls back all completed moves on any failure.
- Prefers `git mv` inside a git repository to keep history. Silently falls
  back to `shutil.move` for untracked files. Use `-n` to opt out entirely.
- Non-numeric files (READMEs, configs, etc.) in the directory produce a
  warning and are skipped. They don't block the operation.

## Naming conventions supported

Both number position (prefix vs. suffix) and digit width are detected
automatically from `FILE`. The `-s` and `-z` flags are override escape
hatches for ambiguous cases.

| Convention     | Example                | Auto-detected |
|----------------|------------------------|---------------|
| Numeric prefix | `003_create_users.sql` | yes           |
| Numeric suffix | `kick_003.wav`         | yes           |
| Wide zero-pad  | `00005_chapter.md`     | yes (zpad=5)  |

Full-regex extraction was considered and rejected as too much surface area.
Prefix and suffix cover the vast majority of real-world patterns, and
either is detected on sight.

## Who it's for

Anyone who keeps order visible in the filename rather than hidden in
metadata, timestamps, or a graph:

- Database migrations in projects that still number them (CodeIgniter, legacy Rails)
- Static-site numbered posts (Jekyll, Hugo)
- Documentation chapters and numbered slides
- DAW stem files
- Zettelkasten numbered notes
- Any directory where humans encode order with leading or trailing numbers

## Why numbered sequences

Timestamp prefixes and linked-list migration graphs (Alembic, Flyway)
exist to avoid the merge-time friction of dense sequences. Two branches
both want slot 017. The usual fix is to abandon the sequence model,
which moves the ordering decision somewhere the human doing the merge
can't see.

Keeping the sequence puts ordering right in the filename, where every
tool and every reader sees it the same way. The cost is renames when
the sequence shifts, and `ro` eats that cost: build the plan, verify
no collisions, execute atomically, keep git history. Human decides the
order. `ro` makes the arithmetic correct.

### Prior art

`perl rename`, `util-linux rename`, `mmv`, and `vidir` all handle
arbitrary rename patterns, but none implement dense-sequence
reordering. That's why the ecosystems that needed it most routed
around the problem rather than solving it.

## License

[MIT](LICENSE)
