1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! Pattern-based rewriting (#47): the capstone of the edit API (RFC #48).
//!
//! [`Parsed::replace`] finds every [`Match`] of a [`Pattern`] and splices a
//! rendered *template* over each one, returning a new source string.
//! [`Parsed::replace_in`] does the same scoped to an anchor node. Both build
//! on the layers below them — the matcher (#46) supplies the matches and the
//! captures, and the splice list ([`crate::edit`], #44) applies the batch —
//! so everything outside the rewritten regions is preserved **byte-for-byte
//! by construction**.
//!
//! # Templates
//!
//! A template is **literal text with substitution holes**, not a fragment to
//! parse. Its `$NAME` / `$$$NAME` holes are recognised by the exact same
//! metavariable rules as patterns (the shared #45 scanner,
//! [`crate::pattern`]); everything else is copied verbatim. For each match a
//! replacement string is rendered:
//!
//! - literal template text is emitted as written;
//! - a `$NAME` hole is replaced by the **original target bytes** of the
//! capture the match bound to `NAME` ([`Capture::text`](crate::matcher::Capture::text) — the RFC
//! preservation guarantee: captured content is copied byte-exact, never
//! reformatted);
//! - a `$$$NAME` hole is likewise replaced by the captured sibling
//! sequence's original bytes (the capture range already spans the
//! separators between siblings, so they too are verbatim).
//!
//! A hole name may repeat (each occurrence substitutes the same capture) and
//! a captured name may go unused (that region of the target is simply
//! dropped — an intentional deletion). A hole that names a metavariable the
//! match's [reading](crate::pattern::Reading) did **not** bind is a
//! [`RewriteError::UnknownMetavar`].
//!
//! # Re-indentation
//!
//! The replacement is spliced at [`Match::range`], whose start sits *after*
//! the matched line's leading indentation (node ranges exclude it), so the
//! template's **first line** lands right after that existing indentation with
//! nothing added. Each subsequent **template** line is a continuation line
//! and is prefixed with the match site's **base indent** — the run of spaces
//! / tabs at the start of the line the match begins on — so multi-line
//! templates stay aligned under the construct they replace. Blank template
//! lines get no indent (no trailing whitespace is introduced).
//!
//! Crucially, re-indentation applies only to the template's *own* literal
//! newlines. The bytes of a capture are emitted verbatim, newlines included:
//! a multi-line `$DESC` substitutes its original source, which already
//! carries the correct relative indentation of same-indented source, so it is
//! never re-indented. This is what makes the preservation law hold — a
//! template that re-emits a match's captures reproduces the match's bytes
//! exactly.
//!
//! # Style strictness and no-ops
//!
//! Rewriting inherits the matcher's [style strictness](crate::matcher): a
//! pattern of a different [`Style`](crate::parse::Style) than the target
//! yields no matches, so the source is returned unchanged (`Ok`). Likewise a
//! pattern that simply matches nothing is a no-op. To re-parse the result,
//! feed the returned string back through the same-style parser (e.g.
//! [`parse`](crate::parse::parse) or [`parse_google`](crate::parse::parse_google)).
//!
//! # Example
//!
//! The issue #26 use case — annotate one entry's line while every other byte
//! of the docstring stays identical:
//!
//! ```rust
//! use pydocstring::parse::{parse, Style};
//! use pydocstring::pattern::Pattern;
//!
//! let src = "Summary.\n\nArgs:\n x (int): The value.\n y (str): Kept.\n";
//! let parsed = parse(src);
//! let pattern = Pattern::new(Style::Google, "$NAME (int): $DESC").unwrap();
//!
//! let out = parsed.replace(&pattern, "$NAME (int): $DESC (deprecated)").unwrap();
//! assert_eq!(
//! out,
//! "Summary.\n\nArgs:\n x (int): The value. (deprecated)\n y (str): Kept.\n",
//! );
//! ```
use fmt;
use crateEditError;
use crateMatch;
use crateMetaVarToken;
use cratePattern;
use cratelex_metavars;
use crateParsed;
use crateSyntaxNode;
// =============================================================================
// RewriteError
// =============================================================================
/// Why [`Parsed::replace`] / [`Parsed::replace_in`] could not produce a
/// result.
///
/// `#[non_exhaustive]`: later phases may add rewrite-time failures, so
/// downstream `match`es need a wildcard arm.
// =============================================================================
// Entry points
// =============================================================================
// =============================================================================
// Template rendering
// =============================================================================
/// Render `template` for one `match`, substituting captured original bytes
/// for holes and re-indenting the template's own continuation lines to the
/// match's base indent (see the [module docs](self#re-indentation)).
/// The base indent of the line that byte offset `start` sits on: the leading
/// run of spaces / tabs at that line's start.