Skip to main content

IncrementalRenderer

Struct IncrementalRenderer 

Source
pub struct IncrementalRenderer { /* private fields */ }

Implementations§

Source§

impl IncrementalRenderer

Source

pub fn new(width: usize, height: usize) -> Self

Creates an incremental renderer with a bounded viewport size.

A minimum viewport size of 1x1 is enforced. The render origin defaults to terminal row 1, column 1.

Examples found in repository?
examples/vt_patch_bridge.rs (line 300)
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 resize(&mut self, width: usize, height: usize)

Resizes the viewport and clips cached state to the new bounds.

Source

pub fn clear_state(&mut self)

Clears all cached frame state for this renderer.

Source

pub fn set_origin(&mut self, row: usize, col: usize)

Sets the terminal origin used for generated CUP cursor positions.

The origin is 1-based terminal coordinates (row, col) in display cells. Values lower than 1 are clamped to 1.

Examples found in repository?
examples/vt_patch_bridge.rs (line 301)
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 origin(&self) -> (usize, usize)

Returns the current 1-based terminal origin (row, col).

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/vt_patch_bridge.rs (line 302)
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/vt_patch_bridge.rs (line 303)
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_patch( &mut self, source: &[u8], spans: &[StyledSpan], ) -> Result<String, RenderError>

Renders only the VT patch from the cached frame to source.

The method validates input spans, projects them to styled terminal cells, diffs against previous state, and returns only changed cursor/style output.

§Errors

Returns an error when spans are out of bounds, unsorted, or overlapping.

Source

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

Runs highlight + theme resolution + incremental diff in one call.

§Errors

Returns an error if highlighting fails or spans fail validation.

Examples found in repository?
examples/vt_patch_bridge.rs (line 307)
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 IncrementalRenderer

Source§

fn clone(&self) -> IncrementalRenderer

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 IncrementalRenderer

Source§

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

Formats the value using the given formatter. 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.