# Multi-Line Replacer (`mlr`)

*Copyright 2025 Caleb Evans*  
*Released under the MIT license*

[![tests](https://github.com/caleb531/multi-line-replacer/actions/workflows/tests.yml/badge.svg)](https://github.com/caleb531/multi-line-replacer/actions/workflows/tests.yml)
[![Coverage Status](https://coveralls.io/repos/caleb531/multi-line-replacer/badge.svg?branch=main)](https://coveralls.io/r/caleb531/multi-line-replacer?branch=main)

Multi-Line Replacer is a CLI utility for replacing multi-line hunks of strings
across one or more files. Matching is mostly textual, but wildcard matching is
supported, and replacements are indentation-aware.

## Usage

The workflow takes one or more files on which to run replacements, and then a
series of "replacement rule" files with the `-r` flag:

```sh
mlr .github/workflows/*.yml -r example-rules/uv-gha.md
```

Each replacement rule must be a Markdown file with one or more pairs of GFM
fenced code blocks ([see documentation][gfm-docs]). Every odd code block
represents the target text to replace, and every even code block represents the
textual replacement. All other Markdown formatting is ignored, so feel free to
add headings, explainer text, or anything else!

````md
This rule replaces flake8 with ruff in a Github Actions linting workflow.

## flake8

```yml
- name: Run flake8
  run: flake8 MATCH_UNTIL_END_OF_LINE
```

## ruff

```yml
- name: Run ruff
  run: |
    uv run ruff check .
    uv run ruff format --check .
```
````

The language specifier at the start of each code fence is ignored by the
utility. Still, it is highly recommended to specify so that syntax highlighting
is enabled in your editor (for a better authoring experience).

### Wildcard Matching

There are two special wildcard variables:

- `MATCH_UNTIL_END_OF_LINE` (`[^\n]*`)
- `MATCH_ALL_BETWEEN` (`[^\n]*?`)

These variables can be used anywhere in a rule (no word boundaries required).

### More Examples

To better understand the expected rules format and what's allowed, please see
the `example-rules` directory.

[gfm-docs]: https://github.github.com/gfm/#fenced-code-blocks
