In your editor¶
A WireWeaver API names its types in Rust: Fixed<Volt, Milli, i16>. That is exact, but it is not what you think while you read a trait. You think "millivolts, 16 bits, up to 32.767 V".
ww_lsp is a language server that writes that for you. It runs beside rust-analyzer and shows the exact_units type of each API item as an inlay hint, with the details on hover.
A prototype
ww_lsp is a prototype. It is not on crates.io yet, there are no releases, and what it does may change. This page shows what it does today.
Inlay hints¶
#[ww_trait]
pub trait Output {
property!(rw v_set: Fixed<Volt, Milli, i16>)mV · i16 · ±32.767 V;
property!(rw i_limit: Fixed<Ampere, Milli, u16, Range<0, 5000>>)mA · u16 · 0..5 A;
property!(rw ramp: Millis<u32>)ms · u32;
property!(rw trim: Q15)Q15 · −1..1;
property!(ro power: Fixed<Watt, Pow2<-8>, u32>, MeterError)UQ24.8 W;
stream!(i_out: Fixed<Ampere, Rational<1, 4096>, i16>)Q3.12 A · −8..8 A;
property!(ro+observe heatsink: Point<Celsius, Fixed<Kelvin, Centi, i16>>)°C;
}
ww_lsp hints on a bench power supply API.A hint reads: unit with its prefix, storage, and the range in the unit.
mV · i16 · ±32.767 V: millivolts in ani16. The range is all ofi16, so it is symmetric.mA · u16 · 0..5 A: theRange<0, 5000>bound shows as the range.Q15 · −1..1: a scale of \(2^{-n}\) on an integer is named as a Q format.UQ24.8 WandQ3.12 A: the same for other widths.°C: aPointshows its origin's symbol.
The aliases (Millis, Hz, Percent, Duty16, Bam16, Q15<U> and the others) are read as the types they are. A type ww_lsp does not know gets no hint.
Hover¶
Hover on a type to see the facts. For Fixed<Volt, Milli, i16>:
mV · i16 · ±32.767 V
- unit: Volt (V), kg·m²·s⁻³·A⁻¹
- scale: 10⁻³ (Milli), exact
- step: 0.001 V
- range: −32.768 ..= 32.767 V (Unbounded, -32768 ..= 32767 steps)
- storage: i16, 2 bytes on the wire
It gives:
- The unit, with its name and dimension.
- The exact scale. A rounded value is marked
≈. - The step, and the whole range to the last digit.
- The bounds.
- The storage and its size on the wire.
Every number comes from exact_units¶
ww_lsp has no table of its own for units and scales. It reads the unit symbols, dimensions, Magnitudes, storage limits and wire sizes from exact_units itself. When the crate changes, the hints change with it, and they cannot disagree with what the compiler does.
Install¶
You need a Rust toolchain. This builds ww_lsp from its repository and puts it in ~/.cargo/bin:
Or clone the repository and run just install in it.
Try it without an editor¶
ww_lsp prints the same analysis for a terminal. Give it any Rust file with a WireWeaver API:
ww_lsp hints my_api.rs # FILE:LINE:COL HINT (ITEM)
ww_lsp hover my_api.rs:30:25 # the hover text at a line and column
The repository has a bench power supply API to try, crates/ww_lsp_core/tests/fixtures/psu_api.rs.
Try it in an editor¶
The server is ww_lsp serve on stdin and stdout. Attach it to Rust files beside rust-analyzer and turn inlay hints on. Both servers stay attached to the buffer, so rust-analyzer is unchanged.
Neovim 0.11 and later:
vim.lsp.config('ww_lsp', {
cmd = { 'ww_lsp', 'serve' },
filetypes = { 'rust' },
root_markers = { 'Cargo.toml', '.git' },
})
vim.lsp.enable('ww_lsp')
vim.lsp.inlay_hint.enable(true)
Helix, in languages.toml:
[language-server.ww_lsp]
command = "ww_lsp"
args = ["serve"]
[[language]]
name = "rust"
language-servers = ["rust-analyzer", "ww_lsp"]
and display-inlay-hints = true under [editor.lsp] in config.toml.
Zed starts only servers that an extension registers, so ww_lsp comes with a small extension, editors/zed in its repository. It is not in Zed's registry yet. The README of ww_lsp has the steps for it and for older Neovim.
What it does not do yet¶
- It reads one file. Types from other files and crates, and aliases defined there, get no hint.
- While the file does not parse, in the middle of typing, the hints of the last good text stay.
- Chemical, photometric, radiation, counting and customary units get no hint yet.
- No diagnostics and no completion yet.