in reply to Handling ANSI Escape Sequences for Printing to Curses

Show us the code you have tried.

True laziness is hard work
  • Comment on Re: Handling ANSI Escape Sequences for Printing to Curses

Replies are listed 'Best First'.
Re^2: Handling ANSI Escape Sequences for Printing to Curses
by atancasis (Sexton) on Aug 01, 2010 at 00:50 UTC

    Code below produces the following output (escape sequence appearing as string): 'a ^[[33YELLOW^[[0m word'

    use Curses; use Term::ANSIColor; initscr(); addstr(stdscr, "a ".color('yellow')."YELLOW".color('reset')." word"); refresh(); getch(); endwin();

    Implementing a parser, with the following code, will produce the desired effects but will be expensive. Not to mention I feel like I'm reinventing the wheel.

    use Curses; use Term::ANSIColor; initscr(); start_color(); init_pair(1, COLOR_YELLOW, COLOR_BLACK); formatted_text(stdscr, "a ".color('yellow')."YELLOW".color('reset')." +word"); refresh(); getch(); endwin(); sub formatted_text { my ( $win, $text ) = @_; # tokenize text on escape sequences foreach ( split(/(\e\[[^m]+m)/, $text) ) { # token starts with <ESC>, set attr and dont add text if ( /^\e/ ) { if ( $_ =~ quotemeta(color('yellow')) ) { attron(COLOR_PAIR(1)); } elsif ( $_ =~ quotemeta(color('reset')) ) { attroff(COLOR_PAIR(1)); } next; } addstr($win, $_); } }
        Implementing a parser, with the following code, will produce the desired effects but will be expensive.

      Expensive? How much text are you putting out to the screen before the "inefficiency" is noticeable? It's a little premature to be optimizing at this time.

        Not to mention I feel like I'm reinventing the wheel.

      But consider what you were doing with the code you posted. You want to attron a color pair each time you encounter a yellow escape sequence. That seems like quite a customized requirement.

      You're using Curses and Term::ANSIColor, so you're leveraging a lot already = good for you! I did a cursory search and couldn't find any more helpful modules beyond those two.

      I'd write formatted_text() using a dispatch hash. Also made the regex quantifier non-greedy:
      my %esc2action = ( color('yellow') => sub { attron(COLOR_PAIR(1)) }, color('reset') => sub { attroff(COLOR_PAIR(1)) }, ); sub formatted_text { my ($win, $text) = @_; # tokenize text on escape sequences for my $token (split /(\e\[[^m]+?m)/, $text) { my $act = $esc2action{$token}; if ($act) { $act->(); } else { addstr($win, $token); } } }

        Yup, utilizing a dispatch table would definitely be the smart way to do it.

        Also, thanks for knocking some sense into me. :-) I guess what I'm trying to do may already be a bit too customized to my requirements anyway. For now, I'll stick to implementing the parser, which would hopefully not be too expensive considering the ncurses utility I'll be doing will be tailing massive amounts of data.

        Thanks!

      For a yellow "word"...
      #!/usr/bin/perl use strict; use warnings; use Term::ANSIColor::Markup; my $text = qq{ <yellow>word</yellow> }; print Term::ANSIColor::Markup->colorize($text);

        Thanks! Although, I'm not having too much of a problem printing out colored text to the terminal. In fact, printing out $text in the first code snippet I posted will print "YELLOW" in yellow to the terminal.

        use Term::ANSIColor; print "a ".color('yellow')."YELLOW".color('reset')." word\n";

        The problem, however, is in trying to add the colorized string to an ncurses window wherein the ANSI escape sequences will be stringified and printed along with the message (instead of just modifying color attributes of the words).