Made the terminal a bit more robust against broken settings.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16524 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-02-27 13:05:20 +00:00
parent 9a0c473378
commit 30da2fcb94
5 changed files with 222 additions and 188 deletions

View File

@ -97,12 +97,11 @@ PrefHandler::GetDefaultPath(BPath& path)
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK) if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK)
return B_ERROR; return B_ERROR;
#ifdef __HAIKU__ #ifdef HAIKU_TARGET_PLATFORM_HAIKU
path.Append("Terminal"); path.Append("Terminal_settings");
#else #else
path.Append("HaikuTerminal"); path.Append("HaikuTerminal_settings");
#endif #endif
//path.Append("settings");
return B_OK; return B_OK;
} }

View File

@ -19,6 +19,7 @@
#include <TextView.h> #include <TextView.h>
#include "TermApp.h" #include "TermApp.h"
#include "TermBuffer.h"
#include "TermWindow.h" #include "TermWindow.h"
#include "TermConst.h" #include "TermConst.h"
#include "spawn.h" #include "spawn.h"
@ -108,7 +109,7 @@ void
TermApp::ReadyToRun() TermApp::ReadyToRun()
{ {
// Prevent opeing window when option -h is given. // Prevent opeing window when option -h is given.
if(usage_requested) if (usage_requested)
return; return;
const char *command = NULL; const char *command = NULL;
@ -133,18 +134,23 @@ TermApp::ReadyToRun()
command = gTermPref->getString(PREF_SHELL); command = gTermPref->getString(PREF_SHELL);
rows = gTermPref->getInt32(PREF_ROWS); rows = gTermPref->getInt32(PREF_ROWS);
if (rows < 1)
gTermPref->setInt32(PREF_ROWS, rows = 1);
cols = gTermPref->getInt32(PREF_COLS); cols = gTermPref->getInt32(PREF_COLS);
if (cols < MIN_COLS)
gTermPref->setInt32(PREF_COLS, cols = MIN_COLS);
pfd = spawn_shell(rows, cols, command, encoding); pfd = spawn_shell(rows, cols, command, encoding);
// failed spawn, print stdout and open alert panel // failed spawn, print stdout and open alert panel
if (pfd == -1 ) { if (pfd == -1 ) {
(new BAlert("alert", "Terminal couldn't start the shell. Sorry.", (new BAlert("alert", "Terminal couldn't start the shell. Sorry.",
"ok", NULL, NULL,B_WIDTH_FROM_LABEL, "ok", NULL, NULL, B_WIDTH_FROM_LABEL,
B_INFO_ALERT))->Go(NULL); B_INFO_ALERT))->Go(NULL);
PostMessage(B_QUIT_REQUESTED); PostMessage(B_QUIT_REQUESTED);
} }
MakeTermWindow(fTermFrame); MakeTermWindow(fTermFrame);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2005, Haiku, Inc. * Copyright (c) 2001-2006, Haiku, Inc.
* Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net> * Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net>
* Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai. * Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
@ -91,29 +91,39 @@ extern PrefHandler *gTermPref;
TermBuffer::TermBuffer(int rows, int cols) TermBuffer::TermBuffer(int rows, int cols)
{ {
if (rows < 1)
rows = 1;
if (cols < MIN_COLS)
cols = MIN_COLS;
else if (cols > MAX_COLS)
cols = MAX_COLS;
mColSize = MAX_COLS; mColSize = MAX_COLS;
mNowColSize = cols; mNowColSize = cols;
mRowSize = rows; mRowSize = rows;
mRowOffset = 0; mRowOffset = 0;
//buffer_size = ARRAY_SIZE; buffer_size = gTermPref->getInt32(PREF_HISTORY_SIZE);
buffer_size = gTermPref->getInt32 (PREF_HISTORY_SIZE); if (buffer_size < 1000)
buffer_size = 1000;
// Allocate buffer // Allocate buffer
mBase = (term_buffer**) malloc (sizeof (term_buffer*) * buffer_size); mBase = (term_buffer**)malloc(sizeof(term_buffer*) * buffer_size);
for (int i = 0; i < buffer_size; i++) for (int i = 0; i < buffer_size; i++) {
mBase[i] = (term_buffer *) calloc (mColSize + 1, sizeof (term_buffer)); mBase[i] = (term_buffer *)calloc(mColSize + 1, sizeof(term_buffer));
}
} }
TermBuffer::~TermBuffer() TermBuffer::~TermBuffer()
{ {
for(int i = 0; i < buffer_size; i++) for (int i = 0; i < buffer_size; i++) {
free (mBase[i]); free(mBase[i]);
}
free(mBase); free(mBase);
} }
@ -142,57 +152,55 @@ TermBuffer::GetString(int row, int col, int num, uchar *buf,
{ {
int count = 0, all_count = 0; int count = 0, all_count = 0;
term_buffer *ptr; term_buffer *ptr;
ptr = (mBase[row % buffer_size]); ptr = (mBase[row % buffer_size]);
ptr += col; ptr += col;
*attr = ptr->attr; *attr = ptr->attr;
if (ptr->status == NO_CHAR) { if (ptr->status == NO_CHAR) {
// Buffer is empty and No selected by mouse. // Buffer is empty and No selected by mouse.
do { do {
if (col >= mNowColSize) if (col >= mNowColSize)
return -1; return -1;
col++; col++;
ptr++; ptr++;
count--; count--;
if (ptr->status == A_CHAR) if (ptr->status == A_CHAR)
return count; return count;
if (mSelStart.y == row) { if (mSelStart.y == row) {
if (col == mSelStart.x) if (col == mSelStart.x)
return count; return count;
} }
if (mSelEnd.y == row) { if (mSelEnd.y == row) {
if (col - 1 == mSelEnd.x) if (col - 1 == mSelEnd.x)
return count; return count;
} }
}while (col <= num); } while (col <= num);
return count; return count;
} } else if (IS_WIDTH(ptr->attr)) {
else if (IS_WIDTH(ptr->attr)) { memcpy(buf, (char *)ptr->code, 4);
memcpy (buf, (char *)ptr->code, 4);
return 2; return 2;
} }
while (col <= num) { while (col <= num) {
memcpy (buf, ptr->code, 4); memcpy(buf, ptr->code, 4);
all_count++; all_count++;
if (*buf == 0) { if (*buf == 0) {
*buf = ' '; *buf = ' ';
*(buf + 1) = '\0'; *(buf + 1) = '\0';
} }
if (ptr->attr != (ptr + 1)->attr) if (ptr->attr != (ptr + 1)->attr)
return all_count; return all_count;
buf = (uchar *)index ((char *)buf, 0x00); buf = (uchar *)index((char *)buf, 0x00);
ptr++; ptr++;
col++; col++;
if (mSelStart.y == row) { if (mSelStart.y == row) {
if (col == mSelStart.x) if (col == mSelStart.x)
return all_count; return all_count;
@ -202,179 +210,189 @@ TermBuffer::GetString(int row, int col, int num, uchar *buf,
return all_count; return all_count;
} }
} }
return all_count; return all_count;
} }
// Write a character at the cursor point.
//! Write a character at the cursor point.
void void
TermBuffer::WriteChar (const CurPos &pos, const uchar *u, ushort attr) TermBuffer::WriteChar(const CurPos &pos, const uchar *u, ushort attr)
{ {
term_buffer *ptr; term_buffer *ptr;
const int row = pos.y; const int row = pos.y;
const int col = pos.x; const int col = pos.x;
ptr = (mBase[ROW(row)] + col); ptr = (mBase[ROW(row)] + col);
memcpy ((char *)ptr->code, u, 4); memcpy ((char *)ptr->code, u, 4);
if (IS_WIDTH(attr)) if (IS_WIDTH(attr))
(ptr + 1)->status = IN_STRING; (ptr + 1)->status = IN_STRING;
ptr->status = A_CHAR; ptr->status = A_CHAR;
ptr->attr = attr; ptr->attr = attr;
} }
// Write CR status to buffer attribute.
//! Write CR status to buffer attribute.
void void
TermBuffer::WriteCR (const CurPos &pos) TermBuffer::WriteCR(const CurPos &pos)
{ {
int row = pos.y; int row = pos.y;
int col = pos.x; int col = pos.x;
term_buffer *ptr = (mBase[ROW(row)] + col); term_buffer *ptr = (mBase[ROW(row)] + col);
ptr->attr |= DUMPCR; ptr->attr |= DUMPCR;
} }
// Insert 'num' spaces at cursor point. //! Insert 'num' spaces at cursor point.
void void
TermBuffer::InsertSpace (const CurPos &pos, int num) TermBuffer::InsertSpace(const CurPos &pos, int num)
{ {
const int row = pos.y; const int row = pos.y;
const int col = pos.x; const int col = pos.x;
for (int i = mNowColSize - num; i >= col; i--) for (int i = mNowColSize - num; i >= col; i--) {
*(mBase[ROW(row)] + i + num) = *(mBase[ROW(row)] + i); *(mBase[ROW(row)] + i + num) = *(mBase[ROW(row)] + i);
}
memset(mBase[ROW(row)] + col, 0, num * sizeof(term_buffer)); memset(mBase[ROW(row)] + col, 0, num * sizeof(term_buffer));
} }
// Delete 'num' characters at cursor point.
//! Delete 'num' characters at cursor point.
void void
TermBuffer::DeleteChar(const CurPos &pos, int num) TermBuffer::DeleteChar(const CurPos &pos, int num)
{ {
const int row = pos.y; const int row = pos.y;
const int col = pos.x; const int col = pos.x;
term_buffer *ptr = mBase[ROW(row)]; term_buffer *ptr = mBase[ROW(row)];
size_t movesize = mNowColSize - (col + num); size_t movesize = mNowColSize - (col + num);
memmove (ptr + col, ptr + col + num, movesize * sizeof(term_buffer)); memmove(ptr + col, ptr + col + num, movesize * sizeof(term_buffer));
memset (ptr + (mNowColSize - num), 0, num * sizeof(term_buffer)); memset(ptr + (mNowColSize - num), 0, num * sizeof(term_buffer));
} }
// Erase characters below cursor position.
//! Erase characters below cursor position.
void void
TermBuffer::EraseBelow(const CurPos &pos) TermBuffer::EraseBelow(const CurPos &pos)
{ {
const int row = pos.y; const int row = pos.y;
const int col = pos.x; const int col = pos.x;
memset (mBase[ROW(row)] + col, 0, (mColSize - col ) * sizeof (term_buffer)); memset(mBase[ROW(row)] + col, 0, (mColSize - col ) * sizeof(term_buffer));
for (int i = row; i < mRowSize; i++) for (int i = row; i < mRowSize; i++) {
EraseLine (i); EraseLine(i);
}
} }
// Scroll the terminal buffer region
//! Scroll the terminal buffer region
void void
TermBuffer::ScrollRegion(int top, int bot, int dir, int num) TermBuffer::ScrollRegion(int top, int bot, int dir, int num)
{ {
if(dir == SCRUP) { if (dir == SCRUP) {
for(int i = 0; i < num; i++){ for (int i = 0; i < num; i++) {
term_buffer *ptr = mBase[ROW(top)]; term_buffer *ptr = mBase[ROW(top)];
for(int j = top; j < bot; j++) for (int j = top; j < bot; j++) {
mBase[ROW(j)] = mBase[ROW(j+1)]; mBase[ROW(j)] = mBase[ROW(j+1)];
}
mBase[ROW(bot)] = ptr; mBase[ROW(bot)] = ptr;
EraseLine(bot); EraseLine(bot);
} }
} else { } else {
// scroll up // scroll up
for(int i = 0; i < num; i++){ for (int i = 0; i < num; i++) {
term_buffer *ptr = mBase[ROW(bot)]; term_buffer *ptr = mBase[ROW(bot)];
for(int j = bot; j > top; j--) for (int j = bot; j > top; j--) {
mBase[ROW(j)] = mBase[ROW(j-1)]; mBase[ROW(j)] = mBase[ROW(j-1)];
}
mBase[ROW(top)] = ptr; mBase[ROW(top)] = ptr;
EraseLine(top); EraseLine(top);
} }
} }
} }
// Scroll the terminal buffer.
//! Scroll the terminal buffer.
void void
TermBuffer::ScrollLine(void) TermBuffer::ScrollLine()
{ {
for (int i = mRowSize; i < mRowSize * 2; i++) for (int i = mRowSize; i < mRowSize * 2; i++) {
EraseLine (i); EraseLine(i);
}
mRowOffset++; mRowOffset++;
} }
// Resize the terminal buffer.
//! Resize the terminal buffer.
void void
TermBuffer::ResizeTo(int newRows, int newCols, int offset) TermBuffer::ResizeTo(int newRows, int newCols, int offset)
{ {
int i; int i;
// TODO: Why is this code #if 0'd? It should either be fixed or removed // make sure the new size is within the allowed limits
#if 0 if (newRows < 1)
if (newCols > mColSize) { newRows = 1;
for (i = 0; i < buffer_size; i++) {
mBase[i] = (ulong *) realloc (mBase[i], sizeof(ulong) * newCols); if (newCols < MIN_COLS)
base = mBase[i] + mColSize; newCols = MIN_COLS;
for (j= 0; j < newCols - mColSize; j++) else if (newCols > MAX_COLS)
*base++ = 0; newCols = MAX_COLS;
}
mColSize = newCols; if (newRows <= mRowSize) {
}
#endif
if ( newRows <= mRowSize) {
for (i = newRows; i <= mRowSize; i++) for (i = newRows; i <= mRowSize; i++)
EraseLine (i); EraseLine(i);
} else { } else {
for (i = mRowSize; i <= newRows * 2; i++) for (i = mRowSize; i <= newRows * 2; i++)
EraseLine (i); EraseLine(i);
} }
mNowColSize = newCols; mNowColSize = newCols;
mRowOffset += offset; mRowOffset += offset;
mRowSize = newRows; mRowSize = newRows;
} }
// Get the buffer's size.
//! Get the buffer's size.
int32 int32
TermBuffer::GetArraySize (void) TermBuffer::GetArraySize()
{ {
return buffer_size; return buffer_size;
} }
// Erase one column.
void void
TermBuffer::EraseLine (int row) TermBuffer::EraseLine(int row)
{ {
memset (mBase[ROW(row)], 0, mColSize * sizeof (term_buffer)); memset(mBase[ROW(row)], 0, mColSize * sizeof(term_buffer));
} }
// Clear the contents of the TermBuffer.
//! Clear the contents of the TermBuffer.
void void
TermBuffer::ClearAll (void) TermBuffer::ClearAll()
{ {
for(int i = 0; i < buffer_size; i++) for (int i = 0; i < buffer_size; i++) {
memset (mBase[i], 0, mColSize * sizeof (term_buffer)); memset(mBase[i], 0, mColSize * sizeof(term_buffer));
}
mRowOffset = 0; mRowOffset = 0;
DeSelect (); DeSelect();
} }
// Mark text in the given range as selected
//! Mark text in the given range as selected
void void
TermBuffer::Select(const CurPos &start, const CurPos &end) TermBuffer::Select(const CurPos &start, const CurPos &end)
{ {
@ -387,103 +405,105 @@ TermBuffer::Select(const CurPos &start, const CurPos &end)
} }
} }
// Mark text in the given range as not selected
//! Mark text in the given range as not selected
void void
TermBuffer::DeSelect (void) TermBuffer::DeSelect()
{ {
mSelStart.Set (-1, -1); mSelStart.Set(-1, -1);
mSelEnd.Set (-1, -1); mSelEnd.Set(-1, -1);
} }
// Check cursor position which be including selected area.
//! Check cursor position which be including selected area.
int int
TermBuffer::CheckSelectedRegion (const CurPos &pos) TermBuffer::CheckSelectedRegion (const CurPos &pos)
{ {
return (mSelStart.y == pos.y || mSelEnd.y == pos.y); return mSelStart.y == pos.y || mSelEnd.y == pos.y;
} }
// Find a word in the TermBuffer
bool bool
TermBuffer::FindWord(const CurPos &pos, CurPos *start, CurPos *end) TermBuffer::FindWord(const CurPos &pos, CurPos *start, CurPos *end)
{ {
uchar buf[5]; uchar buf[5];
ushort attr; ushort attr;
int x, y, start_x; int x, y, start_x;
y = pos.y; y = pos.y;
// Search start point // Search start point
for(x = pos.x - 1; x >= 0; x--){ for (x = pos.x - 1; x >= 0; x--) {
if((this->GetChar (y, x, buf, &attr) == NO_CHAR) || (*buf == ' ')){ if (GetChar(y, x, buf, &attr) == NO_CHAR || *buf == ' ') {
++x; ++x;
break; break;
} }
} }
start_x = x; start_x = x;
// Search end point // Search end point
for(x = pos.x; x < mColSize; x++){ for (x = pos.x; x < mColSize; x++) {
if( (GetChar(y, x, buf, &attr) == NO_CHAR) || (*buf == ' ')) { if (GetChar(y, x, buf, &attr) == NO_CHAR || *buf == ' ') {
--x; --x;
break; break;
} }
} }
if(start_x > x) if (start_x > x)
return false; return false;
mSelStart.Set(start_x, y); mSelStart.Set(start_x, y);
if(start != NULL) if (start != NULL)
start->Set(start_x, y); start->Set(start_x, y);
mSelEnd.Set(x, y); mSelEnd.Set(x, y);
if(end != NULL) if (end != NULL)
end->Set(x, y); end->Set(x, y);
return true; return true;
} }
// Get one character from the selected region.
//! Get one character from the selected region.
void void
TermBuffer::GetCharFromRegion (int x, int y, BString &str) TermBuffer::GetCharFromRegion(int x, int y, BString &str)
{ {
uchar buf[5]; uchar buf[5];
ushort attr; ushort attr;
int status; int status;
status = GetChar(y, x, buf, &attr); status = GetChar(y, x, buf, &attr);
switch(status) { switch (status) {
case NO_CHAR:
case NO_CHAR: if (IS_CR (attr))
if (IS_CR (attr)) str += '\n';
str += '\n'; else
else str += ' ';
str += ' '; break;
break;
case IN_STRING:
case IN_STRING: break;
break;
default:
default: str += (const char *)&buf;
str += (const char *)&buf; break;
break;
} }
} }
// Delete useless char at end of line and convert LF code.
//! Delete useless char at end of line and convert LF code.
inline void inline void
TermBuffer::AvoidWaste (BString &str) TermBuffer::AvoidWaste(BString &str)
{ {
// TODO: Remove the goto // TODO: Remove the goto
int32 len, point; int32 len, point;
start: start:
len = str.Length() - 1; len = str.Length() - 1;
point = str.FindLast (' '); point = str.FindLast (' ');
if (len > 0 && len == point) { if (len > 0 && len == point) {
str.RemoveLast (" "); str.RemoveLast (" ");
goto start; goto start;
@ -491,31 +511,36 @@ TermBuffer::AvoidWaste (BString &str)
// str += '\n'; // str += '\n';
} }
// Get a string from selected region.
//! Get a string from selected region.
void void
TermBuffer::GetStringFromRegion(BString &str) TermBuffer::GetStringFromRegion(BString &str)
{ {
int y; int y;
if(mSelStart.y == mSelEnd.y) { if (mSelStart.y == mSelEnd.y) {
y = mSelStart.y; y = mSelStart.y;
for(int x = mSelStart.x ; x <= mSelEnd.x; x++) for (int x = mSelStart.x ; x <= mSelEnd.x; x++) {
GetCharFromRegion (x, y, str); GetCharFromRegion(x, y, str);
}
} else { } else {
y = mSelStart.y; y = mSelStart.y;
for(int x = mSelStart.x ; x < mNowColSize; x++) for (int x = mSelStart.x ; x < mNowColSize; x++) {
GetCharFromRegion (x, y, str); GetCharFromRegion(x, y, str);
AvoidWaste (str);
for(y = mSelStart.y + 1 ; y < mSelEnd.y; y++){
for(int x = 0 ; x < mNowColSize; x++)
GetCharFromRegion (x, y, str);
AvoidWaste (str);
} }
AvoidWaste(str);
for (y = mSelStart.y + 1 ; y < mSelEnd.y; y++) {
for (int x = 0 ; x < mNowColSize; x++) {
GetCharFromRegion(x, y, str);
}
AvoidWaste(str);
}
y = mSelEnd.y; y = mSelEnd.y;
for(int x = 0 ; x <= mSelEnd.x; x++) for (int x = 0 ; x <= mSelEnd.x; x++) {
GetCharFromRegion (x, y, str); GetCharFromRegion(x, y, str);
} }
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2005, Haiku, Inc. * Copyright (c) 2001-2006, Haiku, Inc.
* Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net> * Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net>
* Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai. * Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
@ -152,9 +152,9 @@ TermView::GetFontSize(int* _width, int* _height)
BRect BRect
TermView::SetTermSize(int rows, int cols, bool resize) TermView::SetTermSize(int rows, int cols, bool resize)
{ {
if (rows) if (rows > 0)
fTermRows = rows; fTermRows = rows;
if (cols) if (cols > 0)
fTermColumns = cols; fTermColumns = cols;
fTextBuffer->ResizeTo(fTermRows, fTermColumns, 0); fTextBuffer->ResizeTo(fTermRows, fTermColumns, 0);
@ -162,12 +162,10 @@ TermView::SetTermSize(int rows, int cols, bool resize)
fScrTop = 0; fScrTop = 0;
fScrBot = fTermRows - 1; fScrBot = fTermRows - 1;
BRect rect(0, 0, BRect rect(0, 0, fTermColumns * fFontWidth, fTermRows * fFontHeight);
fTermColumns * fFontWidth,
fTermRows * fFontHeight);
if (resize) { if (resize) {
ResizeTo(fTermColumns * fFontWidth -1, ResizeTo(fTermColumns * fFontWidth - 1,
fTermRows * fFontHeight -1); fTermRows * fFontHeight -1);
} }
Invalidate(Frame()); Invalidate(Frame());

View File

@ -87,14 +87,20 @@ TermWindow::InitWindow(void)
BFont halfFont; BFont halfFont;
halfFont.SetFamilyAndStyle(family, NULL); halfFont.SetFamilyAndStyle(family, NULL);
halfFont.SetSize(gTermPref->getFloat(PREF_HALF_FONT_SIZE)); float size = gTermPref->getFloat(PREF_HALF_FONT_SIZE);
if (size < 6.0f)
size = 6.0f;
halfFont.SetSize(size);
halfFont.SetSpacing(B_FIXED_SPACING); halfFont.SetSpacing(B_FIXED_SPACING);
family = gTermPref->getString(PREF_FULL_FONT_FAMILY); family = gTermPref->getString(PREF_FULL_FONT_FAMILY);
BFont fullFont; BFont fullFont;
fullFont.SetFamilyAndStyle(family, NULL); fullFont.SetFamilyAndStyle(family, NULL);
fullFont.SetSize(gTermPref->getFloat(PREF_FULL_FONT_SIZE)); size = gTermPref->getFloat(PREF_FULL_FONT_SIZE);
if (size < 6.0f)
size = 6.0f;
fullFont.SetSize(size);
fullFont.SetSpacing(B_FIXED_SPACING); fullFont.SetSpacing(B_FIXED_SPACING);
// Make Terminal text view. // Make Terminal text view.