Terminal changes. This is still work in progress, some features

are disabled, lots of commented debug code is still in there,
and quite a bit of cleanup is needed, but basically things work
at least as well as before with several improvements:
* Changed TerminalBuffer from an interface to a complete
  implementation. Removed all related code from TermView. Removed
  the now obsolete TermBuffer. TermParse uses TerminalBuffer instead
  of TermView, and TerminalBuffer asynchronously notifies TermView.
  This avoids potential deadlocks, fixing #1918. It also speeds
  up tty-output-bound programs. E.g. a "seq 10000" is about twice
  at fast with the default terminal size in my setup, now. It's
  still horribly slow compared to e.g. Konsole, though.
* Replaced CurPos by a more compact and fully inline class TermPos.
* Removed the offset feature (that insets the used text area) from
  TermView, thus simplifying the code. Instead put the view into a
  new parent view which provides the insets. This also fixes
  artifacts that could sometimes be observed in the insets area.
* Scrolling related changes:
  - When scrolling fully down, the (80x25 or whatever) terminal
    screen is seen. It is not possible to scroll below the screen as
    in Be's Terminal. Scrolling in Haiku's Terminal was weirdly
    broken in this respect. As a side effect this fixes #2070.
  - When not scrolled fully down, further output won't cause any
    scrolling. It is thus possible to read earlier output while
    something is still going on. Fixes #1772.
  - Particularly to avoid unnecessary scrolling in the not scrolled
    fully down case, TermView no longer actually scrolls. It only
    sets an internal offset and manually uses CopyBits() as needed.
    Introduced a (hacky) BScrollView subclass using a BScrollBar
    subclass to make that possible.
* Selection related changes:
  - Double/triple click plus dragging allows for selecting multiple
    words/lines.
  - Word selection no longer selects ranges of non-space characters.
    Instead it knows that words are made of alpha numerical chars and
    a certain set of other chars, and selects a range of commonly
    classified characters (word chars, non-word non-whitespace chars,
    whitespace chars). The non-alpha-num word characters should be
    made user-settable. Due to missing multi-byte character
    classification multi-byte whitespace is not recognized.
  - Beyond the end of the line there no longer are invisible spaces.
    Trying to select the region selects the end of the line (i.e.
    line break). This is similar to how Konsole and xterm work.
  - Added auto-scrolling when selecting with the mouse. Formerly the
    Terminal scrolled only while moving the mouse. The scroll speed
    might need some fine-tuning.
  - Don't know what change exactly did that (likely the switch to
    non-end-inclusive text ranges used internally), but the
    occasional selection artifacts are gone.
* Resizing the terminal window re-wraps soft-wrapped lines.
* The find functionality seemed to be completely broken. At least it
  never found anything for me. Should work now, though multi-byte
  characters are not matched correctly in case-insensitive mode.

Regressions:
* Printing is disabled.
* Cursor blinking is disabled. Do we want it anyway?
* In several cases full-width characters are not handled correctly
  (in more cases than before).
* Shrinking the terminal width doesn't work very well with "less"
  (and probably other full-screen terminal apps), due to line
  re-wrapping. "less" expects them to be truncated only. When
  supporting an alternate screen buffer re-wrapping should be
  disabled for it, which should solve the problem.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25881 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-06-09 17:04:26 +00:00
parent 80f4a4f272
commit 52b1d543e8
22 changed files with 2640 additions and 2120 deletions
+1
View File
@@ -26,4 +26,5 @@ class CodeConv {
static unsigned short UTF8toUnicode(const char *utf8);
};
#endif /* CODECONV_H */
-113
View File
@@ -1,113 +0,0 @@
/*
* Copyright (c) 2001-2005, Haiku, Inc.
* Copyright (c) 2003-4 Kian Duffy <[email protected]>
* Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
* Distributed under the terms of the MIT license.
*
* Authors:
* Kian Duffy <[email protected]>
*/
#include "CurPos.h"
CurPos::CurPos()
{
}
CurPos::CurPos(int32 X, int32 Y)
{
x = X;
y = Y;
}
CurPos::CurPos(const CurPos& cp)
{
x = cp.x;
y = cp.y;
}
CurPos &
CurPos::operator=(const CurPos& from)
{
x = from.x;
y = from.y;
return *this;
}
void
CurPos::Set(int32 X, int32 Y)
{
x = X;
y = Y;
}
bool
CurPos::operator!=(const CurPos& from) const
{
return ((x != from.x) || (y != from.y));
}
bool
CurPos::operator==(const CurPos& from) const
{
return ((x == from.x) && (y == from.y));
}
CurPos
CurPos::operator+(const CurPos& from) const
{
return CurPos(x + from.x, y + from.y);
}
CurPos
CurPos::operator- (const CurPos& from) const
{
return CurPos(x - from.x, y - from.y);
}
bool
CurPos::operator> (const CurPos& from) const
{
if (y > from.y)
return true;
else
if (y == from.y && x > from.x)
return true;
return false;
}
bool
CurPos::operator>= (const CurPos& from) const
{
if (y > from.y)
return true;
else
if (y == from.y && x >= from.x)
return true;
return false;
}
bool
CurPos::operator< (const CurPos& from) const
{
if (y < from.y)
return true;
else
if (y == from.y && x < from.x)
return true;
return false;
}
bool
CurPos::operator<= (const CurPos& from) const
{
if (y < from.y)
return true;
else
if (y == from.y && x <= from.x)
return true;
return false;
}
-38
View File
@@ -1,38 +0,0 @@
/*
* Copyright (c) 2001-2005, Haiku, Inc.
* Copyright (c) 2003-4 Kian Duffy <[email protected]>
* Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
* Distributed under the terms of the MIT license.
*
* Authors:
* Kian Duffy <[email protected]>
*/
#ifndef CURPOS_H_INCLUDED
#define CURPOS_H_INCLUDED
#include <SupportDefs.h>
class CurPos
{
public:
CurPos();
CurPos(int32 X, int32 Y);
CurPos(const CurPos& cp);
void Set(int32 X, int32 Y);
CurPos &operator= (const CurPos &from);
CurPos operator+ (const CurPos&) const;
CurPos operator- (const CurPos&) const;
bool operator!= (const CurPos&) const;
bool operator== (const CurPos&) const;
bool operator> (const CurPos&) const;
bool operator>= (const CurPos&) const;
bool operator< (const CurPos&) const;
bool operator<= (const CurPos&) const;
int32 x;
int32 y;
};
#endif
+2 -2
View File
@@ -9,7 +9,6 @@ Application Terminal :
Arguments.cpp
CodeConv.cpp
Coding.cpp
CurPos.cpp
FindWindow.cpp
MenuUtil.cpp
Terminal.cpp
@@ -19,9 +18,10 @@ Application Terminal :
Shell.cpp
SmartTabView.cpp
TermApp.cpp
TermBuffer.cpp
TerminalBuffer.cpp
TerminalCharClassifier.cpp
TermParse.cpp
TermScrollView.cpp
TermView.cpp
TermWindow.cpp
TTextControl.cpp
+1 -1
View File
@@ -234,7 +234,7 @@ Shell::ViewAttached(TermView *view)
if (fAttached)
return;
status_t status = fTermParse->StartThreads(view);
status_t status = fTermParse->StartThreads(view->TextBuffer());
if (status < B_OK) {
// TODO: What can we do here ?
fprintf(stderr, "Shell:ViewAttached():"
-550
View File
@@ -1,550 +0,0 @@
/*
* Copyright (c) 2001-2006, Haiku, Inc.
* Copyright (c) 2003-4 Kian Duffy <[email protected]>
* Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
* Distributed under the terms of the MIT license.
*
* Authors:
* Kian Duffy <[email protected]>
*/
/************************************************************************
MuTerminal Internal Buffer Format.
a. 4bytes character buffer.
3bytes character buffer (UTF8).
1byte status buffer.
b. 2bytes extended buffer.
2byte attribute buffer.
< attribute buffer> <------- character buffer -------->
WBURMfbF rrfffbbb / ssssssss 11111111 22222222 33333333
|||||||| || | | | | | |
|||||||| || | | status utf8 1st utf8 2nd utf8 3rd
|||||||| || | |
|||||||| || | \--> background color
|||||||| || \-----> foreground color
|||||||| |\-------> dumped CR
|||||||| \--------> Reserve
||||||||
||||||||
|||||||\----------> Font information (Not use)
||||||\-----------> background color flag
|||||\------------> foreground color flag
||||\-------------> mouse selected
|||\--------------> reverse attr
||\---------------> underline attr
|\----------------> bold attr
\-----------------> character width
c. 2byte status buffer.
0x00 (A_CHAR): character available.
0x01 (NO_CHAR): buffer is empty.
0xFF (IN_STRING): before buffer is full width character (never draw).
**Language environment. (Not impliment)
--- half width character set ---
0 ... Western (Latin1 / ISO-8859-1, MacRoman)
1 ... Central European(Latin2 / ISO-8859-2)
2 ... Turkish (Latin3 / ISO-8859-3)
3 ... Baltic (Latin4 / ISO-8859-4)
4 ... Cyrillic (Cyrillic / ISO-8859-5)
5 ... Greek (Greek / ISO-8859-7)
6 ... Trukish (Latin5 / ISO-8859-9)
--- full width character set ---
7 ... Japanese (EUC, SJIS, ISO-2022-jp / JIS X 0201, 0208, 0212)
8 ... Chinese (Big5, EUC-tw, ISO-2022-cn / GB2312, CNS-11643-1...7)
9 ... Korean (EUC-kr, ISO-2022-kr / KS C 5601)
--- Universal character set ---
10 ... Unicode (UTF8)
* Variables is set CodeConv class.
* Unicode character width sets CodeConv::UTF8FontWidth member.
JIS X 0201 (half width kana ideograph) character use 1 column,
but it font is full width font on preference panel.
************************************************************************/
#include "TermBuffer.h"
#include "CurPos.h"
#include "TermConst.h"
#include <SupportDefs.h>
#include <String.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROW(x) (((x) + fRowOffset) % fBufferSize)
TermBuffer::TermBuffer(int rows, int cols, int bufferSize)
{
if (rows < 1)
rows = 1;
if (cols < MIN_COLS)
cols = MIN_COLS;
else if (cols > MAX_COLS)
cols = MAX_COLS;
fColumnSize = MAX_COLS;
fCurrentColumnSize = cols;
fRowSize = rows;
fRowOffset = 0;
fSelStart.Set(-1,-1);
fSelEnd.Set(-1,-1);
fBufferSize = bufferSize;
if (fBufferSize < 1000)
fBufferSize = 1000;
// Allocate buffer
fBuffer = (term_buffer**)malloc(sizeof(term_buffer*) * fBufferSize);
for (int i = 0; i < fBufferSize; i++) {
fBuffer[i] = (term_buffer *)calloc(fColumnSize + 1, sizeof(term_buffer));
}
}
TermBuffer::~TermBuffer()
{
for (int i = 0; i < fBufferSize; i++) {
free(fBuffer[i]);
}
free(fBuffer);
}
//! Gets a character from TermBuffer
int
TermBuffer::GetChar(int row, int col, uchar *buf, ushort *attr)
{
if (row < 0 || col < 0)
return -1;
term_buffer *ptr = (fBuffer[row % fBufferSize] + col);
if (ptr->status == A_CHAR)
memcpy(buf, (char *)(ptr->code), 4);
*attr = ptr->attr;
return ptr->status;
}
//! Get a string (length = num) from given position.
int
TermBuffer::GetString(int row, int col, int num, uchar *buf,
ushort *attr)
{
int count = 0, all_count = 0;
term_buffer *ptr;
ptr = (fBuffer[row % fBufferSize]);
ptr += col;
*attr = ptr->attr;
if (ptr->status == NO_CHAR) {
// Buffer is empty and No selected by mouse.
do {
if (col >= fCurrentColumnSize)
return -1;
col++;
ptr++;
count--;
if (ptr->status == A_CHAR)
return count;
if (fSelStart.y == row) {
if (col == fSelStart.x)
return count;
}
if (fSelEnd.y == row) {
if (col - 1 == fSelEnd.x)
return count;
}
} while (col <= num);
return count;
} else if (IS_WIDTH(ptr->attr)) {
memcpy(buf, (char *)ptr->code, 4);
return 2;
}
while (col <= num) {
memcpy(buf, ptr->code, 4);
all_count++;
if (*buf == 0) {
*buf = ' ';
*(buf + 1) = '\0';
}
if (ptr->attr != (ptr + 1)->attr)
return all_count;
buf += strlen((char *)buf);
ptr++;
col++;
if (fSelStart.y == row) {
if (col == fSelStart.x)
return all_count;
}
if (fSelEnd.y == row) {
if (col - 1 == fSelEnd.x)
return all_count;
}
}
return all_count;
}
//! Write a character at the cursor point.
void
TermBuffer::WriteChar(const CurPos &pos, const uchar *u, ushort attr)
{
const int row = pos.y;
const int col = pos.x;
term_buffer *ptr = (fBuffer[ROW(row)] + col);
memcpy ((char *)ptr->code, u, 4);
if (IS_WIDTH(attr))
(ptr + 1)->status = IN_STRING;
ptr->status = A_CHAR;
ptr->attr = attr;
}
//! Write CR status to buffer attribute.
void
TermBuffer::WriteCR(const CurPos &pos)
{
int row = pos.y;
int col = pos.x;
term_buffer *ptr = (fBuffer[ROW(row)] + col);
ptr->attr |= DUMPCR;
}
//! Insert 'num' spaces at cursor point.
void
TermBuffer::InsertSpace(const CurPos &pos, int num)
{
const int row = pos.y;
const int col = pos.x;
for (int i = fCurrentColumnSize - num; i >= col; i--) {
*(fBuffer[ROW(row)] + i + num) = *(fBuffer[ROW(row)] + i);
}
memset(fBuffer[ROW(row)] + col, 0, num * sizeof(term_buffer));
}
//! Delete 'num' characters at cursor point.
void
TermBuffer::DeleteChar(const CurPos &pos, int num)
{
const int row = pos.y;
const int col = pos.x;
term_buffer *ptr = fBuffer[ROW(row)];
size_t movesize = fCurrentColumnSize - (col + num);
memmove(ptr + col, ptr + col + num, movesize * sizeof(term_buffer));
memset(ptr + (fCurrentColumnSize - num), 0, num * sizeof(term_buffer));
}
//! Erase characters below cursor position.
void
TermBuffer::EraseBelow(const CurPos &pos)
{
const int row = pos.y;
const int col = pos.x;
memset(fBuffer[ROW(row)] + col, 0, (fColumnSize - col ) * sizeof(term_buffer));
for (int i = row; i < fRowSize; i++) {
_EraseLine(i);
}
}
//! Scroll the terminal buffer region
void
TermBuffer::ScrollRegion(int top, int bot, int dir, int num)
{
if (dir == SCRUP) {
for (int i = 0; i < num; i++) {
term_buffer *ptr = fBuffer[ROW(top)];
for (int j = top; j < bot; j++) {
fBuffer[ROW(j)] = fBuffer[ROW(j+1)];
}
fBuffer[ROW(bot)] = ptr;
_EraseLine(bot);
}
} else {
// scroll up
for (int i = 0; i < num; i++) {
term_buffer *ptr = fBuffer[ROW(bot)];
for (int j = bot; j > top; j--) {
fBuffer[ROW(j)] = fBuffer[ROW(j-1)];
}
fBuffer[ROW(top)] = ptr;
_EraseLine(top);
}
}
}
//! Scroll the terminal buffer.
void
TermBuffer::ScrollLine()
{
for (int i = fRowSize; i < fRowSize * 2; i++) {
_EraseLine(i);
}
fRowOffset++;
}
//! Resize the terminal buffer.
void
TermBuffer::ResizeTo(int newRows, int newCols, int offset)
{
int i;
// make sure the new size is within the allowed limits
if (newRows < 1)
newRows = 1;
if (newCols < MIN_COLS)
newCols = MIN_COLS;
else if (newCols > MAX_COLS)
newCols = MAX_COLS;
if (newRows <= fRowSize) {
for (i = newRows; i <= fRowSize; i++)
_EraseLine(i);
} else {
for (i = fRowSize; i <= newRows * 2; i++)
_EraseLine(i);
}
fCurrentColumnSize = newCols;
fRowOffset += offset;
fRowSize = newRows;
}
//! Get the buffer's size.
int32
TermBuffer::Size() const
{
return fBufferSize;
}
void
TermBuffer::_EraseLine(int row)
{
memset(fBuffer[ROW(row)], 0, fColumnSize * sizeof(term_buffer));
}
//! Clear the contents of the TermBuffer.
void
TermBuffer::Clear()
{
for (int i = 0; i < fBufferSize; i++) {
memset(fBuffer[i], 0, fColumnSize * sizeof(term_buffer));
}
fRowOffset = 0;
DeSelect();
}
//! Mark text in the given range as selected
void
TermBuffer::Select(const CurPos &start, const CurPos &end)
{
if (end < start) {
fSelStart = end;
fSelEnd = start;
} else {
fSelStart = start;
fSelEnd = end;
}
}
//! Mark text in the given range as not selected
void
TermBuffer::DeSelect()
{
fSelStart.Set(-1, -1);
fSelEnd.Set(-1, -1);
}
bool
TermBuffer::FindWord(const CurPos &pos, CurPos *start, CurPos *end)
{
uchar buf[5];
ushort attr;
int x, y, start_x;
y = pos.y;
// Search start point
for (x = pos.x - 1; x >= 0; x--) {
if (GetChar(y, x, buf, &attr) == NO_CHAR || *buf == ' ') {
++x;
break;
}
}
start_x = x;
// Search end point
for (x = pos.x; x < fColumnSize; x++) {
if (GetChar(y, x, buf, &attr) == NO_CHAR || *buf == ' ') {
--x;
break;
}
}
if (start_x > x)
return false;
if (start != NULL)
start->Set(start_x, y);
if (end != NULL)
end->Set(x, y);
return true;
}
//! Get one character from the selected region.
void
TermBuffer::GetCharFromRegion(int x, int y, BString &str)
{
uchar buf[5];
ushort attr;
int status;
status = GetChar(y, x, buf, &attr);
switch (status) {
case NO_CHAR:
if (IS_CR (attr))
str += '\n';
else
str += ' ';
break;
case IN_STRING:
break;
default:
str += (const char *)&buf;
break;
}
}
//! Delete useless char at end of line and convert LF code.
/* static */
inline void
TermBuffer::AvoidWaste(BString &str)
{
// TODO: Remove the goto
int32 len, point;
start:
len = str.Length() - 1;
point = str.FindLast (' ');
if (len > 0 && len == point) {
str.RemoveLast (" ");
goto start;
}
// str += '\n';
}
//! Get a string from the given region.
void
TermBuffer::GetStringFromRegion(BString &str, const CurPos &start, const CurPos &end)
{
int y;
if (start.y == end.y) {
y = start.y;
for (int x = start.x ; x <= end.x; x++) {
GetCharFromRegion(x, y, str);
}
} else {
y = start.y;
for (int x = start.x ; x < fCurrentColumnSize; x++) {
GetCharFromRegion(x, y, str);
}
AvoidWaste(str);
for (y = start.y + 1 ; y < end.y; y++) {
for (int x = 0 ; x < fCurrentColumnSize; x++) {
GetCharFromRegion(x, y, str);
}
AvoidWaste(str);
}
y = end.y;
for (int x = 0 ; x <= end.x; x++) {
GetCharFromRegion(x, y, str);
}
}
}
//Returns the complete internal buffer as a BString
void
TermBuffer::ToString(BString &str)
{
for (int y = 0; y < fRowSize; y++) {
for (int x = 0; x < fCurrentColumnSize; x++) {
GetCharFromRegion(x, y, str);
}
}
AvoidWaste(str);
}
-124
View File
@@ -1,124 +0,0 @@
/*
* Copyright (c) 2003-4 Kian Duffy <[email protected]>
* Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files or portions
* thereof (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice
* in the binary, as well as this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TERMBUFFER_H
#define _TERMBUFFER_H
#include "CurPos.h"
#include "TermConst.h"
#include <SupportDefs.h>
struct term_buffer
{
uchar code[4];
int16 attr;
int16 status;
};
class CurPos;
class BString;
class TermBuffer {
public:
TermBuffer(int row, int col, int bufferSize = 1000);
~TermBuffer();
//
// Get and Put charactor.
//
int GetChar(int row, int col, uchar *u, ushort *attr);
int GetString(int row, int col, int num, uchar *u, ushort *attr);
void GetStringFromRegion(BString &copyStr, const CurPos &start, const CurPos &end);
void WriteChar(const CurPos &pos, const uchar *u, ushort attr);
void WriteCR(const CurPos &pos);
void InsertSpace(const CurPos &pos, int num);
//
// Delete Character.
//
void DeleteChar(const CurPos &pos, int num);
void EraseBelow(const CurPos &pos);
//
// Movement and Scroll buffer.
//
void ScrollRegion(int top, int bot, int dir, int num);
void ScrollLine();
//
// Resize buffer.
//
void ResizeTo(int newRows, int newCols, int offset);
//
// Clear contents of TermBuffer.
//
void Clear();
//
// Selection Methods
//
void Select(const CurPos &start, const CurPos &end);
void DeSelect();
const CurPos &GetSelectionStart() { return fSelStart; };
const CurPos &GetSelectionEnd() { return fSelEnd; };
//
// Other methods
//
bool FindWord(const CurPos &pos, CurPos *start, CurPos *end);
void GetCharFromRegion (int x, int y, BString &str);
static void AvoidWaste (BString &str);
void ToString(BString &str);
int32 Size() const;
private:
void _EraseLine(int line);
term_buffer **fBuffer;
int fBufferSize;
int fColumnSize;
int fRowSize;
int fCurrentColumnSize;
int fRowOffset;
CurPos fSelStart;
CurPos fSelEnd;
};
#endif // _TERMBUFFER_H
+5 -1
View File
@@ -83,6 +83,10 @@ const uint32 MSG_FONT_CHANGED = 'fntc';
const uint32 SAVE_AS_DEFAULT = 'sadf';
const uint32 MSG_CHECK_CHILDREN = 'ckch';
const uint32 MSG_TERMINAL_BUFFER_CHANGED = 'bufc';
const uint32 MSG_SET_TERMNAL_TITLE = 'sett';
const uint32 MSG_QUIT_TERMNAL = 'qutt';
// Preference Read/Write Keys
const char* const PREF_HALF_FONT_FAMILY = "Half Font Family";
const char* const PREF_HALF_FONT_STYLE = "Half Font Style";
@@ -144,7 +148,7 @@ enum{
#define MIN_COLS 10
#define MAX_COLS 256
#define MIN_ROWS 1
#define MIN_ROWS 10
#define MAX_ROWS 256
// Insert mode flag
+38 -2
View File
@@ -13,6 +13,7 @@
#include <string.h>
#include <unistd.h>
#include <Autolock.h>
#include <Beep.h>
#include <Message.h>
@@ -117,6 +118,7 @@ status_t
TermParse::GetReaderBuf(uchar &c)
{
status_t status;
#if 0
do {
status = acquire_sem_etc(fReaderSem, 1, B_TIMEOUT, 10000);
} while (status == B_INTERRUPTED);
@@ -127,17 +129,23 @@ TermParse::GetReaderBuf(uchar &c)
// Reset cursor blinking time and turn on cursor blinking.
fBuffer->SetCurDraw(true);
#endif
// wait new input from pty.
fBuffer->Unlock();
do {
status = acquire_sem(fReaderSem);
} while (status == B_INTERRUPTED);
fBuffer->Lock();
if (status < B_OK)
return status;
#if 0
} else if (status == B_OK) {
// Do nothing
} else
return status;
#endif
c = fReadBuffer[fBufferPosition % READ_BUF_SIZE];
fBufferPosition++;
@@ -147,7 +155,7 @@ TermParse::GetReaderBuf(uchar &c)
release_sem(fReaderLocker);
}
fBuffer->SetCurDraw(false);
// fBuffer->SetCurDraw(false);
return B_OK;
}
@@ -343,6 +351,9 @@ TermParse::EscParse()
int *parsestate = groundtable;
while (!fQuitting) {
// TODO: Fix the locking!
BAutolock locker(fBuffer);
uchar c;
if (GetReaderBuf(c) < B_OK)
break;
@@ -383,6 +394,7 @@ TermParse::EscParse()
now_coding = fBuffer->Encoding();
}
//debug_printf("TermParse: char: '%c' (%d), parse state: %d\n", c, c, parsestate[c]);
switch (parsestate[c]) {
case CASE_PRINT:
cbuf[0] = c;
@@ -767,7 +779,7 @@ TermParse::EscParse()
case CASE_CPR:
// Q & D hack by Y.Hayakawa ([email protected])
// 21-JUL-99
fBuffer->DeviceStatusReport(param[0]);
_DeviceStatusReport(param[0]);
parsestate = groundtable;
break;
@@ -975,3 +987,27 @@ TermParse::_escparse_thread(void *data)
{
return reinterpret_cast<TermParse *>(data)->EscParse();
}
void
TermParse::_DeviceStatusReport(int n)
{
char sbuf[16] ;
int len;
switch (n) {
case 5:
{
const char* toWrite = "\033[0n";
write(fFd, toWrite, strlen(toWrite));
break ;
}
case 6:
len = sprintf(sbuf, "\033[%ld;%ldR", fBuffer->Height(),
fBuffer->Width()) ;
write(fFd, sbuf, len);
break ;
default:
return;
}
}
+3 -1
View File
@@ -68,7 +68,9 @@ private:
// Reading ReadBuf at one Char.
status_t GetReaderBuf(uchar &c);
void _DeviceStatusReport(int n);
int fFd;
thread_id fParseThread;
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef TERM_POS_H
#define TERM_POS_H
#include <SupportDefs.h>
class TermPos {
public:
int32 x;
int32 y;
inline TermPos() : x(0), y(0) { }
inline TermPos(int32 x, int32 y) : x(x), y(y) { }
inline TermPos(const TermPos& other) : x(other.x), y(other.y) { }
inline void SetTo(int32 x, int32 y)
{
this->x = x;
this->y = y;
}
inline bool operator==(const TermPos& other) const
{
return x == other.x && y == other.y;
}
inline bool operator!=(const TermPos& other) const
{
return x != other.x || y != other.y;
}
inline bool operator<=(const TermPos& other) const
{
return y < other.y || y == other.y && x <= other.x;
}
inline bool operator>=(const TermPos& other) const
{
return other <= *this;
}
inline bool operator<(const TermPos& other) const
{
return !(*this >= other);
}
inline bool operator>(const TermPos& other) const
{
return !(*this <= other);
}
inline TermPos& operator=(const TermPos& other)
{
x = other.x;
y = other.y;
return *this;
}
};
#endif // TERM_POS_H
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
// NOTE: Nasty hack to get access to BScrollView's private parts.
#include <ScrollBar.h>
#define private protected
#include <ScrollView.h>
#undef private
#include "TermScrollView.h"
class TermScrollBar : public BScrollBar {
public:
TermScrollBar(BRect frame, const char *name, BView *target,
float min, float max, orientation direction)
:
BScrollBar(frame, name, target, min, max, direction)
{
}
virtual void ValueChanged(float newValue)
{
if (BView* target = Target())
Target()->ScrollTo(0, newValue);
}
};
TermScrollView::TermScrollView(const char* name, BView* child, BView* target,
uint32 resizingMode)
:
BScrollView(name, child, resizingMode, 0, false, true)
{
// replace the vertical scroll bar with our own
if (fVerticalScrollBar != NULL) {
BRect frame(fVerticalScrollBar->Frame());
RemoveChild(fVerticalScrollBar);
TermScrollBar* scrollBar = new TermScrollBar(frame, "_VSB_", target, 0,
1000, B_VERTICAL);
AddChild(scrollBar);
fVerticalScrollBar = scrollBar;
}
}
TermScrollView::~TermScrollView()
{
}
+20
View File
@@ -0,0 +1,20 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef TERM_SCROLL_VIEW_H
#define TERM_SCROLL_VIEW_H
#include <ScrollView.h>
class TermScrollView : public BScrollView {
public:
TermScrollView(const char* name, BView* child,
BView* target,
uint32 resizingMode = B_FOLLOW_ALL);
~TermScrollView();
};
#endif // TERM_SCROLL_VIEW_H
File diff suppressed because it is too large Load Diff
+58 -97
View File
@@ -12,12 +12,13 @@
#ifndef TERMVIEW_H
#define TERMVIEW_H
#include <Autolock.h>
#include <Messenger.h>
#include <String.h>
#include <View.h>
#include "CurPos.h"
#include "TerminalBuffer.h"
#include "TermPos.h"
class BClipboard;
@@ -27,7 +28,7 @@ class BString;
class Shell;
class TermBuffer;
class TermView : public BView, public TerminalBuffer {
class TermView : public BView {
public:
TermView(BRect frame, int32 argc, const char **argv, int32 historySize = 1000);
TermView(int rows, int columns, int32 argc, const char **argv, int32 historySize = 1000);
@@ -40,6 +41,8 @@ public:
virtual void GetPreferredSize(float *width, float *height);
const char *TerminalName() const;
inline TerminalBuffer* TextBuffer() const { return fTextBuffer; }
void GetTermFont(BFont *font) const;
void SetTermFont(const BFont *font);
@@ -67,52 +70,12 @@ public:
void SelectAll();
void Clear();
// Output Charactor
void Insert(uchar *string, ushort attr);
void InsertCR();
void InsertLF();
void InsertNewLine(int num);
void SetInsertMode(int flag);
void InsertSpace(int num);
// Delete Charactor
void EraseBelow();
void DeleteChar(int num);
void DeleteColumns();
void DeleteLine(int num);
// Get and Set Cursor position
void SetCurPos(int x, int y);
void SetCurX(int x);
void SetCurY(int y);
void GetCurPos(CurPos *inCurPos);
int GetCurX();
int GetCurY();
void SaveCursor();
void RestoreCursor();
// Move Cursor
void MoveCurRight(int num);
void MoveCurLeft(int num);
void MoveCurUp(int num);
void MoveCurDown(int num);
// Cursor setting
void DrawCursor();
void BlinkCursor();
void SetCurDraw(bool flag);
void SetCurBlinking(bool flag);
// Scroll region
void ScrollRegion(int top, int bot, int dir, int num);
void SetScrollRegion(int top, int bot);
void ScrollAtCursor();
// Other
void DeviceStatusReport(int);
void UpdateLine();
void ScrollScreen();
void ScrollScreenDraw();
void GetFrameSize(float *width, float *height);
bool Find(const BString &str, bool forwardSearch, bool matchCase, bool matchWord);
void GetSelection(BString &str);
@@ -135,12 +98,22 @@ protected:
virtual void FrameResized(float width, float height);
virtual void MessageReceived(BMessage* message);
virtual void ScrollTo(BPoint where);
virtual status_t GetSupportedSuites(BMessage *msg);
virtual BHandler* ResolveSpecifier(BMessage *msg, int32 index,
BMessage *specifier, int32 form,
const char *property);
private:
// point and text offset conversion
inline int32 _LineAt(float y);
inline float _LineOffset(int32 index);
inline TermPos _ConvertToTerminal(const BPoint &p);
inline BPoint _ConvertFromTerminal(const TermPos &pos);
inline void _InvalidateTextRect(int32 x1, int32 y1, int32 x2, int32 y2);
status_t _InitObject(int32 argc, const char **argv);
status_t _AttachShell(Shell *shell);
@@ -148,17 +121,18 @@ private:
void _AboutRequested();
void _DrawLines(int , int, ushort, uchar *, int, int, int, BView *);
int _TermDraw(const CurPos &start, const CurPos &end);
int _TermDrawRegion(CurPos start, CurPos end);
int _TermDrawSelectedRegion(CurPos start, CurPos end);
inline void _Redraw(int, int, int, int);
void _DrawLinePart(int32 x1, int32 y1, uint16 attr, char *buf,
int32 width, bool mouse, bool cursor, BView *inView);
void _DrawCursor();
void _InvalidateTextRange(TermPos start, TermPos end);
void _DoPrint(BRect updateRect);
void _ResizeScrBarRange(void);
void _UpdateScrollBarRange();
void _DoFileDrop(entry_ref &ref);
void _WritePTY(const uchar *text, int num_byteses);
void _SynchronizeWithTextBuffer(BRect* invalidateWhenScrolling);
void _WritePTY(const char* text, int32 numBytes);
// Comunicate Input Method
// void _DoIMStart (BMessage* message);
@@ -168,33 +142,36 @@ private:
// void _DoIMConfirm (void);
// void _ConfirmString(const char *, int32);
// Mouse select
void _Select(CurPos start, CurPos end);
void _AddSelectRegion(CurPos);
void _ResizeSelectRegion(CurPos);
void _DeSelect();
// selection
void _Select(TermPos start, TermPos end, bool inclusive,
bool setInitialSelection);
void _ExtendSelection(TermPos, bool inclusive, bool useInitialSelection);
void _Deselect();
bool _HasSelection() const;
void _SelectWord(BPoint where, bool extend, bool useInitialSelection);
void _SelectLine(BPoint where, bool extend, bool useInitialSelection);
// select word function
void _SelectWord(BPoint where, int mod);
void _SelectLine(BPoint where, int mod);
void _AutoScrollUpdate();
// point and text offset conversion.
CurPos _ConvertToTerminal(const BPoint &p);
BPoint _ConvertFromTerminal(const CurPos &pos);
bool _CheckSelectedRegion(const TermPos &pos) const;
bool _CheckSelectedRegion(int32 row, int32 firstColumn,
int32& lastColumn) const;
bool _CheckSelectedRegion(const CurPos &pos);
void _UpdateSIGWINCH();
static void _FixFontAttributes(BFont &font);
void _ScrollTo(float y, bool scrollGfx);
void _ScrollToRange(TermPos start, TermPos end);
private:
class CharClassifier;
Shell *fShell;
BMessageRunner *fWinchRunner;
BMessageRunner *fCursorBlinkRunner;
BMessageRunner *fAutoScrollRunner;
CharClassifier *fCharClassifier;
// Font and Width
BFont fHalfFont;
@@ -203,19 +180,7 @@ private:
int fFontAscent;
struct escapement_delta fEscapement;
// Flags
// Update flag (Set on Insert).
bool fUpdateFlag;
// Terminal insertmode flag (use Insert).
bool fInsertModeFlag;
// Scroll count, range.
int fScrollUpCount;
int fScrollBarRange;
// Frame Resized flag.
// frame resized flag.
bool fFrameResized;
// Cursor Blinking, draw flag.
@@ -227,10 +192,7 @@ private:
int fCursorHeight;
// Cursor position.
CurPos fCurPos;
CurPos fCurStack;
int fBufferStartPos;
TermPos fCursor;
// Terminal rows and columns.
int fTermRows;
@@ -238,12 +200,9 @@ private:
int fEncoding;
// Terminal view pointer.
int fTop;
// Object pointer.
TermBuffer *fTextBuffer;
BScrollBar *fScrollBar;
TerminalBuffer *fTextBuffer;
BScrollBar *fScrollBar;
// Color and Attribute.
rgb_color fTextForeColor, fTextBackColor;
@@ -251,22 +210,24 @@ private:
rgb_color fSelectForeColor, fSelectBackColor;
// Scroll Region
int fScrTop;
int fScrBot;
float fScrollOffset;
int32 fScrBufSize;
bool fScrRegionSet;
// TODO: That's the history capacity -- only needed until the text
// buffer is created.
float fAutoScrollSpeed;
BPoint fClickPoint;
// view selection
CurPos fSelStart;
CurPos fSelEnd;
// selection
TermPos fSelStart;
TermPos fSelEnd;
TermPos fInitialSelectionStart;
TermPos fInitialSelectionEnd;
bool fMouseTracking;
int fSelectGranularity;
// Input Method parameter.
int fIMViewPtr;
CurPos fIMStartPos;
CurPos fIMEndPos;
TermPos fIMStartPos;
TermPos fIMEndPos;
BString fIMString;
bool fIMflag;
BMessenger fIMMessenger;
+98 -47
View File
@@ -9,16 +9,9 @@
#include "TermWindow.h"
#include "Arguments.h"
#include "Coding.h"
#include "MenuUtil.h"
#include "FindWindow.h"
#include "PrefWindow.h"
#include "PrefView.h"
#include "PrefHandler.h"
#include "SmartTabView.h"
#include "TermConst.h"
#include "TermView.h"
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <Alert.h>
#include <Application.h>
@@ -35,12 +28,21 @@
#include <ScrollView.h>
#include <String.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "Arguments.h"
#include "Coding.h"
#include "MenuUtil.h"
#include "FindWindow.h"
#include "PrefWindow.h"
#include "PrefView.h"
#include "PrefHandler.h"
#include "SmartTabView.h"
#include "TermConst.h"
#include "TermScrollView.h"
#include "TermView.h"
const static int32 kMaxTabs = 6;
const static int32 kTermViewOffset = 3;
// messages constants
const static uint32 kNewTab = 'NTab';
@@ -57,6 +59,34 @@ public:
};
class TermViewContainerView : public BView {
public:
TermViewContainerView(TermView* termView)
:
BView(BRect(), "term view container", B_FOLLOW_ALL, 0),
fTermView(termView)
{
termView->MoveTo(kTermViewOffset, kTermViewOffset);
BRect frame(termView->Frame());
ResizeTo(frame.right + kTermViewOffset, frame.bottom + kTermViewOffset);
AddChild(termView);
}
TermView* GetTermView() const { return fTermView; }
virtual void GetPreferredSize(float* _width, float* _height)
{
float width, height;
fTermView->GetPreferredSize(&width, &height);
*_width = width + 2 * kTermViewOffset;
*_height = height + 2 * kTermViewOffset;
}
private:
TermView* fTermView;
};
TermWindow::TermWindow(BRect frame, const char* title, Arguments *args)
: BWindow(frame, title, B_DOCUMENT_WINDOW, B_CURRENT_WORKSPACE|B_QUIT_ON_WINDOW_CLOSE),
fTabView(NULL),
@@ -394,9 +424,11 @@ TermWindow::MessageReceived(BMessage *message)
break;
case MSG_COLOR_CHANGED:
_SetTermColors(_ActiveTermView());
{
_SetTermColors(_ActiveTermViewContainerView());
_ActiveTermView()->Invalidate();
break;
}
case SAVE_AS_DEFAULT:
{
@@ -460,7 +492,7 @@ TermWindow::MessageReceived(BMessage *message)
_ResizeView(view);
break;
}
default:
BWindow::MessageReceived(message);
break;
@@ -476,16 +508,21 @@ TermWindow::WindowActivated(bool activated)
void
TermWindow::_SetTermColors(TermView *termView)
TermWindow::_SetTermColors(TermViewContainerView *containerView)
{
termView->SetTextColor(PrefHandler::Default()->getRGB(PREF_TEXT_FORE_COLOR),
PrefHandler::Default()->getRGB(PREF_TEXT_BACK_COLOR));
PrefHandler* handler = PrefHandler::Default();
rgb_color background = handler->getRGB(PREF_TEXT_BACK_COLOR);
termView->SetSelectColor(PrefHandler::Default()->getRGB(PREF_SELECT_FORE_COLOR),
PrefHandler::Default()->getRGB(PREF_SELECT_BACK_COLOR));
termView->SetCursorColor(PrefHandler::Default()->getRGB(PREF_CURSOR_FORE_COLOR),
PrefHandler::Default()->getRGB(PREF_CURSOR_BACK_COLOR));
containerView->SetViewColor(background);
TermView *termView = containerView->GetTermView();
termView->SetTextColor(handler->getRGB(PREF_TEXT_FORE_COLOR), background);
termView->SetSelectColor(handler->getRGB(PREF_SELECT_FORE_COLOR),
handler->getRGB(PREF_SELECT_BACK_COLOR));
termView->SetCursorColor(handler->getRGB(PREF_CURSOR_FORE_COLOR),
handler->getRGB(PREF_CURSOR_BACK_COLOR));
}
@@ -564,10 +601,11 @@ TermWindow::_AddTab(Arguments *args)
new CustomTermView(PrefHandler::Default()->getInt32(PREF_ROWS),
PrefHandler::Default()->getInt32(PREF_COLS),
argc, (const char **)argv);
BScrollView *scrollView = new BScrollView("scrollView", view, B_FOLLOW_ALL,
B_WILL_DRAW|B_FRAME_EVENTS, false, true);
TermViewContainerView *containerView = new TermViewContainerView(view);
BScrollView *scrollView = new TermScrollView("scrollView",
containerView, view);
BTab *tab = new BTab;
// TODO: Use a better name. For example, do like MacOsX's Terminal
// and update the title using the last executed command ?
@@ -585,9 +623,9 @@ TermWindow::_AddTab(Arguments *args)
BFont font;
_GetPreferredFont(font);
view->SetTermFont(&font);
_SetTermColors(view);
_SetTermColors(containerView);
int width, height;
view->GetFontSize(&width, &height);
@@ -603,8 +641,8 @@ TermWindow::_AddTab(Arguments *args)
// If it's the first time we're called, setup the window
if (fTabView->CountTabs() == 1) {
float viewWidth, viewHeight;
view->GetPreferredSize(&viewWidth, &viewHeight);
containerView->GetPreferredSize(&viewWidth, &viewHeight);
// Resize Window
ResizeTo(viewWidth + B_V_SCROLL_BAR_WIDTH,
viewHeight + fMenubar->Bounds().Height());
@@ -627,14 +665,36 @@ TermWindow::_RemoveTab(int32 index)
PostMessage(B_QUIT_REQUESTED);
}
TermViewContainerView*
TermWindow::_ActiveTermViewContainerView() const
{
return _TermViewContainerViewAt(fTabView->Selection());
}
TermView *
TermWindow::_ActiveTermView()
TermViewContainerView*
TermWindow::_TermViewContainerViewAt(int32 index) const
{
// TODO: BAD HACK:
// We should probably use the observer api to tell
// the various "tabs" when settings are changed. Fix this.
return (TermView *)((BScrollView *)fTabView->ViewForTab(fTabView->Selection()))->Target();
BScrollView* scrollView = (BScrollView*)fTabView->ViewForTab(index);
return scrollView ? (TermViewContainerView*)scrollView->Target() : NULL;
}
TermView *
TermWindow::_ActiveTermView() const
{
return _ActiveTermViewContainerView()->GetTermView();
}
TermView*
TermWindow::_TermViewAt(int32 index) const
{
TermViewContainerView* view = _TermViewContainerViewAt(index);
return view != NULL ? view->GetTermView() : NULL;
}
@@ -647,12 +707,7 @@ TermWindow::_IndexOfTermView(TermView* termView) const
// find the view
int32 count = fTabView->CountTabs();
for (int32 i = count - 1; i >= 0; i--) {
BScrollView* scrollView
= dynamic_cast<BScrollView*>(fTabView->ViewForTab(i));
if (!scrollView)
continue;
if (termView == scrollView->Target())
if (termView == _TermViewAt(i))
return i;
}
@@ -668,11 +723,7 @@ TermWindow::_CheckChildren()
int32 count = fTabView->CountTabs();
for (int32 i = count - 1; i >= 0; i--) {
// get the term view
BScrollView* scrollView
= dynamic_cast<BScrollView*>(fTabView->ViewForTab(i));
if (!scrollView)
continue;
TermView* termView = dynamic_cast<TermView*>(scrollView->Target());
TermView* termView = _TermViewAt(i);
if (!termView)
continue;
@@ -698,7 +749,7 @@ TermWindow::_ResizeView(TermView *view)
minimumHeight + MAX_ROWS * fontHeight);
float width, height;
view->GetPreferredSize(&width, &height);
view->Parent()->GetPreferredSize(&width, &height);
width += B_V_SCROLL_BAR_WIDTH;
height += fMenubar->Bounds().Height() + 2;
+7 -3
View File
@@ -41,8 +41,9 @@ class BMenu;
class BMenuBar;
class FindWindow;
class PrefWindow;
class TermView;
class SmartTabView;
class TermView;
class TermViewContainerView;
class TermWindow : public BWindow {
@@ -56,7 +57,7 @@ protected:
virtual void MenusBeginning();
private:
void _SetTermColors(TermView *termView);
void _SetTermColors(TermViewContainerView *termView);
void _InitWindow();
void _SetupMenu();
void _GetPreferredFont(BFont &font);
@@ -64,7 +65,10 @@ private:
void _DoPrint();
void _AddTab(Arguments *args);
void _RemoveTab(int32 index);
TermView* _ActiveTermView();
TermViewContainerView* _ActiveTermViewContainerView() const;
TermViewContainerView* _TermViewContainerViewAt(int32 index) const;
TermView* _ActiveTermView() const;
TermView* _TermViewAt(int32 index) const;
int32 _IndexOfTermView(TermView* termView) const;
void _CheckChildren();
void _ResizeView(TermView *view);
File diff suppressed because it is too large Load Diff
+167 -40
View File
@@ -5,59 +5,186 @@
#ifndef TERMINAL_BUFFER_H
#define TERMINAL_BUFFER_H
#include <SupportDefs.h>
#include <limits.h>
#include <Locker.h>
#include <Messenger.h>
#include "TermPos.h"
#include "UTF8Char.h"
class TerminalBuffer {
class BString;
class TerminalCharClassifier;
struct TerminalBufferDirtyInfo {
int32 linesScrolled; // number of lines added to the history
int32 dirtyTop; // dirty line range
int32 dirtyBottom; //
bool messageSent; // listener has been notified
bool IsDirtyRegionValid() const
{
return dirtyTop <= dirtyBottom;
}
void Reset()
{
linesScrolled = 0;
dirtyTop = INT_MAX;
dirtyBottom = INT_MIN;
messageSent = false;
}
};
class TerminalBuffer : public BLocker {
public:
TerminalBuffer();
virtual ~TerminalBuffer();
~TerminalBuffer();
virtual int Encoding() const = 0;
status_t Init(int32 width, int32 height,
int32 historySize);
// Output Character
virtual void Insert(uchar* string, ushort attr) = 0;
virtual void InsertCR() = 0;
virtual void InsertLF() = 0;
virtual void InsertNewLine(int num) = 0;
virtual void SetInsertMode(int flag) = 0;
virtual void InsertSpace(int num) = 0;
void SetListener(BMessenger listener);
int Encoding() const;
int32 Width() const { return fWidth; }
int32 Height() const { return fHeight; }
TermPos Cursor() const { return fCursor; }
int32 HistorySize() const { return fHistorySize; }
TerminalBufferDirtyInfo& DirtyInfo() { return fDirtyInfo; }
status_t ResizeTo(int32 width, int32 height);
void Clear();
bool IsFullWidthChar(int32 row, int32 column) const;
int GetChar(int32 row, int32 column,
UTF8Char& character,
uint16& attributes) const;
int32 GetString(int32 row, int32 firstColumn,
int32 lastColumn, char* buffer,
uint16& attributes) const;
void GetStringFromRegion(BString& string,
const TermPos& start,
const TermPos& end) const;
bool FindWord(const TermPos& pos,
TerminalCharClassifier* classifier,
bool findNonWords, TermPos& start,
TermPos& end) const;
int32 LineLength(int32 index) const;
bool Find(const char* pattern, const TermPos& start,
bool forward, bool caseSensitive,
bool matchWord, TermPos& matchStart,
TermPos& matchEnd) const;
// output character
void InsertChar(UTF8Char c, uint32 attributes);
void Insert(uchar* string, ushort attr);
void InsertCR();
void InsertLF();
void InsertNewLine(int numLines);
void SetInsertMode(int flag);
void InsertSpace(int num);
// Delete Character
virtual void EraseBelow() = 0;
virtual void DeleteChar(int num) = 0;
virtual void DeleteColumns() = 0;
virtual void DeleteLine(int num) = 0;
// delete character
void EraseBelow();
void DeleteChar(int num);
void DeleteColumns();
void DeleteLine(int num);
// Get and Set Cursor position
virtual void SetCurPos(int x, int y) = 0;
virtual void SetCurX(int x) = 0;
virtual void SetCurY(int y) = 0;
virtual int GetCurX() = 0;
virtual void SaveCursor() = 0;
virtual void RestoreCursor() = 0;
// get and set cursor position
// TODO: Inline most of these!
void SetCurPos(int x, int y);
void SetCurX(int x);
void SetCurY(int y);
int GetCurX();
void SaveCursor();
void RestoreCursor();
// Move Cursor
virtual void MoveCurRight(int num) = 0;
virtual void MoveCurLeft(int num) = 0;
virtual void MoveCurUp(int num) = 0;
virtual void MoveCurDown(int num) = 0;
// move cursor
void MoveCurRight(int num);
void MoveCurLeft(int num);
void MoveCurUp(int num);
void MoveCurDown(int num);
// Cursor setting
virtual void SetCurDraw(bool flag) = 0;
// scroll region
void ScrollRegion(int top, int bot, int dir,
int num);
void SetScrollRegion(int top, int bot);
// Scroll region
virtual void ScrollRegion(int top, int bot, int dir,
int num) = 0;
virtual void SetScrollRegion(int top, int bot) = 0;
virtual void ScrollAtCursor() = 0;
// other
void SetTitle(const char* title);
void NotifyQuit(int32 reason);
// Other
virtual void DeviceStatusReport(int) = 0;
virtual void UpdateLine() = 0;
private:
struct Cell {
UTF8Char character;
uint16 attributes;
};
virtual void SetTitle(const char* title) = 0;
virtual void NotifyQuit(int32 reason) = 0;
struct Line {
int16 length;
bool softBreak; // soft line break
Cell cells[1];
inline void Clear()
{
length = 0;
softBreak = false;
}
};
inline int32 _LineIndex(int32 index) const;
inline Line* _LineAt(int32 index) const;
inline Line* _HistoryLineAt(int32 index) 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);
void _ClearLines(int32 first, int32 last);
void _Scroll(int32 top, int32 bottom,
int32 numLines);
void _SoftBreakLine();
void _PadLineToCursor();
void _InsertGap(int32 width);
bool _GetPartialLineString(BString& string,
int32 row, int32 startColumn,
int32 endColumn) const;
bool _PreviousChar(TermPos& pos, UTF8Char& c) const;
bool _NextChar(TermPos& pos, UTF8Char& c) const;
private:
// screen width/height
int32 fWidth;
int32 fHeight;
// scroll region top/bottom
int32 fScrollTop; // first line to scroll
int32 fScrollBottom; // last line to scroll (incl.)
// line buffers for the history (ring buffer)
Line** fHistory;
int32 fHistoryCapacity;
int32 fScreenOffset; // index of screen line 0
int32 fHistorySize;
// cursor position (origin: (0, 0))
TermPos fCursor;
TermPos fSavedCursor;
bool fOverwriteMode; // false for insert
// listener/dirty region management
BMessenger fListener;
TerminalBufferDirtyInfo fDirtyInfo;
};
#endif // TERMINAL_BUFFER_H
@@ -0,0 +1,11 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "TerminalCharClassifier.h"
TerminalCharClassifier::~TerminalCharClassifier()
{
}
@@ -0,0 +1,24 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef TERMINAL_CHAR_CLASSIFIER_H
#define TERMINAL_CHAR_CLASSIFIER_H
enum {
CHAR_TYPE_SPACE,
CHAR_TYPE_WORD_CHAR,
CHAR_TYPE_WORD_DELIMITER
};
class TerminalCharClassifier {
public:
virtual ~TerminalCharClassifier();
virtual int Classify(const char* character) = 0;
};
#endif // TERMINAL_CHAR_CLASSIFIER_H
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef UTF8_CHAR_H
#define UTF8_CHAR_H
#include <ctype.h>
#include <string.h>
struct UTF8Char {
char bytes[4];
UTF8Char()
{
}
UTF8Char(char c)
{
bytes[0] = c;
}
static int32 ByteCount(char firstChar)
{
// Note, this does not recognize invalid chars
uint32 c = firstChar;
if (c < 0x80)
return 1;
if (c < 0xe0)
return 2;
return c < 0xf0 ? 3 : 4;
}
int32 ByteCount() const
{
return ByteCount(bytes[0]);
}
bool IsSpace() const
{
// TODO: Support multi-byte chars!
return ByteCount() == 1 ? isspace(bytes[0]) : false;
}
UTF8Char ToLower() const
{
// TODO: Support multi-byte chars!
if (ByteCount() > 1)
return *this;
return UTF8Char((char)tolower(bytes[0]));
}
bool operator==(const UTF8Char& other) const
{
int32 byteCount = ByteCount();
bool equals = bytes[0] == other.bytes[0];
if (byteCount > 1 && equals) {
equals = bytes[1] == other.bytes[1];
if (byteCount > 2 && equals) {
equals = bytes[2] == other.bytes[2];
if (byteCount > 3 && equals)
equals = bytes[3] == other.bytes[3];
}
}
return equals;
}
bool operator!=(const UTF8Char& other) const
{
return !(*this == other);
}
};
#endif // UTF8_CHAR_H