Rewriting
Rewriting
A rewrite replaces each match with a template rendered at it, or with what a function returns for it, and splices the result into the input. The template language is the rewrite accessors section’s; masking is on the redaction page. The flags and parameters are on the CLI and PowerShell pages.
Templates
${name} renders a register, ${0} the whole match, ${1}, ${2} a register by position,
and ${name:accessor} transforms or slices one: upper, lower and trim on any register,
the typed slices on a captured atom (${ip:octet1-2}, ${url:host}, ${e:domain},
${ts:year}), chained with |. $$ is a dollar sign, and \n, \t and \\ are a newline,
a tab and a backslash.
$ trex rewrite '\E:e' '[${e:domain}]' --text 'mail bob@x.com and amy@y.org now'
mail [x.com] and [y.org] now
$ trex rewrite '\I:ip' '${ip:octet1-2}.0.0/16' --text 'conn from 192.168.5.9'
conn from 192.168.0.0/16
$ trex rewrite '\W:a "=" \N:b' '${2} := ${1}' --text 'x = 1'
1 := x
A template naming a register the pattern does not bind, or an accessor the register’s kind does not have, is refused before anything is rewritten.
The first matches
let pat = trex::parse(r"\N").expect("valid pattern");
let out = trex::rewrite_n_with(&pat, b"1 2 3 4", 2, |_| "n");
assert_eq!(out, b"n n 3 4");Computed replacements
A function in place of the template is handed each match and returns its replacement, so a replacement can be computed from a register’s typed value. It reads a register through the same references a template writes.
let pat = trex::parse(r"\E:e").expect("valid pattern");
let mut n = 0;
let out = trex::rewrite_with(&pat, b"bob@x.com, amy@y.org", |m| {
n += 1;
format!("{n}:{}", m.get("e:domain").expect("a slice a template could render"))
});
assert_eq!(out, b"1:x.com, 2:y.org");In Rust the closure receives a Matched, whose get reads a reference such as e:domain,
0:last4 or 1, and whose value reads a typed register where it was built with the
pattern’s capture_kinds. In Python the callable receives the Match and returns str for a
str input and bytes for bytes. In PowerShell the script block runs with the
Trex.Match as $_, and its last output replaces the match.
Files
One input is rewritten to the standard output. A directory or several inputs take
--in-place, which writes each file holding a match back in the encoding it was read in,
behind its own byte order mark, every byte outside a match as it was, or --dry-run, which
prints the unified diff each file would take, with three lines of context or -C N. A
directory is walked as scan walks one, and a binary
file named alone is refused, by name, unless --binary asks for it.
$ cat src/notes.md
The answer is 42, and legacy_call() is the old name.
See legacy_call in the guide.
$ cat src/main.rs
fn main() {
legacy_call(42);
}
$ trex rewrite '"legacy_call"' 'current_call' src/ --dry-run
--- src/main.rs
+++ src/main.rs
@@ -1,3 +1,3 @@
fn main() {
- legacy_call(42);
+ current_call(42);
}
--- src/notes.md
+++ src/notes.md
@@ -1,2 +1,2 @@
-The answer is 42, and legacy_call() is the old name.
-See legacy_call in the guide.
+The answer is 42, and current_call() is the old name.
+See current_call in the guide.
$ trex rewrite '"legacy_call"' 'current_call' src/ --in-place
src/main.rs: 1 replacement
src/notes.md: 2 replacements
In PowerShell -InPlace asks ShouldProcess for each file, so -WhatIf names the files it
would write and writes none, and -Confirm asks for each.
Review
--interactive (-i) shows each change as its unified diff, with the template of its match -
the kinds of the tokens the match spans - and how many later changes share that template,
and asks:
| Answer | Does |
|---|---|
y | applies this change |
n | skips it |
e | takes another replacement, in the editor VISUAL or EDITOR names, or typed at the prompt where neither is set |
t | applies this change and every later one of its template |
T | skips this change and every later one of its template |
a | applies this change and every one after it |
q | stops, leaving every file as it was |
The accepted changes are written once the last one has been answered, so a session that ends
early leaves every file as it was. -U (--update-all) applies every change without asking.
The answers are read from the standard input, so a review runs from a pipe as well as by hand.
How many changes a T passed over is reported; --show-skipped names where each stands.
--explain puts under each diff what scan --explain puts under each match.
$ cat levels.log
alpha 10
beta 20
gamma 300
delta 4000
epsilon 5
$ printf 'n\ny\n' | trex rewrite '\N{>=100}' '[${0}]' levels.log --interactive
--- levels.log
+++ levels.log
@@ -1,5 +1,5 @@
alpha 10
beta 20
-gamma 300
+gamma [300]
delta 4000
epsilon 5
template: number (1 later change shares it)
[1/2] accept, skip or edit this change, all of this template, none of it, accept all, or quit [y/n/e/t/T/a/q]? --- levels.log
+++ levels.log
@@ -1,5 +1,5 @@
alpha 10
beta 20
gamma 300
-delta 4000
+delta [4000]
epsilon 5
template: number (0 later changes share it)
[2/2] accept, skip or edit this change, all of this template, none of it, accept all, or quit [y/n/e/t/T/a/q]? levels.log: 1 replacement
t takes the rest of a template with one answer:
$ cat levels.log
alpha 10
beta 20
gamma 300
delta 4000
epsilon 5
$ printf 't\n' | trex rewrite '\N{>=100}' '[${0}]' levels.log --interactive
--- levels.log
+++ levels.log
@@ -1,5 +1,5 @@
alpha 10
beta 20
-gamma 300
+gamma [300]
delta 4000
epsilon 5
template: number (1 later change shares it)
[1/2] accept, skip or edit this change, all of this template, none of it, accept all, or quit [y/n/e/t/T/a/q]? levels.log: 2 replacements
In PowerShell -Interactive puts each change to the host’s prompt with the same choices,
Y, N (the default), E, T, S for skipping a template, A and Q; a host that cannot
prompt, such as pwsh -NonInteractive, stops at the first question and writes nothing.
Declared atoms
A pattern naming \{name} reads its declaration from a pattern file, --lib FILE on the
command line, lib= in Python, Import-TrexAtom or -Library in PowerShell and a
ShapeSet in Rust; a declared shape decides the token boundaries the rewrite lexes on, so it
replaces what a scan under the same file reports. A rewrite under a declared shape runs on the
CPU engines. The pattern files page has the declarations.