Skip to content

Commit a0120b0

Browse files
committed
docs: Effect-first README with install and API reference
Leads with the Effect angle — the gap this plugin fills in the nvim ecosystem is turning `Effect<A, E, R>` assignability errors from unreadable one-line tooltips into channel-aware diff boxes. Documents: - Motivating example (the Missing Services box) - Feature list split into Effect-specific and general TS sections - lazy.nvim install recipe + manual wiring snippet - Integration snippet for tiny-inline-diagnostic - Config options table - Public API reference - Extension example via `extra_patterns` - How to run the tests locally
1 parent b24e980 commit a0120b0

1 file changed

Lines changed: 158 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# effect-error-pretty.nvim
2+
3+
Effect-first TypeScript diagnostic formatter for Neovim. Turns walls of `Effect<A, E, R>` assignability errors into something you can actually read — with dedicated handling for the Effect ecosystem's pain points.
4+
5+
TypeScript errors in general also get the treatment, but Effect is the headline act.
6+
7+
## Why
8+
9+
When you're learning Effect, half the type errors look like this:
10+
11+
```
12+
Type 'Effect<void, DbError, Database | Logger>' is not assignable to type 'Effect<void, DbError, never>'.
13+
```
14+
15+
VSCode and Zed render that as one wrapped line in a tooltip. The actual information — "you forgot to provide `Database | Logger`" — is buried.
16+
17+
This plugin parses the error, figures out which channel (A, E, or R) actually diverged, and renders:
18+
19+
```
20+
╭─ ◈ Effect — Missing Services
21+
│
22+
│ ◈ Forgot to provide: Database | Logger
23+
│ ⚡ Hint: .pipe(Effect.provide(SomeLayer))
24+
│
25+
│ Got: Effect<void, DbError, Database | Logger>
26+
│ Expected: Effect<void, DbError, never>
27+
╰─
28+
```
29+
30+
## Features
31+
32+
**Effect-specific**
33+
- `Effect<A, E, R>` / `Effect.Effect<A, E, R>` / `Stream<A, E, R>` / `Layer<ROut, E, RIn>` — all parsed, channel-labeled, and diffed
34+
- **Missing services** (forgot `Effect.provide`) — compact box naming the exact services
35+
- **Unhandled errors** (forgot `Effect.catchAll` / `catchTags` / `orDie`) — compact box listing the leftover `E` members
36+
- **Wrong success type** — compact box with Got/Expected for `A` (or `ROut` for Layer)
37+
- **Scope-required** — detects `Scope` in got.R and suggests `Effect.scoped`
38+
- **`Context.Tag<"Id", Service>` unwrapping** — shows just the service name in diffs
39+
- **`YieldWrap<...>` unwrapping** — Effect.gen yields render as plain Effect mismatches
40+
- **Short signatures** — `Effect<A>` and `Effect<A, E>` default missing params to `never`
41+
- **Multi-channel view** — falls back to a full tri-channel table when 2+ channels diverge
42+
- **Type signature at the bottom** of every compact box so you see the full `Effect<...>` context
43+
44+
**General TypeScript**
45+
- Type mismatches (TS2322 / TS2345) with multi-line wrapping for big types
46+
- Missing property (TS2741), Unknown property (TS2339)
47+
- Cannot find name / module / exported member (TS2304 / TS2307 / TS2305)
48+
- Implicit any (TS7006), Uninitialized variable (TS2454), Nullish (TS2531 / TS18048)
49+
- Argument count (TS2554), Const reassignment, Not callable (TS2349)
50+
- Deprecated symbol messages
51+
- Optional fallback to [`format-ts-errors`](https://www.npmjs.com/package/@0no-co/format-ts-errors) when no pattern matches
52+
53+
## Install
54+
55+
Requires Neovim 0.10+.
56+
57+
### lazy.nvim
58+
59+
```lua
60+
{
61+
"rashedInt32/effect-error-pretty.nvim",
62+
event = { "BufReadPre", "BufNewFile" },
63+
opts = {
64+
float = true, -- auto-patch vim.diagnostic.config.float.format
65+
effect = true,
66+
format_ts_errors_fallback = true,
67+
},
68+
}
69+
```
70+
71+
### Manual wiring
72+
73+
If you manage `vim.diagnostic.config` yourself, don't set `float = true`. Call the formatter directly:
74+
75+
```lua
76+
local pretty = require("effect-error-pretty")
77+
pretty.setup({ effect = true })
78+
79+
vim.diagnostic.config({
80+
float = {
81+
format = function(diagnostic)
82+
return pretty.float_format(diagnostic) or diagnostic.message
83+
end,
84+
},
85+
})
86+
```
87+
88+
### tiny-inline-diagnostic.nvim
89+
90+
```lua
91+
{
92+
"rachartier/tiny-inline-diagnostic.nvim",
93+
opts = {
94+
options = {
95+
format = function(diagnostic)
96+
return require("effect-error-pretty").inline_format(diagnostic) or diagnostic.message
97+
end,
98+
},
99+
},
100+
}
101+
```
102+
103+
## Options
104+
105+
| Option | Default | Description |
106+
|------------------------------|---------|-----------------------------------------------------------------------------------------------------------|
107+
| `effect` | `true` | Recognize `Effect` / `Stream` / `Layer` mismatches as first-class. |
108+
| `float` | `false` | Automatically patch `vim.diagnostic.config.float.format` on `setup()`. |
109+
| `sources` | `{ typescript=true, ts=true, vtsls=true }` | Diagnostic sources this plugin handles. Exact match only. |
110+
| `format_ts_errors_fallback` | `true` | When no pattern matches, try `format-ts-errors` if installed. |
111+
| `extra_patterns` | `nil` | List of `function(msg) -> {kind, ...}` parsers run after builtins. Let you add custom shapes. |
112+
113+
## Public API
114+
115+
```lua
116+
local pretty = require("effect-error-pretty")
117+
118+
-- Float box (multi-line) — returns nil if unhandled; caller should fall back.
119+
pretty.float_format(diagnostic)
120+
121+
-- Inline one-line — returns nil if unhandled.
122+
pretty.inline_format(diagnostic)
123+
124+
-- Low-level: parse a raw TS diagnostic message into a structured kind.
125+
-- Returns nil if no pattern matched.
126+
require("effect-error-pretty.parse").parse(message, { effect = true })
127+
```
128+
129+
## Extending
130+
131+
Add a parser for a custom rule you care about:
132+
133+
```lua
134+
require("effect-error-pretty").setup({
135+
extra_patterns = {
136+
function(msg)
137+
local rule = msg:match("^eslint%-plugin%-effect: (.+)$")
138+
if rule then
139+
return { kind = "custom_lint", rule = rule }
140+
end
141+
end,
142+
},
143+
})
144+
```
145+
146+
Render logic for custom `kind`s isn't wired in yet — for now, `parse()` returns the structured result and you render it yourself. If there's demand, we'll expose a renderer registry.
147+
148+
## Tests
149+
150+
```sh
151+
nvim --headless -c "PlenaryBustedDirectory tests/" -c "qa!"
152+
```
153+
154+
Requires [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) on the runtimepath.
155+
156+
## License
157+
158+
MIT

0 commit comments

Comments
 (0)