This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-goldedplus/golded3/geedit.cpp

3453 lines
84 KiB
C++
Raw Normal View History

2000-02-25 11:04:07 +00:00
// ------------------------------------------------------------------
// GoldED+
// Copyright (C) 1990-1999 Odinn Sorensen
// Copyright (C) 1999-2000 Alexander S. Aganichev
// ------------------------------------------------------------------
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA 02111-1307 USA
// ------------------------------------------------------------------
// $Id$
// ------------------------------------------------------------------
// The Internal Editor (IE), part 1.
// ------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation "geedit.h"
#endif
// ------------------------------------------------------------------
#include <golded.h>
#include <geedit.h>
gkey kbxget_raw(int mode);
2000-02-25 11:04:07 +00:00
// ------------------------------------------------------------------
// Globals
Line* Edit__killbuf = NULL;
Line* Edit__pastebuf = NULL;
Path Edit__exportfilename = {""};
UndoItem** UndoItem::last_item;
// ------------------------------------------------------------------
#ifndef NDEBUG
void IEclass::debugtest(char* __test, int __a, int __b, char* __file, int __line, int __values) {
#if defined(GFTRK_ENABLE)
int _tmp = __gftrk_on;
__gftrk_on = false;
#endif
savefile(MODE_UPDATE);
#if defined(GFTRK_ENABLE)
__gftrk_on = _tmp;
#endif
if(__values)
w_infof(" Range check: (%s) <%i,%i> [%s,%u] ", __test, __a, __b, __file, __line);
else
w_infof(" Range check: (%s) [%s,%u] ", __test, __file, __line);
update_statusline(LNG->EscOrContinue);
SayBibi();
while(kbxhit())
kbxget();
gkey _key = kbxget();
w_info(NULL);
if(_key == Key_Esc) {
LOG.errtest(__file, __line);
LOG.printf("! An internal editor range check failed.");
if(__values)
LOG.printf(": Details: (%s) <%i,%i>.", __test, __a, __b);
2003-01-04 10:16:47 +00:00
else {
2000-02-25 11:04:07 +00:00
LOG.printf(": Details: (%s).", __test);
LOG.printf(": Details: r%u,c%u,mr%u,mc%u,i%u,dm%u,qm%u,eqm%u.",
2003-01-04 10:16:47 +00:00
row, col, maxrow, maxcol, insert,
CFG->dispmargin, CFG->quotemargin, EDIT->QuoteMargin());
}
2000-02-25 11:04:07 +00:00
LOG.printf("+ Advice: Report to the Author.");
TestErrorExit();
}
}
#endif
// ------------------------------------------------------------------
2006-03-11 17:04:06 +00:00
#if defined(GCFG_SPELL_INCLUDED)
inline bool isscchar(int c)
{
return isxalnum(c) || (c == '-') || (c == '\'') || (c == '.') ;
}
#endif
2000-02-25 11:04:07 +00:00
// ------------------------------------------------------------------
// Make sure line type is correct
void IEclass::setlinetype(Line* __line) {
_test_halt(__line == NULL);
2001-10-17 04:04:19 +00:00
__line->type &= ~(GLINE_ALL|GLINE_TEAR|GLINE_ORIG|GLINE_TAGL);
2005-10-16 03:41:29 +00:00
if (is_quote(__line->txt.c_str()) &&
is_quote2(__line, __line->txt.c_str()))
{
__line->type |= GLINE_QUOT;
}
else if (__line->txt[0] == CTRL_A)
{
__line->type |= GLINE_HIDD;
}
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
// Insert character in string at position
// ------------------------------------------------------------------
// Zero-based
vattr IEclass::dispchar(vchar __ch, vattr attr) {
2000-02-25 11:04:07 +00:00
2001-01-27 11:52:13 +00:00
if(__ch == NUL) // possible if line empty
__ch = ' ';
2001-05-20 12:23:00 +00:00
if(__ch == '\n') {
2000-02-25 11:04:07 +00:00
__ch = EDIT->CharPara();
}
2001-05-20 12:23:00 +00:00
else if(__ch == ' ') {
__ch = EDIT->CharSpace();
}
2000-02-25 11:04:07 +00:00
vattr atr;
2000-02-25 11:04:07 +00:00
vchar chr;
editwin.getc(crow, ccol, &atr, &chr);
editwin.printc(crow, ccol, attr == DEFATTR ? atr : attr, __ch);
2000-02-25 11:04:07 +00:00
return atr;
}
// ------------------------------------------------------------------
2006-01-14 23:48:53 +00:00
void IEclass::cursoroff() {
2000-02-25 11:04:07 +00:00
vcurhide();
}
// ------------------------------------------------------------------
2006-01-14 23:48:53 +00:00
void IEclass::cursoron() {
2000-02-25 11:04:07 +00:00
vcurshow();
}
// ------------------------------------------------------------------
// Zero-based
void IEclass::scrollup(int __scol, int __srow, int __ecol, int __erow, int __lines) {
editwin.scroll_box_up(__srow, __scol, __erow, __ecol, __lines);
}
// ------------------------------------------------------------------
// Zero-based
void IEclass::scrolldown(int __scol, int __srow, int __ecol, int __erow, int __lines) {
editwin.scroll_box_down(__srow, __scol, __erow, __ecol, __lines);
}
// ------------------------------------------------------------------
// Zero-based
void IEclass::prints(int wrow, int wcol, vattr atr, const char* str) {
2000-02-25 11:04:07 +00:00
editwin.prints(wrow, wcol, atr, str);
}
// ------------------------------------------------------------------
Line* IEclass::findfirstline() {
GFTRK("Editfindfirstline");
if(not currline)
return NULL;
// Rewind to the first line
Line* _firstline = currline;
while(_firstline->prev)
_firstline = _firstline->prev;
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return _firstline;
}
// ------------------------------------------------------------------
// Find out what number the current line is and put it in "thisrow"
void IEclass::getthisrow(Line* __currline) {
GFTRK("Editgetthisrow");
Line* _templine = findfirstline();
thisrow = 0;
while((_templine != __currline) and _templine->next) {
_templine = _templine->next;
thisrow++;
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
// Zero-based
void IEclass::gotorowcol(uint __col, uint __row) {
GFTRK("Editgotorowcol");
_test_haltab(__col > maxcol, __col, maxcol);
_test_haltab(__row > maxrow, __row, maxrow);
editwin.move_cursor(__row, __col);
ccol = __col;
crow = __row;
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
2006-03-11 17:04:06 +00:00
#if defined(GCFG_SPELL_INCLUDED)
void IEclass::dispstringsc(char *__buf, uint __beg, uint __end, uint __row, uint __col, char endchar)
{
char scbuf[EDIT_BUFLEN];
2006-01-14 23:48:53 +00:00
uint bbeg = __beg;
uint bend = __beg;
uint bpos = __beg;
if ((bbeg > 0) && isscchar(__buf[bbeg]) && isscchar(__buf[bbeg-1]))
{
for (; (bpos < __end) && isscchar(__buf[bpos]); bpos++);
bend = bpos;
}
while (bpos < __end)
{
for (; (bpos < __end) && !isscchar(__buf[bpos]); bpos++);
bend = bpos;
uint scpos = 0;
for (; (bpos < __end) && isscchar(__buf[bpos]); bpos++, scpos++)
scbuf[scpos] = __buf[bpos];
if ((scpos == 0) || ((bpos == __end) && isscchar(endchar)))
{
bend = bpos;
break;
}
scbuf[scpos] = NUL;
2006-01-14 23:48:53 +00:00
if (schecker.Check(scbuf))
bend = bpos;
else
{
char savechar = __buf[bend];
__buf[bend] = NUL;
StyleCodeHighlight(__buf+bbeg, __row, __col+bbeg-__beg, false, DEFATTR);
__buf[bend] = savechar;
bbeg = bend; bend += scpos;
bool oldusestylies = AA->adat->usestylies;
bool oldhighlighturls = CFG->highlighturls;
AA->adat->usestylies = false;
CFG->highlighturls = false;
savechar = __buf[bend];
__buf[bend] = NUL;
StyleCodeHighlight(__buf+bbeg, __row, __col+bbeg-__beg, false, C_SCERROR);
__buf[bend] = savechar;
AA->adat->usestylies = oldusestylies;
CFG->highlighturls = oldhighlighturls;
bbeg = bend;
}
}
if (bbeg < bend)
StyleCodeHighlight(__buf+bbeg, __row, __col+bbeg-__beg, false, DEFATTR);
}
// ------------------------------------------------------------------
void IEclass::dispstring(Line* line, uint __row)
{
GFTRK("Editdispstring");
// Get string length
uint _length = strlen(line->txt.c_str());
// String longer than window width?
_test_haltab(_length > (maxcol+1), _length, (maxcol+1));
_length = MinV(_length, (maxcol+1));
// Buffer for translation to visual representation
char _buf[EDIT_BUFLEN];
// Space-pad and nul-terminate the buffer
memset(_buf, ' ', maxcol+1);
_buf[maxcol+1] = NUL;
// Copy/translate string into buffer
for (uint _pos = 0; _pos < _length; _pos++)
{
char chr = line->txt[_pos];
switch (chr)
{
case ' ': _buf[_pos] = EDIT->CharSpace(); break;
case '\n': _buf[_pos] = EDIT->CharPara(); break;
default: _buf[_pos] = chr;
}
}
int selected = 0;
uint begblock = 0;
uint endblock = 0;
Line *fbline = NULL;
Line *lbline = NULL;
if (blockcol != -1)
{
for (Line *ln = findfirstline(); ln; ln = ln->next)
{
if (ln == currline)
{
if (selected) { lbline = ln; selected ^= 1; endblock = col; }
else { fbline = ln; selected ^= 1; begblock = col; }
}
if (ln->type & GLINE_BLOK)
{
if (selected) { lbline = ln; selected ^= 1; endblock = blockcol; }
else { fbline = ln; selected ^= 1; begblock = blockcol; }
}
if (ln == line) { if (ln == lbline) selected = 1; break; }
if (lbline) break;
}
if (selected)
{
if (fbline == lbline)
{
if (begblock > endblock)
{
int temp = begblock;
begblock = endblock;
endblock = temp;
}
else if (begblock == endblock)
begblock = endblock = 0;
}
else if (line == fbline)
endblock = maxcol+1;
else if (line == lbline)
begblock = 0;
else
{
begblock = 0;
endblock = maxcol+1;
}
}
else
begblock = endblock = 0;
}
if (0 < begblock)
{
char savechar = _buf[begblock];
_buf[begblock] = NUL;
if ((CFG->scheckerenabled == GAUTO) && schecker.IsLoaded() &&
!(line->type & (GLINE_TAGL|GLINE_QUOT|GLINE_KLUD|GLINE_TEAR|GLINE_ORIG|GLINE_HIDD)))
{
dispstringsc(_buf, 0, begblock, __row, mincol, savechar);
}
else
StyleCodeHighlight(_buf, __row, mincol, false, DEFATTR);
_buf[begblock] = savechar;
}
if (begblock < endblock)
{
bool oldusestylies = AA->adat->usestylies;
bool oldhighlighturls = CFG->highlighturls;
AA->adat->usestylies = false;
CFG->highlighturls = false;
char savechar = _buf[endblock];
_buf[endblock] = NUL;
StyleCodeHighlight(_buf+begblock, __row, mincol+begblock, false, C_READA);
_buf[endblock] = savechar;
AA->adat->usestylies = oldusestylies;
CFG->highlighturls = oldhighlighturls;
}
if (endblock < (maxcol+1))
{
if ((CFG->scheckerenabled == GAUTO) && schecker.IsLoaded() &&
!(line->type & (GLINE_TAGL|GLINE_QUOT|GLINE_KLUD|GLINE_TEAR|GLINE_ORIG|GLINE_HIDD)))
{
dispstringsc(_buf, endblock, maxcol+1, __row, mincol+endblock, 0);
}
else
StyleCodeHighlight(_buf+endblock, __row, mincol+endblock, false, DEFATTR);
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
}
2006-03-11 17:04:06 +00:00
#else // #if defined(GCFG_SPELL_INCLUDED)
2000-02-25 11:04:07 +00:00
// ------------------------------------------------------------------
2000-03-22 17:59:18 +00:00
void IEclass::dispstring(const char* __string, uint __row, int attr, Line* line) {
2000-02-25 11:04:07 +00:00
GFTRK("Editdispstring");
_test_halt(__string == NULL);
_test_haltab(__row > maxrow, __row, maxrow);
// Get string length
uint _length = strlen(__string);
// String longer than window width?
_test_haltab(_length > (maxcol+1), _length, (maxcol+1));
_length = MinV(_length, (maxcol+1));
// Buffer for translation to visual representation
char _buf[EDIT_BUFLEN];
// Space-pad and nul-terminate the buffer
memset(_buf, ' ', maxcol+1);
_buf[maxcol+1] = NUL;
// Copy/translate string into buffer
if(attr == -1) {
char* _bufptr = _buf;
uint _position = 0;
2000-03-22 17:59:18 +00:00
const char* __str = __string;
2000-02-25 11:04:07 +00:00
while(_position < _length) {
switch(*__str) {
case ' ': *_bufptr = EDIT->CharSpace(); break;
case '\n': *_bufptr = EDIT->CharPara(); break;
default: *_bufptr = *__str;
}
_position++;
_bufptr++;
__str++;
}
}
else {
2000-06-16 23:30:48 +00:00
if(_length)
memcpy(_buf, __string, _length);
2000-02-25 11:04:07 +00:00
}
// mark selected block
if(line and (blockcol != -1)) {
int selected = 0;
for(Line *ln = findfirstline(); ln and ln != line; ln = ln->next) {
if(ln == currline)
selected ^= 1;
if(ln->type & GLINE_BLOK)
selected ^= 1;
}
if((line->type & GLINE_BLOK) and (line == currline)) {
int begblock = ((col < blockcol) ? col : blockcol) - mincol;
int endblock = ((col > blockcol) ? col : blockcol) - mincol;
char savechar = _buf[begblock];
_buf[begblock] = NUL;
StyleCodeHighlight(_buf, __row, mincol, false, attr);
_buf[begblock] = savechar;
savechar = _buf[endblock];
_buf[endblock] = NUL;
bool oldusestylies = AA->adat->usestylies;
2002-10-11 05:54:11 +00:00
bool oldhighlighturls = CFG->highlighturls;
AA->adat->usestylies = false;
2002-10-11 05:54:11 +00:00
CFG->highlighturls = false;
2000-02-25 11:04:07 +00:00
StyleCodeHighlight(_buf+begblock, __row, mincol+begblock, false, C_READA);
AA->adat->usestylies = oldusestylies;
2002-10-11 05:54:11 +00:00
CFG->highlighturls = oldhighlighturls;
2000-02-25 11:04:07 +00:00
_buf[endblock] = savechar;
StyleCodeHighlight(_buf+endblock, __row, mincol+endblock, false, attr);
}
else if((line->type & GLINE_BLOK) or (line == currline)) {
int blockmark = ((line->type & GLINE_BLOK) ? blockcol : col) - mincol;
char savechar = _buf[blockmark];
_buf[blockmark] = NUL;
bool oldusestylies = AA->adat->usestylies;
2002-10-11 05:54:11 +00:00
bool oldhighlighturls = CFG->highlighturls;
if(selected) {
AA->adat->usestylies = false;
2002-10-11 05:54:11 +00:00
CFG->highlighturls = false;
}
2000-02-25 11:04:07 +00:00
StyleCodeHighlight(_buf, __row, mincol, false, selected ? C_READA : attr);
AA->adat->usestylies = oldusestylies;
2000-02-25 11:04:07 +00:00
_buf[blockmark] = savechar;
2002-10-11 05:54:11 +00:00
if(not selected) {
AA->adat->usestylies = false;
2002-10-11 05:54:11 +00:00
CFG->highlighturls = false;
}
2000-02-25 11:04:07 +00:00
StyleCodeHighlight(_buf+blockmark, __row, mincol+blockmark, false, selected ? attr : C_READA);
AA->adat->usestylies = oldusestylies;
2002-10-11 05:54:11 +00:00
CFG->highlighturls = oldhighlighturls;
2000-02-25 11:04:07 +00:00
}
2001-11-04 21:37:03 +00:00
else {
bool oldusestylies = AA->adat->usestylies;
2002-10-11 05:54:11 +00:00
bool oldhighlighturls = CFG->highlighturls;
if(selected) {
AA->adat->usestylies = false;
2002-10-11 05:54:11 +00:00
CFG->highlighturls = false;
}
2000-02-25 11:04:07 +00:00
StyleCodeHighlight(_buf, __row, mincol, false, selected ? C_READA : attr);
AA->adat->usestylies = oldusestylies;
2002-10-11 05:54:11 +00:00
CFG->highlighturls = oldhighlighturls;
2001-11-04 21:37:03 +00:00
}
2000-02-25 11:04:07 +00:00
}
else
StyleCodeHighlight(_buf, __row, mincol, false, attr);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
2006-03-11 17:04:06 +00:00
#endif // #if defined(GCFG_SPELL_INCLUDED)
2000-02-25 11:04:07 +00:00
// ------------------------------------------------------------------
void IEclass::setcolor(Line* __line) {
// Set window attribute
if(__line->type & GLINE_HIDD)
editwin.text_color(C_READKH);
else if(__line->type & GLINE_KLUD)
editwin.text_color(C_READK);
else if(__line->type & GLINE_TAGL)
editwin.text_color(C_READG);
else if(__line->type & GLINE_TEAR)
editwin.text_color(C_READT);
else if(__line->type & GLINE_ORIG)
editwin.text_color(C_READO);
else if(__line->type & GLINE_QUOT)
2000-03-22 17:59:18 +00:00
editwin.text_color(quotecolor(__line->txt.c_str()));
2000-02-25 11:04:07 +00:00
else if(__line->type & GLINE_SIGN)
editwin.text_color(C_READS);
else
editwin.text_color(C_READW);
}
// ------------------------------------------------------------------
// Zero-based
void IEclass::displine(Line* __line, uint __row) {
GFTRK("Editdispline");
_test_halt(__line == NULL);
_test_haltab(__row > maxrow, __row, maxrow);
// Display line
setcolor(__line);
2006-03-11 17:04:06 +00:00
#if defined(GCFG_SPELL_INCLUDED)
dispstring(__line, __row);
#else
2000-03-22 17:59:18 +00:00
dispstring(__line->txt.c_str(), __row, -1, __line);
#endif
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
// Zero-based
void IEclass::clreol(int __col, int __row) {
GFTRK("Editclreol");
if(__col == -1)
__col = ccol;
if(__row == -1)
__row = crow;
if((uint)__col <= maxcol)
editwin.fill(__row, __col, __row, maxcol, ' ', C_READW);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
// Zero-based
void IEclass::refresh(Line* __currline, uint __row) {
GFTRK("Editrefresh");
_test_halt(__currline == NULL);
cursoroff();
// Display as many lines as we can
while(__currline and (__row <= maxrow)) {
displine(__currline, __row++);
__currline = __currline->next;
}
// If we ran out of lines, blank the rest
2006-03-11 17:04:06 +00:00
#if defined(GCFG_SPELL_INCLUDED)
if (__row <= maxrow)
editwin.fill(__row, mincol, __row, maxcol, _box_table(W_BREAD, 1), C_READB|ACSET);
if (++__row <= maxrow)
editwin.fill(__row, mincol, maxrow, maxcol, ' ', C_READW);
#else
2000-02-25 11:04:07 +00:00
if(__row <= maxrow) {
vchar vbuf[256];
for(int c = 0; c < maxcol+1; c++)
vbuf[c] = _box_table(W_BREAD, 1);
vbuf[maxcol+1] = NUL;
wprintvs(__row++, mincol, C_READB|ACSET, vbuf);
while(__row <= maxrow)
dispstring("", __row++);
}
#endif
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
2000-03-22 17:59:18 +00:00
Line* IEclass::insertlinebelow(Line* __currline, const char* __text, long __batch_mode) {
2000-02-25 11:04:07 +00:00
GFTRK("Editinsertlinebelow");
2000-03-22 17:59:18 +00:00
Line* _nextline = new Line(__text ? __text : "");
throw_xnew(_nextline);
2000-02-25 11:04:07 +00:00
if(__currline) {
_nextline->prev = __currline;
_nextline->next = __currline->next;
if(_nextline->next)
_nextline->next->prev = _nextline;
__currline->next = _nextline;
}
2006-01-14 23:48:53 +00:00
2000-02-25 11:04:07 +00:00
Undo->PushItem(EDIT_UNDO_NEW_LINE|batch_mode|__batch_mode, _nextline);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return _nextline;
}
// ------------------------------------------------------------------
// Zero-based
int IEclass::downoneline(uint __row) {
GFTRK("Editdownoneline");
_test_haltab(__row > maxrow, __row, maxrow);
thisrow++;
if(__row == maxrow)
scrollup(mincol, minrow, maxcol, maxrow);
else
__row++;
gotorowcol(mincol, __row);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return __row;
}
// ------------------------------------------------------------------
void IEclass::GoEOL()
{
2000-02-25 11:04:07 +00:00
GFTRK("EditGoEOL");
// Move cursor to the last char on the line
if (mincol != (col = currline->txt.length()))
{
if ((currline->txt[col-1] == '\n') || (currline->txt[col-1] == ' '))
--col;
}
2000-02-25 11:04:07 +00:00
// String must not be longer than the window width
_test_haltab(col > maxcol, col, maxcol);
if(blockcol != -1)
displine(currline, row);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::GoUp() {
GFTRK("EditGoUp");
_test_haltab(row < minrow, row, minrow);
if(currline->prev) {
currline = currline->prev;
thisrow--;
if(row == minrow) {
scrolldown(mincol, row, maxcol, maxrow);
if(blockcol != -1)
displine(currline->next, row+1);
displine(currline, row);
}
else {
row--;
if(blockcol != -1) {
displine(currline->next, row+1);
displine(currline, row);
}
}
2000-03-22 17:59:18 +00:00
if((col+1) > currline->txt.length())
2000-02-25 11:04:07 +00:00
GoEOL();
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::GoDown() {
GFTRK("EditGoDown");
_test_haltab(row > maxrow, row, maxrow);
if(currline->next) {
currline = currline->next;
thisrow++;
if(row == maxrow) {
scrollup(mincol, minrow, maxcol, maxrow);
if(blockcol != -1)
displine(currline->prev, row-1);
displine(currline,row);
}
else {
row++;
if(blockcol != -1) {
displine(currline->prev, row-1);
displine(currline, row);
}
}
2000-03-22 17:59:18 +00:00
if((col+1) > currline->txt.length())
2000-02-25 11:04:07 +00:00
GoEOL();
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::GoLeft() {
GFTRK("EditGoLeft");
_test_haltab(col < mincol, col, mincol);
if(col == mincol) {
if(currline->prev) {
GoUp();
GoEOL();
2001-05-20 12:23:00 +00:00
if((col != mincol) and (currline->txt.c_str()[col] == NUL))
col--;
2000-02-25 11:04:07 +00:00
}
}
else
col--;
if(blockcol != -1)
displine(currline, row);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::GoRight() {
GFTRK("EditGoRight");
_test_haltab(col > maxcol, col, maxcol);
2001-05-20 12:23:00 +00:00
if((col == maxcol) or ((col+1) >= currline->txt.length())) {
2000-02-25 11:04:07 +00:00
if(currline->next != NULL) {
GoDown();
col = mincol;
}
}
else
col++;
if(blockcol != -1)
displine(currline, row);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
2001-03-09 14:40:06 +00:00
Line* IEclass::wrapit(Line** __currline, uint* __curr_col, uint* __curr_row, bool __display) {
2000-02-25 11:04:07 +00:00
_test_halt(__currline == NULL);
_test_halt(*__currline == NULL);
2001-05-20 12:23:00 +00:00
int scroll = 0;
2000-02-25 11:04:07 +00:00
uint _quotelen;
2001-05-09 20:45:13 +00:00
char _quotebuf[MAXQUOTELEN];
*_quotebuf = NUL;
2000-02-25 11:04:07 +00:00
uint _curscol = *__curr_col;
uint _cursrow = *__curr_row;
uint _thisrow = *__curr_row;
Line* _thisline = *__currline;
Line* _lastadded = _thisline;
bool _wrapped_above = false;
// Start wrapping from the current line onwards
while(_thisline) {
// Length of this line
2000-03-22 17:59:18 +00:00
uint _thislen = _thisline->txt.length();
2000-02-25 11:04:07 +00:00
2005-10-16 03:41:29 +00:00
setlinetype(_thisline);
2000-02-25 11:04:07 +00:00
uint _wrapmargin = (_thisline->type & GLINE_QUOT) ? marginquotes : margintext;
// Does this line need wrapping?
2001-05-20 12:23:00 +00:00
if((_thislen > _wrapmargin) or ((_thislen == _wrapmargin) and not ((_thisline->txt[_thislen-1] == ' ') or (_thisline->txt[_thislen-1] == '\n')))) {
2000-02-25 11:04:07 +00:00
// Reset quote string length
_quotelen = 0;
// Is this line quoted?
if(_thisline->type & GLINE_QUOT) {
2000-02-25 11:04:07 +00:00
// Get quote string and length
2000-03-22 17:59:18 +00:00
GetQuotestr(_thisline->txt.c_str(), _quotebuf, &_quotelen);
2000-02-25 11:04:07 +00:00
}
// wrapmargin = 40
// 1111111111222222222233333333334444444444
// 01234567890123456789012345678901234567890123456789
// --------------------------------------------------
// v- wrapptr
// Case 1: this is another test with a bit of text to wrap.
// Case 2: this is a test with a line that need wrapping.
// Case 3: thisxisxaxtestxwithxaxlinexthatxneedxwrapping.
// Case 4: >thisxisxaxtestxwithxaxlinexthatxneedxwrapping.
// Point to the last char inside the margin
2000-03-22 17:59:18 +00:00
int _wrappos = _wrapmargin - 1;
2000-02-25 11:04:07 +00:00
// Locate the word to be wrapped
// Did we find a space?
2000-03-22 17:59:18 +00:00
if(_thisline->txt[_wrappos] == ' ') {
2000-02-25 11:04:07 +00:00
// Case 1: A space was found as the last char inside the margin
//
// Now we must locate the first word outside the margin.
// NOTE: Leading spaces to this word will be nulled out!
// Begin at the first char outside the margin
2001-05-20 12:23:00 +00:00
if(_wrappos <= maxcol)
2001-03-09 14:40:06 +00:00
_wrappos++;
2000-02-25 11:04:07 +00:00
}
else {
// Case 2: A non-space was found as the last char inside the margin
//
// Now we must locate the beginning of the word we found.
// Keep copy of original pointer
2000-03-22 17:59:18 +00:00
int _atmargin = _wrappos;
2000-02-25 11:04:07 +00:00
2006-01-14 23:48:53 +00:00
// Search backwards until a space or the beginning of the line is found
2001-11-03 15:04:16 +00:00
while((_wrappos > _quotelen) and (_thisline->txt[_wrappos-1] != ' '))
2000-03-22 17:59:18 +00:00
_wrappos--;
2000-02-25 11:04:07 +00:00
// Check if we hit leading spaces
2000-03-22 17:59:18 +00:00
int _spacepos = _wrappos;
2000-10-24 05:02:25 +00:00
while(_spacepos > 0) {
_spacepos--;
2001-02-19 22:53:24 +00:00
if(_thisline->txt[_spacepos] != ' ')
2000-10-24 05:02:25 +00:00
break;
2000-02-25 11:04:07 +00:00
}
// Did we search all the way back to the beginning of the line?
2001-11-03 15:04:16 +00:00
if((_wrappos == _quotelen) or (_thisline->txt[_spacepos] == ' ')) {
2000-02-25 11:04:07 +00:00
// Case 3: There are no spaces within the margin or we hit leading spaces
// We have to break it up at the margin
2000-03-22 17:59:18 +00:00
_wrappos = _atmargin;
2000-02-25 11:04:07 +00:00
}
}
2001-05-20 12:23:00 +00:00
// The wrappos now points to the location to be wrapped or NUL
2000-02-25 11:04:07 +00:00
// Is the line hard-terminated?
2000-03-22 17:59:18 +00:00
if(_thisline->txt.find('\n', _wrappos) != _thisline->txt.npos) {
2000-02-25 11:04:07 +00:00
// The line is hard-terminated.
// Copy the quote string, if any, to the new line first
std::string _wrapbuf = _quotebuf;
2000-02-25 11:04:07 +00:00
// Copy/append the wrapped part to the new line
2001-05-09 20:45:13 +00:00
_wrapbuf += _thisline->txt.substr(_wrappos);
// The wrapped part must be placed on a new line below.
Line* _wrapline = _lastadded = insertlinebelow(_thisline, _wrapbuf.c_str(), BATCH_MODE);
2000-02-25 11:04:07 +00:00
// Saves pointer to a line where from the wrapped part was copied, its begining
// and length. While in Undo, appends the copied part to previous line and deletes
// it on current, moving the rest over deleted.
2001-05-09 20:45:13 +00:00
Undo->PushItem(EDIT_UNDO_WRAP_TEXT|BATCH_MODE, _thisline, _quotelen, _wrapbuf.length() - _quotelen);
2001-03-03 20:35:09 +00:00
2000-02-25 11:04:07 +00:00
_wrapline->type = _thisline->type;
// Make sure the type of the line is correct
setlinetype(_wrapline);
if(__display) {
// Is there at least one line below this one?
if(_thisrow < maxrow) {
// Scroll the lines below to make room for the new line
2001-05-20 12:23:00 +00:00
--scroll;
2000-02-25 11:04:07 +00:00
// Display the new line
2000-03-22 17:59:18 +00:00
if(_wrapline->txt.length() <= (maxcol+1))
2000-02-25 11:04:07 +00:00
displine(_wrapline, _thisrow+1);
}
}
}
else {
// The line is not hard-terminated
//
// The wrapped part must be inserted into the next line
// Indicate that one or more lines were wrapped in this way
_wrapped_above = true;
// Pointer to the next line
Line* _nextline = _thisline->next;
2001-05-09 20:45:13 +00:00
// Copy the quote string, if any, to the new line first
std::string _wrapbuf = _quotebuf;
2001-05-09 20:45:13 +00:00
// Copy/append the wrapped part to the new line
_wrapbuf += _thisline->txt.substr(_wrappos);
2000-02-25 11:04:07 +00:00
// Flag to indicate if a new line was added below
bool _line_added_below = false;
// Is there no next line or is the next line quoted?
if((_nextline == NULL) or (_nextline->type & GLINE_QUOT)) {
// The wrapped part must be placed on a new line below
2001-05-09 20:45:13 +00:00
_lastadded = _nextline = insertlinebelow(_thisline, _wrapbuf.c_str(), BATCH_MODE);
2000-02-25 11:04:07 +00:00
_line_added_below = true;
2001-05-09 20:45:13 +00:00
Undo->PushItem(EDIT_UNDO_WRAP_TEXT|BATCH_MODE, _thisline, _quotelen, _wrapbuf.length() - _quotelen);
2000-02-25 11:04:07 +00:00
}
2001-05-09 20:45:13 +00:00
else {
2000-02-25 11:04:07 +00:00
2001-05-09 20:45:13 +00:00
_nextline->txt.insert(0, _wrapbuf);
if(_quotelen)
Undo->PushItem(EDIT_UNDO_INS_TEXT|BATCH_MODE, _nextline, 0, _quotelen);
Undo->PushItem(EDIT_UNDO_WRAP_TEXT|BATCH_MODE, _thisline, _quotelen, _wrapbuf.length() - _quotelen);
}
2000-02-25 11:04:07 +00:00
// Make sure the type of the line is correct
setlinetype(_nextline);
if(__display) {
// Is there at least one line below this one?
if(_line_added_below and (_thisrow < maxrow)) {
// Scroll the lines below to make room for the new line
2001-05-20 12:23:00 +00:00
--scroll;
2000-02-25 11:04:07 +00:00
}
// Display the new/wrapped line
2000-03-22 17:59:18 +00:00
if((_thisrow+1) <= maxrow and _nextline->txt.length() <= (maxcol+1))
2000-02-25 11:04:07 +00:00
displine(_nextline, _thisrow+1);
}
}
2000-03-22 17:59:18 +00:00
// Truncate at the wrapping location
_thisline->txt.erase(_wrappos);
2000-02-25 11:04:07 +00:00
// Was this line quoted?
if (_quotelen)
{
2000-02-25 11:04:07 +00:00
// Trim spaces off the end of the line
2000-03-22 17:59:18 +00:00
int _trimpos = _wrappos - 1;
if (isspace(_thisline->txt[_trimpos]))
{
while (_trimpos > 0 and isspace(_thisline->txt[_trimpos-1]))
2000-03-22 17:59:18 +00:00
_trimpos--;
2000-12-24 19:47:06 +00:00
if(_quotelen and (_trimpos < _quotelen))
2000-03-22 17:59:18 +00:00
_trimpos++;
Undo->PushItem(EDIT_UNDO_OVR_CHAR|BATCH_MODE, _thisline, _trimpos);
_thisline->txt.erase(_trimpos);
2000-02-25 11:04:07 +00:00
}
else
{
Undo->PushItem(EDIT_UNDO_INS_CHAR|BATCH_MODE, _thisline, _trimpos + 1);
}
2000-02-25 11:04:07 +00:00
// Append a new linefeed
2000-03-22 17:59:18 +00:00
_thisline->txt += "\n";
2000-02-25 11:04:07 +00:00
}
// Make sure the line type still is correct
setlinetype(_thisline);
if(__display) {
// Display this line after wrapping
if(_thisrow <= maxrow)
displine(_thisline, _thisrow);
}
2001-03-17 21:17:57 +00:00
_thislen = _thisline->txt.length();
2000-02-25 11:04:07 +00:00
// If we are on the cursor line, check if the cursor char was wrapped
if((_thisrow == _cursrow) and (_thislen <= _curscol)) {
2000-10-24 05:02:25 +00:00
_curscol = _quotelen + ((_curscol > _wrappos) ? _curscol-_wrappos : 0);
_cursrow++;
2000-02-25 11:04:07 +00:00
UndoItem* i = Undo->last_item;
do { i = i->prev; } while(i->action & BATCH_MODE);
2000-03-22 17:59:18 +00:00
if(i->col.num >= i->line->txt.length()) {
2000-02-25 11:04:07 +00:00
i->action |= PREV_LINE;
i->col.sav = i->col.num;
i->col.num = _curscol;
}
}
}
// If this line is hard-terminated, we have finished wrapping
// Unless the next line has grown too large
2000-03-22 17:59:18 +00:00
if(_thisline->txt.find('\n') != _thisline->txt.npos) {
2000-02-25 11:04:07 +00:00
if(_thisline->next == NULL)
break;
_wrapmargin = (_thisline->next->type & GLINE_QUOT) ? marginquotes : margintext;
2000-03-22 17:59:18 +00:00
if(_thisline->next->txt.length() <= _wrapmargin)
2000-02-25 11:04:07 +00:00
break;
}
2001-05-09 20:45:13 +00:00
else if(_thisline->type & GLINE_QUOT) {
Undo->PushItem(EDIT_UNDO_INS_TEXT|BATCH_MODE, _thisline, _thisline->txt.length(), 1);
_thisline->txt += '\n';
}
2000-02-25 11:04:07 +00:00
// Go to the next line
_thisline = _thisline->next;
_thisrow++;
}
if(__display) {
// Display the current line after wrapping
if(*__curr_row <= maxrow)
displine(*__currline, *__curr_row);
// Was the line or lines above wrapped?
if(_wrapped_above) {
// Display the last line in the paragraph
if((_thisrow <= maxrow) and _thisline)
displine(_thisline, _thisrow);
}
}
// Move to the next line if the cursor was wrapped
if(_cursrow != *__curr_row) {
2000-10-24 05:02:25 +00:00
int i = *__curr_row;
while ((i++ != _cursrow) and (__currline != NULL))
*__currline = (*__currline)->next;
2000-02-25 11:04:07 +00:00
if(_cursrow > maxrow) {
_cursrow = maxrow;
2000-10-24 05:02:25 +00:00
if(__display) {
2001-05-20 12:23:00 +00:00
++scroll;
if(scroll > 0) {
scrollup(mincol, minrow, maxcol, maxrow);
scroll = 0;
}
2000-10-24 05:02:25 +00:00
displine(*__currline, *__curr_row);
}
2000-02-25 11:04:07 +00:00
}
}
2001-05-20 12:23:00 +00:00
if(__display and (scroll != 0)) {
if((*__currline)->next != NULL)
refresh((*__currline)->next, _cursrow+1);
else
refresh(*__currline, _cursrow);
2001-05-20 12:23:00 +00:00
}
2000-02-25 11:04:07 +00:00
// Update cursor position
*__curr_row = _cursrow;
*__curr_col = _curscol;
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return _lastadded;
}
// ------------------------------------------------------------------
2001-03-09 14:40:06 +00:00
Line* IEclass::wrapdel(Line** __currline, uint* __curr_col, uint* __curr_row, bool __display) {
2000-02-25 11:04:07 +00:00
GFTRK("Editwrapdel");
Line *tmp = wrapit(__currline, __curr_col, __curr_row, __display);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return tmp;
}
// ------------------------------------------------------------------
2001-03-09 14:40:06 +00:00
Line* IEclass::wrapins(Line** __currline, uint* __curr_col, uint* __curr_row, bool __display) {
2000-02-25 11:04:07 +00:00
GFTRK("Editwrapins");
Line *tmp = wrapit(__currline, __curr_col, __curr_row, __display);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return tmp;
}
// ------------------------------------------------------------------
void IEclass::insertchar(char __ch) {
GFTRK("Editinsertchar");
2000-03-22 17:59:18 +00:00
uint _currline_len = currline->txt.length();
2001-02-19 22:53:24 +00:00
#ifndef NDEBUG
2000-03-22 17:59:18 +00:00
_test_haltab(col > _currline_len, col, _currline_len);
#endif
2000-02-25 11:04:07 +00:00
// Insert or overwrite the char, replacing the block if any
if((selecting ? (BlockCut(true), batch_mode = BATCH_MODE) : false) or
2001-02-19 22:53:24 +00:00
(col >= _currline_len) or (currline->txt[col] == '\n') or insert) {
if(not isspace(__ch) and (col == mincol)) {
// if previous line was wrapped on non-space character
if(currline->prev and not currline->prev->txt.empty() and
(currline->prev->txt.find('\n') == currline->prev->txt.npos) and
not isspace(currline->prev->txt[currline->prev->txt.length()-1])) {
if(not batch_mode) {
Undo->PushItem(EDIT_UNDO_VOID);
batch_mode = BATCH_MODE;
}
GoUp();
GoEOL();
}
}
2000-02-25 11:04:07 +00:00
Undo->PushItem(EDIT_UNDO_INS_CHAR|batch_mode);
2000-03-22 17:59:18 +00:00
currline->txt.insert(col, 1, __ch);
2000-02-25 11:04:07 +00:00
} else {
Undo->PushItem(EDIT_UNDO_OVR_CHAR|batch_mode);
2000-03-22 17:59:18 +00:00
currline->txt[col] = __ch;
2000-02-25 11:04:07 +00:00
}
batch_mode = BATCH_MODE;
// Make sure the line type still is correct
setlinetype(currline);
// Move cursor
col++;
wrapins(&currline, &col, &row);
// Adjust cursor position and display if necessary
if(col > maxcol) {
if(currline->next) {
currline = currline->next;
col = mincol;
row++;
if(row > maxrow) {
row = maxrow;
scrollup(mincol, minrow, maxcol, maxrow);
displine(currline, row);
}
}
else {
col = maxcol;
}
}
gotorowcol(col, row);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::DelChar()
{
2000-02-25 11:04:07 +00:00
GFTRK("EditDelChar");
Line* _thisline = currline;
Line* _nextline = currline->next;
2000-03-22 17:59:18 +00:00
uint _thislen = _thisline->txt.length();
2000-02-25 11:04:07 +00:00
if (!_nextline && (col == _thislen - 1) && (_thisline->txt[col] == '\n'))
{
GFTRK(0);
return;
}
2000-02-25 11:04:07 +00:00
// Cannot delete at or beyond the nul-terminator
if(col < _thislen) {
Undo->PushItem(EDIT_UNDO_DEL_CHAR|batch_mode);
2000-03-22 17:59:18 +00:00
_thisline->txt.erase(col, 1);
2000-02-25 11:04:07 +00:00
batch_mode = BATCH_MODE;
}
else if(col and (col == _thislen) and _nextline) {
2006-05-14 11:45:05 +00:00
GFTRK(0);
if(not batch_mode) {
Undo->PushItem(EDIT_UNDO_VOID);
batch_mode = BATCH_MODE;
}
2001-05-20 12:23:00 +00:00
GoRight();
DelChar();
return;
}
2000-02-25 11:04:07 +00:00
// Did we delete the last char on the line or
// was the cursor at or beyond the nul-terminator?
// And is there a next line at all?
if(((col+1) >= _thislen) and _nextline) {
// Join the next line to this line
// Is the next line quoted?
// And is the cursor column non-zero?
uint _quotelen = 0;
if((_nextline->type & GLINE_QUOT) and col) {
2000-02-25 11:04:07 +00:00
// Get quote string length
2001-05-09 20:45:13 +00:00
char _quotebuf[MAXQUOTELEN];
GetQuotestr(_nextline->txt.c_str(), _quotebuf, &_quotelen);
2000-02-25 11:04:07 +00:00
}
2001-03-17 21:17:57 +00:00
// Copy the next line's text to this line without quote string
const char *_nexttext = _nextline->txt.c_str()+_quotelen;
_thisline->txt += _nexttext + (col ? strspn(_nexttext, " ") : 0);
2000-02-25 11:04:07 +00:00
Undo->PushItem(EDIT_UNDO_CUT_TEXT|batch_mode, _thisline, col);
// Relink this line
_thisline->next = _nextline->next;
if(_thisline->next)
_thisline->next->prev = _thisline;
Undo->PushItem(EDIT_UNDO_DEL_LINE|BATCH_MODE, _nextline);
}
2001-03-09 14:40:06 +00:00
else if((_thislen > 1) and (_thisline->txt.c_str()[_thislen-2] != '\n') and _nextline and not (_nextline->type & GLINE_QUOT)) {
_thisline->txt += _nextline->txt.c_str();
Undo->PushItem(EDIT_UNDO_CUT_TEXT|batch_mode, _thisline, _thislen-1);
// Relink this line
_thisline->next = _nextline->next;
if(_thisline->next)
_thisline->next->prev = _thisline;
2006-01-14 23:48:53 +00:00
Undo->PushItem(EDIT_UNDO_DEL_LINE|BATCH_MODE, _nextline);
2001-03-09 14:40:06 +00:00
}
2000-02-25 11:04:07 +00:00
batch_mode = BATCH_MODE;
// Make sure the line type still is correct
setlinetype(_thisline);
2006-02-03 11:25:19 +00:00
// Rewrap this line
bool display = make_bool_not(row > maxrow / 2);
wrapdel(&currline, &col, &row, display);
if(display) {
2001-05-20 12:23:00 +00:00
refresh(currline, row);
2006-02-03 11:25:19 +00:00
}
else {
// Refresh the display
Line* _topline = findtopline();
refresh(_topline, minrow);
}
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::DelLeft() {
GFTRK("EditDelLeft");
// Cannot backspace from the first column on the first line in the msg
if(currline->prev == NULL)
if(col == mincol) {
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return;
}
// Go left(/up) and delete the character there
if(not batch_mode) {
if(col == mincol)
Undo->PushItem(EDIT_UNDO_VOID|PREV_LINE, currline->prev);
else
Undo->PushItem(EDIT_UNDO_VOID);
batch_mode = BATCH_MODE;
}
2000-02-25 11:04:07 +00:00
GoLeft();
DelChar();
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::GoWordLeft() {
GFTRK("EditGoWordLeft");
if(col == 0) {
if(currline->prev) {
GoUp();
GoEOL();
}
}
else {
2006-01-14 23:48:53 +00:00
2000-02-25 11:04:07 +00:00
col--;
2006-01-14 23:48:53 +00:00
2000-03-22 17:59:18 +00:00
if(not isxalnum(currline->txt[col])) {
while(not isxalnum(currline->txt[col]) and (col > 0))
2000-02-25 11:04:07 +00:00
col--;
2000-03-22 17:59:18 +00:00
while(isxalnum(currline->txt[col]) and (col > 0))
2000-02-25 11:04:07 +00:00
col--;
}
else {
2000-03-22 17:59:18 +00:00
while(isxalnum(currline->txt[col]) and (col > 0))
2000-02-25 11:04:07 +00:00
col--;
}
if(col != 0)
col++;
if(blockcol != -1)
displine(currline, row);
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::GoWordRight() {
GFTRK("EditGoWordRight");
2001-02-21 21:26:28 +00:00
if((col >= currline->txt.length()) or (currline->txt[col] == '\n')) {
2000-02-25 11:04:07 +00:00
if(currline->next) {
GoDown();
col = mincol;
2000-02-25 11:04:07 +00:00
}
2001-02-21 21:26:28 +00:00
}
else {
2001-02-19 22:53:24 +00:00
size_t len = currline->txt.length();
2000-03-22 17:59:18 +00:00
if(not isxalnum(currline->txt[col])) {
2001-02-19 22:53:24 +00:00
while(not isxalnum(currline->txt[col]) and ((col+1) <= len))
2000-02-25 11:04:07 +00:00
col++;
}
else {
2001-02-19 22:53:24 +00:00
while(isxalnum(currline->txt[col]) and ((col+1) <= len))
2000-02-25 11:04:07 +00:00
col++;
2001-02-19 22:53:24 +00:00
while(not isxalnum(currline->txt[col]) and ((col+1) <= len))
2000-02-25 11:04:07 +00:00
col++;
}
2000-03-22 17:59:18 +00:00
if(currline->txt[col-1] == '\n')
2000-02-25 11:04:07 +00:00
col--;
2001-02-19 22:53:24 +00:00
if(len == col) {
2000-02-25 11:04:07 +00:00
if(currline->next) {
GoDown();
col = 0;
}
else
col--;
}
}
if (blockcol != -1)
displine(currline, row);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::Newline() {
GFTRK("EditNewline");
// Pointer to the split position
2000-03-22 17:59:18 +00:00
int _splitpos = col;
2000-02-25 11:04:07 +00:00
// Buffer for the second part of the split line
std::string _splitbuf;
2000-02-25 11:04:07 +00:00
// If the split line was quoted, get the quotestring
// But do not get it if the cursor points to a linefeed or is
2001-05-09 20:45:13 +00:00
uint _quotelen;
char _quotebuf[MAXQUOTELEN];
2001-05-09 20:45:13 +00:00
GetQuotestr(currline->txt.c_str(), _quotebuf, &_quotelen);
2000-02-25 11:04:07 +00:00
// Eliminate the quotestring if
// - the cursor points to a linefeed or
// - the cursor is located inside the quotestring
2001-05-09 20:45:13 +00:00
if(_quotelen and ((currline->txt.length() == col) or (currline->txt[_splitpos] == '\n') or (col < _quotelen))) {
*_quotebuf = NUL;
_quotelen = 0;
}
2000-02-25 11:04:07 +00:00
// Append the second part to the split buffer
2001-05-09 20:45:13 +00:00
_splitbuf = _quotebuf;
_splitbuf += currline->txt.substr(_splitpos);
2000-02-25 11:04:07 +00:00
Undo->PushItem(EDIT_UNDO_INS_TEXT|batch_mode, currline, col, 1);
batch_mode = BATCH_MODE;
2006-01-14 23:48:53 +00:00
2000-02-25 11:04:07 +00:00
// Copy linefeed+nul to the split position
2000-03-22 17:59:18 +00:00
currline->txt.erase(_splitpos);
currline->txt += "\n";
2000-02-25 11:04:07 +00:00
// Re-type and display the split line
setlinetype(currline);
displine(currline, row);
uint _quotelen1 = 0;
char _quotebuf1[MAXQUOTELEN] = "";
if(currline->next != NULL) {
GetQuotestr(currline->next->txt.c_str(), _quotebuf1, &_quotelen1);
}
2000-02-25 11:04:07 +00:00
if((_splitbuf.find('\n') != _splitbuf.npos) or (currline->next == NULL) or not strieql(_quotebuf, _quotebuf1)) {
// Insert a new line below, set the line text to the split-off part
currline = insertlinebelow(currline, _splitbuf.c_str());
2000-02-25 11:04:07 +00:00
// --v--
// This line would be wrapped
// This line would be
// wrapped
2000-02-25 11:04:07 +00:00
Undo->PushItem(EDIT_UNDO_WRAP_TEXT|BATCH_MODE, currline->prev, _quotelen, _splitbuf.length() - _quotelen);
}
else {
currline = currline->next;
currline->txt.insert(_quotelen1, _splitbuf.substr(_quotelen1));
Undo->PushItem(EDIT_UNDO_WRAP_TEXT|BATCH_MODE, currline->prev, _quotelen1, _splitbuf.length() - _quotelen1);
}
2002-06-14 06:46:39 +00:00
setlinetype(currline);
2000-02-25 11:04:07 +00:00
// Move down the cursor
col = 0;
row = downoneline(row);
// Scroll the remaining lines if necessary
if(row < maxrow)
scrolldown(mincol, row, maxcol, maxrow);
// Rewrap the split-off line
wrapdel(&currline, &col, &row, true);
refresh(currline, row);
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::CopyAboveChar() {
GFTRK("EditCopyAboveChar");
char _ch = ' ';
if(currline->prev) {
2000-03-22 17:59:18 +00:00
uint _len = currline->prev->txt.length();
2000-02-25 11:04:07 +00:00
if(_len and _len > col)
2000-03-22 17:59:18 +00:00
_ch = currline->prev->txt[col];
2000-02-25 11:04:07 +00:00
if(_ch == '\n')
_ch = ' ';
}
insertchar(_ch);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::DupLine() {
GFTRK("EditDupLine");
Undo->PushItem(EDIT_UNDO_VOID);
batch_mode = BATCH_MODE;
2006-01-14 23:48:53 +00:00
Line* _nextline = insertlinebelow(currline, currline->txt.c_str(), batch_mode);
2000-02-25 11:04:07 +00:00
_nextline->type = currline->type & ~GLINE_BLOK;
_nextline->color = currline->color;
_nextline->kludge = currline->kludge;
refresh(currline, row);
GoDown();
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
// PageUp behavior:
//
// ... The top line becomes the bottom line.
// ... Always remain at cursor row, except if we can't page up.
// ... If we can't page up, move the cursor row to the top line.
void IEclass::GoPgUp() {
GFTRK("EditGoPgUp");
// Not at the first line in msg?
if(currline->prev) {
// Count lines
int _count = row;
// Move to the top line currently displayed
Line* _topline = currline;
while(_count and _topline->prev) {
_topline = _topline->prev;
_count--;
}
// The count must be zero at this point!
_test_haltab(_count, _count, _count);
// At we already fully at the top?
if(_topline->prev == NULL) {
// Yes, so move the cursor row to the top line
row = minrow;
currline = _topline;
if(blockcol != -1)
refresh(currline, row);
}
else {
// We are not at the top, so continue with paging
// Move a full page of lines, if possible
_count = maxrow;
while(_count and _topline->prev) {
_topline = _topline->prev;
_count--;
}
// Set the current line
_count = row;
currline = _topline;
while(_count--)
currline = currline->next;
// Refresh display
refresh(_topline, minrow);
}
}
else {
GoTopMsg();
}
2000-03-22 17:59:18 +00:00
if(col+1 > currline->txt.length())
2000-02-25 11:04:07 +00:00
GoEOL();
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
// PageDown behavior:
//
// ... The bottom line becomes the top line.
// ... Always remain at cursor row, except if at the last line.
// ... If at the last line, move cursor to the last window line and
// display the lines above.
// ... If there are too few lines to display after the page down, the
// rest are displayed blank.
void IEclass::GoPgDn() {
GFTRK("EditGoPgDn");
// Not at the last line in the msg?
if(currline->next) {
// Go down to the last displayed line in the window
uint _newrow = row, _oldrow = row;
Line *oldcurrline = currline;
while((_newrow < maxrow) and currline->next) {
currline = currline->next;
_newrow++;
}
// If there are more lines after the last line, start displaying from the top
if(currline->next) {
Line *_topline = currline;
// Set current line
_newrow = 0;
while((_newrow < row) and currline->next) {
currline = currline->next;
_newrow++;
}
// Move cursor row if necessary
if(_newrow < row)
row = _newrow;
refresh(_topline, minrow);
}
else {
row = _newrow;
refresh(oldcurrline, _oldrow);
}
}
else {
GoBotMsg();
}
2000-03-22 17:59:18 +00:00
if(col+1 > currline->txt.length())
2000-02-25 11:04:07 +00:00
GoEOL();
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::Tab() {
GFTRK("EditTab");
int tabsz = CFG->disptabsize ? CFG->disptabsize : 1;
// Move to the next tab position
do {
if(insert)
insertchar(' ');
2000-03-22 17:59:18 +00:00
else if(currline->txt[col] != '\n')
2000-02-25 11:04:07 +00:00
GoRight();
else
break;
} while(col % tabsz);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::ReTab() {
GFTRK("EditTabReverse")
int tabsz = CFG->disptabsize ? CFG->disptabsize : 1;
// Move to the next tab position
do {
if(not col)
break;
if(insert)
DelLeft();
else
GoLeft();
} while(col % tabsz);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::DeleteEOL() {
GFTRK("EditDeleteEOL");
2005-10-25 06:11:09 +00:00
bool _has_linefeed = (currline->txt.find('\n') != currline->txt.npos);
2006-01-14 23:48:53 +00:00
2000-02-25 11:04:07 +00:00
Undo->PushItem(EDIT_UNDO_DEL_TEXT, currline);
2000-03-22 17:59:18 +00:00
currline->txt.erase(col);
2000-02-25 11:04:07 +00:00
2001-06-04 03:40:38 +00:00
if(_has_linefeed) {
Undo->PushItem(EDIT_UNDO_INS_CHAR|BATCH_MODE);
2000-03-22 17:59:18 +00:00
currline->txt += "\n";
2001-06-04 03:40:38 +00:00
}
2000-02-25 11:04:07 +00:00
clreol();
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
2001-08-31 14:14:27 +00:00
// ------------------------------------------------------------------
void IEclass::DeleteSOL() {
GFTRK("EditDeleteSOL");
if(col == 0) {
2006-05-14 11:45:05 +00:00
GFTRK(0);
2001-08-31 14:14:27 +00:00
return;
}
int _oldcol = col;
col = 0;
Undo->PushItem(EDIT_UNDO_DEL_TEXT, currline, col, _oldcol);
currline->txt.erase(col, _oldcol);
wrapdel(&currline, &col, &row);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2001-08-31 14:14:27 +00:00
}
2000-02-25 11:04:07 +00:00
// ------------------------------------------------------------------
void IEclass::deleteline(bool zapquotesbelow) {
GFTRK("Editdeleteline");
bool done = false;
do {
2006-01-14 23:48:53 +00:00
2000-02-25 11:04:07 +00:00
// Break if need to zap quotes, but the current line is not quote and is not empty
if(zapquotesbelow and not ((currline->type & GLINE_QUOT) or isempty(currline)))
break;
2000-02-25 11:04:07 +00:00
// Pointer to the deleted line
Line* _deletedline = currline;
// If last line to be deleted delete to EOL and exit
if(currline->next == NULL) {
if(isempty(currline))
2000-02-25 11:04:07 +00:00
break;
insertlinebelow(currline, "", batch_mode);
batch_mode = BATCH_MODE;
done = true;
}
// Pointers to the previous and next lines
Line* _prevline = currline->prev;
Line* _nextline = currline->next;
Undo->PushItem(EDIT_UNDO_PUSH_LINE|batch_mode);
// Set the new current line to the next line (which may be NULL!)
currline = _nextline;
if(currline == NULL) {
currline = _prevline;
currline->next = NULL;
_prevline = _prevline ? _prevline->prev : NULL;
}
// Link the new current line to the previous line
currline->prev = _prevline;
// Link the previous line to this line
if(_prevline)
_prevline->next = currline;
if(_deletedline->type & GLINE_BLOK) {
blockcol = -1;
_deletedline->type &= ~GLINE_BLOK;
}
// Link the deleted line to the killbuffer
if(Edit__killbuf) {
Edit__killbuf->next = _deletedline;
_deletedline->prev = Edit__killbuf;
Edit__killbuf = _deletedline;
}
else {
Edit__killbuf = _deletedline;
Edit__killbuf->prev = NULL;
}
Edit__killbuf->next = NULL;
// Move the cursor to EOL if necessary
2000-03-22 17:59:18 +00:00
if(col+1 > currline->txt.length())
2000-02-25 11:04:07 +00:00
GoEOL();
if(not zapquotesbelow)
break;
batch_mode = BATCH_MODE;
} while(not done);
// Refresh display from cursor row
refresh(currline, row);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::UnDelete(bool before) {
GFTRK("EditUnDelete");
// If there are deleted lines
if(Edit__killbuf) {
Line* _prevline = Edit__killbuf->prev;
bool down = false;
if(before) {
Edit__killbuf->prev = currline ? currline->prev : NULL;
Edit__killbuf->next = currline;
}
else {
Edit__killbuf->prev = currline;
Edit__killbuf->next = currline ? currline->next : NULL;
if(row == maxrow)
down = true;
else if((row < maxrow) and currline)
row++;
}
if(Edit__killbuf->prev)
Edit__killbuf->prev->next = Edit__killbuf;
if(Edit__killbuf->next)
Edit__killbuf->next->prev = Edit__killbuf;
currline = Edit__killbuf;
Edit__killbuf = _prevline;
if(Edit__killbuf)
Edit__killbuf->next = NULL;
Undo->PushItem(EDIT_UNDO_POP_LINE);
// Move the cursor to EOL if necessary
2000-03-22 17:59:18 +00:00
if(col+1 > currline->txt.length())
2000-02-25 11:04:07 +00:00
GoEOL();
if(down)
GoDown();
else
refresh(currline, row);
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::ZapQuoteBelow() {
GFTRK("ZapQuoteBelow");
if(currline->prev)
Undo->PushItem(EDIT_UNDO_VOID|PREV_LINE|batch_mode, currline->prev);
else
Undo->PushItem(EDIT_UNDO_VOID|batch_mode, currline);
batch_mode = BATCH_MODE;
UndoItem* item_to_fix = Undo->last_item;
2000-02-25 11:04:07 +00:00
deleteline(true);
if(row == 0) {
item_to_fix->line = currline;
2000-02-25 11:04:07 +00:00
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
Line* IEclass::findtopline() {
GFTRK("Editfindtopline");
uint _toprow = row;
Line* _topline = currline;
while(_topline->prev and (_toprow > minrow)) {
_topline = _topline->prev;
_toprow--;
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return _topline;
}
// ------------------------------------------------------------------
void IEclass::savefile(int __status) {
Subj statbak;
GFTRK("Editsavefile");
// Turn off cursor and put up a wait window
#if defined(__USE_NCURSES__) || !defined(__WIN32__) /* Fix after bugfix w9x console bug in gvidbase.cpp */
2000-02-25 11:04:07 +00:00
int wascursoron = not vcurhidden();
cursoroff();
#endif
2000-02-25 11:04:07 +00:00
strcpy(statbak, information);
update_statusline(LNG->Wait+1);
// Open the save file
const char* editorfile = AddPath(CFG->goldpath, EDIT->File());
remove(editorfile);
2006-04-26 17:06:23 +00:00
gfile _fp(editorfile, "wb", CFG->sharemode);
2006-05-13 16:15:35 +00:00
if (_fp.isopen())
2006-04-26 17:06:23 +00:00
{
2000-02-25 11:04:07 +00:00
// Find the first line
Line* _saveline = findfirstline();
// First save the "unfinished" identifier
2006-04-26 17:06:23 +00:00
if (__status == MODE_UPDATE)
{
_fp.Fputs(unfinished);
_fp.Fputs("\r\n");
2000-02-25 11:04:07 +00:00
}
// Save as whole paragraphs
while(_saveline) {
// Copy the line to a buffer
char _buf[EDIT_BUFLEN];
2000-03-22 17:59:18 +00:00
strcpy(_buf, _saveline->txt.c_str());
2000-02-25 11:04:07 +00:00
// If a LF was found, replace it with a CR/LF combo
char* _lfptr = strchr(_buf, '\n');
if(_lfptr)
strcpy(_lfptr, "\r\n");
// Save the line
2006-04-26 17:06:23 +00:00
_fp.Fputs(_buf);
2000-02-25 11:04:07 +00:00
// Continue with the next line
_saveline = _saveline->next;
}
}
update_statusline(statbak);
#if defined(__USE_NCURSES__) || !defined(__WIN32__) /* Fix after bugfix w9x console bug in gvidbase.cpp */
2000-02-25 11:04:07 +00:00
if(wascursoron)
cursoron();
#endif
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::SaveFile() {
GFTRK("EditSaveFile");
savefile(MODE_UPDATE);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::SaveMsg() {
GFTRK("EditSaveMsg");
done = MODE_SAVE;
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
2006-03-11 17:04:06 +00:00
#if defined(GCFG_SPELL_INCLUDED)
void IEclass::SCheckerMenu()
{
if (!schecker.IsInited())
return;
const char *txt = currline->txt.c_str();
GMenuSChecker menu;
int finaltag;
if (!isscchar(txt[col]))
finaltag = menu.Run(schecker, "");
else
{
char buff[EDIT_BUFLEN];
size_t beg = col;
size_t end = col;
for (; (beg > 0) && isscchar(txt[beg-1]); beg--);
for (; isscchar(txt[end]); end++);
size_t len = end - beg;
memcpy(buff, &txt[beg], len);
buff[len] = 0;
finaltag = menu.Run(schecker, buff);
if (finaltag >= 0)
{
std::string &str = schecker.GetSuggest()[finaltag].second;
size_t len2 = str.length() - 3;
txt = &str.c_str()[2];
if ((buff[len-1] == '.') && (txt[len2-1] != '.')) len--;
if (col > (beg + len2 - 1)) col = beg + len2 - 1;
Undo->PushItem(EDIT_UNDO_DEL_TEXT, currline, beg, len);
currline->txt.erase(beg, len);
Undo->PushItem(EDIT_UNDO_INS_TEXT|BATCH_MODE, currline, beg, len2);
currline->txt.insert(beg, txt, len2);
wrapit(&currline, &col, &row);
}
}
if (finaltag == -2)
{
Line *line = currline;
uint32_t _row = row;
while (line->prev && (_row > minrow))
{
line = line->prev;
_row--;
}
refresh(line, _row);
}
}
#endif
2000-02-25 11:04:07 +00:00
// ------------------------------------------------------------------
int IEclass::isempty(Line* __line) {
if(__line == NULL)
__line = currline;
2000-03-22 17:59:18 +00:00
return (__line->txt.empty() or __line->txt[0] == '\n');
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
int IEclass::reflowok(char* __qstr) {
// Stop reflow if there is no next line
if(currline->next == NULL)
return false;
// Stop reflow if the next line is empty
if(isempty(currline->next))
return false;
// Stop reflow if the next line is a control line
if(currline->next->type & (GLINE_KLUDGE|GLINE_TEAR|GLINE_ORIG|GLINE_TAGL))
return false;
// Stop reflow if the quotestring on the next line is not the same
uint _qlen2;
2001-05-09 20:45:13 +00:00
char _qstr2[MAXQUOTELEN];
2000-03-22 17:59:18 +00:00
GetQuotestr(currline->next->txt.c_str(), _qstr2, &_qlen2);
2001-05-09 20:45:13 +00:00
if(not cmp_quotes(__qstr, _qstr2))
2000-02-25 11:04:07 +00:00
return false;
return true;
}
// ------------------------------------------------------------------
void IEclass::Reflow() {
GFTRK("EditReflow");
// Skip empty lines
while(isempty()) {
if(currline->next) {
if(not batch_mode) {
Undo->PushItem(EDIT_UNDO_VOID);
batch_mode = BATCH_MODE;
}
2000-02-25 11:04:07 +00:00
GoDown();
}
2000-02-25 11:04:07 +00:00
else {
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return;
}
}
// Get the first quotestring
uint _qlen1;
2001-05-09 20:45:13 +00:00
char _qstr1[MAXQUOTELEN];
2000-03-22 17:59:18 +00:00
GetQuotestr(currline->txt.c_str(), _qstr1, &_qlen1);
const char* _qlenptr = currline->txt.c_str() + _qlen1;
2000-02-25 11:04:07 +00:00
// Strip leading spaces from the first line
2000-09-01 16:23:15 +00:00
const char* ptr = _qlenptr;
2001-02-19 22:53:24 +00:00
while(*ptr and isspace(*ptr) and (*ptr != '\n')) ptr++;
2000-02-25 11:04:07 +00:00
if(ptr != _qlenptr) {
Undo->PushItem(EDIT_UNDO_DEL_TEXT|batch_mode, currline, _qlen1, ptr-_qlenptr);
2000-03-22 17:59:18 +00:00
currline->txt.erase(_qlen1, ptr-_qlenptr);
2000-02-25 11:04:07 +00:00
}
// Perform the reflow
while(reflowok(_qstr1)) {
// Work on the current line until it is done
Line* _thisline = currline;
while(_thisline == currline) {
// Stop reflow?
if(not reflowok(_qstr1))
break;
// Go to the EOL, insert a space and delete the LF
GoEOL();
if(col+1 < maxcol) {
insertchar(' ');
DelChar();
}
else {
GoDown();
col = mincol;
}
}
}
// Go to the next line
displine(currline,row);
GoDown();
2005-10-28 04:59:49 +00:00
col = mincol;
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::ExitMsg() {
GFTRK("EditExitMsg");
done = MODE_QUIT;
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::DelLine() {
GFTRK("EditDelLine");
cursoroff();
deleteline();
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::ToUpper() {
GFTRK("EditToUpper");
2001-02-19 22:53:24 +00:00
if(col < currline->txt.length()) {
Undo->PushItem(EDIT_UNDO_OVR_CHAR);
currline->txt[col] = g_toupper(currline->txt[col]);
2001-02-19 22:53:24 +00:00
}
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::ToLower() {
GFTRK("EditToLower");
if(col < currline->txt.length()) {
2001-02-19 22:53:24 +00:00
Undo->PushItem(EDIT_UNDO_OVR_CHAR);
currline->txt[col] = g_tolower(currline->txt[col]);
2001-02-19 22:53:24 +00:00
}
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::ToggleCase() {
GFTRK("EditToggleCase");
2005-11-01 02:31:41 +00:00
if (col < currline->txt.length())
{
2001-02-19 22:53:24 +00:00
Undo->PushItem(EDIT_UNDO_OVR_CHAR);
2005-11-01 02:31:41 +00:00
char chr = currline->txt[col];
if (g_isupper(chr))
currline->txt[col] = g_tolower(chr);
2001-02-19 22:53:24 +00:00
else
2005-11-01 02:31:41 +00:00
currline->txt[col] = g_toupper(chr);
2001-02-19 22:53:24 +00:00
}
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
2005-10-05 20:35:22 +00:00
// ------------------------------------------------------------------
void IEclass::ToggleCaseChar(gkey key,
std::string::iterator it,
Line *ln, int n)
{
int oldchar = *it;
2005-11-03 11:58:16 +00:00
int newchar = 0;
2005-10-05 20:35:22 +00:00
switch (key)
{
case KK_EditToLower:
2005-11-01 02:31:41 +00:00
newchar = g_tolower(oldchar);
2005-10-05 20:35:22 +00:00
break;
case KK_EditToUpper:
2005-11-01 02:31:41 +00:00
newchar = g_toupper(oldchar);
2005-10-05 20:35:22 +00:00
break;
case KK_EditToggleCase:
2005-11-01 02:31:41 +00:00
if (g_isupper(oldchar))
newchar = g_tolower(oldchar);
2005-10-05 20:35:22 +00:00
else
2005-11-01 02:31:41 +00:00
newchar = g_toupper(oldchar);
2005-10-05 20:35:22 +00:00
break;
}
if (newchar != oldchar)
{
currline = ln; pcol = col = n; getthisrow(currline); prow = thisrow;
Undo->PushItem(EDIT_UNDO_OVR_CHAR);
*it = newchar;
}
}
// ------------------------------------------------------------------
void IEclass::ToggleCaseBlock(gkey key)
{
GFTRK("EditToggleCaseBlock");
// Find the anchor, if any
Line* _anchor = findanchor();
// Did we find the anchor?
if (_anchor)
{
Line* oldline = currline;
int oldcol = col;
Line* _firstline = currline;
Line* _lastline = currline;
int firstcol = col, lastcol = col;
// Search below to find the anchor line
while (_lastline->next and (_lastline != _anchor))
_lastline = _lastline->next;
// Was the anchor line above or on the current line?
if (_lastline != _anchor)
{
// The last copy line is the current line
_lastline = currline;
// Search above to find the anchor line
while (_firstline->prev and (_firstline != _anchor))
_firstline = _firstline->prev;
firstcol = blockcol;
}
else
{
if (currline != _anchor or blockcol > col)
lastcol = blockcol;
else
firstcol = blockcol;
}
// The _firstline and _lastline pointers
// are now pointing where they should
int n;
Line* ln = _firstline;
std::string::iterator it1, it2;
if (ln == _lastline)
{
it1 = ln->txt.begin() + firstcol;
it2 = ln->txt.begin() + lastcol;
for (n = firstcol; it1 < it2; it1++, n++)
ToggleCaseChar(key, it1, ln, n);
}
else
{
it1 = ln->txt.begin() + firstcol;
it2 = ln->txt.end();
for (n = firstcol; it1 < it2; it1++, n++)
ToggleCaseChar(key, it1, ln, n);
for (ln = ln->next; ln != _lastline; ln = ln->next)
{
it1 = ln->txt.begin();
it2 = ln->txt.end();
for (n = 0; it1 < it2; it1++, n++)
ToggleCaseChar(key, it1, ln, n);
}
it1 = ln->txt.begin();
it2 = ln->txt.begin() + lastcol;
for (n = 0; it1 < it2; it1++, n++)
ToggleCaseChar(key, it1, ln, n);
}
currline = oldline;
pcol = col = oldcol;
getthisrow(currline);
prow = thisrow;
}
// Refresh display
Line* _topline = findtopline();
refresh(_topline, minrow);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2005-10-05 20:35:22 +00:00
}
2005-09-27 18:30:31 +00:00
// ------------------------------------------------------------------
void IEclass::SCodeChange(gkey key)
{
GFTRK("EditSCodeChange");
char _ch = ' ';
switch (key)
{
case KK_EditSCodeBold: _ch = '*'; break;
case KK_EditSCodeUnderline: _ch = '_'; break;
case KK_EditSCodeItalic: _ch = '/'; break;
case KK_EditSCodeReverse: _ch = '#'; break;
}
const char *cltxt = currline->txt.c_str();
const char *punct = CFG->stylecodepunct;
if (isspace(cltxt[col]) || strchr(punct, cltxt[col]))
2005-09-27 18:30:31 +00:00
{
if (col && !isspace(cltxt[col-1]) && !strchr(punct, cltxt[col-1]))
2005-09-27 18:30:31 +00:00
GoLeft();
else if (!isspace(cltxt[col+1]) && !strchr(punct, cltxt[col+1]))
2005-09-27 18:30:31 +00:00
GoRight();
else
{
if (isspace(cltxt[col]) && (key != KK_EditSCodeNormal))
2005-09-27 18:30:31 +00:00
{
if (col && !isspace(cltxt[col-1]))
2005-09-27 18:30:31 +00:00
insertchar(' ');
insertchar(_ch);
insertchar(_ch);
GoLeft();
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2005-09-27 18:30:31 +00:00
return;
}
}
uint beg = col;
uint end = col;
while (beg && !isspace(cltxt[beg-1]) && !strchr(punct, cltxt[beg-1]))
2005-09-27 18:30:31 +00:00
beg--;
while (!isspace(cltxt[end+1]) && !strchr(punct, cltxt[end+1]))
2005-09-27 18:30:31 +00:00
end++;
bool replace = false;
char c1 = cltxt[beg];
char c2 = cltxt[end];
2005-09-27 18:30:31 +00:00
if ((_ch == c1) && (c1 == c2))
{
2006-05-14 11:45:05 +00:00
GFTRK(0);
2005-09-27 18:30:31 +00:00
return;
}
2006-01-14 23:48:53 +00:00
if ((_ch != c1) && (c1 == c2) &&
2005-09-27 18:30:31 +00:00
((c1 == '*') || (c1 == '/') || (c1 == '_') || (c1 == '#')))
replace = true;
while (col && !isspace(cltxt[col-1]) && !strchr(punct, cltxt[col-1]))
2005-09-27 18:30:31 +00:00
GoLeft();
if (replace) DelChar();
if (_ch != ' ') insertchar(_ch);
cltxt = currline->txt.c_str();
2006-01-14 23:48:53 +00:00
while (!isspace(cltxt[col+1]) && !strchr(punct, cltxt[col+1]))
2005-09-27 18:30:31 +00:00
GoRight();
if (replace) DelChar();
else GoRight();
if (_ch != ' ') insertchar(_ch);
GoLeft();
2006-05-14 11:45:05 +00:00
GFTRK(0);
2005-09-27 18:30:31 +00:00
}
2000-02-25 11:04:07 +00:00
// ------------------------------------------------------------------
void IEclass::LookupCursor() {
GFTRK("EditLookupCursor");
2000-03-22 17:59:18 +00:00
LookupNode(msgptr, currline->txt.c_str()+col, LOOK_NAME);
2000-02-25 11:04:07 +00:00
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::LookupDest() {
GFTRK("EditLookupDest");
LookupNode(msgptr, "", LOOK_DEST);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::LookupOrig() {
GFTRK("EditLookupOrig");
LookupNode(msgptr, "", LOOK_ORIG);
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void IEclass::Soundkill() {
HandleGEvent(EVTT_STOPVOICE);
}
// ------------------------------------------------------------------
void IEclass::statusline() {
if(chartyped) {
if(EDIT->Completion.First()) {
do {
const char* trig = EDIT->Completion.Trigger();
uint tlen = strlen(trig);
if(col >= tlen) {
2000-03-22 17:59:18 +00:00
if(strneql(trig, currline->txt.c_str()+col-tlen, tlen)) {
2003-03-26 16:05:36 +00:00
int saved_insert = insert;
insert = true;
batch_mode = BATCH_MODE;
2000-02-25 11:04:07 +00:00
uint n;
for(n=0; n<tlen; n++)
DelLeft();
const char* cptr = EDIT->Completion.Text();
uint clen = strlen(cptr);
for(n=0; n<clen; n++)
insertchar(*cptr++);
HandleGEvent(EVTT_EDITCOMPLETION);
2003-03-26 16:05:36 +00:00
insert = saved_insert;
2000-02-25 11:04:07 +00:00
break;
}
}
} while(EDIT->Completion.Next());
}
}
char _buf[EDIT_BUFLEN];
*_buf = NUL;
if(EDIT->Comment.First()) {
do {
const char* trig = EDIT->Comment.Trigger();
uint tlen = strlen(trig);
if(col >= tlen) {
2000-03-22 17:59:18 +00:00
if(strnieql(trig, currline->txt.c_str()+col-tlen, tlen)) {
2000-02-25 11:04:07 +00:00
strcpy(_buf, EDIT->Comment.Text());
break;
}
}
} while(EDIT->Comment.Next());
}
uint chr = currline->txt[col];
update_statuslinef(LNG->EditStatus, "ST_EDITSTATUS", 1+thisrow, 1+col, chr, _buf);
2000-02-25 11:04:07 +00:00
if(*_buf and CFG->switches.get(beepcomment)) {
HandleGEvent(EVTT_EDITCOMMENT);
}
}
// ------------------------------------------------------------------
int IEclass::handlekey(gkey __key) {
2000-12-24 19:47:06 +00:00
int rc = true;
2000-02-25 11:04:07 +00:00
if (drawlines)
{
switch (__key)
{
case KK_EditBlockRight:
case KK_EditBlockLeft:
case KK_EditBlockUp:
case KK_EditBlockDown:
DrawLines(__key);
case KK_EditBlockHome:
case KK_EditBlockEnd:
case KK_EditBlockPgDn:
case KK_EditBlockPgUp:
case KK_EditBlockWordRight:
case KK_EditBlockWordLeft:
undo_ready = NO;
return rc;
default:
drawflag = true;
}
}
switch(__key)
{
2000-02-25 11:04:07 +00:00
case KK_EditBlockRight: __key = KK_EditGoRight; break;
case KK_EditBlockLeft: __key = KK_EditGoLeft; break;
case KK_EditBlockUp: __key = KK_EditGoUp; break;
case KK_EditBlockDown: __key = KK_EditGoDown; break;
case KK_EditBlockHome: __key = KK_EditGoBegLine; break;
case KK_EditBlockEnd: __key = KK_EditGoEOL; break;
case KK_EditBlockPgDn: __key = KK_EditGoPgDn; break;
case KK_EditBlockPgUp: __key = KK_EditGoPgUp; break;
case KK_EditBlockWordRight: __key = KK_EditGoWordRight; break;
case KK_EditBlockWordLeft: __key = KK_EditGoWordLeft; break;
2000-02-25 11:04:07 +00:00
case KK_EditCopy:
case KK_EditCut:
case KK_EditDelete: goto noselecting;
case KK_EditDelChar:
case KK_EditDelLeft:
2002-10-26 16:28:01 +00:00
if(selecting) {
__key = KK_EditUndefine;
}
// fall through
2000-02-25 11:04:07 +00:00
case KK_EditPaste:
2002-10-26 16:28:01 +00:00
case KK_EditNewline:
2000-02-25 11:04:07 +00:00
if(selecting) {
BlockCut(true);
batch_mode = BATCH_MODE;
}
goto noselecting;
break;
2005-10-05 20:35:22 +00:00
case KK_EditToLower:
case KK_EditToUpper:
case KK_EditToggleCase:
if (!selecting) goto noselecting;
ToggleCaseBlock(__key);
undo_ready = NO;
return rc;
2000-02-25 11:04:07 +00:00
default:
2000-12-24 19:47:06 +00:00
rc = PlayMacro(__key, KT_E);
if(rc == true)
return rc;
rc = true;
2000-02-25 11:04:07 +00:00
if(selecting) {
Line *_line;
selecting = NO;
blockcol = -1;
for(_line = findfirstline(); _line; _line = _line->next)
_line->type &= ~GLINE_BLOK;
// refresh screen
int r = row;
for(_line = currline; _line and r; _line = _line->prev)
r--;
refresh(_line, minrow);
}
goto noselecting;
}
if(not selecting) {
Line *_line;
for(_line = findfirstline(); _line; _line = _line->next)
_line->type &= ~GLINE_BLOK;
currline->type |= GLINE_BLOK;
selecting = YES;
blockcol = col;
// refresh screen
int r = row;
for(_line = currline; _line and r; _line = _line->prev)
r--;
refresh(_line, minrow);
}
noselecting:
switch(__key) {
case KK_EditAbort: Abort(); break;
case KK_EditAskExit: AskExit(); break;
case KK_EditClearDeleteBuf: ClearDeleteBuf(); break;
case KK_EditClearPasteBuf: ClearPasteBuf(); break;
case KK_EditCopyAboveChar: CopyAboveChar(); break;
case KK_EditDelChar: DelChar(); break;
case KK_EditDeleteEOL: DeleteEOL(); break;
2001-08-31 14:14:27 +00:00
case KK_EditDeleteSOL: DeleteSOL(); break;
2000-02-25 11:04:07 +00:00
case KK_EditDelLeft: DelLeft(); break;
case KK_EditDelLine: DelLine(); break;
case KK_EditDelLtWord: DelLtWord(); break;
case KK_EditDelRtWord: DelRtWord(); break;
case KK_EditDosShell: DosShell(); break;
case KK_EditDupLine: DupLine(); break;
case KK_EditExitMsg: ExitMsg(); break;
case KK_EditExportText: ExportText(); break;
case KK_EditGoBegLine: GoBegLine(); break;
case KK_EditGoBotLine: GoBotLine(); break;
case KK_EditGoBotMsg: GoBotMsg(); break;
case KK_EditGoDown: GoDown(); break;
case KK_EditGoEOL: GoEOL(); break;
case KK_EditGoLeft: GoLeft(); break;
case KK_EditGoPgDn: GoPgDn(); break;
case KK_EditGoPgUp: GoPgUp(); break;
case KK_EditGoRight: GoRight(); break;
case KK_EditGoTopLine: GoTopLine(); break;
case KK_EditGoTopMsg: GoTopMsg(); break;
case KK_EditGoUp: GoUp(); break;
case KK_EditGoWordLeft: GoWordLeft(); break;
case KK_EditGoWordRight: GoWordRight(); break;
case KK_EditHeader: Header(); break;
case KK_EditImportQuotebuf: ImportQuotebuf(); break;
case KK_EditImportText: ImportText(); break;
case KK_EditLoadFile: LoadFile(); break;
case KK_EditLookupCursor: LookupCursor(); break;
case KK_EditLookupDest: LookupDest(); break;
case KK_EditLookupOrig: LookupOrig(); break;
case KK_EditNewline: Newline(); break;
case KK_EditQuitNow: QuitNow(); break;
case KK_EditReflow: Reflow(); break;
case KK_EditSaveFile: SaveFile(); break;
case KK_EditSaveMsg: SaveMsg(); break;
2006-03-11 17:04:06 +00:00
#if defined(GCFG_SPELL_INCLUDED)
case KK_EditSCheckerMenu: SCheckerMenu(); break;
#endif
2000-02-25 11:04:07 +00:00
case KK_EditSoundkill: Soundkill(); break;
case KK_EditSpellCheck: SpellCheck(); break;
case KK_EditTab: Tab(); break;
case KK_EditTabReverse: ReTab(); break;
case KK_EditToggleCase: ToggleCase(); break;
case KK_EditToggleInsert: ToggleInsert(); break;
case KK_EditToLower: ToLower(); break;
case KK_EditToUpper: ToUpper(); break;
case KK_EditUndefine: break;
case KK_EditUnDelete: UnDelete(); break;
case KK_EditUndo: Undo->PlayItem(); break;
case KK_EditZapQuoteBelow: ZapQuoteBelow(); break;
2005-09-27 18:30:31 +00:00
case KK_EditSCodeNormal:
case KK_EditSCodeBold:
case KK_EditSCodeItalic:
case KK_EditSCodeUnderline:
case KK_EditSCodeReverse: SCodeChange(__key); break;
case KK_EditDrawLines: ToggleDrawLines(); break;
2000-02-25 11:04:07 +00:00
// Block functions
case KK_EditAnchor: BlockAnchor(); break;
case KK_EditCopy: BlockCopy(); break;
case KK_EditCut: BlockCut(); break;
case KK_EditDelete: BlockCut(true); break;
case KK_EditPaste: BlockPaste(); break;
default:
2000-12-24 19:47:06 +00:00
rc = false;
break;
2000-02-25 11:04:07 +00:00
}
if(__key != KK_EditUndo)
undo_ready = NO;
2006-01-14 23:48:53 +00:00
2000-02-25 11:04:07 +00:00
return rc;
}
// ------------------------------------------------------------------
int IEclass::Start(int __mode, uint* __position, GMsg* __msg) {
GFTRK("EditStart");
thisrow = 0;
quitnow = NO;
col = mincol;
row = minrow;
msgptr = __msg;
msgmode = __mode;
currline = __msg->lin;
2006-03-11 17:04:06 +00:00
#if defined(GCFG_SPELL_INCLUDED)
if (CFG->scheckerenabled)
{
int save_chartableno = LoadCharset(NULL,NULL,1); // Workaround: internal for LoadCharset() charset table number changed in the schecker.Load()
2006-03-11 17:04:06 +00:00
schecker.Init(CFG->xlatlocalset, CFG->scheckerdicpath);
2011-03-15 07:32:45 +00:00
char *str = strdup(AA->adat->scheckerdeflang);
char *token = strtok(str, " ");
while(token != NULL)
{
schecker.Load(token, CFG->scheckeruserdic);
/* Get next token: */
token = strtok(NULL, " ");
}
2011-03-15 07:32:45 +00:00
free(str);
if(save_chartableno != -1) // restore value of the default chaset table // workaround: internal for LoadCharset() charset table number changed in the schecker.Load()
LoadCharset(CFG->xlatcharset[save_chartableno].imp, CFG->xlatcharset[save_chartableno].exp);
else
LoadCharset("N/A","N/A");
}
#endif
2001-02-19 22:53:24 +00:00
if(AA->isinternet() and (CFG->soupexportmargin <= CFG->dispmargin))
2000-02-25 11:04:07 +00:00
margintext = CFG->soupexportmargin;
else
margintext = CFG->dispmargin;
2001-08-07 10:51:00 +00:00
marginquotes = EDIT->QuoteMargin() + 1; // Add one for CR
2000-02-25 11:04:07 +00:00
if(marginquotes > margintext)
marginquotes = margintext;
if(currline == NULL) {
2000-03-22 17:59:18 +00:00
currline = new Line("\n");
throw_xnew(currline);
2000-02-25 11:04:07 +00:00
}
// Check if there is an unfinished backup message
2006-04-26 17:06:23 +00:00
gfile _fp(AddPath(CFG->goldpath, EDIT->File()), "rt", CFG->sharemode);
2006-05-13 16:15:35 +00:00
if (_fp.isopen())
2006-04-26 17:06:23 +00:00
{
2000-02-25 11:04:07 +00:00
char _buf[EDIT_BUFLEN];
2006-04-26 17:06:23 +00:00
_fp.Fgets(_buf, sizeof(_buf));
_fp.Fclose();
if (striinc(unfinished, _buf))
{
2000-02-25 11:04:07 +00:00
w_info(LNG->UnfinishedMsg);
update_statusline(LNG->LoadUnfinished);
HandleGEvent(EVTT_ATTENTION);
gkey _ch = getxch();
w_info(NULL);
if(_ch != Key_Esc) {
LoadFile();
*__position = 0;
remove(AddPath(CFG->goldpath, EDIT->File()));
}
}
}
if(*__position) {
for(uint _posrow=0; _posrow < *__position; _posrow++) {
if(currline->next) {
currline = currline->next;
row++;
}
}
thisrow = row;
}
done = NO;
// If the starting line is outside the first screenful
if(*__position >= (maxrow+1)) {
refresh(currline->prev, minrow);
row = 1;
}
else {
refresh(findfirstline(), minrow);
}
gotorowcol(mincol, minrow);
dispins();
2005-10-20 21:10:42 +00:00
time32_t _lasttime = gtime(NULL);
2000-02-25 11:04:07 +00:00
while(not done) {
statusline();
gotorowcol(col, row);
batch_mode = 0;
vattr backattr = BLACK_|_BLACK;
2000-02-25 11:04:07 +00:00
if(blockcol == -1) {
backattr = dispchar(currline->txt.c_str()[col], C_READC);
2000-02-25 11:04:07 +00:00
gotorowcol(col, row);
}
cursoron();
if(insert)
vcursmall();
else
vcurlarge();
gkey _ch;
2006-01-14 23:48:53 +00:00
#if defined(__WIN32__)
gkey keystatus = 0;
2006-01-14 23:48:53 +00:00
#endif
2000-02-25 11:04:07 +00:00
do {
_ch = getxchtick();
// TO_PORT_TAG: kbxget_raw(3)
#if defined(__WIN32__)
keystatus = kbxget_raw(3);
#endif
2000-02-25 11:04:07 +00:00
if(EDIT->AutoSave()) {
2005-10-20 21:10:42 +00:00
time32_t _thistime = gtime(NULL);
2000-02-25 11:04:07 +00:00
if(_thistime >= (_lasttime+EDIT->AutoSave())) {
_lasttime = _thistime;
SaveFile();
}
}
if(_ch == Key_Tick)
CheckTick(KK_EditQuitNow);
} while(_ch == Key_Tick);
pcol = col; getthisrow(currline); prow = thisrow;
int ismacro = false;
gkey _kk = SearchKey(_ch, EditKey, EditKeys);
if(_kk) {
_ch = _kk;
// TO_PORT_TAG: kbxget_raw(3)
#if defined(__WIN32__)
if (keystatus & SHIFT_PRESSED)
#else
if (0)
#endif
{
switch(_ch)
{
case KK_EditGoUp: _ch = KK_EditBlockUp; break;
case KK_EditGoDown: _ch = KK_EditBlockDown; break;
case KK_EditGoLeft: _ch = KK_EditBlockLeft; break;
case KK_EditGoWordLeft: _ch = KK_EditBlockWordLeft; break;
case KK_EditGoRight: _ch = KK_EditBlockRight; break;
case KK_EditGoWordRight: _ch = KK_EditBlockWordRight; break;
case KK_EditGoBegLine:
case KK_EditGoTopMsg: _ch = KK_EditBlockHome; break;
case KK_EditGoEOL:
case KK_EditGoBotMsg: _ch = KK_EditBlockEnd; break;
case KK_EditGoPgUp:
case KK_EditGoTopLine: _ch = KK_EditBlockPgUp; break;
case KK_EditGoPgDn:
case KK_EditGoBotLine: _ch = KK_EditBlockPgDn; break;
}
}
2000-02-25 11:04:07 +00:00
}
else {
ismacro = IsMacro(_ch, KT_E);
}
if(blockcol == -1)
dispchar(currline->txt.c_str()[col], backattr);
2000-02-25 11:04:07 +00:00
chartyped = false;
if((_ch < KK_Commands) and (_ch & 0xFF) and not ismacro) {
drawflag = true;
2000-02-25 11:04:07 +00:00
chartyped = true;
_ch &= 0xFF;
insertchar((char)_ch);
undo_ready = YES;
}
else if(handlekey(_ch)) {
getthisrow(currline);
}
}
cursoroff();
msgptr->lin = findfirstline();
savefile(quitnow ? MODE_UPDATE : MODE_SAVE);
// Prune killbuffer
if(Edit__killbuf) {
Line *__line = Edit__killbuf;
int _count = EDIT->UnDelete();
while(__line and _count--)
__line = __line->prev;
if(__line)
if(__line->next)
__line->next->prev = NULL;
while(__line) {
if(Undo->FixPushLine(__line)) {
if(__line->prev) {
__line = __line->prev;
__line->next = NULL;
}
else {
__line = NULL;
}
}
else {
if(__line->prev) {
__line = __line->prev;
2000-03-22 17:59:18 +00:00
throw_xdelete(__line->next);
2000-02-25 11:04:07 +00:00
}
2000-03-22 17:59:18 +00:00
else
throw_xdelete(__line);
2000-02-25 11:04:07 +00:00
}
}
}
*__position = 1 + thisrow;
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
return done;
}
// ------------------------------------------------------------------
UndoStack::UndoStack(IEclass* this_editor) :
editor(this_editor),
row(editor->row),
col(editor->col),
pcol(editor->pcol),
prow(editor->prow),
minrow(editor->minrow),
maxrow(editor->maxrow),
thisrow(editor->thisrow),
2006-01-14 23:48:53 +00:00
currline(editor->currline),
2000-02-25 11:04:07 +00:00
undo_ready(editor->undo_ready) {
UndoItem::last_item = &last_item;
last_item = NULL;
undo_enabled = YES;
}
// ------------------------------------------------------------------
UndoStack::~UndoStack() {
while(last_item) {
switch(last_item->action & EDIT_UNDO_ACTION) {
case EDIT_UNDO_DEL_TEXT:
2000-11-27 06:15:29 +00:00
case EDIT_UNDO_INS_TEXT:
2000-02-25 11:04:07 +00:00
case EDIT_UNDO_WRAP_TEXT:
2000-03-22 17:59:18 +00:00
throw_delete(last_item->data.text_ptr);
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_DEL_LINE:
2000-03-22 17:59:18 +00:00
throw_xdelete(last_item->data.line_ptr);
2000-02-25 11:04:07 +00:00
}
delete last_item;
}
}
// ------------------------------------------------------------------
bool UndoStack::FixPushLine(Line* __line) {
UndoItem* item = last_item;
while(item) {
if(((item->action & EDIT_UNDO_ACTION) == EDIT_UNDO_PUSH_LINE) and (item->data.line_ptr == __line)) {
item->action &= ~EDIT_UNDO_ACTION;
item->action |= EDIT_UNDO_ORPHAN_LINE;
return true;
}
item = item->prev;
}
return false;
}
// ------------------------------------------------------------------
void UndoStack::PushItem(uint action, Line* __line, uint __col, uint __len) {
GFTRK("PushItem");
2000-02-25 11:04:07 +00:00
if(undo_enabled) {
throw_new(last_item = new UndoItem);
last_item->col.num = (__col != NO_VALUE) ? __col : col;
last_item->col.sav = 0;
last_item->action = action;
last_item->pcol = pcol;
last_item->prow = prow;
switch(action & EDIT_UNDO_ACTION) {
case EDIT_UNDO_VOID:
case EDIT_UNDO_INS_CHAR:
last_item->line = __line ? __line : currline;
last_item->data.char_int = NUL;
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_DEL_CHAR:
case EDIT_UNDO_OVR_CHAR:
last_item->line = __line ? __line : currline;
2000-03-22 17:59:18 +00:00
last_item->data.char_int = last_item->line->txt[last_item->col.num];
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_DEL_TEXT:
last_item->line = __line;
2000-10-24 05:02:25 +00:00
__col = last_item->col.num;
2000-02-25 11:04:07 +00:00
if(__len == NO_VALUE)
2001-06-04 03:40:38 +00:00
__len = __line->txt.length() - __col;
2000-02-25 11:04:07 +00:00
throw_new(last_item->data.text_ptr = new(__len) text_item(__col, __len));
2000-03-22 17:59:18 +00:00
memcpy(last_item->data.text_ptr->text, __line->txt.c_str() + __col, __len);
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_CUT_TEXT:
last_item->line = __line;
last_item->data.text_ptr = NULL;
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_INS_TEXT:
case EDIT_UNDO_WRAP_TEXT:
2000-06-16 23:30:48 +00:00
last_item->line = __line;
2001-02-20 21:29:42 +00:00
if(__len == NO_VALUE)
2001-05-09 20:45:13 +00:00
__len = __line->txt.length() - __col;
2000-12-24 19:47:06 +00:00
throw_new(last_item->data.text_ptr = new text_item(__col, __len));
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_NEW_LINE:
last_item->line = last_item->data.line_ptr = __line;
break;
case EDIT_UNDO_DEL_LINE:
last_item->line = __line->prev ? __line->prev : __line->next;
last_item->data.line_ptr = __line;
break;
case EDIT_UNDO_PUSH_LINE:
if(currline->next)
last_item->line = currline->next;
else {
last_item->action |= LAST_LINE;
last_item->line = currline->prev;
}
last_item->data.line_ptr = currline;
break;
case EDIT_UNDO_POP_LINE:
last_item->line = currline;
last_item->data.line_ptr = NULL;
break;
2006-01-14 23:48:53 +00:00
}
2000-02-25 11:04:07 +00:00
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------
void UndoStack::PlayItem() {
GFTRK("PlayItem");
2000-02-25 11:04:07 +00:00
if(last_item) {
UndoItem* item;
// Don't save any new items while in Undo function
undo_enabled = NO;
// Find first of the batch items
for(item = last_item; item->action & BATCH_MODE; item = item->prev);
uint curr_row_num = thisrow;
uint curr_col_num = col;
2002-11-23 16:06:53 +00:00
if((item->action & PREV_LINE) and item->line->next)
currline = item->line->next;
else
currline = item->line;
2000-02-25 11:04:07 +00:00
editor->getthisrow(currline);
2002-11-23 16:06:53 +00:00
int _maxrow = maxrow;
if((item->action & PREV_LINE) and not item->line->next)
_maxrow--;
2000-02-25 11:04:07 +00:00
col = item->col.num;
if(curr_row_num != thisrow) {
// Let user to see the position before performing Undo, unless it's a
// neighbour line and the same column.
undo_ready = ((abs(int(curr_row_num - thisrow)) < 2) and ((curr_col_num == col) or (col+1 > currline->txt.length())));
2000-02-25 11:04:07 +00:00
// Move cursor up or down depending on where the undo line is,
// then refresh window if the line is invisible.
do {
if(curr_row_num > thisrow) {
if(row > minrow)
curr_row_num--, row--;
else {
editor->refresh(currline, row);
break;
}
}
else {
2002-11-23 16:06:53 +00:00
if(row < _maxrow)
2000-02-25 11:04:07 +00:00
curr_row_num++, row++;
else {
Line* l = currline;
for(uint r = row; r; l = l->prev, r--) {}
editor->refresh(l, minrow);
break;
}
}
} while(curr_row_num != thisrow);
}
else
undo_ready = ((abs(int(curr_col_num - col)) < 2) or (col+1 > currline->txt.length()));
2000-02-25 11:04:07 +00:00
uint _pcol = item->pcol;
uint _prow = item->prow;
if(undo_ready) {
2002-11-23 16:06:53 +00:00
if((item->action & PREV_LINE) and not item->line->next) {
row++; thisrow++; curr_row_num++;
}
2000-02-25 11:04:07 +00:00
bool in_batch;
// Keep undoing until item with no BATCH_MODE flag is reached.
do {
uint undo_type = last_item->action & EDIT_UNDO_TYPE;
uint undo_action = last_item->action & EDIT_UNDO_ACTION;
2005-10-22 02:45:18 +00:00
in_batch = make_bool(last_item->action & BATCH_MODE);
2000-02-25 11:04:07 +00:00
currline = last_item->line;
if(last_item->action & PREV_LINE) {
col = last_item->col.num = last_item->col.sav;
if(row > minrow)
row--;
}
switch(undo_type) {
case EDIT_UNDO_CHAR:
switch(undo_action) {
case EDIT_UNDO_INS_CHAR:
currline->txt.erase(last_item->col.num, 1);
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_DEL_CHAR:
2000-03-22 17:59:18 +00:00
currline->txt.insert(last_item->col.num, 1, last_item->data.char_int);
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_OVR_CHAR:
2000-03-22 17:59:18 +00:00
currline->txt[last_item->col.num] = last_item->data.char_int;
2000-02-25 11:04:07 +00:00
break;
}
editor->setlinetype(currline);
break;
case EDIT_UNDO_TEXT: {
text_item* text_data = last_item->data.text_ptr;
std::string *txt = &currline->txt;
2000-02-25 11:04:07 +00:00
switch(undo_action) {
case EDIT_UNDO_DEL_TEXT:
2000-10-24 05:02:25 +00:00
txt->insert(text_data->col, text_data->text, text_data->len);
2000-03-22 17:59:18 +00:00
throw_delete(text_data);
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_CUT_TEXT:
2000-10-24 05:02:25 +00:00
txt->erase(last_item->col.num);
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_WRAP_TEXT:
2000-10-24 05:02:25 +00:00
txt->append(currline->next->txt.c_str()+text_data->col, text_data->len);
txt = &currline->next->txt;
2000-02-25 11:04:07 +00:00
// fall through...
case EDIT_UNDO_INS_TEXT:
2000-10-24 05:02:25 +00:00
txt->erase(text_data->col, text_data->len);
2000-03-22 17:59:18 +00:00
throw_delete(text_data);
2000-02-25 11:04:07 +00:00
break;
}
2001-05-09 20:45:13 +00:00
editor->setlinetype((undo_action == EDIT_UNDO_WRAP_TEXT) ? currline->next : currline);
2000-02-25 11:04:07 +00:00
break;
}
case EDIT_UNDO_LINE: {
Line* thisline = last_item->data.line_ptr;
switch(undo_action) {
case EDIT_UNDO_NEW_LINE:
if(thisline->next)
thisline->next->prev = thisline->prev;
if(thisline->prev) {
thisline->prev->next = thisline->next;
currline = thisline->prev;
}
else
currline = thisline->next;
2000-03-22 17:59:18 +00:00
throw_xdelete(thisline);
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_ORPHAN_LINE:
if(last_item->action & LAST_LINE) {
thisline->prev = currline;
thisline->next = currline ? currline->next : NULL;
2000-03-22 17:59:18 +00:00
if((row < maxrow) and currline)
2000-02-25 11:04:07 +00:00
row++;
}
else {
thisline->prev = currline ? currline->prev : NULL;
thisline->next = currline;
}
// fall through...
case EDIT_UNDO_DEL_LINE:
if(thisline->prev)
thisline->prev->next = thisline;
if(thisline->next)
thisline->next->prev = thisline;
currline = thisline;
break;
case EDIT_UNDO_PUSH_LINE:
2005-10-25 06:11:09 +00:00
editor->UnDelete(make_bool_not(last_item->action & LAST_LINE));
2000-02-25 11:04:07 +00:00
break;
case EDIT_UNDO_POP_LINE:
editor->DelLine();
break;
}
}
}
_pcol = last_item->pcol;
_prow = last_item->prow;
delete last_item;
} while(last_item and in_batch);
undo_enabled = YES;
2000-02-25 11:04:07 +00:00
editor->getthisrow(currline);
uint temprow = row;
Line *templine = currline;
Line *topline = editor->findfirstline();
int delta = _prow-thisrow;
if(not in_range(row+delta, minrow, maxrow)) {
// we need to fit thisrow into the screen boundaries
if(delta > 0) {
2003-01-04 10:16:47 +00:00
for(row += delta; row > maxrow; row--) {
2001-02-19 22:53:24 +00:00
if(templine) // cause refresh() issue an error since templine should never be NULL
2003-01-04 10:16:47 +00:00
templine = templine->prev;
}
2003-01-04 10:16:47 +00:00
temprow = maxrow;
2000-02-25 11:04:07 +00:00
}
else {
2003-01-04 10:16:47 +00:00
for(row += delta; (int)row < (int)minrow; row++) {
2001-02-19 22:53:24 +00:00
if(templine) // cause refresh() issue an error since templine should never be NULL
2003-01-04 10:16:47 +00:00
templine = templine->next;
}
2003-01-04 10:16:47 +00:00
temprow = minrow;
}
// move pointer to the top of screen so we refresh scrolled area
while (row != minrow) {
2001-02-19 22:53:24 +00:00
if(templine) // cause refresh() issue an error since templine should never be NULL
templine = templine->prev;
--row;
2000-02-25 11:04:07 +00:00
}
}
else {
2001-02-19 22:53:24 +00:00
if(delta < 0) {
templine = topline;
for(thisrow=0; thisrow < _prow; thisrow++)
if(templine) // cause refresh() issue an error if thisrow != _prow
templine = templine->next;
}
temprow = row+delta;
}
// refresh screen
editor->refresh(templine, row);
// set cursor position
thisrow = _prow;
col = _pcol;
row = temprow;
// set currline according to thisrow
currline = topline;
for(thisrow=0; thisrow < _prow; thisrow++)
if(currline)
currline = currline->next;
2000-02-25 11:04:07 +00:00
}
// Move the cursor to EOL if necessary
2000-03-22 17:59:18 +00:00
else if(col+1 > currline->txt.length())
2000-02-25 11:04:07 +00:00
editor->GoEOL();
undo_ready = YES;
}
2006-05-14 11:45:05 +00:00
GFTRK(0);
2000-02-25 11:04:07 +00:00
}
// ------------------------------------------------------------------