Skip to main content

StreamLineRenderer

Struct StreamLineRenderer 

Source
pub struct StreamLineRenderer { /* private fields */ }
Expand description

Incremental renderer for a single mutable line without terminal width assumptions.

This renderer avoids absolute cursor positioning. It assumes each emitted patch is written to the same terminal line and the cursor remains at the end of the previously rendered line.

Implementations§

Source§

impl StreamLineRenderer

Source

pub fn new() -> Self

Creates a line renderer with truecolor output.

Examples found in repository?
examples/stream_line_bridge.rs (line 149)
132fn main() -> Result<(), Box<dyn Error>> {
133    let args: Vec<String> = env::args().collect();
134    let options = match parse_args(&args) {
135        Ok(options) => options,
136        Err(err) => {
137            eprintln!("invalid arguments: {err}");
138            eprintln!();
139            print_usage();
140            return Ok(());
141        }
142    };
143
144    let grammar =
145        parse_grammar(&options.grammar_name).map_err(|msg| format!("invalid grammar: {msg}"))?;
146    let source = fs::read(&options.source_path)?;
147    let theme = load_theme(&options.theme_name)?;
148    let mut highlighter = SpanHighlighter::new()?;
149    let mut renderer = StreamLineRenderer::new();
150    renderer.set_color_mode(options.color_mode);
151    renderer.set_preserve_terminal_background(options.preserve_terminal_background);
152
153    if let Some(previous_source_path) = &options.previous_source_path {
154        let previous_source = fs::read(previous_source_path)?;
155        let _ = renderer.highlight_line_to_patch(
156            &mut highlighter,
157            &previous_source,
158            grammar,
159            &theme,
160        )?;
161    }
162
163    let patch = renderer.highlight_line_to_patch(&mut highlighter, &source, grammar, &theme)?;
164    print!("{patch}");
165    io::stdout().flush()?;
166
167    Ok(())
168}
More examples
Hide additional examples
examples/vt_patch_bridge.rs (line 328)
276fn main() -> Result<(), Box<dyn Error>> {
277    let args: Vec<String> = env::args().collect();
278    let options = match parse_args(&args) {
279        Ok(options) => options,
280        Err(err) => {
281            eprintln!("invalid arguments: {err}");
282            eprintln!();
283            print_usage();
284            return Ok(());
285        }
286    };
287
288    let grammar =
289        parse_grammar(&options.grammar_name).map_err(|msg| format!("invalid grammar: {msg}"))?;
290    let source = fs::read(&options.source_path)?;
291    let previous_source = if let Some(previous_source_path) = &options.previous_source_path {
292        Some(fs::read(previous_source_path)?)
293    } else {
294        None
295    };
296    let theme = load_theme(&options.theme_name)?;
297    let mut highlighter = SpanHighlighter::new()?;
298
299    let patch = if let Some(origin_row) = options.origin_row {
300        let mut renderer = IncrementalRenderer::new(options.width, options.height);
301        renderer.set_origin(origin_row, options.origin_col);
302        renderer.set_color_mode(options.color_mode);
303        renderer.set_preserve_terminal_background(options.preserve_terminal_background);
304
305        if let Some(previous_source) = previous_source.as_deref() {
306            let _ =
307                renderer.highlight_to_patch(&mut highlighter, previous_source, grammar, &theme)?;
308        }
309
310        renderer.highlight_to_patch(&mut highlighter, &source, grammar, &theme)?
311    } else {
312        let source_is_multiline = source.contains(&b'\n');
313        let previous_is_multiline = previous_source
314            .as_ref()
315            .is_some_and(|snapshot| snapshot.contains(&b'\n'));
316
317        if source_is_multiline || previous_is_multiline {
318            let rendered = highlight_to_ansi_with_highlighter_and_mode_and_background(
319                &mut highlighter,
320                &source,
321                grammar,
322                &theme,
323                options.color_mode,
324                options.preserve_terminal_background,
325            )?;
326            build_full_rerender_patch(rendered, previous_source.as_deref())
327        } else {
328            let mut renderer = StreamLineRenderer::new();
329            renderer.set_color_mode(options.color_mode);
330            renderer.set_preserve_terminal_background(options.preserve_terminal_background);
331
332            if let Some(previous_source) = previous_source.as_deref() {
333                let _ = renderer
334                    .highlight_line_to_patch(&mut highlighter, previous_source, grammar, &theme)
335                    .map_err(streamline_mode_error)?;
336            }
337
338            renderer
339                .highlight_line_to_patch(&mut highlighter, &source, grammar, &theme)
340                .map_err(streamline_mode_error)?
341        }
342    };
343
344    print!("{patch}");
345    io::stdout().flush()?;
346
347    Ok(())
348}
Source

pub fn clear_state(&mut self)

Clears prior line state.

Source

pub fn set_color_mode(&mut self, color_mode: ColorMode)

Sets the ANSI color mode used by this renderer.

Examples found in repository?
examples/stream_line_bridge.rs (line 150)
132fn main() -> Result<(), Box<dyn Error>> {
133    let args: Vec<String> = env::args().collect();
134    let options = match parse_args(&args) {
135        Ok(options) => options,
136        Err(err) => {
137            eprintln!("invalid arguments: {err}");
138            eprintln!();
139            print_usage();
140            return Ok(());
141        }
142    };
143
144    let grammar =
145        parse_grammar(&options.grammar_name).map_err(|msg| format!("invalid grammar: {msg}"))?;
146    let source = fs::read(&options.source_path)?;
147    let theme = load_theme(&options.theme_name)?;
148    let mut highlighter = SpanHighlighter::new()?;
149    let mut renderer = StreamLineRenderer::new();
150    renderer.set_color_mode(options.color_mode);
151    renderer.set_preserve_terminal_background(options.preserve_terminal_background);
152
153    if let Some(previous_source_path) = &options.previous_source_path {
154        let previous_source = fs::read(previous_source_path)?;
155        let _ = renderer.highlight_line_to_patch(
156            &mut highlighter,
157            &previous_source,
158            grammar,
159            &theme,
160        )?;
161    }
162
163    let patch = renderer.highlight_line_to_patch(&mut highlighter, &source, grammar, &theme)?;
164    print!("{patch}");
165    io::stdout().flush()?;
166
167    Ok(())
168}
More examples
Hide additional examples
examples/vt_patch_bridge.rs (line 329)
276fn main() -> Result<(), Box<dyn Error>> {
277    let args: Vec<String> = env::args().collect();
278    let options = match parse_args(&args) {
279        Ok(options) => options,
280        Err(err) => {
281            eprintln!("invalid arguments: {err}");
282            eprintln!();
283            print_usage();
284            return Ok(());
285        }
286    };
287
288    let grammar =
289        parse_grammar(&options.grammar_name).map_err(|msg| format!("invalid grammar: {msg}"))?;
290    let source = fs::read(&options.source_path)?;
291    let previous_source = if let Some(previous_source_path) = &options.previous_source_path {
292        Some(fs::read(previous_source_path)?)
293    } else {
294        None
295    };
296    let theme = load_theme(&options.theme_name)?;
297    let mut highlighter = SpanHighlighter::new()?;
298
299    let patch = if let Some(origin_row) = options.origin_row {
300        let mut renderer = IncrementalRenderer::new(options.width, options.height);
301        renderer.set_origin(origin_row, options.origin_col);
302        renderer.set_color_mode(options.color_mode);
303        renderer.set_preserve_terminal_background(options.preserve_terminal_background);
304
305        if let Some(previous_source) = previous_source.as_deref() {
306            let _ =
307                renderer.highlight_to_patch(&mut highlighter, previous_source, grammar, &theme)?;
308        }
309
310        renderer.highlight_to_patch(&mut highlighter, &source, grammar, &theme)?
311    } else {
312        let source_is_multiline = source.contains(&b'\n');
313        let previous_is_multiline = previous_source
314            .as_ref()
315            .is_some_and(|snapshot| snapshot.contains(&b'\n'));
316
317        if source_is_multiline || previous_is_multiline {
318            let rendered = highlight_to_ansi_with_highlighter_and_mode_and_background(
319                &mut highlighter,
320                &source,
321                grammar,
322                &theme,
323                options.color_mode,
324                options.preserve_terminal_background,
325            )?;
326            build_full_rerender_patch(rendered, previous_source.as_deref())
327        } else {
328            let mut renderer = StreamLineRenderer::new();
329            renderer.set_color_mode(options.color_mode);
330            renderer.set_preserve_terminal_background(options.preserve_terminal_background);
331
332            if let Some(previous_source) = previous_source.as_deref() {
333                let _ = renderer
334                    .highlight_line_to_patch(&mut highlighter, previous_source, grammar, &theme)
335                    .map_err(streamline_mode_error)?;
336            }
337
338            renderer
339                .highlight_line_to_patch(&mut highlighter, &source, grammar, &theme)
340                .map_err(streamline_mode_error)?
341        }
342    };
343
344    print!("{patch}");
345    io::stdout().flush()?;
346
347    Ok(())
348}
Source

pub fn color_mode(&self) -> ColorMode

Returns the current ANSI color mode.

Source

pub fn set_preserve_terminal_background( &mut self, preserve_terminal_background: bool, )

Controls whether ANSI rendering preserves the terminal’s existing background.

When set to true (default), background colors from the theme are ignored. When set to false, background colors from resolved theme styles are emitted.

Examples found in repository?
examples/stream_line_bridge.rs (line 151)
132fn main() -> Result<(), Box<dyn Error>> {
133    let args: Vec<String> = env::args().collect();
134    let options = match parse_args(&args) {
135        Ok(options) => options,
136        Err(err) => {
137            eprintln!("invalid arguments: {err}");
138            eprintln!();
139            print_usage();
140            return Ok(());
141        }
142    };
143
144    let grammar =
145        parse_grammar(&options.grammar_name).map_err(|msg| format!("invalid grammar: {msg}"))?;
146    let source = fs::read(&options.source_path)?;
147    let theme = load_theme(&options.theme_name)?;
148    let mut highlighter = SpanHighlighter::new()?;
149    let mut renderer = StreamLineRenderer::new();
150    renderer.set_color_mode(options.color_mode);
151    renderer.set_preserve_terminal_background(options.preserve_terminal_background);
152
153    if let Some(previous_source_path) = &options.previous_source_path {
154        let previous_source = fs::read(previous_source_path)?;
155        let _ = renderer.highlight_line_to_patch(
156            &mut highlighter,
157            &previous_source,
158            grammar,
159            &theme,
160        )?;
161    }
162
163    let patch = renderer.highlight_line_to_patch(&mut highlighter, &source, grammar, &theme)?;
164    print!("{patch}");
165    io::stdout().flush()?;
166
167    Ok(())
168}
More examples
Hide additional examples
examples/vt_patch_bridge.rs (line 330)
276fn main() -> Result<(), Box<dyn Error>> {
277    let args: Vec<String> = env::args().collect();
278    let options = match parse_args(&args) {
279        Ok(options) => options,
280        Err(err) => {
281            eprintln!("invalid arguments: {err}");
282            eprintln!();
283            print_usage();
284            return Ok(());
285        }
286    };
287
288    let grammar =
289        parse_grammar(&options.grammar_name).map_err(|msg| format!("invalid grammar: {msg}"))?;
290    let source = fs::read(&options.source_path)?;
291    let previous_source = if let Some(previous_source_path) = &options.previous_source_path {
292        Some(fs::read(previous_source_path)?)
293    } else {
294        None
295    };
296    let theme = load_theme(&options.theme_name)?;
297    let mut highlighter = SpanHighlighter::new()?;
298
299    let patch = if let Some(origin_row) = options.origin_row {
300        let mut renderer = IncrementalRenderer::new(options.width, options.height);
301        renderer.set_origin(origin_row, options.origin_col);
302        renderer.set_color_mode(options.color_mode);
303        renderer.set_preserve_terminal_background(options.preserve_terminal_background);
304
305        if let Some(previous_source) = previous_source.as_deref() {
306            let _ =
307                renderer.highlight_to_patch(&mut highlighter, previous_source, grammar, &theme)?;
308        }
309
310        renderer.highlight_to_patch(&mut highlighter, &source, grammar, &theme)?
311    } else {
312        let source_is_multiline = source.contains(&b'\n');
313        let previous_is_multiline = previous_source
314            .as_ref()
315            .is_some_and(|snapshot| snapshot.contains(&b'\n'));
316
317        if source_is_multiline || previous_is_multiline {
318            let rendered = highlight_to_ansi_with_highlighter_and_mode_and_background(
319                &mut highlighter,
320                &source,
321                grammar,
322                &theme,
323                options.color_mode,
324                options.preserve_terminal_background,
325            )?;
326            build_full_rerender_patch(rendered, previous_source.as_deref())
327        } else {
328            let mut renderer = StreamLineRenderer::new();
329            renderer.set_color_mode(options.color_mode);
330            renderer.set_preserve_terminal_background(options.preserve_terminal_background);
331
332            if let Some(previous_source) = previous_source.as_deref() {
333                let _ = renderer
334                    .highlight_line_to_patch(&mut highlighter, previous_source, grammar, &theme)
335                    .map_err(streamline_mode_error)?;
336            }
337
338            renderer
339                .highlight_line_to_patch(&mut highlighter, &source, grammar, &theme)
340                .map_err(streamline_mode_error)?
341        }
342    };
343
344    print!("{patch}");
345    io::stdout().flush()?;
346
347    Ok(())
348}
Source

pub fn preserve_terminal_background(&self) -> bool

Returns whether terminal background passthrough is enabled.

Source

pub fn render_line_patch( &mut self, source: &[u8], spans: &[StyledSpan], ) -> Result<String, RenderError>

Renders a width-independent patch for a single line.

§Errors

Returns an error when spans are invalid or input contains a newline.

Source

pub fn highlight_line_to_patch( &mut self, highlighter: &mut SpanHighlighter, source: &[u8], flavor: Grammar, theme: &Theme, ) -> Result<String, RenderError>

Runs highlight + theme resolution + stream-safe single-line diff.

§Errors

Returns an error if highlighting fails, spans are invalid, or input has newlines.

Examples found in repository?
examples/stream_line_bridge.rs (lines 155-160)
132fn main() -> Result<(), Box<dyn Error>> {
133    let args: Vec<String> = env::args().collect();
134    let options = match parse_args(&args) {
135        Ok(options) => options,
136        Err(err) => {
137            eprintln!("invalid arguments: {err}");
138            eprintln!();
139            print_usage();
140            return Ok(());
141        }
142    };
143
144    let grammar =
145        parse_grammar(&options.grammar_name).map_err(|msg| format!("invalid grammar: {msg}"))?;
146    let source = fs::read(&options.source_path)?;
147    let theme = load_theme(&options.theme_name)?;
148    let mut highlighter = SpanHighlighter::new()?;
149    let mut renderer = StreamLineRenderer::new();
150    renderer.set_color_mode(options.color_mode);
151    renderer.set_preserve_terminal_background(options.preserve_terminal_background);
152
153    if let Some(previous_source_path) = &options.previous_source_path {
154        let previous_source = fs::read(previous_source_path)?;
155        let _ = renderer.highlight_line_to_patch(
156            &mut highlighter,
157            &previous_source,
158            grammar,
159            &theme,
160        )?;
161    }
162
163    let patch = renderer.highlight_line_to_patch(&mut highlighter, &source, grammar, &theme)?;
164    print!("{patch}");
165    io::stdout().flush()?;
166
167    Ok(())
168}
More examples
Hide additional examples
examples/vt_patch_bridge.rs (line 334)
276fn main() -> Result<(), Box<dyn Error>> {
277    let args: Vec<String> = env::args().collect();
278    let options = match parse_args(&args) {
279        Ok(options) => options,
280        Err(err) => {
281            eprintln!("invalid arguments: {err}");
282            eprintln!();
283            print_usage();
284            return Ok(());
285        }
286    };
287
288    let grammar =
289        parse_grammar(&options.grammar_name).map_err(|msg| format!("invalid grammar: {msg}"))?;
290    let source = fs::read(&options.source_path)?;
291    let previous_source = if let Some(previous_source_path) = &options.previous_source_path {
292        Some(fs::read(previous_source_path)?)
293    } else {
294        None
295    };
296    let theme = load_theme(&options.theme_name)?;
297    let mut highlighter = SpanHighlighter::new()?;
298
299    let patch = if let Some(origin_row) = options.origin_row {
300        let mut renderer = IncrementalRenderer::new(options.width, options.height);
301        renderer.set_origin(origin_row, options.origin_col);
302        renderer.set_color_mode(options.color_mode);
303        renderer.set_preserve_terminal_background(options.preserve_terminal_background);
304
305        if let Some(previous_source) = previous_source.as_deref() {
306            let _ =
307                renderer.highlight_to_patch(&mut highlighter, previous_source, grammar, &theme)?;
308        }
309
310        renderer.highlight_to_patch(&mut highlighter, &source, grammar, &theme)?
311    } else {
312        let source_is_multiline = source.contains(&b'\n');
313        let previous_is_multiline = previous_source
314            .as_ref()
315            .is_some_and(|snapshot| snapshot.contains(&b'\n'));
316
317        if source_is_multiline || previous_is_multiline {
318            let rendered = highlight_to_ansi_with_highlighter_and_mode_and_background(
319                &mut highlighter,
320                &source,
321                grammar,
322                &theme,
323                options.color_mode,
324                options.preserve_terminal_background,
325            )?;
326            build_full_rerender_patch(rendered, previous_source.as_deref())
327        } else {
328            let mut renderer = StreamLineRenderer::new();
329            renderer.set_color_mode(options.color_mode);
330            renderer.set_preserve_terminal_background(options.preserve_terminal_background);
331
332            if let Some(previous_source) = previous_source.as_deref() {
333                let _ = renderer
334                    .highlight_line_to_patch(&mut highlighter, previous_source, grammar, &theme)
335                    .map_err(streamline_mode_error)?;
336            }
337
338            renderer
339                .highlight_line_to_patch(&mut highlighter, &source, grammar, &theme)
340                .map_err(streamline_mode_error)?
341        }
342    };
343
344    print!("{patch}");
345    io::stdout().flush()?;
346
347    Ok(())
348}

Trait Implementations§

Source§

impl Clone for StreamLineRenderer

Source§

fn clone(&self) -> StreamLineRenderer

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for StreamLineRenderer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for StreamLineRenderer

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.