diff --git a/ChangeLog b/ChangeLog index 30c6d068..e68e97fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2017-11-30 Markus Gans + * Refactoring FVTerm::updateTerminalLine + 2017-11-26 Markus Gans * Better code readability by splitting FOptiMove::moveCursor into sub-functions diff --git a/examples/calculator.cpp b/examples/calculator.cpp index 86e50b62..6fd0e22e 100644 --- a/examples/calculator.cpp +++ b/examples/calculator.cpp @@ -987,8 +987,8 @@ void Calc::cb_buttonClicked (FWidget*, data_ptr data) { // remove trailing zeros while ( ! input.includes(L'e') - && input.includes(L'.') - && input.back() == L'0' ) + && input.includes(L'.') + && input.back() == L'0' ) input = input.left(input.getLength() - 1); } } diff --git a/include/final/fterm.h b/include/final/fterm.h index 13066542..7a55fea5 100644 --- a/include/final/fterm.h +++ b/include/final/fterm.h @@ -202,12 +202,12 @@ class FTerm #if defined(__linux__) static void setLinuxConsoleCursorStyle \ - (fc::linuxConsoleCursorStyle, bool); + (fc::linuxConsoleCursorStyle, bool); #endif #if defined(__FreeBSD__) || defined(__DragonFly__) static void setFreeBSDConsoleCursorStyle \ - (fc::freebsdConsoleCursorStyle, bool); + (fc::freebsdConsoleCursorStyle, bool); #endif static void setTTY (const termios&); diff --git a/include/final/fvterm.h b/include/final/fvterm.h index 96cd0524..7899259d 100644 --- a/include/final/fvterm.h +++ b/include/final/fvterm.h @@ -343,9 +343,16 @@ class FVTerm : public FTerm term_area* vwin; // virtual window private: - // Typedef + // Typedef and Enumeration typedef FTermcap::tcap_map termcap_map; + enum exit_state + { + not_used, + used, + line_completely_printed + }; + // Constants static const uInt TERMINAL_OUTPUT_BUFFER_SIZE = 32768; // Buffer size for character output on the terminal @@ -363,6 +370,14 @@ class FVTerm : public FTerm void init(); void finish(); static bool clearTerm (int = ' '); + static bool canClearToEOL (uInt, uInt); + static bool canClearLeadingWS (uInt&, uInt); + static bool canClearTailingWS (uInt&, uInt); + static bool skipUnchangedCharacters (uInt&, uInt, uInt); + static void printRange (uInt, uInt, uInt, bool); + static exit_state eraseCharacters (uInt&, uInt, uInt, bool); + static exit_state repeatCharacter (uInt&, uInt, uInt); + static void cursorWrap(); static void updateTerminalLine (uInt); static bool updateTerminalCursor(); static bool isInsideTerminal (int, int); diff --git a/src/ffiledialog.cpp b/src/ffiledialog.cpp index a7ae2a19..74f94fce 100644 --- a/src/ffiledialog.cpp +++ b/src/ffiledialog.cpp @@ -709,7 +709,7 @@ int FFileDialog::changeDir (const FString& dirname) int i = 1; std::vector::const_iterator iter, last; const char* const baseName = \ - basename(const_cast(lastdir.c_str())); + basename(const_cast(lastdir.c_str())); iter = dir_entries.begin(); last = dir_entries.end(); diff --git a/src/fterm.cpp b/src/fterm.cpp index c6e82067..8f69b803 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -3220,13 +3220,13 @@ void FTerm::init_pc_charset() { // Select iso8859-1 + null mapping TCAP(fc::t_enter_pc_charset_mode) = \ - const_cast(ESC "%@" ESC "(U"); + const_cast(ESC "%@" ESC "(U"); } else { // Select null mapping TCAP(fc::t_enter_pc_charset_mode) = \ - const_cast(ESC "(U"); + const_cast(ESC "(U"); } opti_attr->set_enter_pc_charset_mode \ @@ -3241,17 +3241,17 @@ void FTerm::init_pc_charset() { // Select ascii mapping + utf8 TCAP(fc::t_exit_pc_charset_mode) = \ - const_cast(ESC "(B" ESC "%G"); + const_cast(ESC "(B" ESC "%G"); } else { // Select ascii mapping TCAP(fc::t_enter_pc_charset_mode) = \ - const_cast(ESC "(B"); + const_cast(ESC "(B"); } opti_attr->set_exit_pc_charset_mode \ - (TCAP(fc::t_exit_pc_charset_mode)); + (TCAP(fc::t_exit_pc_charset_mode)); reinit = true; } } @@ -3501,21 +3501,21 @@ static void FTerm::init_termcaps_freebsd_quirks() // FreeBSD console fixes TCAP(fc::t_acs_chars) = \ - const_cast("-\036.\0370\333" - "a\260f\370g\361" - "h\261j\331k\277" - "l\332m\300n\305" - "q\304t\303u\264" - "v\301w\302x\263" - "y\363z\362~\371"); + const_cast("-\036.\0370\333" + "a\260f\370g\361" + "h\261j\331k\277" + "l\332m\300n\305" + "q\304t\303u\264" + "v\301w\302x\263" + "y\363z\362~\371"); TCAP(fc::t_set_attributes) = \ - const_cast(CSI "0" - "%?%p1%p6%|%t;1%;" - "%?%p2%t;4%;" - "%?%p1%p3%|%t;7%;" - "%?%p4%t;5%;m" - "%?%p9%t\016%e\017%;"); + const_cast(CSI "0" + "%?%p1%p6%|%t;1%;" + "%?%p2%t;4%;" + "%?%p1%p3%|%t;7%;" + "%?%p4%t;5%;m" + "%?%p9%t\016%e\017%;"); FTermcap::attr_without_color = 18; } @@ -3527,17 +3527,17 @@ void FTerm::init_termcaps_cygwin_quirks() // Set invisible cursor for cygwin terminal if ( ! TCAP(fc::t_cursor_invisible) ) TCAP(fc::t_cursor_invisible) = \ - const_cast(CSI "?25l"); + const_cast(CSI "?25l"); // Set visible cursor for cygwin terminal if ( ! TCAP(fc::t_cursor_visible) ) TCAP(fc::t_cursor_visible) = \ - const_cast(CSI "?25h"); + const_cast(CSI "?25h"); // Set ansi blink for cygwin terminal if ( ! TCAP(fc::t_enter_blink_mode) ) TCAP(fc::t_enter_blink_mode) = \ - const_cast(CSI "5m"); + const_cast(CSI "5m"); // Set background color erase for cygwin terminal FTermcap::background_color_erase = true; @@ -3546,20 +3546,20 @@ void FTerm::init_termcaps_cygwin_quirks() if ( FTermcap::max_color > 8 ) { TCAP(fc::t_set_a_foreground) = \ - const_cast(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m"); + const_cast(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m"); TCAP(fc::t_set_a_background) = \ - const_cast(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m"); + const_cast(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m"); } else { TCAP(fc::t_set_a_foreground) = \ - const_cast(CSI "3%p1%dm"); + const_cast(CSI "3%p1%dm"); TCAP(fc::t_set_a_background) = \ - const_cast(CSI "4%p1%dm"); + const_cast(CSI "4%p1%dm"); } TCAP(fc::t_orig_pair) = \ - const_cast(CSI "39;49;25m"); + const_cast(CSI "39;49;25m"); // Avoid dim + underline TCAP(fc::t_enter_dim_mode) = 0; @@ -3577,20 +3577,20 @@ void FTerm::init_termcaps_linux_quirks() if ( FTermcap::max_color > 8 ) { TCAP(fc::t_set_a_foreground) = \ - const_cast(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m"); + const_cast(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m"); TCAP(fc::t_set_a_background) = \ - const_cast(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m"); + const_cast(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m"); } else { TCAP(fc::t_set_a_foreground) = \ - const_cast(CSI "3%p1%dm"); + const_cast(CSI "3%p1%dm"); TCAP(fc::t_set_a_background) = \ - const_cast(CSI "4%p1%dm"); + const_cast(CSI "4%p1%dm"); } TCAP(fc::t_orig_pair) = \ - const_cast(CSI "39;49;25m"); + const_cast(CSI "39;49;25m"); // Avoid dim + underline TCAP(fc::t_enter_dim_mode) = 0; @@ -3607,10 +3607,10 @@ void FTerm::init_termcaps_xterm_quirks() if ( ! TCAP(fc::t_initialize_color) ) { TCAP(fc::t_initialize_color) = \ - const_cast(OSC "4;%p1%d;rgb:" - "%p2%{255}%*%{1000}%/%2.2X/" - "%p3%{255}%*%{1000}%/%2.2X/" - "%p4%{255}%*%{1000}%/%2.2X" ESC "\\"); + const_cast(OSC "4;%p1%d;rgb:" + "%p2%{255}%*%{1000}%/%2.2X/" + "%p3%{255}%*%{1000}%/%2.2X/" + "%p4%{255}%*%{1000}%/%2.2X" ESC "\\"); } } @@ -3621,18 +3621,18 @@ void FTerm::init_termcaps_rxvt_quirks() if ( std::strncmp(termtype, "rxvt-16color", 12) == 0 ) { TCAP(fc::t_enter_alt_charset_mode) = \ - const_cast(ESC "(0"); + const_cast(ESC "(0"); TCAP(fc::t_exit_alt_charset_mode) = \ - const_cast(ESC "(B"); + const_cast(ESC "(B"); } // Set ansi foreground and background color if ( ! urxvt_terminal ) { TCAP(fc::t_set_a_foreground) = \ - const_cast(CSI "%?%p1%{8}%<%t%p1%{30}%+%e%p1%'R'%+%;%dm"); + const_cast(CSI "%?%p1%{8}%<%t%p1%{30}%+%e%p1%'R'%+%;%dm"); TCAP(fc::t_set_a_background) = \ - const_cast(CSI "%?%p1%{8}%<%t%p1%'('%+%e%p1%{92}%+%;%dm"); + const_cast(CSI "%?%p1%{8}%<%t%p1%'('%+%e%p1%{92}%+%;%dm"); } } @@ -3644,7 +3644,7 @@ void FTerm::init_termcaps_vte_quirks() // set exit underline for gnome terminal TCAP(fc::t_exit_underline_mode) = \ - const_cast(CSI "24m"); + const_cast(CSI "24m"); } //---------------------------------------------------------------------- @@ -3659,78 +3659,78 @@ void FTerm::init_termcaps_putty_quirks() // Set ansi foreground and background color TCAP(fc::t_set_a_foreground) = \ - const_cast(CSI "%?%p1%{8}%<" - "%t3%p1%d" - "%e%p1%{16}%<" - "%t9%p1%{8}%-%d" - "%e38;5;%p1%d%;m"); + const_cast(CSI "%?%p1%{8}%<" + "%t3%p1%d" + "%e%p1%{16}%<" + "%t9%p1%{8}%-%d" + "%e38;5;%p1%d%;m"); TCAP(fc::t_set_a_background) = \ - const_cast(CSI "%?%p1%{8}%<" - "%t4%p1%d" - "%e%p1%{16}%<" - "%t10%p1%{8}%-%d" - "%e48;5;%p1%d%;m"); + const_cast(CSI "%?%p1%{8}%<" + "%t4%p1%d" + "%e%p1%{16}%<" + "%t10%p1%{8}%-%d" + "%e48;5;%p1%d%;m"); TCAP(fc::t_set_attributes) = \ - const_cast(CSI "0" - "%?%p1%p6%|%t;1%;" - "%?%p5%t;2%;" // since putty 0.71 - "%?%p2%t;4%;" - "%?%p1%p3%|%t;7%;" - "%?%p4%t;5%;m" - "%?%p9%t\016%e\017%;"); + const_cast(CSI "0" + "%?%p1%p6%|%t;1%;" + "%?%p5%t;2%;" // since putty 0.71 + "%?%p2%t;4%;" + "%?%p1%p3%|%t;7%;" + "%?%p4%t;5%;m" + "%?%p9%t\016%e\017%;"); // PuTTY 0.71 or higher TCAP(fc::t_enter_dim_mode) = \ - const_cast(CSI "2m"); + const_cast(CSI "2m"); // PuTTY 0.71 or higher TCAP(fc::t_exit_dim_mode) = \ - const_cast(CSI "22m"); + const_cast(CSI "22m"); if ( ! TCAP(fc::t_clr_bol) ) TCAP(fc::t_clr_bol) = \ - const_cast(CSI "1K"); + const_cast(CSI "1K"); if ( ! TCAP(fc::t_orig_pair) ) TCAP(fc::t_orig_pair) = \ - const_cast(CSI "39;49m"); + const_cast(CSI "39;49m"); if ( ! TCAP(fc::t_orig_colors) ) TCAP(fc::t_orig_colors) = \ - const_cast(OSC "R"); + const_cast(OSC "R"); if ( ! TCAP(fc::t_column_address) ) TCAP(fc::t_column_address) = \ - const_cast(CSI "%i%p1%dG"); + const_cast(CSI "%i%p1%dG"); if ( ! TCAP(fc::t_row_address) ) TCAP(fc::t_row_address) = \ - const_cast(CSI "%i%p1%dd"); + const_cast(CSI "%i%p1%dd"); if ( ! TCAP(fc::t_enable_acs) ) TCAP(fc::t_enable_acs) = \ - const_cast(ESC "(B" ESC ")0"); + const_cast(ESC "(B" ESC ")0"); if ( ! TCAP(fc::t_enter_am_mode) ) TCAP(fc::t_enter_am_mode) = \ - const_cast(CSI "?7h"); + const_cast(CSI "?7h"); if ( ! TCAP(fc::t_exit_am_mode) ) TCAP(fc::t_exit_am_mode) = \ - const_cast(CSI "?7l"); + const_cast(CSI "?7l"); if ( ! TCAP(fc::t_enter_pc_charset_mode) ) TCAP(fc::t_enter_pc_charset_mode) = \ - const_cast(CSI "11m"); + const_cast(CSI "11m"); if ( ! TCAP(fc::t_exit_pc_charset_mode) ) TCAP(fc::t_exit_pc_charset_mode) = \ - const_cast(CSI "10m"); + const_cast(CSI "10m"); if ( ! TCAP(fc::t_key_mouse) ) TCAP(fc::t_key_mouse) = \ - const_cast(CSI "M"); + const_cast(CSI "M"); } //---------------------------------------------------------------------- @@ -3741,13 +3741,13 @@ void FTerm::init_termcaps_teraterm_quirks() // Tera Term color settings TCAP(fc::t_set_a_foreground) = \ - const_cast(CSI "38;5;%p1%dm"); + const_cast(CSI "38;5;%p1%dm"); TCAP(fc::t_set_a_background) = \ - const_cast(CSI "48;5;%p1%dm"); + const_cast(CSI "48;5;%p1%dm"); TCAP(fc::t_exit_attribute_mode) = \ - const_cast(CSI "0m" SI); + const_cast(CSI "0m" SI); TCAP(fc::t_orig_pair) = \ - const_cast(CSI "39;49m"); + const_cast(CSI "39;49m"); } //---------------------------------------------------------------------- @@ -3759,18 +3759,18 @@ void FTerm::init_termcaps_screen_quirks() if ( tmux_terminal ) { TCAP(fc::t_initialize_color) = \ - const_cast(ESC "Ptmux;" ESC OSC "4;%p1%d;rgb:" - "%p2%{255}%*%{1000}%/%2.2X/" - "%p3%{255}%*%{1000}%/%2.2X/" - "%p4%{255}%*%{1000}%/%2.2X" BEL ESC "\\"); + const_cast(ESC "Ptmux;" ESC OSC "4;%p1%d;rgb:" + "%p2%{255}%*%{1000}%/%2.2X/" + "%p3%{255}%*%{1000}%/%2.2X/" + "%p4%{255}%*%{1000}%/%2.2X" BEL ESC "\\"); } else { TCAP(fc::t_initialize_color) = \ - const_cast(ESC "P" OSC "4;%p1%d;rgb:" - "%p2%{255}%*%{1000}%/%2.2X/" - "%p3%{255}%*%{1000}%/%2.2X/" - "%p4%{255}%*%{1000}%/%2.2X" BEL ESC "\\"); + const_cast(ESC "P" OSC "4;%p1%d;rgb:" + "%p2%{255}%*%{1000}%/%2.2X/" + "%p3%{255}%*%{1000}%/%2.2X/" + "%p4%{255}%*%{1000}%/%2.2X" BEL ESC "\\"); } } } @@ -3789,37 +3789,37 @@ void FTerm::init_termcaps_general_quirks() // Fallback if "AF" is not found if ( ! TCAP(fc::t_set_a_foreground) ) TCAP(fc::t_set_a_foreground) = \ - const_cast(CSI "3%p1%dm"); + const_cast(CSI "3%p1%dm"); // Fallback if "AB" is not found if ( ! TCAP(fc::t_set_a_background) ) TCAP(fc::t_set_a_background) = \ - const_cast(CSI "4%p1%dm"); + const_cast(CSI "4%p1%dm"); // Fallback if "Ic" is not found if ( ! TCAP(fc::t_initialize_color) ) { TCAP(fc::t_initialize_color) = \ - const_cast(OSC "P%p1%x" - "%p2%{255}%*%{1000}%/%02x" - "%p3%{255}%*%{1000}%/%02x" - "%p4%{255}%*%{1000}%/%02x"); + const_cast(OSC "P%p1%x" + "%p2%{255}%*%{1000}%/%02x" + "%p3%{255}%*%{1000}%/%02x" + "%p4%{255}%*%{1000}%/%02x"); } // Fallback if "ti" is not found if ( ! TCAP(fc::t_enter_ca_mode) ) TCAP(fc::t_enter_ca_mode) = \ - const_cast(ESC "7" CSI "?47h"); + const_cast(ESC "7" CSI "?47h"); // Fallback if "te" is not found if ( ! TCAP(fc::t_exit_ca_mode) ) TCAP(fc::t_exit_ca_mode) = \ - const_cast(CSI "?47l" ESC "8" CSI "m"); + const_cast(CSI "?47l" ESC "8" CSI "m"); // Set ansi move if "cm" is not found if ( ! TCAP(fc::t_cursor_address) ) TCAP(fc::t_cursor_address) = \ - const_cast(CSI "%i%p1%d;%p2%dH"); + const_cast(CSI "%i%p1%d;%p2%dH"); // Test for standard ECMA-48 (ANSI X3.64) terminal if ( TCAP(fc::t_exit_underline_mode) @@ -3827,34 +3827,34 @@ void FTerm::init_termcaps_general_quirks() { // Seems to be a ECMA-48 (ANSI X3.64) compatible terminal TCAP(fc::t_enter_dbl_underline_mode) = \ - const_cast(CSI "21m"); // Exit single underline, too + const_cast(CSI "21m"); // Exit single underline, too TCAP(fc::t_exit_dbl_underline_mode) = \ - const_cast(CSI "24m"); + const_cast(CSI "24m"); TCAP(fc::t_exit_bold_mode) = \ - const_cast(CSI "22m"); // Exit dim, too + const_cast(CSI "22m"); // Exit dim, too TCAP(fc::t_exit_dim_mode) = \ - const_cast(CSI "22m"); + const_cast(CSI "22m"); TCAP(fc::t_exit_underline_mode) = \ - const_cast(CSI "24m"); + const_cast(CSI "24m"); TCAP(fc::t_exit_blink_mode) = \ - const_cast(CSI "25m"); + const_cast(CSI "25m"); TCAP(fc::t_exit_reverse_mode) = \ - const_cast(CSI "27m"); + const_cast(CSI "27m"); TCAP(fc::t_exit_secure_mode) = \ - const_cast(CSI "28m"); + const_cast(CSI "28m"); TCAP(fc::t_enter_crossed_out_mode) = \ - const_cast(CSI "9m"); + const_cast(CSI "9m"); TCAP(fc::t_exit_crossed_out_mode) = \ - const_cast(CSI "29m"); + const_cast(CSI "29m"); } } @@ -3946,7 +3946,7 @@ void FTerm::init_OptiMove() opti_move->set_cursor_left (TCAP(fc::t_cursor_left)); opti_move->set_cursor_right (TCAP(fc::t_cursor_right)); cursor_addres_lengths = \ - opti_move->set_cursor_address (TCAP(fc::t_cursor_address)); + opti_move->set_cursor_address (TCAP(fc::t_cursor_address)); opti_move->set_column_address (TCAP(fc::t_column_address)); opti_move->set_row_address (TCAP(fc::t_row_address)); opti_move->set_parm_up_cursor (TCAP(fc::t_parm_up_cursor)); @@ -3956,9 +3956,9 @@ void FTerm::init_OptiMove() opti_move->set_auto_left_margin (FTermcap::automatic_left_margin); opti_move->set_eat_newline_glitch (FTermcap::eat_nl_glitch); erase_ch_length = \ - opti_move->set_erase_chars (TCAP(fc::t_erase_chars)); + opti_move->set_erase_chars (TCAP(fc::t_erase_chars)); repeat_char_length = \ - opti_move->set_repeat_char (TCAP(fc::t_repeat_char)); + opti_move->set_repeat_char (TCAP(fc::t_repeat_char)); clr_bol_length = opti_move->set_clr_bol (TCAP(fc::t_clr_bol)); clr_eol_length = opti_move->set_clr_eol (TCAP(fc::t_clr_eol)); } diff --git a/src/fvterm.cpp b/src/fvterm.cpp index c77a44c7..7bc71437 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -2244,264 +2244,316 @@ bool FVTerm::clearTerm (int fillchar) } //---------------------------------------------------------------------- -void FVTerm::updateTerminalLine (uInt y) +bool FVTerm::canClearToEOL (uInt xmin, uInt y) { - // Updates pending changes from line y to the terminal - term_area* vt = vterm; - uInt& xmin = vt->changes[y].xmin; - uInt& xmax = vt->changes[y].xmax; - int term_width = vt->width - 1; - int term_height = vt->height - 1; + // Is the line from xmin to the end of the line blank? + // => clear to end of line - if ( xmin <= xmax ) + term_area*& vt = vterm; + bool& ut = FTermcap::background_color_erase; + char*& ce = TCAP(fc::t_clr_eol); + char_data* min_char = &vt->text[y * uInt(vt->width) + xmin]; + + if ( ce && min_char->code == ' ' ) { - bool is_eol_clean = false; - bool draw_leading_ws = false; - bool draw_tailing_ws = false; - char*& ce = TCAP(fc::t_clr_eol); - char*& cb = TCAP(fc::t_clr_bol); - bool ut = FTermcap::background_color_erase; - char_data* first_char = &vt->text[y * uInt(vt->width)]; - char_data* last_char = &vt->text[(y + 1) * uInt(vt->width) - 1]; - char_data* min_char = &vt->text[y * uInt(vt->width) + xmin]; + uInt beginning_whitespace = 1; + bool normal = isNormal(min_char); - // Is the line from xmin to the end of the line blank? - if ( ce && min_char->code == ' ' ) + for (uInt x = xmin + 1; x < uInt(vt->width); x++) { - uInt beginning_whitespace = 1; - bool normal = isNormal(min_char); + char_data* ch = &vt->text[y * uInt(vt->width) + x]; - for (uInt x = xmin + 1; x < uInt(vt->width); x++) - { - char_data* ch = &vt->text[y * uInt(vt->width) + x]; - - if ( *min_char == *ch ) - beginning_whitespace++; - else - break; - } - - if ( beginning_whitespace == uInt(vt->width) - xmin - && (ut || normal) - && clr_eol_length < int(beginning_whitespace) ) - is_eol_clean = true; + if ( *min_char == *ch ) + beginning_whitespace++; + else + break; } - if ( ! is_eol_clean ) + if ( beginning_whitespace == uInt(vt->width) - xmin + && (ut || normal) + && clr_eol_length < int(beginning_whitespace) ) + return true; + } + + return false; +} + +//---------------------------------------------------------------------- +bool FVTerm::canClearLeadingWS (uInt& xmin, uInt y) +{ + // Line has leading whitespace + // => clear from xmin to beginning of line + + term_area*& vt = vterm; + bool& ut = FTermcap::background_color_erase; + char*& cb = TCAP(fc::t_clr_bol); + char_data* first_char = &vt->text[y * uInt(vt->width)]; + + if ( cb && first_char->code == ' ' ) + { + uInt leading_whitespace = 1; + bool normal = isNormal(first_char); + + for (uInt x = 1; x < uInt(vt->width); x++) { - // leading whitespace - if ( cb && first_char->code == ' ' ) - { - uInt leading_whitespace = 1; - bool normal = isNormal(first_char); + char_data* ch = &vt->text[y * uInt(vt->width) + x]; - for (uInt x = 1; x < uInt(vt->width); x++) - { - char_data* ch = &vt->text[y * uInt(vt->width) + x]; - - if ( *first_char == *ch ) - leading_whitespace++; - else - break; - } - - if ( leading_whitespace > xmin - && (ut || normal) - && clr_bol_length < int(leading_whitespace) ) - { - draw_leading_ws = true; - xmin = leading_whitespace - 1; - } - } - - // tailing whitespace - if ( ce && last_char->code == ' ' ) - { - uInt tailing_whitespace = 1; - bool normal = isNormal(last_char); - - for (uInt x = uInt(vt->width) - 1; x > 0 ; x--) - { - char_data* ch = &vt->text[y * uInt(vt->width) + x]; - - if ( *last_char == *ch ) - tailing_whitespace++; - else - break; - } - - if ( tailing_whitespace > uInt(vt->width) - xmax - && (ut || normal) - && clr_bol_length < int(tailing_whitespace) ) - { - draw_tailing_ws = true; - xmax = uInt(vt->width) - tailing_whitespace; - } - } + if ( *first_char == *ch ) + leading_whitespace++; + else + break; } - setTermXY (int(xmin), int(y)); - - if ( is_eol_clean ) + if ( leading_whitespace > xmin + && (ut || normal) + && clr_bol_length < int(leading_whitespace) ) { - appendAttributes (min_char); - appendOutputBuffer (ce); - markAsPrinted (xmin, uInt(vt->width - 1), y); + xmin = leading_whitespace - 1; + return true; + } + } + + return false; +} + +//---------------------------------------------------------------------- +bool FVTerm::canClearTailingWS (uInt& xmax, uInt y) +{ + // Line has tailing whitespace + // => clear from xmax to end of line + + term_area*& vt = vterm; + bool& ut = FTermcap::background_color_erase; + char*& ce = TCAP(fc::t_clr_eol); + char_data* last_char = &vt->text[(y + 1) * uInt(vt->width) - 1]; + + if ( ce && last_char->code == ' ' ) + { + uInt tailing_whitespace = 1; + bool normal = isNormal(last_char); + + for (uInt x = uInt(vt->width) - 1; x > 0 ; x--) + { + char_data* ch = &vt->text[y * uInt(vt->width) + x]; + + if ( *last_char == *ch ) + tailing_whitespace++; + else + break; + } + + if ( tailing_whitespace > uInt(vt->width) - xmax + && (ut || normal) + && clr_bol_length < int(tailing_whitespace) ) + { + xmax = uInt(vt->width) - tailing_whitespace; + return true; + } + } + + return false; +} + +//---------------------------------------------------------------------- +bool FVTerm::skipUnchangedCharacters(uInt& x, uInt xmax, uInt y) +{ + // Skip characters without changes if it is faster than redrawing + + term_area*& vt = vterm; + char_data* print_char = &vt->text[y * uInt(vt->width) + x]; + print_char->attr.bit.printed = true; + + if ( print_char->attr.bit.no_changes ) + { + uInt count = 1; + + for (uInt i = x + 1; i <= xmax; i++) + { + char_data* ch = &vt->text[y * uInt(vt->width) + i]; + + if ( ch->attr.bit.no_changes ) + count++; + else + break; + } + + if ( count > uInt(cursor_addres_lengths) ) + { + setTermXY (int(x + count), int(y)); + x = x + count - 1; + return true; + } + } + + return false; +} + +//---------------------------------------------------------------------- +void FVTerm::printRange ( uInt xmin, uInt xmax, uInt y + , bool draw_tailing_ws ) +{ + for (uInt x = xmin; x <= xmax; x++) + { + char_data* print_char; + term_area*& vt = vterm; + char*& ec = TCAP(fc::t_erase_chars); + char*& rp = TCAP(fc::t_repeat_char); + print_char = &vt->text[y * uInt(vt->width) + x]; + print_char->attr.bit.printed = true; + + // skip character with no changes + if ( skipUnchangedCharacters(x, xmax, y) ) + continue; + + // Erase character + if ( ec && print_char->code == ' ' ) + { + exit_state erase_state = \ + eraseCharacters(x, xmax, y, draw_tailing_ws); + + if ( erase_state == line_completely_printed ) + break; + } + else if ( rp ) // Repeat one character n-fold + { + repeatCharacter(x, xmax, y); } else { - if ( draw_leading_ws ) - { - appendAttributes (first_char); - appendOutputBuffer (cb); - markAsPrinted (0, xmin, y); - } - - for (uInt x = xmin; x <= xmax; x++) - { - char_data* print_char; - char*& ec = TCAP(fc::t_erase_chars); - char*& rp = TCAP(fc::t_repeat_char); - print_char = &vt->text[y * uInt(vt->width) + x]; - print_char->attr.bit.printed = true; - - // skip character with no changes - if ( print_char->attr.bit.no_changes ) - { - uInt count = 1; - - for (uInt i = x + 1; i <= xmax; i++) - { - char_data* ch = &vt->text[y * uInt(vt->width) + i]; - - if ( ch->attr.bit.no_changes ) - count++; - else - break; - } - - if ( count > uInt(cursor_addres_lengths) ) - { - setTermXY (int(x + count), int(y)); - x = x + count - 1; - continue; - } - } - - // Erase a number of characters to draw simple whitespaces - if ( ec && print_char->code == ' ' ) - { - uInt whitespace = 1; - bool normal = isNormal(print_char); - - for (uInt i = x + 1; i <= xmax; i++) - { - char_data* ch = &vt->text[y * uInt(vt->width) + i]; - - if ( *print_char == *ch ) - whitespace++; - else - break; - } - - if ( whitespace == 1 ) - { - appendCharacter (print_char); - markAsPrinted (x, y); - } - else - { - uInt start_pos = x; - - if ( whitespace > uInt(erase_ch_length) + uInt(cursor_addres_lengths) - && (ut || normal) ) - { - appendAttributes (print_char); - appendOutputBuffer (tparm(ec, whitespace, 0, 0, 0, 0, 0, 0, 0, 0)); - - if ( x + whitespace - 1 < xmax || draw_tailing_ws ) - setTermXY (int(x + whitespace), int(y)); - else - break; - - x = x + whitespace - 1; - } - else - { - x--; - - for (uInt i = 0; i < whitespace; i++, x++) - appendCharacter (print_char); - } - - markAsPrinted (start_pos, x, y); - } - } - else if ( rp ) // Repeat one character n-fold - { - uInt repetitions = 1; - - for (uInt i = x + 1; i <= xmax; i++) - { - char_data* ch = &vt->text[y * uInt(vt->width) + i]; - - if ( *print_char == *ch ) - repetitions++; - else - break; - } - - if ( repetitions == 1 ) - { - appendCharacter (print_char); - markAsPrinted (x, y); - } - else - { - uInt start_pos = x; - - if ( repetitions > uInt(repeat_char_length) - && print_char->code < 128 ) - { - newFontChanges (print_char); - charsetChanges (print_char); - appendAttributes (print_char); - appendOutputBuffer (tparm(rp, print_char->code, repetitions, 0, 0, 0, 0, 0, 0, 0)); - term_pos->x_ref() += short(repetitions); - x = x + repetitions - 1; - } - else - { - x--; - - for (uInt i = 0; i < repetitions; i++, x++) - appendCharacter (print_char); - } - - markAsPrinted (start_pos, x, y); - } - } - else // General character output - { - appendCharacter (print_char); - markAsPrinted (x, y); - } - } - - if ( draw_tailing_ws ) - { - appendAttributes (last_char); - appendOutputBuffer (ce); - markAsPrinted (xmax + 1, uInt(vt->width - 1), y); - } + // General character output + appendCharacter (print_char); + markAsPrinted (x, y); } + } +} +//---------------------------------------------------------------------- +FVTerm::exit_state FVTerm::eraseCharacters ( uInt& x, uInt xmax, uInt y + , bool draw_tailing_ws ) +{ + // Erase a number of characters to draw simple whitespaces - // Reset line changes - xmin = uInt(vt->width); - xmax = 0; + term_area*& vt = vterm; + bool& ut = FTermcap::background_color_erase; + char*& ec = TCAP(fc::t_erase_chars); + char_data* print_char = &vt->text[y * uInt(vt->width) + x]; + + if ( ! ec || print_char->code != ' ' ) + return not_used; + + uInt whitespace = 1; + bool normal = isNormal(print_char); + + for (uInt i = x + 1; i <= xmax; i++) + { + char_data* ch = &vt->text[y * uInt(vt->width) + i]; + + if ( *print_char == *ch ) + whitespace++; + else + break; } - // cursor wrap + if ( whitespace == 1 ) + { + appendCharacter (print_char); + markAsPrinted (x, y); + } + else + { + uInt start_pos = x; + + if ( whitespace > uInt(erase_ch_length) + uInt(cursor_addres_lengths) + && (ut || normal) ) + { + appendAttributes (print_char); + appendOutputBuffer (tparm(ec, whitespace, 0, 0, 0, 0, 0, 0, 0, 0)); + + if ( x + whitespace - 1 < xmax || draw_tailing_ws ) + setTermXY (int(x + whitespace), int(y)); + else + return line_completely_printed; + + x = x + whitespace - 1; + } + else + { + x--; + + for (uInt i = 0; i < whitespace; i++, x++) + appendCharacter (print_char); + } + + markAsPrinted (start_pos, x, y); + } + + return used; +} + +//---------------------------------------------------------------------- +FVTerm::exit_state FVTerm::repeatCharacter (uInt& x, uInt xmax, uInt y) +{ + // Repeat one character n-fold + + term_area*& vt = vterm; + char*& rp = TCAP(fc::t_repeat_char); + char_data* print_char = &vt->text[y * uInt(vt->width) + x]; + + if ( ! rp ) + return not_used; + + uInt repetitions = 1; + + for (uInt i = x + 1; i <= xmax; i++) + { + char_data* ch = &vt->text[y * uInt(vt->width) + i]; + + if ( *print_char == *ch ) + repetitions++; + else + break; + } + + if ( repetitions == 1 ) + { + appendCharacter (print_char); + markAsPrinted (x, y); + } + else + { + uInt start_pos = x; + + if ( repetitions > uInt(repeat_char_length) + && print_char->code < 128 ) + { + newFontChanges (print_char); + charsetChanges (print_char); + appendAttributes (print_char); + appendOutputBuffer (tparm(rp, print_char->code, repetitions, 0, 0, 0, 0, 0, 0, 0)); + term_pos->x_ref() += short(repetitions); + x = x + repetitions - 1; + } + else + { + x--; + + for (uInt i = 0; i < repetitions; i++, x++) + appendCharacter (print_char); + } + + markAsPrinted (start_pos, x, y); + } + + return used; +} + +//---------------------------------------------------------------------- +void FVTerm::cursorWrap() +{ + // Wrap the cursor + term_area*& vt = vterm; + int term_width = vt->width - 1; + int term_height = vt->height - 1; + if ( term_pos->getX() > term_width ) { if ( term_pos->getY() == term_height ) @@ -2523,6 +2575,72 @@ void FVTerm::updateTerminalLine (uInt y) } } +//---------------------------------------------------------------------- +void FVTerm::updateTerminalLine (uInt y) +{ + // Updates pending changes from line y to the terminal + + term_area*& vt = vterm; + uInt& xmin = vt->changes[y].xmin; + uInt& xmax = vt->changes[y].xmax; + + if ( xmin <= xmax ) + { + bool draw_leading_ws = false; + bool draw_tailing_ws = false; + char*& ce = TCAP(fc::t_clr_eol); + char*& cb = TCAP(fc::t_clr_bol); + char_data* first_char = &vt->text[y * uInt(vt->width)]; + char_data* last_char = &vt->text[(y + 1) * uInt(vt->width) - 1]; + char_data* min_char = &vt->text[y * uInt(vt->width) + xmin]; + + // Clear rest of line + bool is_eol_clean = canClearToEOL (xmin, y); + + if ( ! is_eol_clean ) + { + // leading whitespace + draw_leading_ws = canClearLeadingWS (xmin, y); + + // tailing whitespace + draw_tailing_ws = canClearTailingWS (xmax, y); + } + + setTermXY (int(xmin), int(y)); + + if ( is_eol_clean ) + { + appendAttributes (min_char); + appendOutputBuffer (ce); + markAsPrinted (xmin, uInt(vt->width - 1), y); + } + else + { + if ( draw_leading_ws ) + { + appendAttributes (first_char); + appendOutputBuffer (cb); + markAsPrinted (0, xmin, y); + } + + printRange (xmin, xmax, y, draw_tailing_ws); + + if ( draw_tailing_ws ) + { + appendAttributes (last_char); + appendOutputBuffer (ce); + markAsPrinted (xmax + 1, uInt(vt->width - 1), y); + } + } + + // Reset line changes + xmin = uInt(vt->width); + xmax = 0; + } + + cursorWrap(); +} + //---------------------------------------------------------------------- bool FVTerm::updateTerminalCursor() {