Skip to content

Commit eac03e9

Browse files
committed
Rewrite README for onboarding and NuGet image rendering
1 parent e88cbde commit eac03e9

1 file changed

Lines changed: 222 additions & 84 deletions

File tree

README.md

Lines changed: 222 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -3,133 +3,271 @@
33
[![CI](https://github.com/jonathanvdc/Pixie/actions/workflows/ci.yml/badge.svg)](https://github.com/jonathanvdc/Pixie/actions/workflows/ci.yml)
44
[![NuGet](https://img.shields.io/nuget/v/Pixie.svg)](https://www.nuget.org/packages/Pixie)
55

6-
Pixie is a C# library that prints beautifully formatted output to the console. You describe your layout using a high-level API and Pixie turns it into neatly-formatted text.
6+
Pixie is a C# library for building polished command-line applications. It gives you a high-level API for terminal output, diagnostics, help text, and GNU-style option parsing, then renders the best output your terminal can support.
77

8-
Essentially, Pixie is all about creating gorgeous console applications with minimal effort.
8+
Pixie is a good fit when you want to:
99

10-
Key features:
10+
* print structured, readable console output instead of hand-formatting strings,
11+
* show rich diagnostics with source context and caret highlights,
12+
* generate help output from the same option definitions you parse, and
13+
* keep CLI output readable across terminals with different Unicode and styling support.
1114

12-
* **Caret diagnostics.** Pixie has built-in support for caret diagnostics. Want to point out an error in source code? Pixie's really good at that. It highlights the error and colors both the highlighted text and the squiggle beneath it. Pixie also prints line numbers and even throws in a couple of lines of context.
15+
## Quick start
1316

14-
![Diagnostic](docs/img/caret.svg)
17+
Install Pixie:
1518

16-
* **Argument parsing.** In addition to formatting application output, Pixie can also parse command-line arguments.
19+
```sh
20+
dotnet add package Pixie
21+
```
1722

18-
When parsing command-line arguments, Pixie tries to go the extra mile and guide users toward correct program usage by spellchecking options and proactively printing option usage. Here's what that looks like in action.
23+
Then write and log a message:
1924

20-
![Option parsing feedback](docs/img/option-parsing-feedback.svg)
25+
```cs
26+
using Pixie;
27+
using Pixie.Terminal;
2128

22-
* **Help messages.** Help messages are wonderful for users but they're kind of tedious to write and maintain. Pixie generates them automatically from the same data that is used to parse command-line arguments.
23-
24-
Here's an excerpt from an example help message. The formatting, grouping and fancy Unicode characters are all automagically generated by Pixie.
29+
var log = TerminalLog.Acquire();
2530

26-
![Help message](docs/img/help-message.svg)
31+
log.Log(new LogEntry(
32+
Severity.Info,
33+
"Hello from Pixie."));
34+
```
2735

28-
* **Graceful degradation.** Pixie tries to make its output as pretty as your terminal will allow and degrades its output gracefully on terminal implementations that don't support all of Unicode.
29-
30-
For example, when rendered on `xterm` (a Unix terminal), this bulleted list item uses Unicode characters and ANSI control sequences:
36+
`TerminalLog.Acquire()` is the usual entry point for application output. In most applications, you should acquire a log once and reuse it.
3137

32-
![Fancy bullets](docs/img/degradation-fancy.svg)
38+
## Packages
3339

34-
The default Windows console doesn't support those features, so Pixie uses ASCII characters and the `System.Console` API there:
40+
Pixie is split into a small set of packages and assemblies:
3541

36-
![Simple bullets](docs/img/degradation-simple.svg)
42+
| Package | Purpose |
43+
| --- | --- |
44+
| [`Pixie`](https://www.nuget.org/packages/Pixie) | Core logging, markup, diagnostics, option parsing, and terminal integration. |
45+
| `Pixie.Terminal` | Terminal rendering types. This assembly ships with the `Pixie` package, so you usually do not install it separately. |
46+
| [`Pixie.Loyc`](https://www.nuget.org/packages/Pixie.Loyc) | Optional Loyc interoperability for translating Loyc diagnostics into Pixie output. |
3747

38-
* **Pretty output.** Pixie makes a real effort to produce good-looking output. It supports aligning and word-wrapping text. It also has built-in support for common types of messages, like diagnostics (errors, warnings, etc.) and help messages.
48+
Install Loyc support only if you need it:
3949

40-
To see why this is something you might want, just take a look at the formatting of `mcs`'s error message below. Note in particular how the word "suitable" is split up awkwardly.
50+
```sh
51+
dotnet add package Pixie.Loyc
52+
```
4153

42-
![Sad line break](docs/img/sad-line-break.svg)
54+
## What Pixie can do
4355

44-
Here's what that error message would have looked like if `mcs` used Pixie. Much better, right?
56+
### Caret diagnostics
4557

46-
![Happy line break](docs/img/happy-line-break.svg)
58+
Pixie has built-in support for caret diagnostics. It can highlight a source region, emphasize the most relevant span, and render line numbers with surrounding context.
4759

48-
* **Loyc interop.** Pixie can gracefully translate and log diagnostics produced by [Loyc](https://github.com/qwertie/ecsharp) libraries (including the EC# parser and LeMP). The optional Loyc interop logic is bundled in the `Pixie.Loyc` package, which can be installed in addition to the regular `Pixie` package.
60+
![Diagnostic](https://raw.githubusercontent.com/jonathanvdc/Pixie/main/docs/img/caret.svg)
4961

50-
Here's what a diagnostic produced by Loyc looks like after Pixie has translated it:
62+
### Argument parsing with feedback
5163

52-
![Loyc diagnostic](docs/img/loyc-interop.svg)
64+
Pixie can parse GNU-style command-line options and report mistakes in a user-friendly way, including usage guidance and option name suggestions.
5365

54-
* **Customization.** Pixie is customizable: you can easily configure the existing renderers and define your own markup elements and renderers.
66+
![Option parsing feedback](https://raw.githubusercontent.com/jonathanvdc/Pixie/main/docs/img/option-parsing-feedback.svg)
67+
68+
### Help messages
69+
70+
Pixie can generate help output from the same option definitions you use for parsing, so parsing and documentation stay in sync.
71+
72+
![Help message](https://raw.githubusercontent.com/jonathanvdc/Pixie/main/docs/img/help-message.svg)
73+
74+
### Graceful terminal degradation
75+
76+
Pixie tries to produce the nicest output your terminal can handle. When Unicode characters or ANSI styling are unavailable, it falls back to simpler representations instead of breaking formatting.
77+
78+
Unicode-rich rendering:
79+
80+
![Fancy bullets](https://raw.githubusercontent.com/jonathanvdc/Pixie/main/docs/img/degradation-fancy.svg)
81+
82+
Simpler fallback rendering:
83+
84+
![Simple bullets](https://raw.githubusercontent.com/jonathanvdc/Pixie/main/docs/img/degradation-simple.svg)
85+
86+
### Readable layout
87+
88+
Pixie supports alignment, wrapping, and reusable markup nodes for common CLI output patterns.
89+
90+
Without careful layout, terminal messages can become awkward:
91+
92+
![Sad line break](https://raw.githubusercontent.com/jonathanvdc/Pixie/main/docs/img/sad-line-break.svg)
93+
94+
With Pixie, the same message can be wrapped and structured more cleanly:
95+
96+
![Happy line break](https://raw.githubusercontent.com/jonathanvdc/Pixie/main/docs/img/happy-line-break.svg)
97+
98+
### Loyc interoperability
99+
100+
If you use Loyc libraries such as EC# or LeMP, `Pixie.Loyc` can translate their diagnostics into Pixie markup so they render consistently with the rest of your application output.
101+
102+
![Loyc diagnostic](https://raw.githubusercontent.com/jonathanvdc/Pixie/main/docs/img/loyc-interop.svg)
55103

56104
## Getting started
57105

58-
To use Pixie in one of your projects, simply install the [Pixie NuGet package](https://www.nuget.org/packages/Pixie) and start coding. Here are some basic first steps:
106+
### 1. Acquire a log
107+
108+
Pixie's main output abstraction is `ILog`. Logs accept `LogEntry` values, which are self-contained messages with a severity and a markup tree.
109+
110+
For terminal applications, `TerminalLog.Acquire()` is the usual choice:
111+
112+
```cs
113+
using Pixie.Terminal;
114+
115+
var log = TerminalLog.Acquire();
116+
```
117+
118+
### 2. Log a message
119+
120+
A `LogEntry` consists of a `Severity` and a `MarkupNode`. Plain strings can be used directly as markup, so the smallest useful example is:
121+
122+
```cs
123+
using Pixie;
124+
using Pixie.Terminal;
125+
126+
var log = TerminalLog.Acquire();
59127

60-
* **Acquiring a log.** Your application will probably want to send output to the terminal. Pixie's preferred abstraction for doing that is the `ILog`. All logs define a `void Log(LogEntry)` method, which sends a single, self-contained message to the log.
128+
log.Log(new LogEntry(
129+
Severity.Error,
130+
"Something went wrong."));
131+
```
61132

62-
There are many log implementations, but you probably want a log that sends messages straight to the terminal. You can acquire one of those like so:
133+
If you want explicit markup nodes, use types from `Pixie.Markup`, such as `Text`, `Sequence`, `BulletedList`, or `HighlightedSource`.
63134

64-
```cs
65-
using Pixie.Terminal;
66-
// ...
67-
var log = TerminalLog.Acquire();
68-
```
135+
### 3. Parse command-line arguments
69136

70-
> **Pro tip:** acquiring a log is something you want to do only once, for concurrency and performance reasons.
137+
Pixie includes GNU-style option parsing. You define options once, then parse arguments and read back typed values.
71138

72-
* **Logging messages.** As stated before, a `LogEntry` is a self-contained message that can be sent to any log. It consists of a `Severity` (which can be either `Error`, `Warning`, `Message` or `Info`) and a `MarkupNode`. The latter is essentially a description of what you want the user to see.
139+
```cs
140+
using Pixie;
141+
using Pixie.Options;
142+
using Pixie.Terminal;
73143

74-
A `MarkupNode` implementation can be anything ranging from a lowly text message to a full-blown caret diagnostic. In this example, we'll just log a text message. Those can be created by calling `new Text("message")` or by implicitly converting a `string` to a `MarkupNode`.
144+
var log = TerminalLog.Acquire();
75145

76-
Putting it all together:
146+
var helpFlag = FlagOption.CreateFlagOption(
147+
OptionForm.Short("h"),
148+
OptionForm.Long("help"));
77149

78-
```cs
79-
using Pixie;
80-
using Pixie.Markup;
81-
// ...
82-
log.Log(
83-
new LogEntry(
84-
Severity.Error,
85-
new Text("Something went horribly wrong.")));
86-
```
150+
var filesOption = SequenceOption.CreateStringOption(
151+
OptionForm.Long("files"));
87152

88-
* **Parsing command-line arguments.** Pixie's approach to parsing command-line arguments is pretty standard. You define a set of options and then use those to parse command-line arguments.
153+
var parser = new GnuOptionSetParser(
154+
new Option[] { helpFlag },
155+
filesOption);
89156

90-
```cs
91-
using Pixie.Options;
92-
// ...
93-
// Define a --help/-h flag option.
94-
var helpFlag = FlagOption.CreateFlagOption(
95-
OptionForm.Short("h"),
96-
OptionForm.Long("help"));
157+
var parsedArgs = parser.Parse(new[] { "input.cs", "-h" }, log);
97158

98-
// Define a pseudo-option for positional arguments.
99-
var filesOption = SequenceOption.CreateStringOption(
100-
OptionForm.Long("files"));
159+
bool showHelp = parsedArgs.GetValue<bool>(helpFlag);
160+
string[] files = parsedArgs.GetValue<string[]>(filesOption);
161+
```
101162

102-
// Create a parser for GNU-style command-line arguments.
103-
var parser = new GnuOptionSetParser(
104-
new Option[] { helpFlag }, // <-- options
105-
filesOption); // <-- pseudo-option for positional arguments
163+
When parsing fails, Pixie can report errors to the log instead of leaving formatting and recovery entirely up to the application.
106164

107-
// Parse command-line arguments. The parser automatically
108-
// recovers from errors and sends error messages to `log`.
109-
var parsedArgs = parser.Parse(new[] { "hi", "-h" }, log);
165+
### 4. Document options and generate help
110166

111-
// Recover parsed arguments.
112-
bool showHelp = parsedArgs.GetValue<bool>(helpFlag);
113-
string[] files = parsedArgs.GetValue<string[]>(filesOption);
114-
```
167+
Options can carry categories, descriptions, and parameter metadata. That same information can then be used to generate help output.
115168

116-
* **Documenting options.** Adding documentation to your options is easy. Just call `WithCategory`, `WithDescription` and/or `WithParameters` on the options you'd like to document.
169+
```cs
170+
using Pixie.Markup;
171+
using Pixie.Options;
117172

118-
For example, here's how to document the `-x` option from `gcc` and `clang`.
173+
var xOption = SequenceOption.CreateStringOption(OptionForm.Short("x"))
174+
.WithCategory("Input and output")
175+
.WithDescription(
176+
"Specify explicitly the language for the following input files.")
177+
.WithParameters(
178+
new SymbolicOptionParameter("language"),
179+
new SymbolicOptionParameter("file", true));
119180

120-
```cs
121-
xOption = SequenceOption.CreateStringOption(OptionForm.Short("x"))
122-
.WithCategory("Input and output")
123-
.WithDescription(
124-
"Specify explicitly the language for the " +
125-
"following input files.")
126-
.WithParameters(
127-
new SymbolicOptionParameter("language"), // <-- not varargs
128-
new SymbolicOptionParameter("file", true)); // <-- varargs
129-
```
181+
var help = new HelpMessage(
182+
"An example application built with Pixie.",
183+
"example [files-or-options]",
184+
new Option[] { xOption });
185+
```
186+
187+
To see a more complete example, check [Examples/PrintHelp/Program.cs](Examples/PrintHelp/Program.cs).
188+
189+
### 5. Render rich diagnostics
190+
191+
Pixie's diagnostic model is especially useful when you already know the source span you want to highlight.
192+
193+
```cs
194+
using Pixie;
195+
using Pixie.Code;
196+
using Pixie.Markup;
197+
using Pixie.Terminal;
198+
199+
var log = TerminalLog.Acquire();
200+
201+
const string source = "public static class Program\n{\n public Program()\n { }\n}";
202+
var document = new StringDocument("code.cs", source);
203+
var nameOffset = source.IndexOf("Program()");
204+
205+
var focusRegion = new SourceRegion(
206+
new SourceSpan(document, nameOffset, "Program".Length));
207+
208+
log.Log(new LogEntry(
209+
Severity.Error,
210+
new HighlightedSource(focusRegion, focusRegion)));
211+
```
212+
213+
For a fuller version with transforms and custom renderer configuration, see [Examples/CaretDiagnostics/Program.cs](Examples/CaretDiagnostics/Program.cs).
214+
215+
## Examples
216+
217+
The repository includes small example programs you can run directly:
218+
219+
```sh
220+
dotnet run --project Examples/PrintHelp/PrintHelp.csproj
221+
dotnet run --project Examples/ParseOptions/ParseOptions.csproj -- --helo file.cs
222+
dotnet run --project Examples/CaretDiagnostics/CaretDiagnostics.csproj
223+
```
224+
225+
Other examples live in [`Examples/`](Examples).
226+
227+
## Building and testing
228+
229+
Build the solution:
230+
231+
```sh
232+
dotnet build Pixie.sln
233+
```
234+
235+
Run the test suite:
236+
237+
```sh
238+
dotnet test Tests/Tests.csproj
239+
```
240+
241+
## Repository layout
242+
243+
| Path | Contents |
244+
| --- | --- |
245+
| [`Pixie/`](Pixie) | Core library: logs, markup nodes, diagnostics, options, and transforms. |
246+
| [`Pixie.Terminal/`](Pixie.Terminal) | Terminal rendering and device-specific behavior. |
247+
| [`Pixie.Loyc/`](Pixie.Loyc) | Loyc interoperability layer. |
248+
| [`Examples/`](Examples) | Small runnable sample applications. |
249+
| [`Tests/`](Tests) | NUnit test suite. |
250+
| [`docs/img/`](docs/img) | SVG assets used in this README. |
251+
252+
## Customization
253+
254+
Pixie is designed to be extensible. You can:
255+
256+
* compose markup trees from reusable node types,
257+
* configure or replace renderers,
258+
* wrap logs in transforms, and
259+
* define your own markup elements and rendering behavior.
260+
261+
The examples in [Examples/CaretDiagnostics/Program.cs](Examples/CaretDiagnostics/Program.cs) and [Examples/ParseOptions/Program.cs](Examples/ParseOptions/Program.cs) show some of that flexibility in practice.
130262

131263
## Contributing
132264

133-
Thank you so much for considering to contribute! Feel free to fork the Pixie repository and send me a pull request&mdash;I'd love to merge it in! It'd also be nice if you opened an issue beforehand so we can talk about your wonderful new feature.
265+
Issues, questions, and pull requests are all welcome.
266+
267+
If you want to contribute code:
268+
269+
1. Open an issue first for larger changes so the direction is clear.
270+
2. Build the solution with `dotnet build Pixie.sln`.
271+
3. Run tests with `dotnet test Tests/Tests.csproj`.
134272

135-
Alternatively, if you think you found a bug or just have a question about Pixie: open an issue.
273+
Bug reports and usage questions are also welcome in the issue tracker.

0 commit comments

Comments
 (0)