From 71dfd5a7630fa569799c920633539d5d99ec45f6 Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Wed, 9 Feb 2011 15:30:50 -0500 Subject: [PATCH] Modularize display code and add representation of wrapped line flag --- terminal.cpp | 1 + terminal.hpp | 18 +---- terminaldisplay.cpp | 165 ++++++++++++++++++++-------------------- terminaldisplay.hpp | 30 ++++++++ terminalframebuffer.cpp | 9 +++ terminalframebuffer.hpp | 12 ++- terminalfunctions.cpp | 10 +-- 7 files changed, 141 insertions(+), 104 deletions(-) create mode 100644 terminaldisplay.hpp diff --git a/terminal.cpp b/terminal.cpp index 4054602..8e76f4d 100644 --- a/terminal.cpp +++ b/terminal.cpp @@ -40,6 +40,7 @@ void Emulator::print( Parser::Print *act ) case 1: /* normal character */ case 2: /* wide character */ if ( fb.ds.auto_wrap_mode && fb.ds.next_print_will_wrap ) { + fb.get_row( -1 )->wrap = true; fb.ds.move_col( 0 ); fb.move_rows_autoscroll( 1 ); } diff --git a/terminal.hpp b/terminal.hpp index e892f13..69fe811 100644 --- a/terminal.hpp +++ b/terminal.hpp @@ -10,25 +10,9 @@ #include "terminalframebuffer.hpp" #include "terminaldispatcher.hpp" #include "terminaluserinput.hpp" +#include "terminaldisplay.hpp" namespace Terminal { - class Display { - private: - bool initialized; - Framebuffer last_frame; - std::string current_rendition_string; - int cursor_x, cursor_y; - - public: - Display( int width, int height ) - : initialized( false ), last_frame( width, height ), - current_rendition_string(), cursor_x( -1 ), cursor_y( -1 ) - {} - - std::string new_frame( Framebuffer &f ); - void invalidate( void ) { initialized = false; } - }; - class Emulator { friend void Parser::Print::act_on_terminal( Emulator * ); friend void Parser::Execute::act_on_terminal( Emulator * ); diff --git a/terminaldisplay.cpp b/terminaldisplay.cpp index e7abf41..3611169 100644 --- a/terminaldisplay.cpp +++ b/terminaldisplay.cpp @@ -1,4 +1,4 @@ -#include "terminal.hpp" +#include "terminaldisplay.hpp" using namespace Terminal; @@ -6,33 +6,34 @@ using namespace Terminal; std::string Display::new_frame( Framebuffer &f ) { + /* fill in background color on any cells that have been reset + or created since last time */ f.back_color_erase(); - std::string screen; + str.clear(); + char tmp[ 64 ]; /* has window title changed? */ if ( (!initialized) || (f.get_window_title() != last_frame.get_window_title()) ) { /* set window title */ - screen.append( "\033]0;[rtm] " ); + str.append( "\033]0;[rtm] " ); std::vector window_title = f.get_window_title(); for ( std::vector::iterator i = window_title.begin(); i != window_title.end(); i++ ) { - char utf8[ 8 ]; - snprintf( utf8, 8, "%lc", *i ); - screen.append( utf8 ); + snprintf( tmp, 64, "%lc", *i ); + str.append( tmp ); } - screen.append( "\033\\" ); + str.append( "\033\\" ); } /* has reverse video state changed? */ if ( (!initialized) || (f.ds.reverse_video != last_frame.ds.reverse_video) ) { /* set reverse video */ - char rev[ 8 ]; - snprintf( rev, 8, "\033[?5%c", (f.ds.reverse_video ? 'h' : 'l') ); - screen.append( rev ); + snprintf( tmp, 64, "\033[?5%c", (f.ds.reverse_video ? 'h' : 'l') ); + str.append( tmp ); } /* has size changed? */ @@ -40,77 +41,16 @@ std::string Display::new_frame( Framebuffer &f ) || (f.ds.get_width() != last_frame.ds.get_width()) || (f.ds.get_height() != last_frame.ds.get_height()) ) { /* clear screen */ - screen.append( "\033[0m\033[H\033[2J" ); + str.append( "\033[0m\033[H\033[2J" ); initialized = false; cursor_x = cursor_y = 0; current_rendition_string = "\033[0m"; } /* iterate for every cell */ - for ( int y = 0; y < f.ds.get_height(); y++ ) { - for ( int x = 0; x < f.ds.get_width(); /* let charwidth handle advance */ ) { - Cell *cell = f.get_cell( y, x ); - - if ( initialized - && ( *cell == *(last_frame.get_cell( y, x )) ) ) { - x += cell->width; - continue; - } - - if ( (x != cursor_x) || (y != cursor_y) ) { - char curmove[ 32 ]; - snprintf( curmove, 32, "\033[%d;%dH", y + 1, x + 1 ); - screen.append( curmove ); - } - - cursor_x = x; - cursor_y = y; - - std::string rendition_str = cell->renditions.sgr(); - - if ( current_rendition_string != rendition_str ) { - /* print renditions */ - screen.append( rendition_str ); - current_rendition_string = rendition_str; - } - - if ( cell->contents.empty() ) { - /* see how far we can stretch a clear */ - int clear_count = 0; - for ( int col = x; col < f.ds.get_width(); col++ ) { - Cell *other_cell = f.get_cell( y, col ); - if ( (cell->renditions == other_cell->renditions) - && (other_cell->contents.empty()) ) { - clear_count++; - } else { - break; - } - } - char clearer[ 32 ]; - snprintf( clearer, 32, "\033[%dX", clear_count ); - screen.append( clearer ); - - x += clear_count; - continue; - } - - /* cells that begin with combining character get combiner attached to no-break space */ - if ( cell->fallback ) { - char utf8[ 8 ]; - snprintf( utf8, 8, "%lc", 0xA0 ); - screen.append( utf8 ); - } - - for ( std::vector::iterator i = cell->contents.begin(); - i != cell->contents.end(); - i++ ) { - char utf8[ 8 ]; - snprintf( utf8, 8, "%lc", *i ); - screen.append( utf8 ); - } - - x += cell->width; - cursor_x += cell->width; + for ( y = 0; y < f.ds.get_height(); y++ ) { + for ( x = 0; x < f.ds.get_width(); /* let charwidth handle advance */ ) { + put_cell( f ); } } @@ -118,10 +58,9 @@ std::string Display::new_frame( Framebuffer &f ) if ( (!initialized) || (f.ds.get_cursor_row() != cursor_y) || (f.ds.get_cursor_col() != cursor_x) ) { - char curmove[ 32 ]; - snprintf( curmove, 32, "\033[%d;%dH", f.ds.get_cursor_row() + 1, + snprintf( tmp, 64, "\033[%d;%dH", f.ds.get_cursor_row() + 1, f.ds.get_cursor_col() + 1 ); - screen.append( curmove ); + str.append( tmp ); cursor_x = f.ds.get_cursor_col(); cursor_y = f.ds.get_cursor_row(); } @@ -130,14 +69,78 @@ std::string Display::new_frame( Framebuffer &f ) if ( (!initialized) || (f.ds.cursor_visible != last_frame.ds.cursor_visible) ) { if ( f.ds.cursor_visible ) { - screen.append( "\033[?25h" ); + str.append( "\033[?25h" ); } else { - screen.append( "\033[?25l" ); + str.append( "\033[?25l" ); } } last_frame = f; initialized = true; - return screen; + return str; +} + +void Display::put_cell( Framebuffer &f ) +{ + char tmp[ 64 ]; + + Cell *cell = f.get_cell( y, x ); + Cell *last_cell = last_frame.get_cell( y, x ); + + if ( initialized + && ( *cell == *last_cell ) ) { + x += cell->width; + return; + } + + if ( (x != cursor_x) || (y != cursor_y) ) { + snprintf( tmp, 64, "\033[%d;%dH", y + 1, x + 1 ); + str.append( tmp ); + cursor_x = x; + cursor_y = y; + } + + std::string rendition_str = cell->renditions.sgr(); + + if ( current_rendition_string != rendition_str ) { + /* print renditions */ + str.append( rendition_str ); + current_rendition_string = rendition_str; + } + + if ( cell->contents.empty() ) { + /* see how far we can stretch a clear */ + int clear_count = 0; + for ( int col = x; col < f.ds.get_width(); col++ ) { + Cell *other_cell = f.get_cell( y, col ); + if ( (cell->renditions == other_cell->renditions) + && (other_cell->contents.empty()) ) { + clear_count++; + } else { + break; + } + } + snprintf( tmp, 64, "\033[%dX", clear_count ); + str.append( tmp ); + + x += clear_count; + return; + } + + /* cells that begin with combining character get combiner attached to no-break space */ + if ( cell->fallback ) { + snprintf( tmp, 64, "%lc", 0xA0 ); + str.append( tmp ); + } + + for ( std::vector::iterator i = cell->contents.begin(); + i != cell->contents.end(); + i++ ) { + snprintf( tmp, 64, "%lc", *i ); + str.append( tmp ); + } + + x += cell->width; + cursor_x += cell->width; } diff --git a/terminaldisplay.hpp b/terminaldisplay.hpp new file mode 100644 index 0000000..ac79cfb --- /dev/null +++ b/terminaldisplay.hpp @@ -0,0 +1,30 @@ +#ifndef TERMINALDISPLAY_HPP +#define TERMINALDISPLAY_HPP + +#include "terminalframebuffer.hpp" + +namespace Terminal { + class Display { + private: + bool initialized; + Framebuffer last_frame; + std::string current_rendition_string; + int cursor_x, cursor_y; + int x, y; + std::string str; + + void put_cell( Framebuffer &f ); + + public: + Display( int width, int height ) + : initialized( false ), last_frame( width, height ), + current_rendition_string(), cursor_x( -1 ), cursor_y( -1 ), + x( 0 ), y( 0 ), str( "" ) + {} + + std::string new_frame( Framebuffer &f ); + void invalidate( void ) { initialized = false; } + }; +} + +#endif diff --git a/terminalframebuffer.cpp b/terminalframebuffer.cpp index c5240d8..d786aa4 100644 --- a/terminalframebuffer.cpp +++ b/terminalframebuffer.cpp @@ -411,3 +411,12 @@ std::string Renditions::sgr( void ) return ret; } + +void Row::reset( void ) +{ + for ( std::vector::iterator i = cells.begin(); + i != cells.end(); + i++ ) { + i->reset(); + } +} diff --git a/terminalframebuffer.hpp b/terminalframebuffer.hpp index c4927bc..b7928ab 100644 --- a/terminalframebuffer.hpp +++ b/terminalframebuffer.hpp @@ -60,13 +60,16 @@ namespace Terminal { class Row { public: std::vector cells; + bool wrap; Row( size_t s_width ) - : cells( s_width ) + : cells( s_width ), wrap( false ) {} void insert_cell( int col ); void delete_cell( int col ); + + void reset( void ); }; class SavedCursor { @@ -161,6 +164,13 @@ namespace Terminal { void move_rows_autoscroll( int rows ); + Row *get_row( int row ) + { + if ( row == -1 ) row = ds.get_cursor_row(); + + return &rows[ row ]; + } + inline Cell *get_cell( void ) { return &rows[ ds.get_cursor_row() ].cells[ ds.get_cursor_col() ]; diff --git a/terminalfunctions.cpp b/terminalfunctions.cpp index 590a553..21e5303 100644 --- a/terminalfunctions.cpp +++ b/terminalfunctions.cpp @@ -27,7 +27,7 @@ void CSI_EL( Framebuffer *fb, Dispatcher *dispatch ) clearline( fb, -1, 0, fb->ds.get_cursor_col() ); break; case 2: /* all of line */ - clearline( fb, -1, 0, fb->ds.get_width() - 1 ); + fb->get_row( -1 )->reset(); break; } } @@ -40,18 +40,18 @@ void CSI_ED( Framebuffer *fb, Dispatcher *dispatch ) { case 0: /* active position to end of screen, inclusive */ clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 ); for ( int y = fb->ds.get_cursor_row() + 1; y < fb->ds.get_height(); y++ ) { - clearline( fb, y, 0, fb->ds.get_width() - 1 ); + fb->get_row( y )->reset(); } break; case 1: /* start of screen to active position, inclusive */ for ( int y = 0; y < fb->ds.get_cursor_row(); y++ ) { - clearline( fb, y, 0, fb->ds.get_width() - 1 ); + fb->get_row( y )->reset(); } clearline( fb, -1, 0, fb->ds.get_cursor_col() ); break; case 2: /* entire screen */ for ( int y = 0; y < fb->ds.get_height(); y++ ) { - clearline( fb, y, 0, fb->ds.get_width() - 1 ); + fb->get_row( y )->reset(); } break; } @@ -215,7 +215,7 @@ static bool *get_DEC_mode( int param, Framebuffer *fb ) { fb->ds.move_row( 0 ); fb->ds.move_col( 0 ); for ( int y = 0; y < fb->ds.get_height(); y++ ) { - clearline( fb, y, 0, fb->ds.get_width() - 1 ); + fb->get_row( y )->reset(); } return NULL; case 5: /* reverse video */