* Change the line history to a more compact format. We reserve

lines * (width + 8) bytes which is only a little more than a sixth of
  what it was before. The effect on performance is relatively small. In
  my tests I measured about 2% slowdown.
* Fixed artifacts after soft-wrapped lines.
* Re-enabled cursor blinking. I changed it so that the cursor is 1s
  shown and 0.5s hidden (instead of 1s each). Tell me what you think.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25957 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2008-06-14 21:37:40 +00:00
parent 345dc29f8a
commit 4c9d4b02ef
10 changed files with 991 additions and 441 deletions

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,14 @@
#include <limits.h>
#include "HistoryBuffer.h"
#include "TermPos.h"
#include "UTF8Char.h"
class BString;
class TerminalCharClassifier;
struct TerminalLine;
struct TerminalBufferDirtyInfo {
@ -54,7 +56,8 @@ public:
int32 Width() const { return fWidth; }
int32 Height() const { return fHeight; }
int32 HistorySize() const { return fHistorySize; }
inline int32 HistorySize() const;
inline int32 HistoryCapacity() const;
TerminalBufferDirtyInfo& DirtyInfo() { return fDirtyInfo; }
@ -125,40 +128,32 @@ public:
void SetScrollRegion(int32 top, int32 bot);
protected:
struct Cell {
UTF8Char character;
uint16 attributes;
};
struct Line {
int16 length;
bool softBreak; // soft line break
Cell cells[1];
inline void Clear()
{
length = 0;
softBreak = false;
}
};
virtual void NotifyListener();
inline int32 _LineIndex(int32 index) const;
inline Line* _LineAt(int32 index) const;
inline Line* _HistoryLineAt(int32 index) const;
inline TerminalLine* _LineAt(int32 index) const;
inline TerminalLine* _HistoryLineAt(int32 index,
TerminalLine* lineBuffer) const;
inline void _Invalidate(int32 top, int32 bottom);
inline void _CursorChanged();
static Line** _AllocateLines(int32 width, int32 count);
static void _FreeLines(Line** lines, int32 count);
static TerminalLine** _AllocateLines(int32 width, int32 count);
static void _FreeLines(TerminalLine** lines, int32 count);
void _ClearLines(int32 first, int32 last);
status_t _ResizeHistory(int32 width,
int32 historyCapacity);
status_t _ResizeSimple(int32 width, int32 height,
int32 historyCapacity);
status_t _ResizeRewrap(int32 width, int32 height,
int32 historyCapacity);
void _Scroll(int32 top, int32 bottom,
int32 numLines);
void _SoftBreakLine();
void _PadLineToCursor();
static void _TruncateLine(TerminalLine* line, int32 length);
void _InsertGap(int32 width);
bool _GetPartialLineString(BString& string,
int32 row, int32 startColumn,
@ -176,10 +171,9 @@ protected:
int32 fScrollBottom; // last line to scroll (incl.)
// line buffers for the history (ring buffer)
Line** fHistory;
int32 fHistoryCapacity;
TerminalLine** fScreen;
int32 fScreenOffset; // index of screen line 0
int32 fHistorySize;
HistoryBuffer* fHistory;
// cursor position (origin: (0, 0))
TermPos fCursor;
@ -194,6 +188,20 @@ protected:
};
int32
BasicTerminalBuffer::HistorySize() const
{
return fHistory != NULL ? fHistory->Size() : 0;
}
int32
BasicTerminalBuffer::HistoryCapacity() const
{
return fHistory != NULL ? fHistory->Capacity() : 0;
}
void
BasicTerminalBuffer::InsertChar(const char* c, int32 length, uint32 attributes)
{

View File

@ -0,0 +1,280 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "HistoryBuffer.h"
#include <new>
#include <OS.h>
#include "TermConst.h"
HistoryBuffer::HistoryBuffer()
:
fLines(NULL),
fWidth(0),
fCapacity(0),
fNextLine(0),
fSize(0),
fBuffer(NULL),
fBufferSize(0),
fBufferAllocationOffset(0)
{
}
HistoryBuffer::~HistoryBuffer()
{
delete[] fLines;
delete[] fBuffer;
}
status_t
HistoryBuffer::Init(int32 width, int32 capacity)
{
if (width <= 0 || capacity <= 0)
return B_BAD_VALUE;
int32 bufferSize = (width + 4) * capacity;
if (capacity > 0) {
fLines = new(std::nothrow) HistoryLine[capacity];
fBuffer = new(std::nothrow) uint8[bufferSize];
if (fLines == NULL || fBuffer == NULL)
return B_NO_MEMORY;
}
fWidth = width;
fCapacity = capacity;
fNextLine = 0;
fSize = 0;
fBufferSize = bufferSize;
fBufferAllocationOffset = 0;
return B_OK;
}
void
HistoryBuffer::Clear()
{
fNextLine = 0;
fSize = 0;
fBufferAllocationOffset = 0;
}
TerminalLine*
HistoryBuffer::GetTerminalLineAt(int32 index, TerminalLine* buffer) const
{
HistoryLine* line = LineAt(index);
if (line == NULL)
return NULL;
int32 charCount = 0;
const char* chars = line->Chars();
buffer->length = 0;
uint16 attributes = 0;
AttributesRun* attributesRun = line->AttributesRuns();
int32 attributesRunCount = line->attributesRunCount;
int32 nextAttributesAt = attributesRunCount > 0
? attributesRun->offset : INT_MAX;
for (int32 i = 0; i < line->byteLength;) {
// get attributes
if (charCount == nextAttributesAt) {
if (attributesRunCount > 0) {
attributes = attributesRun->attributes;
nextAttributesAt = attributesRun->offset + attributesRun->length;
attributesRun++;
attributesRunCount--;
} else {
attributes = 0;
nextAttributesAt = INT_MAX;
}
}
// copy character
TerminalCell& cell = buffer->cells[charCount++];
int32 charLength = UTF8Char::ByteCount(chars[i]);
cell.character.SetTo(chars + i, charLength);
i += charLength;
// set attributes
cell.attributes = attributes;
// full width char?
if (cell.character.IsFullWidth()) {
cell.attributes |= A_WIDTH;
charCount++;
}
}
buffer->length = charCount;
buffer->softBreak = line->softBreak;
return buffer;
}
void
HistoryBuffer::AddLine(const TerminalLine* line)
{
//debug_printf("HistoryBuffer::AddLine(%p): length: %d\n", line, line->length);
// determine the amount of memory we need for the line
uint16 attributes = 0;
int32 attributesRuns = 0;
int32 byteLength = 0;
for (int32 i = 0; i < line->length; i++) {
const TerminalCell& cell = line->cells[i];
byteLength += cell.character.ByteCount();
if ((cell.attributes & CHAR_ATTRIBUTES) != attributes) {
attributes = cell.attributes & CHAR_ATTRIBUTES;
if (attributes != 0)
attributesRuns++;
}
if (IS_WIDTH(cell.attributes))
i++;
}
//debug_printf(" attributesRuns: %ld, byteLength: %ld\n", attributesRuns, byteLength);
// allocate and translate the line
HistoryLine* historyLine = _AllocateLine(attributesRuns, byteLength);
attributes = 0;
AttributesRun* attributesRun = historyLine->AttributesRuns();
char* chars = historyLine->Chars();
for (int32 i = 0; i < line->length; i++) {
const TerminalCell& cell = line->cells[i];
// copy char
int32 charLength = cell.character.ByteCount();
memcpy(chars, cell.character.bytes, charLength);
chars += charLength;
// deal with attributes
if ((cell.attributes & CHAR_ATTRIBUTES) != attributes) {
// terminate the previous attributes run
if (attributes != 0) {
attributesRun->length = i - attributesRun->offset;
attributesRun++;
}
attributes = cell.attributes & CHAR_ATTRIBUTES;
// init the new one
if (attributes != 0) {
attributesRun->attributes = attributes;
attributesRun->offset = i;
}
}
if (IS_WIDTH(cell.attributes))
i++;
}
historyLine->softBreak = line->softBreak;
//debug_printf(" line: \"%.*s\", history size now: %ld\n", historyLine->byteLength, historyLine->Chars(), fSize);
}
void
HistoryBuffer::AddEmptyLines(int32 count)
{
if (count <= 0)
return;
if (count > fCapacity)
count = fCapacity;
if (count + fSize > fCapacity)
DropLines(count + fSize - fCapacity);
// All lines use the same buffer address, since they don't use any memory.
AttributesRun* attributesRun
= (AttributesRun*)(fBuffer + fBufferAllocationOffset);
for (int32 i = 0; i < count; i++) {
HistoryLine* line = _LineAt(fNextLine++);
line->attributesRuns = attributesRun;
line->attributesRunCount = 0;
line->byteLength = 0;
line->softBreak = false;
}
fSize += count;
}
void
HistoryBuffer::DropLines(int32 count)
{
if (count <= 0)
return;
if (count < fSize) {
fSize -= count;
} else {
fSize = 0;
fNextLine = 0;
fBufferAllocationOffset = 0;
}
}
HistoryLine*
HistoryBuffer::_AllocateLine(int32 attributesRuns, int32 byteLength)
{
// we need at least one spare line slot
int32 toDrop = 0;
if (fSize == fCapacity)
toDrop = 1;
int32 bytesNeeded = attributesRuns * sizeof(AttributesRun) + byteLength;
if (fBufferAllocationOffset + bytesNeeded > fBufferSize) {
// drop all lines after the allocation index
for (; toDrop < fSize; toDrop++) {
HistoryLine* line = _LineAt(fSize - toDrop - 1);
int32 offset = (uint8*)line->AttributesRuns() - fBuffer;
if (offset < fBufferAllocationOffset)
break;
}
fBufferAllocationOffset = 0;
}
// drop all lines interfering
int32 nextOffset = (fBufferAllocationOffset + bytesNeeded + 1) & ~1;
for (; toDrop < fSize; toDrop++) {
HistoryLine* line = _LineAt(fSize - toDrop - 1);
int32 offset = (uint8*)line->AttributesRuns() - fBuffer;
if (offset + line->BufferSize() <= fBufferAllocationOffset
|| offset >= nextOffset) {
break;
}
}
DropLines(toDrop);
// init the line
HistoryLine* line = &fLines[fNextLine];
fNextLine = (fNextLine + 1) % fCapacity;
fSize++;
line->attributesRuns = (AttributesRun*)(fBuffer + fBufferAllocationOffset);
line->attributesRunCount = attributesRuns;
line->byteLength = byteLength;
fBufferAllocationOffset = (fBufferAllocationOffset + bytesNeeded + 1) & ~1;
// DropLines() may have changed fBufferAllocationOffset, so don't use
// nextOffset.
return line;
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef HISTORY_BUFFER_H
#define HISTORY_BUFFER_H
#include <SupportDefs.h>
#include "TerminalLine.h"
struct HistoryLine;
struct TerminalLine;
class HistoryBuffer {
public:
HistoryBuffer();
~HistoryBuffer();
status_t Init(int32 width, int32 capacity);
void Clear();
int32 Width() const { return fWidth; }
int32 Capacity() const { return fCapacity; }
int32 Size() const { return fSize; }
inline HistoryLine* LineAt(int32 index) const;
TerminalLine* GetTerminalLineAt(int32 index,
TerminalLine* buffer) const;
void AddLine(const TerminalLine* line);
void AddEmptyLines(int32 count);
void DropLines(int32 count);
private:
HistoryLine* _AllocateLine(int32 attributesRuns,
int32 byteLength);
inline HistoryLine* _LineAt(int32 index) const;
private:
HistoryLine* fLines;
int32 fWidth;
int32 fCapacity;
int32 fNextLine;
int32 fSize;
uint8* fBuffer;
int32 fBufferSize;
int32 fBufferAllocationOffset;
};
inline HistoryLine*
HistoryBuffer::_LineAt(int32 index) const
{
return &fLines[(fCapacity + fNextLine - index - 1) % fCapacity];
}
inline HistoryLine*
HistoryBuffer::LineAt(int32 index) const
{
return index >= 0 && index < fSize ? _LineAt(index) : NULL;
}
#endif // HISTORY_BUFFER_H

View File

@ -11,6 +11,7 @@ Application Terminal :
CodeConv.cpp
Coding.cpp
FindWindow.cpp
HistoryBuffer.cpp
MenuUtil.cpp
Terminal.cpp
PrefHandler.cpp

View File

@ -161,18 +161,19 @@ enum{
#define IN_STRING 0xFF
// TermBuffer extended attribute
#define A_WIDTH 0x8000
#define BOLD 0x4000
#define UNDERLINE 0x2000
#define INVERSE 0x1000
#define MOUSE 0x0800
#define FORESET 0x0400
#define BACKSET 0x0200
#define FONT 0x0100
#define RESERVE 0x0080
#define DUMPCR 0x0040
#define FORECOLOR 0x0038
#define BACKCOLOR 0x0007
#define A_WIDTH 0x8000
#define BOLD 0x4000
#define UNDERLINE 0x2000
#define INVERSE 0x1000
#define MOUSE 0x0800
#define FORESET 0x0400
#define BACKSET 0x0200
#define FONT 0x0100
#define RESERVE 0x0080
#define DUMPCR 0x0040
#define FORECOLOR 0x0038
#define BACKCOLOR 0x0007
#define CHAR_ATTRIBUTES 0x773f
#define IS_WIDTH(x) (((x) & A_WIDTH) )
#define IS_BOLD(x) (((x) & BOLD) )

View File

@ -96,6 +96,10 @@ static const uint32 kAutoScroll = 'AScr';
static const bigtime_t kSyncUpdateGranularity = 100000; // 0.1 s
static const int32 kCursorBlinkIntervals = 3;
static const int32 kCursorVisibleIntervals = 2;
static const bigtime_t kCursorBlinkInterval = 500000;
static const rgb_color kBlackColor = { 0, 0, 0, 255 };
static const rgb_color kWhiteColor = { 255, 255, 255, 255 };
@ -198,11 +202,8 @@ TermView::TermView(BRect frame, int32 argc, const char **argv, int32 historySize
fFontHeight(0),
fFontAscent(0),
fFrameResized(false),
fLastCursorTime(0),
fCursorDrawFlag(true),
fCursorStatus(true),
fCursorBlinkingFlag(true),
fCursorRedrawFlag(true),
fLastActivityTime(0),
fCursorState(0),
fCursorHeight(0),
fCursor(0, 0),
fTermRows(ROWS_DEFAULT),
@ -244,11 +245,8 @@ TermView::TermView(int rows, int columns, int32 argc, const char **argv, int32 h
fFontHeight(0),
fFontAscent(0),
fFrameResized(false),
fLastCursorTime(0),
fCursorDrawFlag(true),
fCursorStatus(true),
fCursorBlinkingFlag(true),
fCursorRedrawFlag(true),
fLastActivityTime(0),
fCursorState(0),
fCursorHeight(0),
fCursor(0, 0),
fTermRows(rows),
@ -302,11 +300,8 @@ TermView::TermView(BMessage *archive)
fFontHeight(0),
fFontAscent(0),
fFrameResized(false),
fLastCursorTime(0),
fCursorDrawFlag(true),
fCursorStatus(true),
fCursorBlinkingFlag(true),
fCursorRedrawFlag(true),
fLastActivityTime(0),
fCursorState(0),
fCursorHeight(0),
fCursor(0, 0),
fTermRows(ROWS_DEFAULT),
@ -379,8 +374,7 @@ TermView::_InitObject(int32 argc, const char **argv)
return error;
fTextBuffer->SetEncoding(fEncoding);
error = fVisibleTextBuffer->Init(fTermColumns, fTermRows + 2,
fTermRows + 2);
error = fVisibleTextBuffer->Init(fTermColumns, fTermRows + 2, 0);
if (error != B_OK)
return error;
@ -503,7 +497,7 @@ TermView::SetTermSize(int rows, int columns, bool resize)
{
BAutolock _(fTextBuffer);
if (fTextBuffer->ResizeTo(columns, rows) != B_OK
|| fVisibleTextBuffer->ResizeTo(columns, rows + 2, rows + 2)
|| fVisibleTextBuffer->ResizeTo(columns, rows + 2, 0)
!= B_OK) {
return Bounds();
}
@ -718,6 +712,7 @@ TermView::Clear()
BAutolock _(fTextBuffer);
fTextBuffer->Clear();
}
fVisibleTextBuffer->Clear();
//debug_printf("Invalidate()\n");
Invalidate();
@ -750,59 +745,6 @@ TermView::_InvalidateTextRange(TermPos start, TermPos end)
}
void
TermView::BlinkCursor()
{
#if 0
if (fCursorDrawFlag
&& fCursorBlinkingFlag
&& Window()->IsActive()) {
if (fCursorStatus)
_TermDraw(fCurPos, fCurPos);
else
DrawCursor();
fCursorStatus = !fCursorStatus;
fLastCursorTime = system_time();
}
#endif // 0
}
//! Draw / Clear cursor.
void
TermView::SetCurDraw(bool flag)
{
#if 0
if (!flag) {
if (fCursorStatus)
_TermDraw(fCurPos, fCurPos);
fCursorStatus = false;
fCursorDrawFlag = false;
} else {
if (!fCursorDrawFlag) {
fCursorDrawFlag = true;
fCursorStatus = true;
if (LockLooper()) {
DrawCursor();
UnlockLooper();
}
}
}
#endif
}
//! Sets cursor Blinking flag.
void
TermView::SetCurBlinking(bool flag)
{
fCursorBlinkingFlag = flag;
}
status_t
TermView::_AttachShell(Shell *shell)
{
@ -905,6 +847,8 @@ TermView::_DrawCursor()
UTF8Char character;
uint16 attr;
bool cursorVisible = _IsCursorVisible();
bool selected = _CheckSelectedRegion(TermPos(fCursor.x, fCursor.y));
if (fVisibleTextBuffer->GetChar(fCursor.y - firstVisible, fCursor.x,
character, attr) == A_CHAR) {
@ -920,18 +864,52 @@ TermView::_DrawCursor()
buffer[bytes] = '\0';
_DrawLinePart(fCursor.x * fFontWidth, (int32)rect.top, attr, buffer,
width, selected, true, this);
width, selected, cursorVisible, this);
} else {
if (selected)
SetHighColor(fSelectBackColor);
else
SetHighColor(fCursorBackColor);
SetHighColor(cursorVisible ? fCursorBackColor : fTextBackColor);
FillRect(rect);
}
}
bool
TermView::_IsCursorVisible() const
{
return fCursorState < kCursorVisibleIntervals;
}
void
TermView::_BlinkCursor()
{
bool wasVisible = _IsCursorVisible();
bigtime_t now = system_time();
if (Window()->IsActive() && now - fLastActivityTime >= kCursorBlinkInterval)
fCursorState = (fCursorState + 1) % kCursorBlinkIntervals;
else
fCursorState = 0;
if (wasVisible != _IsCursorVisible())
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
}
void
TermView::_ActivateCursor(bool invalidate)
{
fLastActivityTime = system_time();
if (invalidate && fCursorState != 0)
_BlinkCursor();
else
fCursorState = 0;
}
//! Update scroll bar range and knob size.
void
TermView::_UpdateScrollBarRange()
@ -983,10 +961,6 @@ TermView::AttachedToWindow()
BMessage message(kUpdateSigWinch);
fWinchRunner = new (std::nothrow) BMessageRunner(thisMessenger,
&message, 500000);
BMessage blinkMessage(kBlinkCursor);
fCursorBlinkRunner = new (std::nothrow) BMessageRunner(thisMessenger,
&blinkMessage, 1000000);
}
@ -1009,8 +983,6 @@ TermView::Draw(BRect updateRect)
// return;
// }
// BAutolock _(fTextBuffer);
// debug_printf("TermView::Draw((%f, %f) - (%f, %f))\n", updateRect.left,
// updateRect.top, updateRect.right, updateRect.bottom);
// {
@ -1027,8 +999,6 @@ TermView::Draw(BRect updateRect)
// }
// }
// _SynchronizeWithTextBuffer(&updateRect);
int32 x1 = (int32)(updateRect.left) / fFontWidth;
int32 x2 = (int32)(updateRect.right) / fFontWidth;
@ -1045,7 +1015,6 @@ TermView::Draw(BRect updateRect)
int32 k = x1;
char buf[fTermColumns * 4 + 1];
// if (fTextBuffer->IsFullWidthChar(j, k))
if (fVisibleTextBuffer->IsFullWidthChar(j - firstVisible, k))
k--;
@ -1056,7 +1025,6 @@ TermView::Draw(BRect updateRect)
int32 lastColumn = x2;
bool insideSelection = _CheckSelectedRegion(j, i, lastColumn);
uint16 attr;
// int32 count = fTextBuffer->GetString(j, i, lastColumn, buf, attr);
int32 count = fVisibleTextBuffer->GetString(j - firstVisible, i,
lastColumn, buf, attr);
@ -1079,8 +1047,6 @@ TermView::Draw(BRect updateRect)
_DrawLinePart(fFontWidth * i, (int32)_LineOffset(j),
attr, buf, count, insideSelection, false, this);
i += count;
if (i >= fTermColumns)
break;
}
}
@ -1141,8 +1107,21 @@ void
TermView::WindowActivated(bool active)
{
BView::WindowActivated(active);
if (active == false) {
if (active) {
// start cursor blinking
if (fCursorBlinkRunner == NULL) {
BMessage blinkMessage(kBlinkCursor);
fCursorBlinkRunner = new (std::nothrow) BMessageRunner(
BMessenger(this), &blinkMessage, kCursorBlinkInterval);
}
} else {
// DoIMConfirm();
// make sure the cursor becomes visible
fCursorState = 0;
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
delete fCursorBlinkRunner;
fCursorBlinkRunner = NULL;
}
}
@ -1162,6 +1141,8 @@ TermView::KeyDown(const char *bytes, int32 numBytes)
currentMessage->FindInt32("key", &key);
currentMessage->FindInt32("raw_char", &rawChar);
_ActivateCursor(true);
// Terminal filters RET, ENTER, F1...F12, and ARROW key code.
// TODO: Cleanup
if (numBytes == 1) {
@ -1441,7 +1422,7 @@ TermView::MessageReceived(BMessage *msg)
// }
// }
case kBlinkCursor:
BlinkCursor();
_BlinkCursor();
break;
case kUpdateSigWinch:
_UpdateSIGWINCH();
@ -1738,6 +1719,7 @@ TermView::_SynchronizeWithTextBuffer(int32 visibleDirtyTop,
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
fCursor = cursor;
_InvalidateTextRect(fCursor.x, fCursor.y, fCursor.x, fCursor.y);
_ActivateCursor(false);
}
info.Reset();

View File

@ -70,11 +70,6 @@ public:
void SelectAll();
void Clear();
// Cursor setting
void BlinkCursor();
void SetCurDraw(bool flag);
void SetCurBlinking(bool flag);
// Other
void GetFrameSize(float *width, float *height);
bool Find(const BString &str, bool forwardSearch, bool matchCase, bool matchWord);
@ -126,6 +121,10 @@ private:
void _DrawCursor();
void _InvalidateTextRange(TermPos start, TermPos end);
bool _IsCursorVisible() const;
void _BlinkCursor();
void _ActivateCursor(bool invalidate);
void _DoPrint(BRect updateRect);
void _UpdateScrollBarRange();
void _DoFileDrop(entry_ref &ref);
@ -185,11 +184,8 @@ private:
bool fFrameResized;
// Cursor Blinking, draw flag.
bigtime_t fLastCursorTime;
bool fCursorDrawFlag;
bool fCursorStatus;
bool fCursorBlinkingFlag;
bool fCursorRedrawFlag;
bigtime_t fLastActivityTime;
int32 fCursorState;
int fCursorHeight;
// Cursor position.

View File

@ -0,0 +1,62 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef TERMINAL_LINE_H
#define TERMINAL_LINE_H
#include <SupportDefs.h>
#include "UTF8Char.h"
struct TerminalCell {
UTF8Char character;
uint16 attributes;
};
struct TerminalLine {
int16 length;
bool softBreak; // soft line break
TerminalCell cells[1];
inline void Clear()
{
length = 0;
softBreak = false;
}
};
struct AttributesRun {
uint16 attributes;
uint16 offset; // character offset
uint16 length; // length of the run in characters
};
struct HistoryLine {
AttributesRun* attributesRuns;
uint16 attributesRunCount; // number of attribute runs
uint16 byteLength : 15; // number of bytes in the line
bool softBreak : 1; // soft line break;
AttributesRun* AttributesRuns() const
{
return attributesRuns;
}
char* Chars() const
{
return (char*)(attributesRuns + attributesRunCount);
}
int32 BufferSize() const
{
return attributesRunCount * sizeof(AttributesRun) + byteLength;
}
};
#endif // TERMINAL_LINE_H

View File

@ -55,6 +55,12 @@ struct UTF8Char {
return ByteCount(bytes[0]);
}
bool IsFullWidth() const
{
// TODO: Implement!
return false;
}
bool IsSpace() const
{
// TODO: Support multi-byte chars!