Added support for combined unicode characters

This commit is contained in:
Markus Gans 2021-02-09 22:01:21 +01:00
parent 5b789e4110
commit baa0c60c79
40 changed files with 3965 additions and 326 deletions

View File

@ -154,3 +154,18 @@ jobs:
- autoreconf -v --install --force
- ./configure --prefix=/usr
- make -j10
#
# FreeBSD
#
- os: freebsd
env:
- TEST="FreeBSD"
before_install:
- uname -a
- g++ --version
script:
- autoreconf -v --install --force
- ./configure --prefix=/usr
- make -j10

View File

@ -1,5 +1,10 @@
2021-02-09 Markus Gans <guru.mail@muenster.de>
* Added support for combined unicode characters
* Added a unit test for the FTermBuffera class
* Added a unit test for the FTterm functions
2020-12-31 Markus Gans <guru.mail@muenster.de>
* Refactoring to scaled enumerations
* Refactoring to scoped enumerations
2020-11-18 Markus Gans <guru.mail@muenster.de>
* The terminal update rate is now limited to 60 Hz

View File

@ -330,32 +330,32 @@ types and send them to other objects and widgets.
### Available event types ###
```cpp
enum events
enum class Event
{
None_Event, // invalid event
KeyPress_Event, // key pressed
KeyUp_Event, // key released
KeyDown_Event, // key pressed
MouseDown_Event, // mouse button pressed
MouseUp_Event, // mouse button released
MouseDoubleClick_Event, // mouse button double click
MouseWheel_Event, // mouse wheel rolled
MouseMove_Event, // mouse move
FocusIn_Event, // focus in
FocusOut_Event, // focus out
ChildFocusIn_Event, // child focus in
ChildFocusOut_Event, // child focus out
WindowActive_Event, // activate window
WindowInactive_Event, // deactivate window
WindowRaised_Event, // raise window
WindowLowered_Event, // lower window
Accelerator_Event, // keyboard accelerator
Resize_Event, // terminal resize
Show_Event, // widget is shown
Hide_Event, // widget is hidden
Close_Event, // widget close
Timer_Event, // timer event occur
User_Event // user defined event
None, // invalid event
KeyPress, // key pressed
KeyUp, // key released
KeyDown, // key pressed
MouseDown, // mouse button pressed
MouseUp, // mouse button released
MouseDoubleClick, // mouse button double click
MouseWheel, // mouse wheel rolled
MouseMove, // mouse move
FocusIn, // focus in
FocusOut, // focus out
ChildFocusIn, // child focus in
ChildFocusOut, // child focus out
WindowActive, // activate window
WindowInactive, // deactivate window
WindowRaised, // raise window
WindowLowered, // lower window
Accelerator, // keyboard accelerator
Resize, // terminal resize
Show, // widget is shown
Hide, // widget is hidden
Close, // widget close
Timer, // timer event occur
User // user defined event
};
```
@ -1337,15 +1337,15 @@ requires it. You can controll this behavior by the two methods
`setHorizontalScrollBarMode()` and `setVerticalScrollBarMode()`.
```cpp
setHorizontalScrollBarMode (fc::scrollBarMode);
setVerticalScrollBarMode (fc::scrollBarMode);
setHorizontalScrollBarMode (finalcut::ScrollBarMode);
setVerticalScrollBarMode (finalcut::ScrollBarMode);
```
You pass the scroll bar visibility mode as a value of the enum type
`fc::scrollBarMode`.
`finalcut::ScrollBarMode`.
```cpp
enum scrollBarMode
enum class ScrollBarMode
{
Auto = 0, // Shows a scroll bar when area is larger than viewport
Hidden = 1, // Never shows a scroll bar

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2012-2020 Markus Gans *
* Copyright 2012-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -26,7 +26,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FColorPair;
using finalcut::FColor;
using finalcut::FRect;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -28,7 +28,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FPoint;
using finalcut::FRect;
using finalcut::FSize;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -28,7 +28,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FPoint;
using finalcut::FSize;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2015-2020 Markus Gans *
* Copyright 2015-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -22,7 +22,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FColor;
using finalcut::FPoint;
using finalcut::FSize;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -22,7 +22,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FColorPair;
using finalcut::FColor;
using finalcut::FRect;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2020 Markus Gans *
* Copyright 2020-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -28,7 +28,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::chrono::system_clock;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -22,7 +22,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FPoint;
using finalcut::FSize;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2015-2020 Markus Gans *
* Copyright 2015-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -24,7 +24,6 @@
#include <vector>
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FPoint;
using finalcut::FSize;
using finalcut::FColorPair;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -27,7 +27,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::Termcap;
// Function prototype
@ -239,7 +238,7 @@ void debug (const finalcut::FApplication& TermApp)
std::cout << "`------------------- debug -------------------\r\n";
}
#else
void debug (finalcut::FApplication&)
void debug (const finalcut::FApplication&)
{
// FINAL CUT was compiled without debug option
}

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2014-2020 Markus Gans *
* Copyright 2014-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -22,8 +22,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
//----------------------------------------------------------------------
// class Timer

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2016-2020 Markus Gans *
* Copyright 2016-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -22,7 +22,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FColorPair;
using finalcut::FColor;
using finalcut::FPoint;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -27,7 +27,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FPoint;
using finalcut::FSize;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2016-2020 Markus Gans *
* Copyright 2016-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -25,7 +25,6 @@
#include <final/final.h>
namespace fc = finalcut::fc;
using finalcut::FPoint;
using finalcut::FSize;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2014-2020 Markus Gans *
* Copyright 2014-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -252,26 +252,16 @@ void FLabel::setHotkeyAccelerator()
std::size_t FLabel::getAlignOffset (const std::size_t length) const
{
const std::size_t width(getWidth());
assert ( alignment == Align::Left
|| alignment == Align::Center
|| alignment == Align::Right );
switch ( alignment )
if ( alignment == Align::Center )
{
case Align::Left:
return 0;
case Align::Center:
if ( length < width )
return (width - length) / 2;
else
return 0;
case Align::Right:
if ( length < width )
return width - length;
else
return 0;
if ( length < width )
return (width - length) / 2;
}
else if ( alignment == Align::Right )
{
if ( length < width )
return width - length;
}
return 0;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2012-2020 Markus Gans *
* Copyright 2012-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -938,21 +938,52 @@ void FLineEdit::adjustTextOffset()
//----------------------------------------------------------------------
inline void FLineEdit::cursorLeft()
{
if ( cursor_pos > 0 )
cursor_pos--;
auto prev_char_len = getPrevCharLength(text, cursor_pos);
adjustTextOffset();
if ( prev_char_len < 0 )
{
const auto pos = searchLeftCharBegin(text, cursor_pos);
if ( pos != NOT_FOUND )
{
cursor_pos = pos;
adjustTextOffset();
}
return;
}
if ( cursor_pos >= std::size_t(prev_char_len) )
{
cursor_pos -= std::size_t(prev_char_len);
adjustTextOffset();
}
}
//----------------------------------------------------------------------
inline void FLineEdit::cursorRight()
{
const auto& len = text.getLength();
const auto len = text.getLength();
const auto char_len = getCharLength(text, cursor_pos);
if ( cursor_pos < len )
cursor_pos++;
if ( char_len < 0 )
{
const auto pos = searchRightCharBegin(text, cursor_pos);
adjustTextOffset();
if ( pos != NOT_FOUND )
{
cursor_pos = pos;
adjustTextOffset();
}
return;
}
if ( cursor_pos + std::size_t(char_len) <= len )
{
cursor_pos += std::size_t(char_len);
adjustTextOffset();
}
}
//----------------------------------------------------------------------
@ -981,10 +1012,15 @@ inline void FLineEdit::deleteCurrentCharacter()
// Delete key functionality
const auto& len = text.getLength();
const auto char_len = getCharLength(text, cursor_pos);
if ( len > 0 && cursor_pos < len )
if ( char_len < 0 )
return;
if ( len >= std::size_t(char_len)
&& cursor_pos <= len - std::size_t(char_len) )
{
text.remove(cursor_pos, 1);
text.remove(cursor_pos, std::size_t(char_len));
print_text = ( isPasswordField() ) ? getPasswordText() : text;
processChanged();
}

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -1479,26 +1479,15 @@ std::size_t FListView::getAlignOffset ( const Align align
, const std::size_t column_width
, const std::size_t width ) const
{
assert ( align == Align::Left
|| align == Align::Center
|| align == Align::Right );
switch ( align )
if ( align == Align::Center )
{
case Align::Left:
return 0;
case Align::Center:
if ( column_width < width )
return (width - column_width) / 2;
else
return 0;
case Align::Right:
if ( column_width < width )
return width - column_width;
else
return 0;
if ( column_width < width )
return (width - column_width) / 2;
}
else if ( align == Align::Right )
{
if ( column_width < width )
return width - column_width;
}
return 0;
@ -1603,15 +1592,9 @@ void FListView::drawHeadlines()
while ( iter != header.end() )
{
const auto& text = iter->name;
if ( ! iter->name.isEmpty() )
drawHeadlineLabel(iter); // Draw into FTermBuffer object
if ( text.isNull() || text.isEmpty() )
{
++iter;
continue;
}
drawHeadlineLabel(iter); // Draw into FTermBuffer object
++iter;
}

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2016-2020 Markus Gans *
* Copyright 2016-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -1386,13 +1386,13 @@ inline void FOptiAttr::change_current_color ( const FChar& term
if ( term.fg_color != fg || frev )
{
color_str = FTermcap::encodeParameter(AF, ansi_fg, 0, 0, 0, 0, 0, 0, 0, 0);
color_str = FTermcap::encodeParameter(AF, uInt16(ansi_fg), 0, 0, 0, 0, 0, 0, 0, 0);
append_sequence (color_str);
}
if ( term.bg_color != bg || frev )
{
color_str = FTermcap::encodeParameter(AB, ansi_bg, 0, 0, 0, 0, 0, 0, 0, 0);
color_str = FTermcap::encodeParameter(AB, uInt16(ansi_bg), 0, 0, 0, 0, 0, 0, 0, 0);
append_sequence (color_str);
}
}
@ -1400,13 +1400,13 @@ inline void FOptiAttr::change_current_color ( const FChar& term
{
if ( term.fg_color != fg || frev )
{
color_str = FTermcap::encodeParameter(Sf, fg, 0, 0, 0, 0, 0, 0, 0, 0);
color_str = FTermcap::encodeParameter(Sf, uInt16(fg), 0, 0, 0, 0, 0, 0, 0, 0);
append_sequence (color_str);
}
if ( term.bg_color != bg || frev )
{
color_str = FTermcap::encodeParameter(Sb, bg, 0, 0, 0, 0, 0, 0, 0, 0);
color_str = FTermcap::encodeParameter(Sb, uInt16(bg), 0, 0, 0, 0, 0, 0, 0, 0);
append_sequence (color_str);
}
}
@ -1414,7 +1414,7 @@ inline void FOptiAttr::change_current_color ( const FChar& term
{
fg = vga2ansi(fg);
bg = vga2ansi(bg);
color_str = FTermcap::encodeParameter(sp, fg, bg, 0, 0, 0, 0, 0, 0, 0);
color_str = FTermcap::encodeParameter(sp, uInt16(fg), uInt16(bg), 0, 0, 0, 0, 0, 0, 0);
append_sequence (color_str);
}
}

View File

@ -4,7 +4,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -799,52 +799,40 @@ void FScrollView::calculateScrollbarPos() const
//----------------------------------------------------------------------
void FScrollView::setHorizontalScrollBarVisibility() const
{
assert ( h_mode == ScrollBarMode::Auto
|| h_mode == ScrollBarMode::Hidden
|| h_mode == ScrollBarMode::Scroll );
switch ( h_mode )
if ( h_mode == ScrollBarMode::Auto )
{
case ScrollBarMode::Auto:
if ( getScrollWidth() > getViewportWidth() )
hbar->show();
else
hbar->hide();
break;
case ScrollBarMode::Hidden:
hbar->hide();
break;
case ScrollBarMode::Scroll:
if ( getScrollWidth() > getViewportWidth() )
hbar->show();
break;
else
hbar->hide();
}
else if ( h_mode == ScrollBarMode::Hidden )
{
hbar->hide();
}
else if ( h_mode == ScrollBarMode::Scroll )
{
hbar->show();
}
}
//----------------------------------------------------------------------
void FScrollView::setVerticalScrollBarVisibility() const
{
assert ( v_mode == ScrollBarMode::Auto
|| v_mode == ScrollBarMode::Hidden
|| v_mode == ScrollBarMode::Scroll );
switch ( v_mode )
if ( v_mode == ScrollBarMode::Auto )
{
case ScrollBarMode::Auto:
if ( getScrollHeight() > getViewportHeight() )
vbar->show();
else
vbar->hide();
break;
case ScrollBarMode::Hidden:
vbar->hide();
break;
case ScrollBarMode::Scroll:
if ( getScrollHeight() > getViewportHeight() )
vbar->show();
break;
else
vbar->hide();
}
else if ( v_mode == ScrollBarMode::Hidden )
{
vbar->hide();
}
else if ( v_mode == ScrollBarMode::Scroll )
{
vbar->show();
}
}

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2012-2020 Markus Gans *
* Copyright 2012-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -745,7 +745,7 @@ FStringList FString::split (const FString& delimiter) const
while ( token )
{
string_list.push_back (FString{token});
string_list.emplace_back(token);
token = _extractToken (&rest, nullptr, delimiter.wc_str());
}

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2012-2020 Markus Gans *
* Copyright 2012-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -903,9 +903,9 @@ void FTerm::setPalette (FColor index, int r, int g, int b)
const int bb = (b * 1001) / 256;
if ( Ic )
color_str = FTermcap::encodeParameter(Ic, index, rr, gg, bb, 0, 0, 0, 0, 0);
color_str = FTermcap::encodeParameter(Ic, uInt16(index), rr, gg, bb, 0, 0, 0, 0, 0);
else if ( Ip )
color_str = FTermcap::encodeParameter(Ip, index, 0, 0, 0, rr, gg, bb, 0, 0);
color_str = FTermcap::encodeParameter(Ip, uInt16(index), 0, 0, 0, rr, gg, bb, 0, 0);
if ( color_str )
{
@ -1949,7 +1949,7 @@ void FTerm::enableMouse()
#if defined(__linux__)
if ( isLinuxTerm() && openConsole() == 0 )
{
if ( FTerm::getFTermLinux()->isLinuxConsole() )
if ( FTermLinux::isLinuxConsole() )
gpm_mouse = true;
closeConsole();
@ -2364,6 +2364,7 @@ void FTerm::finishOSspecifics() const
const auto& freebsd_console = FTerm::getFTermFreeBSD();
freebsd_console->finish();
#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(UNIT_TEST)
const auto& openbsd_console = FTerm::getFTermOpenBSD();
openbsd_console->finish();
#endif
}

View File

@ -50,6 +50,9 @@ enum class FullWidthSupport
Yes = 1
};
// Constant
constexpr std::size_t NOT_FOUND = static_cast<std::size_t>(-1);
// global state
static FullWidthSupport has_fullwidth_support = FullWidthSupport::Unknown;
@ -407,7 +410,11 @@ FString getColumnSubString ( const FString& str
}
else
{
if ( col_num + width <= col_len )
if ( col_first == col_pos && width == 0 && num == 0 )
{
first++;
}
else if ( col_num + width <= col_len )
{
col_num += width;
num++;
@ -418,6 +425,8 @@ FString getColumnSubString ( const FString& str
num++;
break;
}
else
break;
}
}
@ -447,7 +456,7 @@ std::size_t getLengthFromColumnWidth ( const FString& str
}
//----------------------------------------------------------------------
std::size_t getColumnWidth (const FString& s, std::size_t pos)
std::size_t getColumnWidth (const FString& s, std::size_t end_pos)
{
if ( s.isEmpty() )
return 0;
@ -455,10 +464,10 @@ std::size_t getColumnWidth (const FString& s, std::size_t pos)
std::size_t column_width{0};
const auto length = s.getLength();
if ( pos > length )
pos = length;
if ( end_pos > length )
end_pos = length;
for (std::size_t i{0}; i < pos; i++)
for (std::size_t i{0}; i < end_pos; i++)
{
try
{
@ -501,17 +510,40 @@ std::size_t getColumnWidth (const wchar_t wchar)
else
#endif
column_width = wcwidth(wchar);
if ( (wchar >= UniChar::NF_rev_left_arrow2 && wchar <= UniChar::NF_check_mark)
|| ! hasFullWidthSupports() )
column_width = 1;
else
column_width = wcwidth(wchar);
{
column_width = std::min(column_width, 1);
}
return ( column_width == -1 ) ? 0 : std::size_t(column_width);
}
//----------------------------------------------------------------------
std::size_t getColumnWidth (FChar& term_char)
std::size_t getColumnWidth (const FChar& term_char)
{
return std::size_t(term_char.attr.bit.char_width);
}
//----------------------------------------------------------------------
std::size_t getColumnWidth (const FTermBuffer& tbuf)
{
return ( tbuf.isEmpty() )
? 0
: std::accumulate ( std::next(tbuf.begin())
, tbuf.end()
, tbuf.front().attr.bit.char_width
, [] (std::size_t s, const FChar& c)
{
return s + c.attr.bit.char_width;
}
);
}
//----------------------------------------------------------------------
void addColumnWidth (FChar& term_char)
{
const std::size_t char_width = getColumnWidth(term_char.ch[0]);
@ -522,21 +554,117 @@ std::size_t getColumnWidth (FChar& term_char)
}
else
term_char.attr.bit.char_width = char_width & 0x03;
return char_width;
}
//----------------------------------------------------------------------
std::size_t getColumnWidth (const FTermBuffer& tb)
inline int isWhitespace (const wchar_t ch) noexcept
{
return std::accumulate ( std::next(tb.begin())
, tb.end()
, tb.front().attr.bit.char_width
, [] (std::size_t s, const FChar& c)
{
return s + c.attr.bit.char_width;
}
);
return std::iswspace(static_cast<wint_t>(ch));
}
//----------------------------------------------------------------------
int getCharLength (const FString& string, std::size_t pos)
{
// Gets the number of characters of the combined character
// at string position pos
const std::size_t len = string.getLength();
std::size_t n = pos;
const auto& ch = string[n];
std::size_t char_width = getColumnWidth(ch);
if ( isWhitespace(ch) )
return 1;
if ( char_width == 0 || n >= len )
return -1;
do
{
n++;
char_width = getColumnWidth(string[n]);
}
while ( n < len && char_width == 0 && ! isWhitespace(string[n]) );
return int(n - pos);
}
//----------------------------------------------------------------------
int getPrevCharLength (const FString& string, std::size_t pos)
{
// Gets the number of characters of the previous combined character
// at string position pos
const std::size_t len = string.getLength();
std::size_t n = pos;
const auto& ch = string[n];
std::size_t char_width = getColumnWidth(ch);
if ( (char_width == 0 || n == 0 || n >= len) && ! isWhitespace(ch) )
return -1;
do
{
n--;
char_width = getColumnWidth(string[n]);
}
while ( n > 0 && char_width == 0 && ! isWhitespace(string[n]) );
if ( char_width == 0 )
return -1;
return int(pos - n);
}
//----------------------------------------------------------------------
std::size_t searchLeftCharBegin (const FString& string, std::size_t pos)
{
// Search for the next character position to the left of string position pos
std::size_t n = pos;
if ( n == 0 )
return NOT_FOUND;
std::size_t char_width{0};
do
{
n--;
char_width = getColumnWidth(string[n]);
}
while ( n > 0 && char_width == 0 && ! isWhitespace(string[n]) );
if ( n == 0 && char_width == 0 )
return NOT_FOUND;
return n;
}
//----------------------------------------------------------------------
std::size_t searchRightCharBegin (const FString& string, std::size_t pos)
{
// Search for the next character position to the right of string position pos
const std::size_t len = string.getLength();
std::size_t n = pos;
if ( n >= len )
return NOT_FOUND;
std::size_t char_width{0};
do
{
n++;
char_width = getColumnWidth(string[n]);
}
while ( n < len && char_width == 0 && ! isWhitespace(string[n]) );
if ( n == len && char_width == 0 )
return NOT_FOUND;
return n;
}
//----------------------------------------------------------------------
@ -581,7 +709,7 @@ FPoint readCursorPos()
if ( pos > 4 )
{
constexpr auto parse = "\033[%4d;%4dR";
std::sscanf(temp.data(), parse, &x, &y);
std::sscanf(temp.data(), parse, &y, &x );
}
return FPoint{x, y};

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -47,14 +47,19 @@ FString FTermBuffer::toString() const
{
std::wstring wide_string{};
wide_string.reserve(data.size());
std::transform ( data.begin()
, data.end()
, std::back_inserter(wide_string)
, [] (const FChar& fchar)
{
return fchar.ch[0];
}
);
std::for_each ( data.begin()
, data.end()
, [&wide_string] (const FChar& fchar)
{
for (auto&& ch : fchar.ch)
{
if ( ch == L'\0' )
return;
else
wide_string.push_back(ch);
}
}
);
return wide_string;
}
@ -62,19 +67,41 @@ FString FTermBuffer::toString() const
int FTermBuffer::write (const FString& string)
{
assert ( ! string.isNull() );
const auto len = int(string.getLength());
data.reserve(data.size() + string.getLength());
const auto last = string.end();
auto begin = string.begin();
auto iter = begin;
int char_width{0};
for (auto&& c : string)
for (auto&& ch : string)
{
FChar nc{FVTerm::getAttribute()}; // next character
nc.ch[0] = c;
nc.attr.byte[2] = 0;
nc.attr.byte[3] = 0;
getColumnWidth(nc); // add column width
data.emplace_back(nc);
auto width = getColumnWidth(ch);
auto wspace = std::iswspace(wint_t(ch));
if ( width == 0 && ! wspace ) // zero-width character
{
if ( iter == begin)
++begin;
++iter;
}
else if ( iter != begin )
add(begin, iter, char_width);
if ( iter == begin && (width > 0 || is7bit(ch)) ) // 1st char
++iter;
if ( width > 0 )
char_width += width;
if ( wspace )
add(begin, iter, char_width);
}
return len;
if ( iter == last )
add(begin, iter, char_width);
return int(string.getLength());
}
//----------------------------------------------------------------------
@ -82,7 +109,7 @@ int FTermBuffer::write (wchar_t ch)
{
FChar nc{FVTerm::getAttribute()}; // next character
nc.ch[0] = ch;
getColumnWidth(nc); // add column width
addColumnWidth(nc); // add column width
nc.attr.bit.no_changes = false;
nc.attr.bit.printed = false;
data.emplace_back(nc);
@ -96,34 +123,23 @@ void FTermBuffer::write (const FStyle& style) const
if ( attr == Style::None )
FVTerm::setNormal();
else if ( (attr & Style::Bold) != Style::None )
FVTerm::setBold();
else if ( (attr & Style::Dim) != Style::None )
FVTerm::setDim();
else if ( (attr & Style::Italic) != Style::None )
FVTerm::setItalic();
else if ( (attr & Style::Underline) != Style::None )
FVTerm::setUnderline();
else if ( (attr & Style::Blink) != Style::None )
FVTerm::setBlink();
else if ( (attr & Style::Reverse) != Style::None )
FVTerm::setReverse();
else if ( (attr & Style::Standout) != Style::None )
FVTerm::setStandout();
else if ( (attr & Style::Invisible) != Style::None )
FVTerm::setInvisible();
else if ( (attr & Style::Protected) != Style::None )
FVTerm::setProtected();
else if ( (attr & Style::CrossedOut) != Style::None )
FVTerm::setCrossedOut();
else if ( (attr & Style::DoubleUnderline) != Style::None )
FVTerm::setDoubleUnderline();
else if ( (attr & Style::Transparent) != Style::None )
FVTerm::setTransparent();
else if ( (attr & Style::ColorOverlay) != Style::None )
FVTerm::setColorOverlay();
else if ( (attr & Style::InheritBackground) != Style::None )
FVTerm::setInheritBackground();
else
{
if ( (attr & Style::Bold) != Style::None ) FVTerm::setBold();
if ( (attr & Style::Dim) != Style::None ) FVTerm::setDim();
if ( (attr & Style::Italic) != Style::None ) FVTerm::setItalic();
if ( (attr & Style::Underline) != Style::None ) FVTerm::setUnderline();
if ( (attr & Style::Blink) != Style::None ) FVTerm::setBlink();
if ( (attr & Style::Reverse) != Style::None ) FVTerm::setReverse();
if ( (attr & Style::Standout) != Style::None ) FVTerm::setStandout();
if ( (attr & Style::Invisible) != Style::None ) FVTerm::setInvisible();
if ( (attr & Style::Protected) != Style::None ) FVTerm::setProtected();
if ( (attr & Style::CrossedOut) != Style::None ) FVTerm::setCrossedOut();
if ( (attr & Style::DoubleUnderline) != Style::None ) FVTerm::setDoubleUnderline();
if ( (attr & Style::Transparent) != Style::None ) FVTerm::setTransparent();
if ( (attr & Style::ColorOverlay) != Style::None ) FVTerm::setColorOverlay();
if ( (attr & Style::InheritBackground) != Style::None ) FVTerm::setInheritBackground();
}
}
//----------------------------------------------------------------------
@ -133,6 +149,34 @@ void FTermBuffer::write (const FColorPair& pair) const
}
// private methods of FTermBuffer
//----------------------------------------------------------------------
void FTermBuffer::add ( FString::const_iterator& begin
, FString::const_iterator& end
, int& char_width )
{
if ( begin == end )
return;
FChar nc{FVTerm::getAttribute()}; // next character
nc.attr.byte[2] = 0;
nc.attr.byte[3] = 0;
if ( char_width == 2 && FTerm::getEncoding() != Encoding::UTF8 )
{
nc.ch[0] = '.';
nc.attr.bit.char_width = 1;
}
else
nc.attr.bit.char_width = char_width & 0x03;
std::copy(begin, std::min(end, begin + UNICODE_MAX), nc.ch.begin());
data.emplace_back(nc);
begin = end;
char_width = 0;
}
// FTermBuffer non-member operators
//----------------------------------------------------------------------
FTermBuffer::FCharVector& operator << ( FTermBuffer::FCharVector& termString

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2015-2020 Markus Gans *
* Copyright 2015-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -92,14 +92,14 @@ void FTermcap::termcap()
#else
const char* termtype = fterm_data->getTermType();
#endif
terminals.push_back(termtype); // available terminal type
terminals.emplace_back(termtype); // available terminal type
if ( color256 ) // 1st fallback if not found
terminals.push_back("xterm-256color");
terminals.emplace_back("xterm-256color");
terminals.push_back("xterm"); // 2nd fallback if not found
terminals.push_back("ansi"); // 3rd fallback if not found
terminals.push_back("vt100"); // 4th fallback if not found
terminals.emplace_back("xterm"); // 2nd fallback if not found
terminals.emplace_back("ansi"); // 3rd fallback if not found
terminals.emplace_back("vt100"); // 4th fallback if not found
auto iter = terminals.begin();
while ( iter != terminals.end() )

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2018-2020 Markus Gans *
* Copyright 2018-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -241,7 +241,7 @@ void FTermLinux::initCharMap() const
}
//----------------------------------------------------------------------
void FTermLinux::finish()
void FTermLinux::finish() const
{
if ( FTerm::isLinuxTerm() )
{

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2014-2020 Markus Gans *
* Copyright 2014-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -29,6 +29,7 @@
#include "final/fstring.h"
#include "final/fscrollbar.h"
#include "final/fstatusbar.h"
#include "final/ftermbuffer.h"
#include "final/ftextview.h"
#include "final/fwidgetcolors.h"
@ -224,7 +225,6 @@ void FTextView::insert (const FString& str, int pos)
else
s = FString{str}.rtrim().expandTabs(FTerm::getTabstop());
auto text_split = s.split("\r\n");
for (auto&& line : text_split) // Line loop
@ -641,19 +641,17 @@ void FTextView::drawText()
const std::size_t pos = std::size_t(xoffset) + 1;
const auto text_width = getTextWidth();
const FString line(getColumnSubString(data[n], pos, text_width));
const auto column_width = getColumnWidth(line);
std::size_t trailing_whitespace{0};
print() << FPoint{2, 2 - nf_offset + int(y)};
FTermBuffer line_buffer{};
line_buffer.write(line);
for (auto&& ch : line) // Column loop
{
if ( getColumnWidth(ch) == 0 )
continue;
else if ( isPrintable(ch) )
print (ch);
else
print ('.');
}
for (auto&& fchar : line_buffer) // Column loop
if ( ! isPrintable(fchar.ch[0]) )
fchar.ch[0] = L'.';
print(line_buffer);
const auto column_width = getColumnWidth(line);
if ( column_width <= text_width )
trailing_whitespace = text_width - column_width;
@ -693,7 +691,7 @@ inline bool FTextView::isPrintable (wchar_t ch) const
const bool utf8 = ( FTerm::getEncoding() == Encoding::UTF8 ) ? true : false;
if ( (utf8 && std::iswprint(std::wint_t(ch)))
|| (!utf8 && std::isprint(char(ch))) )
|| (! utf8 && std::isprint(char(ch))) )
return true;
return false;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2016-2020 Markus Gans *
* Copyright 2016-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -40,8 +40,10 @@
#include "final/fstyle.h"
#include "final/fsystem.h"
#include "final/fterm.h"
#include "final/ftermdata.h"
#include "final/ftermbuffer.h"
#include "final/ftermdata.h"
#include "final/ftermdetection.h"
#include "final/ftermfreebsd.h"
#include "final/ftermcap.h"
#include "final/ftypes.h"
#include "final/fvterm.h"
@ -53,6 +55,7 @@ namespace finalcut
// static class attributes
bool FVTerm::draw_completed{false};
bool FVTerm::combined_char_support{false};
bool FVTerm::no_terminal_updates{false};
bool FVTerm::cursor_hideable{false};
bool FVTerm::force_terminal_update{false};
@ -490,10 +493,11 @@ int FVTerm::print (FTermArea* area, FChar& term_char)
const int ax = area->cursor_x - 1;
const int ay = area->cursor_y - 1;
std::size_t char_width = term_char.attr.bit.char_width;
if ( char_width == 0 )
char_width = getColumnWidth(term_char); // add column width
if ( term_char.attr.bit.char_width == 0 )
addColumnWidth(term_char); // add column width
auto char_width = term_char.attr.bit.char_width;
if ( char_width == 0 && ! term_char.attr.bit.fullwidth_padding )
return 0;
@ -535,34 +539,23 @@ void FVTerm::print (const FStyle& style)
if ( attr == Style::None )
setNormal();
else if ( (attr & Style::Bold) != Style::None )
setBold();
else if ( (attr & Style::Dim) != Style::None )
setDim();
else if ( (attr & Style::Italic) != Style::None )
setItalic();
else if ( (attr & Style::Underline) != Style::None )
setUnderline();
else if ( (attr & Style::Blink) != Style::None )
setBlink();
else if ( (attr & Style::Reverse) != Style::None )
setReverse();
else if ( (attr & Style::Standout) != Style::None )
setStandout();
else if ( (attr & Style::Invisible) != Style::None )
setInvisible();
else if ( (attr & Style::Protected) != Style::None )
setProtected();
else if ( (attr & Style::CrossedOut) != Style::None )
setCrossedOut();
else if ( (attr & Style::DoubleUnderline) != Style::None )
setDoubleUnderline();
else if ( (attr & Style::Transparent) != Style::None )
setTransparent();
else if ( (attr & Style::ColorOverlay) != Style::None )
setColorOverlay();
else if ( (attr & Style::InheritBackground) != Style::None )
setInheritBackground();
else
{
if ( (attr & Style::Bold) != Style::None ) setBold();
if ( (attr & Style::Dim) != Style::None ) setDim();
if ( (attr & Style::Italic) != Style::None ) setItalic();
if ( (attr & Style::Underline) != Style::None ) setUnderline();
if ( (attr & Style::Blink) != Style::None ) setBlink();
if ( (attr & Style::Reverse) != Style::None ) setReverse();
if ( (attr & Style::Standout) != Style::None ) setStandout();
if ( (attr & Style::Invisible) != Style::None ) setInvisible();
if ( (attr & Style::Protected) != Style::None ) setProtected();
if ( (attr & Style::CrossedOut) != Style::None ) setCrossedOut();
if ( (attr & Style::DoubleUnderline) != Style::None ) setDoubleUnderline();
if ( (attr & Style::Transparent) != Style::None ) setTransparent();
if ( (attr & Style::ColorOverlay) != Style::None ) setColorOverlay();
if ( (attr & Style::InheritBackground) != Style::None ) setInheritBackground();
}
}
//----------------------------------------------------------------------
@ -1285,6 +1278,9 @@ void FVTerm::initTerminal()
// Initialize character lengths
init_characterLengths();
// Check for support for combined characters
init_combined_character();
}
@ -1884,6 +1880,31 @@ void FVTerm::init_characterLengths()
if ( clr_eol_length == 0 )
clr_eol_length = INT_MAX;
}
#include <unistd.h>
//----------------------------------------------------------------------
void FVTerm::init_combined_character()
{
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(UNIT_TEST)
if ( FTermFreeBSD::isFreeBSDConsole() )
return;
#endif
if ( FTerm::getEncoding() != Encoding::UTF8 )
return;
const auto& term_detection = FTerm::getFTermDetection();
if ( term_detection->isCygwinTerminal() )
return;
if ( term_detection->isXTerminal()
|| term_detection->isUrxvtTerminal()
|| term_detection->isMinttyTerm()
|| term_detection->isPuttyTerminal() )
{
combined_char_support = true;
}
}
//----------------------------------------------------------------------
void FVTerm::finish()
@ -2006,7 +2027,7 @@ void FVTerm::getAreaCharacter ( const FPoint& pos, const FTermArea* area
}
//----------------------------------------------------------------------
bool FVTerm::clearTerm (int fillchar) const
bool FVTerm::clearTerm (wchar_t fillchar) const
{
// Clear the real terminal and put cursor at home
@ -2018,7 +2039,7 @@ bool FVTerm::clearTerm (int fillchar) const
appendAttributes (next_attribute);
if ( ! ( (cl || cd || cb) && (normal || ut) )
|| fillchar != ' ' )
|| fillchar != L' ' )
{
return false;
}
@ -2570,7 +2591,7 @@ FVTerm::PrintState FVTerm::repeatCharacter (uInt& x, uInt xmax, uInt y) const
const uInt start_pos = x;
if ( repetitions > repeat_char_length
&& print_char.ch[0] < 128 )
&& is7bit(print_char.ch[0]) && print_char.ch[1] == L'\0' )
{
newFontChanges (print_char);
charsetChanges (print_char);
@ -2917,7 +2938,9 @@ inline void FVTerm::newFontChanges (FChar& next_char)
inline void FVTerm::charsetChanges (FChar& next_char)
{
const wchar_t& ch = next_char.ch[0];
next_char.encoded_char[0] = ch;
std::copy( next_char.ch.begin()
, next_char.ch.end()
, next_char.encoded_char.begin() );
if ( FTerm::getEncoding() == Encoding::UTF8 )
return;
@ -2979,7 +3002,15 @@ inline void FVTerm::appendChar (FChar& next_char) const
charsetChanges (next_char);
appendAttributes (next_char);
characterFilter (next_char);
appendOutputBuffer (next_char.encoded_char[0]);
for (auto&& ch : next_char.encoded_char)
{
if ( ch != L'\0')
appendOutputBuffer(ch);
if ( ! combined_char_support )
return;
}
}
//----------------------------------------------------------------------

View File

@ -801,7 +801,7 @@ enum class FKey : uInt32
struct FKeyHash
{
std::size_t operator () (const FKey& p) const
std::size_t operator () (const FKey& p) const noexcept
{
return std::hash<uInt32>()(uInt32(p));
}

View File

@ -170,6 +170,7 @@ class FLineEdit : public FWidget
// Constants
static constexpr auto NOT_SET = static_cast<std::size_t>(-1);
static constexpr auto NOT_FOUND = static_cast<std::size_t>(-1);
// Methods
void init();

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2012-2020 Markus Gans *
* Copyright 2012-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -167,21 +167,21 @@ class FString
virtual FString getClassName() const;
// inquiries
bool isNull() const;
bool isEmpty() const;
bool isNull() const noexcept;
bool isEmpty() const noexcept;
// Methods
std::size_t getLength() const;
std::size_t capacity() const;
std::size_t getLength() const noexcept;
std::size_t capacity() const noexcept;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
reference front();
reference back() ;
const_reference front() const;
const_reference back() const;
iterator begin() noexcept;
iterator end() noexcept;
const_iterator begin() const noexcept;
const_iterator end() const noexcept;
reference front() noexcept;
reference back() noexcept;
const_reference front() const noexcept;
const_reference back() const noexcept;
template <typename... Args>
FString& sprintf (const FString&, Args&&...);
@ -371,60 +371,60 @@ inline FString FString::getClassName() const
{ return "FString"; }
//----------------------------------------------------------------------
inline bool FString::isNull() const
inline bool FString::isNull() const noexcept
{ return ( bufsize == 0 || (bufsize > 0 && ! string) ); }
//----------------------------------------------------------------------
inline bool FString::isEmpty() const
inline bool FString::isEmpty() const noexcept
{ return ( length == 0 || (length > 0 && string[0] == L'\0') ); }
//----------------------------------------------------------------------
inline std::size_t FString::getLength() const
inline std::size_t FString::getLength() const noexcept
{ return length; }
//----------------------------------------------------------------------
inline std::size_t FString::capacity() const
inline std::size_t FString::capacity() const noexcept
{ return ( length > 0 ) ? bufsize - 1 : 0; }
//----------------------------------------------------------------------
inline FString::iterator FString::begin()
inline FString::iterator FString::begin() noexcept
{ return string; }
//----------------------------------------------------------------------
inline FString::iterator FString::end()
inline FString::iterator FString::end() noexcept
{ return string + length; }
//----------------------------------------------------------------------
inline FString::const_iterator FString::begin() const
inline FString::const_iterator FString::begin() const noexcept
{ return string; }
//----------------------------------------------------------------------
inline FString::const_iterator FString::end() const
inline FString::const_iterator FString::end() const noexcept
{ return string + length; }
//----------------------------------------------------------------------
inline FString::reference FString::front()
inline FString::reference FString::front() noexcept
{
assert ( ! isEmpty() );
return (*this)[0];
}
//----------------------------------------------------------------------
inline FString::reference FString::back()
inline FString::reference FString::back() noexcept
{
assert( ! isEmpty() );
return (*this)[length - 1];
}
//----------------------------------------------------------------------
inline FString::const_reference FString::front() const
inline FString::const_reference FString::front() const noexcept
{
assert ( ! isEmpty() );
return (*this)[0];
}
//----------------------------------------------------------------------
inline FString::const_reference FString::back() const
inline FString::const_reference FString::back() const noexcept
{
assert( ! isEmpty() );
return (*this)[length - 1];

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2012-2020 Markus Gans *
* Copyright 2012-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -381,10 +381,23 @@ std::size_t getLengthFromColumnWidth (const FString&, std::size_t);
std::size_t getColumnWidth (const FString&, std::size_t);
std::size_t getColumnWidth (const FString&);
std::size_t getColumnWidth (const wchar_t);
std::size_t getColumnWidth (FChar&);
std::size_t getColumnWidth (const FChar&);
std::size_t getColumnWidth (const FTermBuffer&);
void addColumnWidth (FChar&);
int getCharLength (const FString&, std::size_t);
int getPrevCharLength (const FString&, std::size_t);
std::size_t searchLeftCharBegin (const FString&, std::size_t);
std::size_t searchRightCharBegin (const FString&, std::size_t);
FPoint readCursorPos();
// Check for 7-bit ASCII
template<typename CharT>
inline bool is7bit (CharT ch)
{
using char_type = typename std::make_unsigned<CharT>::type;
return static_cast<char_type>(ch) < 128;
}
// FTerm inline functions
//----------------------------------------------------------------------
inline FString FTerm::getClassName()

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -110,6 +110,9 @@ class FTermBuffer
private:
FCharVector data{};
void add ( FString::const_iterator&
, FString::const_iterator&
, int& );
// Non-member operators
friend FCharVector& operator << ( FCharVector&

View File

@ -109,7 +109,7 @@ class FTermLinux final
// Methods
void init();
void initCharMap() const;
void finish();
void finish() const;
bool loadVGAFont();
bool loadNewFont();
bool loadOldFont();

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2017-2020 Markus Gans *
* Copyright 2017-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -157,7 +157,7 @@ union attribute
uInt8 byte[4];
};
static constexpr uInt UNICODE_MAX = 5;
static constexpr std::size_t UNICODE_MAX = 5;
using FUnicode = std::array<wchar_t, UNICODE_MAX>;

View File

@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2016-2020 Markus Gans *
* Copyright 2016-2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -339,7 +339,7 @@ class FVTerm
// Constants
// Buffer size for character output on the terminal
static constexpr uInt TERMINAL_OUTPUT_BUFFER_SIZE = 131072;
static constexpr std::size_t TERMINAL_OUTPUT_BUFFER_SIZE = 131072;
// Methods
void resetTextAreaToDefault ( const FTermArea*
@ -371,13 +371,14 @@ class FVTerm
static FChar getOverlappedCharacter (const FPoint&, const FTermArea*);
void init();
static void init_characterLengths();
static void init_combined_character();
void finish();
static void putAreaLine (const FChar&, FChar&, std::size_t);
static void putAreaCharacter ( const FPoint&, const FTermArea*
, const FChar&, FChar& );
static void getAreaCharacter ( const FPoint&, const FTermArea*
, FChar*& );
bool clearTerm (int = ' ') const;
bool clearTerm (wchar_t = L' ') const;
bool clearFullArea (const FTermArea*, FChar&) const;
static void clearAreaWithShadow (const FTermArea*, const FChar&);
static bool canClearToEOL (uInt, uInt);
@ -439,6 +440,7 @@ class FVTerm
static timeval time_last_flush;
static timeval last_term_size_check;
static bool draw_completed;
static bool combined_char_support;
static bool no_terminal_updates;
static bool force_terminal_update;
static uInt64 flush_wait;

View File

@ -12,7 +12,9 @@ noinst_PROGRAMS = \
fdata_test \
fmouse_test \
fkeyboard_test \
fterm_functions_test \
ftermdata_test \
ftermbuffer_test \
ftermdetection_test \
ftermcapquirks_test \
ftermlinux_test \
@ -34,7 +36,9 @@ fcallback_test_SOURCES = fcallback-test.cpp
fdata_test_SOURCES = fdata-test.cpp
fmouse_test_SOURCES = fmouse-test.cpp
fkeyboard_test_SOURCES = fkeyboard-test.cpp
fterm_functions_test_SOURCES = fterm_functions-test.cpp
ftermdata_test_SOURCES = ftermdata-test.cpp
ftermbuffer_test_SOURCES = ftermbuffer-test.cpp
ftermdetection_test_SOURCES = ftermdetection-test.cpp
ftermcapquirks_test_SOURCES = ftermcapquirks-test.cpp
ftermlinux_test_SOURCES = ftermlinux-test.cpp
@ -56,7 +60,9 @@ TESTS = fobject_test \
fdata_test \
fmouse_test \
fkeyboard_test \
fterm_functions_test \
ftermdata_test \
ftermbuffer_test \
ftermdetection_test \
ftermcapquirks_test \
ftermlinux_test \

File diff suppressed because it is too large Load Diff

848
test/ftermbuffer-test.cpp Normal file
View File

@ -0,0 +1,848 @@
/***********************************************************************
* ftermbuffer-test.cpp - FTermBuffer unit tests *
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2021 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 3 of *
* the License, or (at your option) any later version. *
* *
* FINAL CUT is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this program. If not, see *
* <http://www.gnu.org/licenses/>. *
***********************************************************************/
#include <wchar.h>
#include <limits>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestFixture.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TestRunner.h>
#include <final/final.h>
//----------------------------------------------------------------------
// class FTermBufferTest
//----------------------------------------------------------------------
class FTermBufferTest : public CPPUNIT_NS::TestFixture
{
public:
FTermBufferTest()
{
std::setlocale (LC_CTYPE, "en_US.UTF-8");
fwide(stdout, 1); // Makes stream wide-character oriented
}
protected:
void classNameTest();
void noArgumentTest();
void writeTest();
void streamTest();
void combiningCharacterTest();
private:
// Adds code needed to register the test suite
CPPUNIT_TEST_SUITE (FTermBufferTest);
// Add a methods to the test suite
CPPUNIT_TEST (classNameTest);
CPPUNIT_TEST (noArgumentTest);
CPPUNIT_TEST (writeTest);
CPPUNIT_TEST (streamTest);
CPPUNIT_TEST (combiningCharacterTest);
// End of test suite definition
CPPUNIT_TEST_SUITE_END();
};
//----------------------------------------------------------------------
void FTermBufferTest::classNameTest()
{
const finalcut::FTermBuffer s;
const finalcut::FString& classname = s.getClassName();
CPPUNIT_ASSERT ( classname == "FTermBuffer" );
}
//----------------------------------------------------------------------
void FTermBufferTest::noArgumentTest()
{
const finalcut::FTermBuffer term_buf{};
CPPUNIT_ASSERT ( term_buf.isEmpty() );
CPPUNIT_ASSERT ( term_buf.getLength() == 0 );
std::vector<finalcut::FChar> data{};
CPPUNIT_ASSERT ( term_buf.getBuffer() == data );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 0 );
CPPUNIT_ASSERT ( term_buf.begin() == term_buf.end() );
CPPUNIT_ASSERT ( finalcut::UNICODE_MAX == 5 );
}
//----------------------------------------------------------------------
void FTermBufferTest::writeTest()
{
const auto& data = finalcut::FTerm::getFTermData();
data->setTermEncoding (finalcut::Encoding::UTF8);
finalcut::FTermBuffer term_buf{};
// Write wchar_t
const wchar_t wch{L'\U0000263a'}; // ☺
term_buf.write(wch);
CPPUNIT_ASSERT ( ! term_buf.isEmpty() );
CPPUNIT_ASSERT ( term_buf.getLength() == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 1 );
CPPUNIT_ASSERT ( term_buf.begin() + 1 == term_buf.end() );
CPPUNIT_ASSERT ( term_buf.front().ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.front().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().ch[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[0] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().fg_color == 0 );
CPPUNIT_ASSERT ( term_buf.front().bg_color == 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.byte[2] != 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.byte[3] == 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.bit.char_width == 1 );
term_buf.front().attr.bit.char_width = 0;
CPPUNIT_ASSERT ( term_buf.front().attr.byte[2] == 0 );
CPPUNIT_ASSERT ( term_buf.toString() == finalcut::FString(wch) );
// Clear after write
term_buf.clear();
CPPUNIT_ASSERT ( term_buf.isEmpty() );
CPPUNIT_ASSERT ( term_buf.getLength() == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 0 );
CPPUNIT_ASSERT ( term_buf.begin() == term_buf.end() );
CPPUNIT_ASSERT ( term_buf.toString() == finalcut::FString() );
// Write char
const char ch{'@'};
term_buf.write(ch);
CPPUNIT_ASSERT ( ! term_buf.isEmpty() );
CPPUNIT_ASSERT ( term_buf.getLength() == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 1 );
CPPUNIT_ASSERT ( term_buf.begin() + 1 == term_buf.end() );
CPPUNIT_ASSERT ( term_buf.front().ch[0] == L'@' );
CPPUNIT_ASSERT ( term_buf.front().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().ch[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[0] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().encoded_char[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().fg_color == 0 );
CPPUNIT_ASSERT ( term_buf.front().bg_color == 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.byte[2] != 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.byte[3] == 0 );
CPPUNIT_ASSERT ( term_buf.front().attr.bit.char_width == 1 );
term_buf.front().attr.bit.char_width = 0;
CPPUNIT_ASSERT ( term_buf.front().attr.byte[2] == 0 );
CPPUNIT_ASSERT ( term_buf.toString() == finalcut::FString(ch) );
// Write FString
const finalcut::FString str = "abc…";
term_buf.clear();
term_buf.write(str);
CPPUNIT_ASSERT ( ! term_buf.isEmpty() );
CPPUNIT_ASSERT ( term_buf.getLength() == 7 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 7 );
CPPUNIT_ASSERT ( term_buf.begin() + 7 == term_buf.end() );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L'b' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[0] == L'c' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[6].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].attr.bit.char_width == 2 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].attr.bit.char_width == 2 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[6].attr.bit.char_width == 2 );
CPPUNIT_ASSERT ( term_buf.toString() == str );
for (std::size_t i{0}; i < 7; i++)
{
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[0] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].fg_color == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].bg_color == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[2] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[3] == 0 );
}
// Write formatted output
term_buf.clear();
term_buf.writef ("%'.2f%C", 0.25 * 7.0, L'£');
CPPUNIT_ASSERT ( ! term_buf.isEmpty() );
CPPUNIT_ASSERT ( term_buf.getLength() == 5 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 5 );
CPPUNIT_ASSERT ( term_buf.begin() + 5 == term_buf.end() );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'1' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L'.' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[0] == L'7' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[0] == L'5' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].ch[0] == L'£' );
CPPUNIT_ASSERT ( term_buf.toString() == "1.75£" );
for (std::size_t i{0}; i < 5; i++)
{
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[0] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].fg_color == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].bg_color == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[2] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[3] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.bit.char_width == 1 );
}
// Write with color
term_buf.clear();
finalcut::FVTerm::setColor(finalcut::FColor::Default, finalcut::FColor::Default);
term_buf.write (L'');
auto color_pair = finalcut::FColorPair(finalcut::FColor::DarkRed, finalcut::FColor::Yellow4);
term_buf.write (color_pair);
term_buf.write (L'');
finalcut::FVTerm::setNormal();
term_buf.write ("");
color_pair = finalcut::FColorPair(finalcut::FColor::Black, finalcut::FColor::White);
term_buf.write (color_pair);
term_buf.write ("");
CPPUNIT_ASSERT ( ! term_buf.isEmpty() );
CPPUNIT_ASSERT ( term_buf.getLength() == 4 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 4 );
CPPUNIT_ASSERT ( term_buf.begin() + 4 == term_buf.end() );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].fg_color == finalcut::FColor::Default );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].bg_color == finalcut::FColor::Default );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].fg_color == finalcut::FColor::DarkRed );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].bg_color == finalcut::FColor::Yellow4 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].fg_color == finalcut::FColor::Default );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].bg_color == finalcut::FColor::Default );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].fg_color == finalcut::FColor::Black );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].bg_color == finalcut::FColor::White );
CPPUNIT_ASSERT ( term_buf.toString() == "♥☺♪↑" );
for (std::size_t i{0}; i < 4; i++)
{
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[0] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[2] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[3] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.bit.char_width == 1 );
}
// Write with style
term_buf.clear();
auto style = finalcut::FStyle(finalcut::Style::Italic | finalcut::Style::Reverse);
term_buf.write (style);
CPPUNIT_ASSERT ( uInt(style.getStyle()) == uInt(finalcut::FVTerm::getAttribute().attr.byte[0]) );
term_buf.write (L'');
term_buf.write ( finalcut::FStyle(finalcut::Style::None) ); // Reset style
style = finalcut::FStyle(finalcut::Style::Bold | finalcut::Style::Underline);
term_buf.write (style);
term_buf.write (L'');
term_buf.write ( finalcut::FStyle(finalcut::Style::Transparent) );
term_buf.write (L'🧸');
term_buf.write ( finalcut::FStyle(finalcut::Style::None) ); // Reset style
term_buf.write (L'🦡');
CPPUNIT_ASSERT ( ! term_buf.isEmpty() );
CPPUNIT_ASSERT ( term_buf.getLength() == 4 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 4 );
CPPUNIT_ASSERT ( term_buf.begin() + 4 == term_buf.end() );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.italic == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.reverse == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.byte[0] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.bit.bold == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.bit.underline == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.byte[0] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[0] == L'🧸' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.bold == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.underline == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.transparent == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.byte[0] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.byte[1] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[0] == L'🦡' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.bit.bold == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.bit.underline == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.bit.transparent == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.toString() == "☕⛄🧸🦡" );
for (std::size_t i{0}; i < 3; i++)
{
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[0] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[2] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[3] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.bit.char_width == 2 );
}
}
//----------------------------------------------------------------------
void FTermBufferTest::streamTest()
{
const auto& data = finalcut::FTerm::getFTermData();
data->setTermEncoding (finalcut::Encoding::UTF8);
finalcut::FTermBuffer::FCharVector fchar_vec = { finalcut::FChar{} };
CPPUNIT_ASSERT ( fchar_vec.size() == 1 );
fchar_vec.front().ch[0] = L'🥨';
fchar_vec.front().fg_color = finalcut::FColor::White;
fchar_vec.front().bg_color = finalcut::FColor::Cyan;
finalcut::addColumnWidth(fchar_vec.front());
finalcut::FTermBuffer term_buf{};
term_buf.write() << L'a'
<< finalcut::FColorPair{finalcut::FColor::Yellow, finalcut::FColor::Blue}
<< 1
<< finalcut::FColorPair{finalcut::FColor::Cyan, finalcut::FColor::White}
<< finalcut::FStyle(finalcut::Style::Dim)
<< finalcut::UniChar::NF_Bullet
<< finalcut::FStyle(finalcut::Style::Blink)
<< fchar_vec
<< std::string("🧭")
<< finalcut::FStyle(finalcut::Style::None)
<< finalcut::FStyle(finalcut::Style::DoubleUnderline)
<< finalcut::FColorPair{finalcut::FColor::Black, finalcut::FColor::White}
<< std::wstring(L"🚴");
CPPUNIT_ASSERT ( ! term_buf.isEmpty() );
CPPUNIT_ASSERT ( term_buf.getLength() == 6 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 6 );
CPPUNIT_ASSERT ( term_buf.begin() + 6 == term_buf.end() );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].fg_color == finalcut::FColor::Default );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].bg_color == finalcut::FColor::Default );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L'1' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].fg_color == finalcut::FColor::Yellow );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].bg_color == finalcut::FColor::Blue );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[0] == L'\U0000e1f9' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].fg_color == finalcut::FColor::Cyan );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].bg_color == finalcut::FColor::White );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.dim == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.byte[0] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[0] == L'🥨' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].fg_color == finalcut::FColor::White );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].bg_color == finalcut::FColor::Cyan );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.bit.char_width == 2 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].ch[0] == L'🧭' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].fg_color == finalcut::FColor::Cyan );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].bg_color == finalcut::FColor::White );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].attr.bit.dim == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].attr.bit.blink == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].attr.byte[0] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].attr.byte[1] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].attr.bit.char_width == 2 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].ch[0] == L'🚴' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].fg_color == finalcut::FColor::Black );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].bg_color == finalcut::FColor::White );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].attr.bit.dbl_underline == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].attr.byte[0] == 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].attr.byte[1] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].attr.bit.char_width == 2 );
CPPUNIT_ASSERT ( term_buf.toString() == "a1\U0000e1f9🥨🧭🚴" );
for (std::size_t i{0}; i < 6; i++)
{
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].ch[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[0] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].encoded_char[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[2] != 0 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[i].attr.byte[3] == 0 );
}
}
//----------------------------------------------------------------------
void FTermBufferTest::combiningCharacterTest()
{
const auto& data = finalcut::FTerm::getFTermData();
data->setTermEncoding (finalcut::Encoding::UTF8);
finalcut::FTermBuffer term_buf{};
// Skip leading zero-width characters
std::wstring combining = L"\U00000323\U00000300\U0000ff2f\n"; // [] [] [NL]
term_buf.write(combining);
CPPUNIT_ASSERT ( ! term_buf.isEmpty() );
CPPUNIT_ASSERT ( combining.length() == 4 );
CPPUNIT_ASSERT ( wcwidth(combining[0]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[1]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[2]) == 2 );
CPPUNIT_ASSERT ( wcwidth(combining[3]) == -1 );
CPPUNIT_ASSERT ( term_buf.getLength() == 2 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 2 );
CPPUNIT_ASSERT ( term_buf.begin() != term_buf.end() );
CPPUNIT_ASSERT ( term_buf.front().ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.front().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().ch[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.front().attr.bit.char_width == 2 );
CPPUNIT_ASSERT ( term_buf.back().ch[0] == L'\012' );
CPPUNIT_ASSERT ( term_buf.back().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.back().ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.back().ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.back().ch[4] == L'\0' );
CPPUNIT_ASSERT ( term_buf.back().attr.bit.char_width == 0 );
CPPUNIT_ASSERT ( term_buf.toString() != combining );
CPPUNIT_ASSERT ( term_buf.toString() == L"\012" );
// Characters with separate and with combined diacritical marks
combining = L"u\U00000300=\U000000f9"; // u ` = ù
term_buf.clear();
term_buf.write(combining);
CPPUNIT_ASSERT ( ! term_buf.isEmpty() );
CPPUNIT_ASSERT ( combining.length() == 4 );
CPPUNIT_ASSERT ( wcwidth(combining[0]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[1]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[2]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[3]) == 1 );
CPPUNIT_ASSERT ( term_buf.getLength() == 3 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 3 );
CPPUNIT_ASSERT ( term_buf.begin() != term_buf.end() );
CPPUNIT_ASSERT ( term_buf.front().ch[0] == L'u' );
CPPUNIT_ASSERT ( int(term_buf.front().ch[1]) == 0x300 );
CPPUNIT_ASSERT ( term_buf.front().ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'u' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[1] == L'\U00000300' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L'=' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[0] == L'ù' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.back().ch[0] == L'ù' );
CPPUNIT_ASSERT ( term_buf.back().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.toString() == combining );
CPPUNIT_ASSERT ( term_buf.toString() == L"ù=ù" );
combining = L"o\U0000031b\U00000323=\U00001ee3"; // o ‍̛ ‍̣ = ợ
term_buf.clear();
term_buf.write(combining);
CPPUNIT_ASSERT ( combining.length() == 5 );
CPPUNIT_ASSERT ( wcwidth(combining[0]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[1]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[2]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[3]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[4]) == 1 );
CPPUNIT_ASSERT ( term_buf.getLength() == 3 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 3 );
CPPUNIT_ASSERT ( term_buf.begin() != term_buf.end() );
CPPUNIT_ASSERT ( term_buf.front().ch[0] == L'o' );
CPPUNIT_ASSERT ( term_buf.front().ch[1] == L'\U0000031b' );
CPPUNIT_ASSERT ( term_buf.front().ch[2] == L'\U00000323' );
CPPUNIT_ASSERT ( term_buf.front().ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'o' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[1] == L'\U0000031b' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[2] == L'\U00000323' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L'=' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.back().ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.back().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.toString() == combining );
CPPUNIT_ASSERT ( term_buf.toString() == L"ợ=ợ" );
// Too many combination characters
combining = L"v" \
L"\U00000300\U0000032e\U00000368" \
L"\U00000364\U00000348\U0000034b"; // v ̀ ̮ ͨ ͤ ͈ ͋
term_buf.clear();
term_buf << combining;
CPPUNIT_ASSERT ( combining.length() == 7 );
CPPUNIT_ASSERT ( wcwidth(combining[0]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[1]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[2]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[3]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[4]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[5]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[6]) == 0 );
CPPUNIT_ASSERT ( term_buf.getLength() == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 1 );
CPPUNIT_ASSERT ( term_buf.begin() != term_buf.end() );
CPPUNIT_ASSERT ( term_buf.front() == term_buf.back() );
CPPUNIT_ASSERT ( term_buf.front().ch[0] == L'v' );
CPPUNIT_ASSERT ( term_buf.front().ch[1] == L'\U00000300' );
CPPUNIT_ASSERT ( term_buf.front().ch[2] == L'\U0000032e' );
CPPUNIT_ASSERT ( term_buf.front().ch[3] == L'\U00000368' );
CPPUNIT_ASSERT ( term_buf.front().ch[4] == L'\U00000364' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'v' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[1] == L'\U00000300' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[2] == L'\U0000032e' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[3] == L'\U00000368' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[4] == L'\U00000364' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.back().ch[0] == L'v' );
CPPUNIT_ASSERT ( term_buf.back().ch[1] == L'\U00000300' );
CPPUNIT_ASSERT ( term_buf.back().ch[2] == L'\U0000032e' );
CPPUNIT_ASSERT ( term_buf.back().ch[3] == L'\U00000368' );
CPPUNIT_ASSERT ( term_buf.back().ch[4] == L'\U00000364' );
CPPUNIT_ASSERT ( term_buf.toString() != combining );
CPPUNIT_ASSERT ( term_buf.toString() == L"v̮̀ͨͤ" );
// Ignore trailing uncombined zero-width characters
combining = L"a\t\U00000300\U00000323"; // a [Tab] [] []
term_buf.clear();
term_buf.write(combining);
CPPUNIT_ASSERT ( combining.length() == 4 );
CPPUNIT_ASSERT ( wcwidth(combining[0]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[1]) == -1 );
CPPUNIT_ASSERT ( wcwidth(combining[2]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[3]) == 0 );
CPPUNIT_ASSERT ( term_buf.getLength() == 2 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 2 );
CPPUNIT_ASSERT ( term_buf.begin() != term_buf.end() );
CPPUNIT_ASSERT ( term_buf.front().ch[0] == L'a' );
CPPUNIT_ASSERT ( term_buf.front().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L'\t' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.bit.char_width == 0 );
CPPUNIT_ASSERT ( term_buf.back().ch[0] == L'\t' );
CPPUNIT_ASSERT ( term_buf.back().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.toString() != combining );
CPPUNIT_ASSERT ( term_buf.toString() == L"a\t" );
// Thai (ISO 10646-1 - UCS implementation level 2)
combining = L"๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช";
term_buf.clear();
term_buf.write(combining);
CPPUNIT_ASSERT ( combining.length() == 32 );
CPPUNIT_ASSERT ( wcwidth(combining[0]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[1]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[2]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[3]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[4]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[5]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[6]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[7]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[8]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[9]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[10]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[11]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[12]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[13]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[14]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[15]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[16]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[17]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[18]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[19]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[20]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[21]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[22]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[23]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[24]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[25]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[26]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[27]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[28]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[29]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[30]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[31]) == 1 );
CPPUNIT_ASSERT ( term_buf.getLength() == 25 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 25 );
CPPUNIT_ASSERT ( term_buf.begin() != term_buf.end() );
CPPUNIT_ASSERT ( term_buf.front().ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.front().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'\U00000e4f' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L' ' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[0] == L'\U00000e41' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[0] == L'\U00000e1c' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[1] == L'\U00000e48' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].ch[0] == L'\U00000e19' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].ch[0] == L'\U00000e14' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].ch[1] == L'\U00000e34' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[6].ch[0] == L'\U00000e19' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[6].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[7].ch[0] == L'\U00000e2e' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[7].ch[1] == L'\U00000e31' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[7].ch[2] == L'\U00000e48' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[7].ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[8].ch[0] == L'\U00000e19' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[8].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[9].ch[0] == L'\U00000e40' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[9].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[10].ch[0] == L'\U00000e2a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[10].ch[1] == L'\U00000e37' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[10].ch[2] == L'\U00000e48' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[10].ch[3] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[11].ch[0] == L'\U00000e2d' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[11].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[12].ch[0] == L'\U00000e21' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[12].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[13].ch[0] == L'\U00000e42' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[13].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[14].ch[0] == L'\U00000e17' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[14].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[15].ch[0] == L'\U00000e23' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[15].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[16].ch[0] == L'\U00000e21' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[16].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[17].ch[0] == L'\U00000e41' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[17].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[18].ch[0] == L'\U00000e2a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[18].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[19].ch[0] == L'\U00000e19' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[19].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[20].ch[0] == L'\U00000e2a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[20].ch[1] == L'\U00000e31' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[20].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[21].ch[0] == L'\U00000e07' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[21].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[22].ch[0] == L'\U00000e40' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[22].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[23].ch[0] == L'\U00000e27' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[23].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[24].ch[0] == L'\U00000e0a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[24].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[6].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[7].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[8].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[9].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[10].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[11].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[12].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[13].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[14].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[15].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[16].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[17].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[18].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[19].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[20].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[21].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[22].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[23].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[24].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.back().ch[0] == L'' );
CPPUNIT_ASSERT ( term_buf.back().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.toString() == combining );
CPPUNIT_ASSERT ( term_buf.toString() == L"๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช" );
// Devanagari script (ISO 10646-1 - UCS implementation level 2)
combining = L"पन्ह पन्ह त्र र्च कृकृ ड्ड न्ह";
term_buf.clear();
term_buf.write(combining);
CPPUNIT_ASSERT ( combining.length() == 30 );
CPPUNIT_ASSERT ( wcwidth(combining[0]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[1]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[2]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[3]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[4]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[5]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[6]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[7]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[8]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[9]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[10]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[11]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[12]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[13]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[14]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[15]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[16]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[17]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[18]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[19]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[20]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[21]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[22]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[23]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[24]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[25]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[26]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[27]) == 1 );
CPPUNIT_ASSERT ( wcwidth(combining[28]) == 0 );
CPPUNIT_ASSERT ( wcwidth(combining[29]) == 1 );
CPPUNIT_ASSERT ( term_buf.getLength() == 22 );
CPPUNIT_ASSERT ( term_buf.getBuffer().size() == 22 );
CPPUNIT_ASSERT ( term_buf.begin() != term_buf.end() );
CPPUNIT_ASSERT ( term_buf.front().ch[0] == L'\U0000092a' );
CPPUNIT_ASSERT ( term_buf.front().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[0] == L'\U0000092a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[0] == L'\U00000928' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[1] == L'\U0000094d' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[0] == L'\U00000939' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[0] == L' ' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].ch[0] == L'\U0000092a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].ch[0] == L'\U00000928' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].ch[1] == L'\U0000094d' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[6].ch[0] == L'\U00000939' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[6].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[7].ch[0] == L' ' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[7].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[8].ch[0] == L'\U00000924' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[8].ch[1] == L'\U0000094d' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[8].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[9].ch[0] == L'\U00000930' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[9].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[10].ch[0] == L' ' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[10].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[11].ch[0] == L'\U00000930' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[11].ch[1] == L'\U0000094d' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[11].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[12].ch[0] == L'\U0000091a' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[12].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[13].ch[0] == L' ' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[13].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[14].ch[0] == L'\U00000915' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[14].ch[1] == L'\U00000943' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[14].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[15].ch[0] == L'\U00000915' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[15].ch[1] == L'\U00000943' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[15].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[16].ch[0] == L' ' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[16].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[17].ch[0] == L'\U00000921' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[17].ch[1] == L'\U0000094d' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[17].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[18].ch[0] == L'\U00000921' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[18].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[19].ch[0] == L' ' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[19].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[20].ch[0] == L'\U00000928' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[20].ch[1] == L'\U0000094d' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[20].ch[2] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[21].ch[0] == L'\U00000939' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[21].ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.getBuffer()[0].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[1].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[2].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[3].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[4].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[5].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[6].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[7].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[8].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[9].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[10].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[11].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[12].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[13].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[14].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[15].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[16].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[17].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[18].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[19].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[20].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.getBuffer()[21].attr.bit.char_width == 1 );
CPPUNIT_ASSERT ( term_buf.back().ch[0] == L'\U00000939' );
CPPUNIT_ASSERT ( term_buf.back().ch[1] == L'\0' );
CPPUNIT_ASSERT ( term_buf.toString() == combining );
CPPUNIT_ASSERT ( term_buf.toString() == L"पन्ह पन्ह त्र र्च कृकृ ड्ड न्ह" );
}
// Put the test suite in the registry
CPPUNIT_TEST_SUITE_REGISTRATION (FTermBufferTest);
// The general unit test main part
#include <main-test.inc>