prettycsharp 1.0.0__tar.gz → 1.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/AGENTS.md +6 -1
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/CHANGELOG.md +33 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/DESIGN.md +55 -4
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/PKG-INFO +41 -8
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/README.md +40 -7
- prettycsharp-1.1.1/src/prettycsharp/__init__.py +18 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/cli.py +7 -2
- prettycsharp-1.1.1/src/prettycsharp/conditional.py +399 -0
- prettycsharp-1.1.1/src/prettycsharp/formatter.py +279 -0
- prettycsharp-1.1.1/src/prettycsharp/isolate.py +118 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/parsing.py +12 -5
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/printer/core.py +9 -3
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/rewrites.py +19 -2
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/settings.py +2 -0
- prettycsharp-1.1.1/tests/fuzz_corpus/csharp/split_by_conditionals.cs +17 -0
- prettycsharp-1.1.1/tests/test_conditional.py +333 -0
- prettycsharp-1.1.1/tests/test_format_around.py +110 -0
- prettycsharp-1.0.0/src/prettycsharp/__init__.py +0 -9
- prettycsharp-1.0.0/src/prettycsharp/formatter.py +0 -106
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.gitattributes +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/codeql/codeql-config.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/dependabot.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/build.in +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/build.txt +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/fuzz.in +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/fuzz.txt +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/pip-audit.in +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/pip-audit.txt +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/runtime.in +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/runtime.txt +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/test.in +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/test.txt +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/zizmor.in +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/requirements/zizmor.txt +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/security/accepted.toml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/security/clamav/Dockerfile +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/security/malware-accepted.toml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/security/semgrep/Dockerfile +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/security/yara.json +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/security/yara_update.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/workflows/auto-merge.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/workflows/ci.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/workflows/fuzz.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/workflows/malware-scan.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/workflows/publish.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/workflows/scorecard.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/workflows/security.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/workflows/update-yara-rules.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.github/zizmor.yml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/.gitignore +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/CLAUDE.md +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/LICENSE +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/SECURITY.md +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/fuzz/fuzz_formatter.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/pyproject.toml +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/scripts/security/malware_report.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/scripts/security/security_report.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/__main__.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/config.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/doc.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/ignore.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/printer/__init__.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/printer/declarations.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/printer/expressions.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/printer/statements.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/project.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/py.typed +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/syntax.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/src/prettycsharp/verify.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/fuzz_corpus/csharp/declarations.cs +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/fuzz_corpus/csharp/directives.cs +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/fuzz_corpus/csharp/embedded_statements.cs +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/fuzz_corpus/csharp/expressions.cs +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/fuzz_corpus/csharp/members.cs +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/fuzz_corpus/csharp/order.cs +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/fuzz_corpus/csharp/queries_and_patterns.cs +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/fuzz_corpus/csharp/statements.cs +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/fuzz_corpus/csharp/strings.cs +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/support.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_cli.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_config.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_doc.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_docs.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_fuzz_corpus.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_ignore.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_layout.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_parsing.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_project.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_rewrites.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_settings.py +0 -0
- {prettycsharp-1.0.0 → prettycsharp-1.1.1}/tests/test_verify.py +0 -0
|
@@ -10,7 +10,12 @@ token-changing rewrites; `printer/` turns nodes into a layout document
|
|
|
10
10
|
(`core.py` dispatch, tokens, comments and lists; `expressions.py`,
|
|
11
11
|
`statements.py` and `declarations.py` the handlers, each `p_<node type>`);
|
|
12
12
|
`doc.py` fits the document to the width; `verify.py` reparses the output and
|
|
13
|
-
compares canonical trees.
|
|
13
|
+
compares canonical trees. When `#if` branches split code so the file does
|
|
14
|
+
not parse whole, `conditional.py` formats one view (set of defined symbols)
|
|
15
|
+
at a time, with directive lines and inactive branches behind placeholder
|
|
16
|
+
comments, and checks every view at the end. With `syntax_errors =
|
|
17
|
+
"format_around"`, `isolate.py` finds the fewest lines whose removal lets the
|
|
18
|
+
file parse and hides them behind the same placeholders. `settings.py`, `config.py`, `project.py`,
|
|
14
19
|
`ignore.py` and `cli.py` are the settings, files and command line.
|
|
15
20
|
|
|
16
21
|
## Commands
|
|
@@ -2,6 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
Each release's section becomes the body of its GitHub release.
|
|
4
4
|
|
|
5
|
+
## [1.1.1] - 2026-10-17
|
|
6
|
+
|
|
7
|
+
- `syntax_errors = "format_around"` now works inside each view of a file
|
|
8
|
+
split by `#if`: a view that does not parse is formatted around its own
|
|
9
|
+
unreadable lines, so both branches of a split class header are formatted
|
|
10
|
+
even when a method holds syntax newer than the parser. Before, the
|
|
11
|
+
fallback ran on the whole file and kept the branch lines as written.
|
|
12
|
+
- A comma followed only by hidden `#if` lines before the closing brace is no
|
|
13
|
+
longer removed as a trailing comma, since in another view it separates
|
|
14
|
+
items. Files like this were skipped before; on ten open-source
|
|
15
|
+
repositories the default settings now skip 11 files instead of 14, and
|
|
16
|
+
`format_around` skips 2.
|
|
17
|
+
|
|
18
|
+
## [1.1.0] - 2026-10-17
|
|
19
|
+
|
|
20
|
+
- Files whose `#if` branches split a declaration or statement, such as a
|
|
21
|
+
class header with a different base list in each branch, are formatted
|
|
22
|
+
instead of refused. Each view of the file (a set of defined symbols) is
|
|
23
|
+
formatted on its own with the other branches set aside, so every branch
|
|
24
|
+
is formatted, and the result is checked through every view. On ten
|
|
25
|
+
open-source repositories this formats 94 of the 108 files that 1.0.0
|
|
26
|
+
skipped.
|
|
27
|
+
- A file that ends in a directive without a final line break, such as
|
|
28
|
+
`#pragma warning restore`, parses.
|
|
29
|
+
- A new setting, `syntax_errors = "format_around"`, formats files that hold
|
|
30
|
+
syntax newer than the parser, such as C# 14's null-conditional assignment
|
|
31
|
+
or the `#:` directives of file-based apps. The fewest lines the parser
|
|
32
|
+
cannot read are left as written, moved to the new indentation, and the
|
|
33
|
+
rest is formatted; the command line names the lines it kept. The default,
|
|
34
|
+
`skip_file`, leaves such files untouched as before.
|
|
35
|
+
- `format_details()` returns the formatted text with the lines left as
|
|
36
|
+
written.
|
|
37
|
+
|
|
5
38
|
## [1.0.0] - 2026-10-17
|
|
6
39
|
|
|
7
40
|
The first release: a complete formatter for C# files, projects and
|
|
@@ -322,9 +322,60 @@ On by default:
|
|
|
322
322
|
|
|
323
323
|
`--no-ignore` turns off both ignore files for one run.
|
|
324
324
|
|
|
325
|
+
## Conditional compilation
|
|
326
|
+
|
|
327
|
+
tree-sitter's C# grammar parses every `#if` branch as code. When the
|
|
328
|
+
branches together are valid C#, the file is formatted as a whole. When they
|
|
329
|
+
are not, because a declaration or statement is split between branches, the
|
|
330
|
+
file is formatted one view at a time (`conditional.py`):
|
|
331
|
+
|
|
332
|
+
1. A view is a set of defined symbols. Conditions are evaluated as the
|
|
333
|
+
compiler does (`!`, `&&`, `||`, `==`, `!=`, parentheses, `true`, `false`),
|
|
334
|
+
with `#define` and `#undef` honoured where they are compiled.
|
|
335
|
+
2. In a view, each directive line and each run of inactive lines is replaced
|
|
336
|
+
by a placeholder comment. What is left is the code the compiler sees, and
|
|
337
|
+
it is formatted normally, verification included. The placeholders then go
|
|
338
|
+
back to the text they stood for, exactly as written.
|
|
339
|
+
3. Views are tried simplest first (no symbols, each symbol alone, all, all
|
|
340
|
+
but one, at most 16) and kept when they parse and make a branch active
|
|
341
|
+
that no earlier view did, so every branch is formatted in its own view.
|
|
342
|
+
4. The result is checked through every view used: with the same lines set
|
|
343
|
+
aside, it must be the same code as the source. Otherwise the file is left
|
|
344
|
+
untouched.
|
|
345
|
+
|
|
346
|
+
In this mode no rewrite moves code across a directive: the namespace style
|
|
347
|
+
is left as it is, a using never moves past a directive, modifiers split by
|
|
348
|
+
one keep their order, and a comma with hidden lines between it and the
|
|
349
|
+
closing brace is not taken for a trailing comma.
|
|
350
|
+
|
|
351
|
+
With `syntax_errors = "format_around"` (below), a view that does not parse
|
|
352
|
+
is still used when hiding its fewest unreadable lines makes it parse: the
|
|
353
|
+
view is formatted around those lines, and the final check hides the same
|
|
354
|
+
lines, found by their text, in the view of the source and of the result.
|
|
355
|
+
|
|
356
|
+
## Code the parser cannot read
|
|
357
|
+
|
|
358
|
+
| Setting | Default | Alternatives |
|
|
359
|
+
| --- | --- | --- |
|
|
360
|
+
| `syntax_errors` | `skip_file`: a file that does not parse is reported and left untouched | `format_around` |
|
|
361
|
+
|
|
362
|
+
Syntax newer than the grammar, such as C# 14's null-conditional assignment
|
|
363
|
+
or the `#:` directives of file-based apps, does not parse. With
|
|
364
|
+
`format_around`, the formatter looks for the fewest whole lines whose removal
|
|
365
|
+
lets the file parse (`isolate.py`), trying the lines around each error in
|
|
366
|
+
turn. Those lines are hidden behind placeholder comments, the rest is
|
|
367
|
+
formatted and verified, and they go back exactly as written, moved to the
|
|
368
|
+
indentation their placeholder was printed at (unless they could hold a
|
|
369
|
+
multi-line string). Each hidden line must sit between the same two code
|
|
370
|
+
tokens before and after formatting, so the order of the code cannot change.
|
|
371
|
+
The command line names the lines left as written.
|
|
372
|
+
|
|
373
|
+
No more than half a file's lines are hidden, and some code must be left to
|
|
374
|
+
format; otherwise the file is skipped as before.
|
|
375
|
+
|
|
325
376
|
## Limits
|
|
326
377
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
378
|
+
A file still is not formatted when no view of its `#if` branches parses and,
|
|
379
|
+
with `format_around`, hiding lines makes neither a view nor the whole file
|
|
380
|
+
parse. Lines are hidden whole, so a one-line member that holds unreadable
|
|
381
|
+
syntax is kept as written in full.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: prettycsharp
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.1
|
|
4
4
|
Summary: An opinionated formatter for C#, in the spirit of Prettier
|
|
5
5
|
Project-URL: Homepage, https://github.com/WilliamSmithEdward/prettyCSharp
|
|
6
6
|
Project-URL: Repository, https://github.com/WilliamSmithEdward/prettyCSharp
|
|
@@ -147,10 +147,14 @@ and left untouched.
|
|
|
147
147
|
From Python:
|
|
148
148
|
|
|
149
149
|
```python
|
|
150
|
-
from prettycsharp import CSharpSyntaxError, FormattingError, Settings, format_source
|
|
150
|
+
from prettycsharp import CSharpSyntaxError, FormattingError, Settings, format_details, format_source
|
|
151
151
|
|
|
152
152
|
formatted = format_source(source)
|
|
153
153
|
narrow = format_source(source, Settings().with_values({"max_line_length": 100}))
|
|
154
|
+
|
|
155
|
+
# format_details also says which lines were left as written (format_around).
|
|
156
|
+
result = format_details(source, Settings().with_values({"syntax_errors": "format_around"}))
|
|
157
|
+
print(result.text, result.kept_lines)
|
|
154
158
|
```
|
|
155
159
|
|
|
156
160
|
## Settings
|
|
@@ -199,13 +203,42 @@ same words. If anything else differs, the file is not changed and the
|
|
|
199
203
|
command reports the difference. String literals, including verbatim, raw and
|
|
200
204
|
interpolated strings, are printed exactly as written.
|
|
201
205
|
|
|
202
|
-
##
|
|
206
|
+
## Conditional compilation
|
|
207
|
+
|
|
208
|
+
`#if` branches can split a declaration, as in:
|
|
209
|
+
|
|
210
|
+
```csharp
|
|
211
|
+
#if NET10_0_OR_GREATER
|
|
212
|
+
public sealed class Pool : IAsyncDisposable
|
|
213
|
+
#else
|
|
214
|
+
public sealed class Pool : IDisposable
|
|
215
|
+
#endif
|
|
216
|
+
{
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Such a file is formatted the way the compiler reads it, one set of defined
|
|
220
|
+
symbols at a time: the directive lines and the inactive branches are set
|
|
221
|
+
aside, the rest is formatted, and they are put back as written. Symbol sets
|
|
222
|
+
are chosen so that every branch is active in one of them, so every branch
|
|
223
|
+
gets formatted. The result is checked under each symbol set, and a file
|
|
224
|
+
where any branch would change in meaning is left untouched.
|
|
225
|
+
|
|
226
|
+
## Code the parser cannot read
|
|
227
|
+
|
|
228
|
+
prettycsharp reads C# through tree-sitter's C# grammar, and syntax newer
|
|
229
|
+
than the grammar, such as C# 14's null-conditional assignment, does not
|
|
230
|
+
parse. By default such a file is reported with its line and column and left
|
|
231
|
+
untouched. With `syntax_errors = "format_around"`, the formatter finds the
|
|
232
|
+
fewest lines it cannot read, leaves just those as written, formats the rest,
|
|
233
|
+
and names the lines it kept:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
prettycsharp format src/ -o syntax_errors=format_around
|
|
237
|
+
```
|
|
203
238
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
grammar (such as C# 14's null-conditional assignment). Such files are
|
|
208
|
-
reported with their line and column and left untouched.
|
|
239
|
+
This works together with conditional compilation: in a file split by `#if`,
|
|
240
|
+
each view is formatted around its own unreadable lines. A file is still left
|
|
241
|
+
untouched when hiding lines does not make it parse.
|
|
209
242
|
|
|
210
243
|
## License
|
|
211
244
|
|
|
@@ -112,10 +112,14 @@ and left untouched.
|
|
|
112
112
|
From Python:
|
|
113
113
|
|
|
114
114
|
```python
|
|
115
|
-
from prettycsharp import CSharpSyntaxError, FormattingError, Settings, format_source
|
|
115
|
+
from prettycsharp import CSharpSyntaxError, FormattingError, Settings, format_details, format_source
|
|
116
116
|
|
|
117
117
|
formatted = format_source(source)
|
|
118
118
|
narrow = format_source(source, Settings().with_values({"max_line_length": 100}))
|
|
119
|
+
|
|
120
|
+
# format_details also says which lines were left as written (format_around).
|
|
121
|
+
result = format_details(source, Settings().with_values({"syntax_errors": "format_around"}))
|
|
122
|
+
print(result.text, result.kept_lines)
|
|
119
123
|
```
|
|
120
124
|
|
|
121
125
|
## Settings
|
|
@@ -164,13 +168,42 @@ same words. If anything else differs, the file is not changed and the
|
|
|
164
168
|
command reports the difference. String literals, including verbatim, raw and
|
|
165
169
|
interpolated strings, are printed exactly as written.
|
|
166
170
|
|
|
167
|
-
##
|
|
171
|
+
## Conditional compilation
|
|
172
|
+
|
|
173
|
+
`#if` branches can split a declaration, as in:
|
|
174
|
+
|
|
175
|
+
```csharp
|
|
176
|
+
#if NET10_0_OR_GREATER
|
|
177
|
+
public sealed class Pool : IAsyncDisposable
|
|
178
|
+
#else
|
|
179
|
+
public sealed class Pool : IDisposable
|
|
180
|
+
#endif
|
|
181
|
+
{
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Such a file is formatted the way the compiler reads it, one set of defined
|
|
185
|
+
symbols at a time: the directive lines and the inactive branches are set
|
|
186
|
+
aside, the rest is formatted, and they are put back as written. Symbol sets
|
|
187
|
+
are chosen so that every branch is active in one of them, so every branch
|
|
188
|
+
gets formatted. The result is checked under each symbol set, and a file
|
|
189
|
+
where any branch would change in meaning is left untouched.
|
|
190
|
+
|
|
191
|
+
## Code the parser cannot read
|
|
192
|
+
|
|
193
|
+
prettycsharp reads C# through tree-sitter's C# grammar, and syntax newer
|
|
194
|
+
than the grammar, such as C# 14's null-conditional assignment, does not
|
|
195
|
+
parse. By default such a file is reported with its line and column and left
|
|
196
|
+
untouched. With `syntax_errors = "format_around"`, the formatter finds the
|
|
197
|
+
fewest lines it cannot read, leaves just those as written, formats the rest,
|
|
198
|
+
and names the lines it kept:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
prettycsharp format src/ -o syntax_errors=format_around
|
|
202
|
+
```
|
|
168
203
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
grammar (such as C# 14's null-conditional assignment). Such files are
|
|
173
|
-
reported with their line and column and left untouched.
|
|
204
|
+
This works together with conditional compilation: in a file split by `#if`,
|
|
205
|
+
each view is formatted around its own unreadable lines. A file is still left
|
|
206
|
+
untouched when hiding lines does not make it parse.
|
|
174
207
|
|
|
175
208
|
## License
|
|
176
209
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""An opinionated formatter for C#, in the spirit of Prettier."""
|
|
2
|
+
|
|
3
|
+
from prettycsharp.formatter import FormatResult, FormattingError, format_details, format_source
|
|
4
|
+
from prettycsharp.parsing import CSharpSyntaxError
|
|
5
|
+
from prettycsharp.settings import Settings, SettingsError
|
|
6
|
+
|
|
7
|
+
__version__ = "1.1.1"
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"CSharpSyntaxError",
|
|
11
|
+
"FormatResult",
|
|
12
|
+
"FormattingError",
|
|
13
|
+
"Settings",
|
|
14
|
+
"SettingsError",
|
|
15
|
+
"__version__",
|
|
16
|
+
"format_details",
|
|
17
|
+
"format_source",
|
|
18
|
+
]
|
|
@@ -25,7 +25,7 @@ from pathlib import Path
|
|
|
25
25
|
|
|
26
26
|
from prettycsharp import __version__, config, ignore, project
|
|
27
27
|
from prettycsharp.config import settings_for
|
|
28
|
-
from prettycsharp.formatter import FormattingError,
|
|
28
|
+
from prettycsharp.formatter import FormattingError, format_details
|
|
29
29
|
from prettycsharp.ignore import Ignorer
|
|
30
30
|
from prettycsharp.parsing import CSharpSyntaxError
|
|
31
31
|
from prettycsharp.project import compiled_files, lang_version_for, solution_projects
|
|
@@ -163,7 +163,12 @@ def _format_text(text: str, path: Path, settings: Settings) -> str:
|
|
|
163
163
|
"""Format text read from ``path``, keeping or changing its byte order mark."""
|
|
164
164
|
bom = _BOM if text.startswith(_BOM) else ""
|
|
165
165
|
lang = lang_version_for(path) if settings.lang_version == "auto" else None
|
|
166
|
-
|
|
166
|
+
result = format_details(text[len(bom) :], settings, lang_version=lang)
|
|
167
|
+
formatted = result.text
|
|
168
|
+
if result.kept_lines:
|
|
169
|
+
numbers = ", ".join(str(n) for n in result.kept_lines)
|
|
170
|
+
noun = "line" if len(result.kept_lines) == 1 else "lines"
|
|
171
|
+
print(f"{path}: {noun} {numbers} left as written; the parser cannot read them", file=sys.stderr)
|
|
167
172
|
if settings.charset == "utf-8-bom":
|
|
168
173
|
bom = _BOM
|
|
169
174
|
elif settings.charset == "utf-8":
|