rich/protocol.rs
1//! Rendering & extension protocols.
2//!
3//! Port of upstream `rich/protocol.py` + `rich/abc.py` + the highlighter
4//! interface. **These traits are the sanctioned extension points of the port.**
5//! Extensions in `rich-ext` (and, later, third-party plugins) implement them;
6//! the faithful core only ever ships upstream's built-in implementations. See
7//! docs/PLUGINS.md.
8
9use crate::console::{Console, ConsoleOptions};
10use crate::measure::Measurement;
11use crate::segment::Segment;
12use crate::text::Text;
13
14/// Anything that can be rendered to a stream of [`Segment`]s within a width.
15///
16/// The Rust equivalent of upstream's `__rich_console__(console, options)`
17/// protocol. Implement it to make a custom type printable by [`Console`]. The
18/// `options` carry the available width (and, later, height/justify) the
19/// renderable must fit into. Newlines between lines are emitted as ordinary
20/// segments containing `\n`.
21pub trait Renderable {
22 fn rich_render(&self, console: &Console, options: &ConsoleOptions) -> Vec<Segment>;
23
24 /// The `(minimum, maximum)` cell width this renderable wants. The default
25 /// assumes the renderable fills the available width (e.g. `Panel`, `Table`);
26 /// `Text` overrides it with its content width so the top-level print path can
27 /// shrink to fit. Port of `__rich_measure__` / `Measurement.get`.
28 fn measure(&self, _console: &Console, options: &ConsoleOptions) -> Measurement {
29 Measurement::new(options.max_width, options.max_width)
30 }
31}
32
33/// Optional line-streaming extension point for renderables.
34///
35/// Mirrors the incremental consumption of upstream's rendering generators.
36/// Consumers can write each visual line immediately instead of collecting the
37/// complete segment stream. Implementations may still retain source data for
38/// measurement. This trait keeps streaming hooks out of inherent core APIs.
39pub trait LineRenderable: Renderable {
40 /// Emit styled visual lines without trailing newlines, stopping immediately
41 /// on the callback's first error. An empty segment represents a blank line;
42 /// calling the callback zero times represents no output.
43 fn try_for_each_line<E>(
44 &self,
45 console: &Console,
46 options: &ConsoleOptions,
47 emit: impl FnMut(Vec<Segment>) -> Result<(), E>,
48 ) -> Result<(), E>;
49}
50
51/// A transformer that adds style spans to [`Text`] (e.g. syntax/number/URL
52/// highlighting). The Rust equivalent of upstream's `Highlighter` ABC.
53///
54/// This is the primary *plugin* seam for the first slice: `rich-ext` registers
55/// [`Highlighter`]s onto a [`Console`] without the core knowing they exist.
56pub trait Highlighter {
57 /// Inspect `text` and apply any style spans in place.
58 fn highlight(&self, text: &mut Text);
59}