Skip to content

r3bl_terminal_async SharedWriter Indentation Bug #439

@BrunoGoirand

Description

@BrunoGoirand

Problem Description

I am integrating r3bl_terminal_async in a Rust application and using its SharedWriter as the output for the fern logger. Everything works in terms of asynchronous logging and prompt preservation, but the output exhibits a reproducible visual issue:

Issue Summary

When writing log messages through the SharedWriter (via log::info!, log::warn!, etc.), the first log line is correctly aligned at column 0, but every subsequent log line is automatically prefixed with exactly one extra space.

Example output:

banner
line 1
 line 2
 line 3

This happens even though:

• none of my log messages contain leading spaces,
• my logger does not insert any leading whitespace,
• ANSI color codes have been completely removed,
• the logger was reduced to a minimal formatter writing raw strings,
• the underlying Write implementation also does not add spaces.

The issue persists regardless of logger configuration.

Minimal Reproduction Example

// src/main.rs

use anyhow::Result;
use anyhow::anyhow;
use r3bl_terminal_async::TerminalAsync;
use log::info;
use fern::Dispatch;
use log::LevelFilter;
use std::io::Write;

pub fn init_logger<W>(
    writer: W,
    level: LevelFilter,
) -> Result<(), fern::InitError>
where
    W: Write + Send + 'static,
{
    let boxed: Box<dyn Write + Send> = Box::new(writer);

    Dispatch::new()
        .level(level)
        .format(|out, msg, _record| {
            // Writes exactly: "<message>\n"
            out.finish(format_args!("{}", msg))
        })
        .chain(boxed)
        .apply()?;

    Ok(())
}

#[tokio::main]
async fn main() -> Result<()> {
    let maybe_terminal_async = TerminalAsync::try_new("> ")
        .await
        .map_err(|e| anyhow!(e.to_string()))?;

    let Some(mut terminal_async) = maybe_terminal_async else {
        println!("Not an interactive terminal.");
        return Ok(());
    };

    let writer = terminal_async.clone_shared_writer();

    init_logger(writer, LevelFilter::Info)?;

    terminal_async.println("banner").await;
    info!("line 1");
    info!("line 2");

    Ok(())
}

Cargo.toml

[package]
name = "r3bl_test"
version = "0.1.0"
edition = "2024"

[dependencies]
anyhow = "1.0.100"
fern = "0.7.1"
log = "0.4.28"
r3bl_terminal_async = "0.6.0"
tokio = "1.48.0"

Actual output

banner
line 1
 line 2

Expected output

banner
line 1
line 2

Observations

• The indentation only appears when using the SharedWriter.
• Writing logs to stderr removes the indentation but breaks prompt redrawing (as expected).
• The extra leading space seems to be injected internally when SharedWriter handles multiple consecutive writes.
• The indentation appears consistently for every log message after the first one.

Conclusion

This is likely a rendering or buffer-handling quirk inside r3bl_terminal_async::SharedWriter, where the library inserts a padding space before lines printed after the first one in order to avoid overwriting the prompt or input buffer.

However, this padding occurs even with a completely empty formatter and no ANSI sequences, and results in misaligned multi-line log output.

I would appreciate guidance on:

• whether this is an intended behavior,
• whether there’s an API to disable this padding,
• or if this qualifies as a bug in the SharedWriter implementation.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions