Skip to content
This repository has been archived by the owner on Aug 6, 2023. It is now read-only.

Colors doesn't work very well #88

Closed
macabeus opened this issue Nov 17, 2018 · 6 comments · Fixed by #316
Closed

Colors doesn't work very well #88

macabeus opened this issue Nov 17, 2018 · 6 comments · Fixed by #316

Comments

@macabeus
Copy link

If we use termion::color at a Text inside of a widget, we will get a strange behaviour. For example:

format!(
    " 0x00: {color_green}green{reset} foo {color_blue}blue{reset}",
    color_green = COLOR_GREEN!(),
    color_blue = COLOR_BLUE!(),
    reset = color::Fg(color::Reset),
)

We expected a result like 0x00: green foo blue, but we get it:

image

A workaround that I use (and works sometimes) is using cursor::Left, for example:

format!(
    " 0x00: {color_green}green{reset} {goto}foo {color_blue}{goto_blue}blue{reset}",
    color_green = COLOR_GREEN!(),
    color_blue = COLOR_BLUE!(),
    goto = cursor::Left(14),
    goto_blue = cursor::Left(19),
    reset = color::Fg(color::Reset),
)

it will print:

image

But, this workaround isn't work in all situations, for example, if this text change.

Full example code:

extern crate termion;
extern crate tui;
use std::io::{stdout, stdin};
use tui::Terminal;
use tui::backend::TermionBackend;
use tui::layout::{Layout, Constraint, Direction};
use termion::clear;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use tui::backend::Backend;
use tui::widgets::{Widget, Block, Borders, Text, List};
use tui::layout::Rect;
use tui::Frame;
use termion::{color, cursor};

macro_rules! COLOR_GREEN { () => { color::Fg(color::Green) } }
macro_rules! COLOR_BLUE { () => { color::Fg(color::LightBlue) } }

fn format_line(i: usize, text: &str) -> String {
    format!(
        " {:#04X}: {color_green}green{reset} {} {color_blue}blue{reset}",
        i, text,
        color_green = COLOR_GREEN!(),
        color_blue = COLOR_BLUE!(),
        reset = color::Fg(color::Reset),
    )
}

fn draw_list<B>(f: &mut Frame<B>, area: Rect)
where
    B: Backend,
{
    let raw_text = ["foo", "bar"];
    let formatted_text = raw_text
        .iter()
        .enumerate()
        .map(|(i, text)|
            Text::raw(
                format_line(i, text)
            )
        );

    List::new(formatted_text)
      .block(Block::default().borders(Borders::ALL).title(" Table "))
      .render(f, area);
}

fn main() -> Result<(), Box<std::error::Error>> {
    let stdout_raw_mode = stdout().into_raw_mode()?;
    let backend = TermionBackend::new(stdout_raw_mode);
    let mut terminal = Terminal::new(backend)?;

    let size = terminal.size()?;

    println!("{}", clear::All);

    'main: loop {
        terminal.draw(|mut f| {
            let chunks = Layout::default()
                .direction(Direction::Horizontal)
                .constraints([Constraint::Percentage(100)].as_ref())
                .split(size);

            draw_list(&mut f, chunks[0]);
        })?;

        for c in stdin().keys() {
            match c? {
                Key::Char('q') => break 'main Ok(()),
                _ => {}
            }
        }
    }
}
@macabeus macabeus changed the title Colors don't work very well Colors doesn't work very well Nov 17, 2018
macabeus added a commit to macabeus/rust-neander that referenced this issue Nov 18, 2018
macabeus added a commit to macabeus/rust-neander that referenced this issue Nov 25, 2018
macabeus added a commit to macabeus/rust-neander that referenced this issue Dec 9, 2018
@iximeow
Copy link

iximeow commented Jul 13, 2019

this seemed related to the issue in #98, but after finding out the control character there is overwritten i was wondering why colors are shown in this test case at all

it turns out termion-colored strings are still handled poorly, but differently! a reproduction from the current version of tui:
should be, but isn't actually, colored string with garbled ansi sequences

the underlying issue is the same as in #98 - "\x1b".width() is 0 so index doesn't advance when printing out the string, and the escape is overwritten, leaving the rest of the ansi sequence to print un-escaped.

the original issue OP saw was likely similar: ansi sequences were handled as color commands, but counted as printed characters. i imagine a prior revision of set_stringn counted word lengths for line wrapping reasons and was incorrectly counting the word and adjacent control characters as all printing characters, overcounting the length of the word and placing the next word too far forward

a simple but wildly insufficient fix here could be to count \x1b specifically as length 1, which at least avoids garbling the escape. more generally ansi sequences should probably be parsed and handled independently of graphemes, and maybe turned into a style rule on cells? this is the point where i'm less familiar with what tui does and applicable rust crates :D

@macabeus
Copy link
Author

@iximeow Amazing research that you made 😄
I even forgot that I opened this issue at the last year

@fdehau
Copy link
Owner

fdehau commented Jul 16, 2019

I think the recommendation there is not to use control characters directly in favor of the available Style that will be properly translated by the underlying backend. However, the current version of the crate does not allow complex styling for the use case of OP. I think I have a solution in #102 (i.e Text becomes a Vec of strings each associated to a different Style) but I need to find time to finish it.

@Roger
Copy link

Roger commented Sep 22, 2019

Also, not supporting control characters makes hard to use input, for example from a pipe, with colors already inserted, I'm working in a tool that reads some logs and I would like to preserve the already applied colors

@hilbigan
Copy link

bump, same issue as @Roger

@DevinR528
Copy link

@Roger , @hilbigan , @macabeus I see it has been a while for this issue but if anyone is interested I have a control sequence parser that converts to a Vec<Text> if anyone is interested I could make this a crate ctrl-chars

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants