Refactoring FVTerm::updateTerminalLine

This commit is contained in:
Markus Gans 2017-11-30 02:38:55 +01:00
parent 6be608ba57
commit abf89f1538
7 changed files with 484 additions and 348 deletions

View File

@ -1,3 +1,6 @@
2017-11-30 Markus Gans <guru.mail@muenster.de>
* Refactoring FVTerm::updateTerminalLine
2017-11-26 Markus Gans <guru.mail@muenster.de>
* Better code readability by splitting FOptiMove::moveCursor
into sub-functions

View File

@ -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);
}
}

View File

@ -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&);

View File

@ -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);

View File

@ -709,7 +709,7 @@ int FFileDialog::changeDir (const FString& dirname)
int i = 1;
std::vector<dir_entry>::const_iterator iter, last;
const char* const baseName = \
basename(const_cast<char*>(lastdir.c_str()));
basename(const_cast<char*>(lastdir.c_str()));
iter = dir_entries.begin();
last = dir_entries.end();

View File

@ -3220,13 +3220,13 @@ void FTerm::init_pc_charset()
{
// Select iso8859-1 + null mapping
TCAP(fc::t_enter_pc_charset_mode) = \
const_cast<char*>(ESC "%@" ESC "(U");
const_cast<char*>(ESC "%@" ESC "(U");
}
else
{
// Select null mapping
TCAP(fc::t_enter_pc_charset_mode) = \
const_cast<char*>(ESC "(U");
const_cast<char*>(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<char*>(ESC "(B" ESC "%G");
const_cast<char*>(ESC "(B" ESC "%G");
}
else
{
// Select ascii mapping
TCAP(fc::t_enter_pc_charset_mode) = \
const_cast<char*>(ESC "(B");
const_cast<char*>(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<char*>("-\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<char*>("-\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<char*>(CSI "0"
"%?%p1%p6%|%t;1%;"
"%?%p2%t;4%;"
"%?%p1%p3%|%t;7%;"
"%?%p4%t;5%;m"
"%?%p9%t\016%e\017%;");
const_cast<char*>(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<char*>(CSI "?25l");
const_cast<char*>(CSI "?25l");
// Set visible cursor for cygwin terminal
if ( ! TCAP(fc::t_cursor_visible) )
TCAP(fc::t_cursor_visible) = \
const_cast<char*>(CSI "?25h");
const_cast<char*>(CSI "?25h");
// Set ansi blink for cygwin terminal
if ( ! TCAP(fc::t_enter_blink_mode) )
TCAP(fc::t_enter_blink_mode) = \
const_cast<char*>(CSI "5m");
const_cast<char*>(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<char*>(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m");
const_cast<char*>(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m");
TCAP(fc::t_set_a_background) = \
const_cast<char*>(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m");
const_cast<char*>(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m");
}
else
{
TCAP(fc::t_set_a_foreground) = \
const_cast<char*>(CSI "3%p1%dm");
const_cast<char*>(CSI "3%p1%dm");
TCAP(fc::t_set_a_background) = \
const_cast<char*>(CSI "4%p1%dm");
const_cast<char*>(CSI "4%p1%dm");
}
TCAP(fc::t_orig_pair) = \
const_cast<char*>(CSI "39;49;25m");
const_cast<char*>(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<char*>(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m");
const_cast<char*>(CSI "3%p1%{8}%m%d%?%p1%{7}%>%t;1%e;21%;m");
TCAP(fc::t_set_a_background) = \
const_cast<char*>(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m");
const_cast<char*>(CSI "4%p1%{8}%m%d%?%p1%{7}%>%t;5%e;25%;m");
}
else
{
TCAP(fc::t_set_a_foreground) = \
const_cast<char*>(CSI "3%p1%dm");
const_cast<char*>(CSI "3%p1%dm");
TCAP(fc::t_set_a_background) = \
const_cast<char*>(CSI "4%p1%dm");
const_cast<char*>(CSI "4%p1%dm");
}
TCAP(fc::t_orig_pair) = \
const_cast<char*>(CSI "39;49;25m");
const_cast<char*>(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<char*>(OSC "4;%p1%d;rgb:"
"%p2%{255}%*%{1000}%/%2.2X/"
"%p3%{255}%*%{1000}%/%2.2X/"
"%p4%{255}%*%{1000}%/%2.2X" ESC "\\");
const_cast<char*>(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<char*>(ESC "(0");
const_cast<char*>(ESC "(0");
TCAP(fc::t_exit_alt_charset_mode) = \
const_cast<char*>(ESC "(B");
const_cast<char*>(ESC "(B");
}
// Set ansi foreground and background color
if ( ! urxvt_terminal )
{
TCAP(fc::t_set_a_foreground) = \
const_cast<char*>(CSI "%?%p1%{8}%<%t%p1%{30}%+%e%p1%'R'%+%;%dm");
const_cast<char*>(CSI "%?%p1%{8}%<%t%p1%{30}%+%e%p1%'R'%+%;%dm");
TCAP(fc::t_set_a_background) = \
const_cast<char*>(CSI "%?%p1%{8}%<%t%p1%'('%+%e%p1%{92}%+%;%dm");
const_cast<char*>(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<char*>(CSI "24m");
const_cast<char*>(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<char*>(CSI "%?%p1%{8}%<"
"%t3%p1%d"
"%e%p1%{16}%<"
"%t9%p1%{8}%-%d"
"%e38;5;%p1%d%;m");
const_cast<char*>(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<char*>(CSI "%?%p1%{8}%<"
"%t4%p1%d"
"%e%p1%{16}%<"
"%t10%p1%{8}%-%d"
"%e48;5;%p1%d%;m");
const_cast<char*>(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<char*>(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<char*>(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<char*>(CSI "2m");
const_cast<char*>(CSI "2m");
// PuTTY 0.71 or higher
TCAP(fc::t_exit_dim_mode) = \
const_cast<char*>(CSI "22m");
const_cast<char*>(CSI "22m");
if ( ! TCAP(fc::t_clr_bol) )
TCAP(fc::t_clr_bol) = \
const_cast<char*>(CSI "1K");
const_cast<char*>(CSI "1K");
if ( ! TCAP(fc::t_orig_pair) )
TCAP(fc::t_orig_pair) = \
const_cast<char*>(CSI "39;49m");
const_cast<char*>(CSI "39;49m");
if ( ! TCAP(fc::t_orig_colors) )
TCAP(fc::t_orig_colors) = \
const_cast<char*>(OSC "R");
const_cast<char*>(OSC "R");
if ( ! TCAP(fc::t_column_address) )
TCAP(fc::t_column_address) = \
const_cast<char*>(CSI "%i%p1%dG");
const_cast<char*>(CSI "%i%p1%dG");
if ( ! TCAP(fc::t_row_address) )
TCAP(fc::t_row_address) = \
const_cast<char*>(CSI "%i%p1%dd");
const_cast<char*>(CSI "%i%p1%dd");
if ( ! TCAP(fc::t_enable_acs) )
TCAP(fc::t_enable_acs) = \
const_cast<char*>(ESC "(B" ESC ")0");
const_cast<char*>(ESC "(B" ESC ")0");
if ( ! TCAP(fc::t_enter_am_mode) )
TCAP(fc::t_enter_am_mode) = \
const_cast<char*>(CSI "?7h");
const_cast<char*>(CSI "?7h");
if ( ! TCAP(fc::t_exit_am_mode) )
TCAP(fc::t_exit_am_mode) = \
const_cast<char*>(CSI "?7l");
const_cast<char*>(CSI "?7l");
if ( ! TCAP(fc::t_enter_pc_charset_mode) )
TCAP(fc::t_enter_pc_charset_mode) = \
const_cast<char*>(CSI "11m");
const_cast<char*>(CSI "11m");
if ( ! TCAP(fc::t_exit_pc_charset_mode) )
TCAP(fc::t_exit_pc_charset_mode) = \
const_cast<char*>(CSI "10m");
const_cast<char*>(CSI "10m");
if ( ! TCAP(fc::t_key_mouse) )
TCAP(fc::t_key_mouse) = \
const_cast<char*>(CSI "M");
const_cast<char*>(CSI "M");
}
//----------------------------------------------------------------------
@ -3741,13 +3741,13 @@ void FTerm::init_termcaps_teraterm_quirks()
// Tera Term color settings
TCAP(fc::t_set_a_foreground) = \
const_cast<char*>(CSI "38;5;%p1%dm");
const_cast<char*>(CSI "38;5;%p1%dm");
TCAP(fc::t_set_a_background) = \
const_cast<char*>(CSI "48;5;%p1%dm");
const_cast<char*>(CSI "48;5;%p1%dm");
TCAP(fc::t_exit_attribute_mode) = \
const_cast<char*>(CSI "0m" SI);
const_cast<char*>(CSI "0m" SI);
TCAP(fc::t_orig_pair) = \
const_cast<char*>(CSI "39;49m");
const_cast<char*>(CSI "39;49m");
}
//----------------------------------------------------------------------
@ -3759,18 +3759,18 @@ void FTerm::init_termcaps_screen_quirks()
if ( tmux_terminal )
{
TCAP(fc::t_initialize_color) = \
const_cast<char*>(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<char*>(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<char*>(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<char*>(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<char*>(CSI "3%p1%dm");
const_cast<char*>(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<char*>(CSI "4%p1%dm");
const_cast<char*>(CSI "4%p1%dm");
// Fallback if "Ic" is not found
if ( ! TCAP(fc::t_initialize_color) )
{
TCAP(fc::t_initialize_color) = \
const_cast<char*>(OSC "P%p1%x"
"%p2%{255}%*%{1000}%/%02x"
"%p3%{255}%*%{1000}%/%02x"
"%p4%{255}%*%{1000}%/%02x");
const_cast<char*>(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<char*>(ESC "7" CSI "?47h");
const_cast<char*>(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<char*>(CSI "?47l" ESC "8" CSI "m");
const_cast<char*>(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<char*>(CSI "%i%p1%d;%p2%dH");
const_cast<char*>(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<char*>(CSI "21m"); // Exit single underline, too
const_cast<char*>(CSI "21m"); // Exit single underline, too
TCAP(fc::t_exit_dbl_underline_mode) = \
const_cast<char*>(CSI "24m");
const_cast<char*>(CSI "24m");
TCAP(fc::t_exit_bold_mode) = \
const_cast<char*>(CSI "22m"); // Exit dim, too
const_cast<char*>(CSI "22m"); // Exit dim, too
TCAP(fc::t_exit_dim_mode) = \
const_cast<char*>(CSI "22m");
const_cast<char*>(CSI "22m");
TCAP(fc::t_exit_underline_mode) = \
const_cast<char*>(CSI "24m");
const_cast<char*>(CSI "24m");
TCAP(fc::t_exit_blink_mode) = \
const_cast<char*>(CSI "25m");
const_cast<char*>(CSI "25m");
TCAP(fc::t_exit_reverse_mode) = \
const_cast<char*>(CSI "27m");
const_cast<char*>(CSI "27m");
TCAP(fc::t_exit_secure_mode) = \
const_cast<char*>(CSI "28m");
const_cast<char*>(CSI "28m");
TCAP(fc::t_enter_crossed_out_mode) = \
const_cast<char*>(CSI "9m");
const_cast<char*>(CSI "9m");
TCAP(fc::t_exit_crossed_out_mode) = \
const_cast<char*>(CSI "29m");
const_cast<char*>(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));
}

View File

@ -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()
{