home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
fed0217s.zip
/
source
/
buffer.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2001-08-08
|
18KB
|
843 lines
/*
** Module :BUFFER.CPP
** Abstract :Class buffer methods.
**
** Copyright (C) Sergey I. Yevtushenko
**
** Log: Wed 05/03/1997 Updated to V0.5
** Sat 12/04/1997 Updated to V0.8
** Fri 07/11/1997 Updated to V0.9, UNDO implemented
** Sun 09/11/1997 Updated to V0.91, fixed memory leaks
*/
#include <string.h>
#include <buffer.h>
#include <version.h>
#define UNDO 1
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
//----------------------------------------------------------------------
//
// Class BUFFER
//
//----------------------------------------------------------------------
void Buffer::init_buffer()
{
changed =
col_block =
cur_col =
cur_row =
mark_state =
num_cols =
old_abs_col =
old_abs_row =
start_col =
start_row =
tracking =
undo_count =
found_show =
found_row =
found_len =
found_col =
is_unix = 0;
word_wrap = iWWDef;
ww_width = iDefWidth;
draw_save.start_row = 0;
draw_save.start_col = 0;
hiliting = HI_CPP;
ins_mode = 1;
auto_indent = 1;
pal_start = CL_EDITBOX_START;
track_head = undobuff = 0;
custom_syntax = 0;
set_xlate(0);
}
Buffer::Buffer(int sz):Collection(sz, 1024)
{
init_buffer();
}
Buffer::Buffer():Collection(1024, 1024)
{
init_buffer();
}
Buffer::~Buffer()
{
clear_undobuff();
RemoveAll();
}
void Buffer::Free(Ptr p)
{
delete PLine(p);
}
//----------------------------------------------------------------------
// Editing routines
//
//----------------------------------------------------------------------
void Buffer::ins_char(Rect& rect, int chr)
{
unmark();
changed = 1;
if(chr == '\n' || chr == '\r')
{
split_line(rect);
return;
}
//-----------------------------------
// C/C++ Smart indent (Part 1)
//-----------------------------------
if(chr == '}' && do_smart())
{
//Here trapped pressing of closing curly brace in new line
// Step 1: check line for spaces
int i;
for(i = 0; i < abs_col(); i++)
{
if(chr_out(abs_line()->char_at(i)) != ' ')
break;
}
if(i == abs_col()) //If not, process key in usual way
{
//find prev tabstop
int pos = abs_col();
while((--pos) % TAB_WIDTH)
{
//Nothing
}
goto_col(rect, pos);
}
}
// end
int _cur_col = cur_col;
int _start_col = start_col;
track(opDelChar);
cur_col += abs_line()->ins_char(chr_in(chr), abs_col());
for(int k = 1; k < (cur_col - _cur_col); k++)
track(opDelChar);
if(cur_col >= rect.cols)
{
start_col += cur_col - rect.cols + 1;
cur_col = rect.cols - 1;
}
if(_cur_col != cur_col)
track(opCurCol,(void *)_cur_col);
if(_start_col != start_col)
track(opStartCol,(void *)_start_col);
if((word_wrap & WW_STATE) && ww_need(abs_row()))
{
int wrap_pos = 0;
wrap_pos = ww_perform(rect, abs_row());
if(wrap_pos)
{
if(word_wrap & WW_LONG)
{
int i;
for(i = abs_row() + 1; ww_need(i) && (i < Count()); i++)
ww_perform(rect, i);
}
if(abs_col() >= wrap_pos)
{
int offset = 0;
goto_line(rect, abs_row() + 1);
if(auto_indent)
{
for(chr = abs_line()->char_at(offset);
chr && __issp(chr_out(chr));
chr = abs_line()->char_at(offset))
{
offset++;
}
}
goto_col(rect, abs_col() - wrap_pos + offset);
}
}
}
check_hiliting();
}
int Buffer::del_char(Rect&)
{
unmark();
changed = 1;
int chr = 0;
if(chr_out(abs_line()->char_at(abs_col())) == ' ')
{
int not_eof = 0;
//Check if all chars up to end of line are spaces
for(int i = abs_col() + 1; i < abs_line()->len(); i++)
{
if(chr_out(abs_line()->char_at(i)) != ' ')
{
not_eof = 1;
break;
}
}
if(!not_eof)
{
//Delete to the end of line
track(opRestoreLine,(void *)abs_line(),(void *)abs_row());
abs_line()->del_char(abs_col(), abs_line()->len() - abs_col());
}
}
if(abs_col() >= abs_line()->len()) //Special case, merge lines
{
track(opRestoreLine,(void *)abs_line(),(void *)abs_row());
PLine ln = PLine(Remove(abs_row() + 1));
if(ln)
{
track(opInsLine,(void *)ln,(void *)(abs_row()+1));
/*
int ins_pos = abs_col();
while(ln->len())
{
int chr = ln->del_char(0);
abs_line()->ins_char(chr, ins_pos++);
}
*/
abs_line()->ins_char(abs_col(), ln);
}
}
else
{
chr = chr_out(abs_line()->del_char(abs_col()));
track(opInsChar, (void *)chr);
}
check_hiliting();
return chr;
}
void Buffer::split_line(Rect& rect)
{
unmark();
PLine ln = new Line;
int chr;
int offset = 0;
changed = 1;
int smart_indent = 0;
//-----------------------------------
// C/C++ Smart indent (Part 2)
//-----------------------------------
if(abs_line()->char_at(abs_col() - 1) == '{' && do_smart())
smart_indent = 1;
// end
int pos_state = abs_line()->state();
track(opRestoreLine,(void *)abs_line(),(void *)abs_row());
do
{
chr = abs_line()->del_char(abs_col());
ln->ins_char(chr,ln->len());
}
while(chr);
if(auto_indent)
{
for(chr = abs_line()->char_at(offset);
chr && __issp(chr_out(chr));
chr = abs_line()->char_at(offset))
{
offset++;
}
}
track(opDelLine,(void *)(abs_row()+1));
ins_line(ln, abs_row()+1);
if(hiliting)
fill_hiliting(abs_row(), pos_state);
cursor_down(rect);
line_begin(rect);
if(auto_indent)
{
while(offset--)
ins_char(rect, ' ');
if(smart_indent)
{
int pos = (abs_col() / TAB_WIDTH + 1) * TAB_WIDTH;
while(abs_col() < pos)
ins_char(rect, ' ');
}
}
}
int Buffer::replace_char(Rect& rect, int chr)
{
unmark();
changed = 1;
if(chr == '\n' || chr == '\r')
{
//split_line(rect);
cursor_down(rect);
line_begin(rect);
return 0;
}
track(opRestoreLine,(void *)abs_line(),(void *)abs_row());
int old_chr = chr_out(abs_line()->del_char(abs_col()));
int _cur_col = cur_col;
int _start_col = start_col;
cur_col += abs_line()->ins_char(chr_in(chr), abs_col());
if(cur_col >= rect.cols)
{
start_col += cur_col - rect.cols + 1;
cur_col = rect.cols - 1;
}
if(_cur_col != cur_col)
track(opCurCol,(void *)_cur_col);
if(_start_col != start_col)
track(opStartCol,(void *)_start_col);
check_hiliting();
return old_chr;
}
void Buffer::del_word_right(Rect& rect)
{
unmark();
changed = 1;
if(abs_col() >= abs_line()->len())
{
del_char(rect); // 'del_char' check hiliting itself
return;
}
else
{
int chr;
int deleted = 0;
track(opRestoreLine,(void *)abs_line(),(void *)abs_row());
// Stage 1: delete characted in word
do
{ //Deleting characters in this way doesn't change screen appearance,
//but prevents merging lines
chr = chr_out(abs_line()->del_char(abs_col()));
if(!deleted)
deleted = chr;
}
while(__isic(chr));
if(chr)
{
// Last char was not 'isascii', return it back
if(__isic(deleted))
abs_line()->ins_char(chr_in(chr), abs_col());
// Stage 2: delete spaces after word
do
{
chr = chr_out(abs_line()->del_char(abs_col()));
}
while(__issp(chr));
if(chr)
abs_line()->ins_char(chr_in(chr), abs_col());
}
}
check_hiliting();
}
void Buffer::del_word_left(Rect& rect)
{
unmark();
changed = 1;
if(abs_col() > abs_line()->len())
line_end(rect);
else
{
int chr;
int save_col;
int deleted = 0;
track(opRestoreLine,(void *)abs_line(),(void *)abs_row());
// Stage 1: delete characters in word
while(1)
{
save_col = abs_col();
cursor_left(rect);
chr = chr_out(abs_line()->char_at(abs_col()));
if(__isic(chr) && save_col != abs_col())
{
deleted = chr_out(abs_line()->del_char(abs_col()));
}
else
{
if(!__issp(chr) && !deleted && save_col != abs_col())
abs_line()->del_char(abs_col());
break;
}
}
if(save_col != abs_col())
cursor_right(rect);
//deleted = 0;
while(1)
{
save_col = abs_col();
cursor_left(rect);
chr = chr_out(abs_line()->char_at(abs_col()));
if(__issp(chr) && save_col != abs_col())
{
deleted = chr_out(abs_line()->del_char(abs_col()));
}
else
{
if(deleted && save_col != abs_col())
cursor_right(rect);
break;
}
}
}
check_hiliting();
}
void Buffer::del_to_EOL(Rect& rect)
{
unmark();
changed = 1;
if(abs_col() > abs_line()->len())
line_end(rect);
else
{
int deleted = 0;
track(opRestoreLine,(void *)abs_line(),(void *)abs_row());
/*
do
{
deleted = chr_out(abs_line()->del_char(abs_col()));
}
while(deleted);
*/
abs_line()->del_char(abs_col(), abs_line()->len() - abs_col());
}
check_hiliting();
}
void Buffer::dup_line(Rect&, int line_num)
{
if(line_num >= Count())
return;
changed = 1;
PLine pLn = new Line(line(line_num));
track(opDelLine,(void *)(line_num+1));
ins_line(pLn, line_num+1);
check_hiliting();
}
Line* Buffer::del_line(Rect&, int line_num)
{
changed = 1;
if(line_num >= Count())
return 0;
if(line_num == Count() - 1 && line_num == abs_row())
return 0;
track(opInsLine,(void *)line(line_num),(void *)line_num);
if(hiliting)
{
// Removing this line may affect rest of lines in buffer
// If start conditions in this and next line doesn't equal
// then recalculate rest of lines with new conditions
PLine ln0 = line(line_num);
PLine ln1 = line(line_num + 1);
//Use start conditions of line which will be removed,
//and recalculate rest of lines
if(ln0 && ln1 && ln0->state() != ln1->state())
fill_hiliting(line_num + 1, ln0->state());
}
return PLine(Remove(line_num));
}
void Buffer::back_space(Rect& rect)
{
changed = 1;
int pos = abs_col();
cursor_left(rect);
if(chr_out(abs_line()->char_at(abs_col())) == ' ')
{
int is_eof = 1;
//Check if all chars up to end of line are spaces
for(int i = abs_col() + 1; i < abs_line()->len(); i++)
{
if(chr_out(abs_line()->char_at(i)) != ' ')
{
is_eof = 0;
break;
}
}
if(is_eof)
return;
}
if(abs_col() >= abs_line()->len())
return;
if(pos != abs_col())
del_char(rect);
else
{
if(abs_row() > 0)
{
cursor_up(rect);
line_end(rect);
del_char(rect);
}
}
}
//----------------------------------------------------------------------
// Utility routines
//
//----------------------------------------------------------------------
Parser* Buffer::gen_parser(int i)
{
Parser *res = Parser::GenParser(hiliting);
if(!res)
res = new Parser;
if(i)
res->SetXlat(cp_out);
return res;
}
void Buffer::mark()
{
if(!mark_state)
{
track(opMarking,(void *)mark_state);
old_abs_col = abs_col();
old_abs_row = abs_row();
}
mark_state = 1;
}
void Buffer::unmark()
{
if(mark_state)
{
track(opMarking,(void *)mark_state);
track(opMarkPos,(void *)old_abs_col,(void *)old_abs_row);
}
mark_state = 0;
}
void Buffer::set_column_block(int mode)
{
track(opColBlock,(void *)col_block);
col_block = (mode) ? 1:0;
}
void Buffer::set_hiliting(int mode)
{
custom_syntax = 1;
track(opHiliting,(void *)hiliting);
hiliting = (mode <= HI_LAST && mode >= 0) ? mode : hiliting;
}
void Buffer::set_ins_mode(int mode)
{
track(opInsMode,(void *)ins_mode);
ins_mode = (mode) ? 1:0;
}
void Buffer::set_changed(int i)
{
changed = i;
}
void Buffer::set_found(int h_row, int h_col, int h_len)
{
found_row = h_row;
found_len = h_len;
found_col = h_col;
found_show = 1;
}
void Buffer::ins_line(Line* ln, int line_num)
{
if(!ln || line_num < 0 || line_num > Count() + 1)
return;
At(ln, line_num);
}
void Buffer::add_line(Line* ln0)
{
if(Count())
{
PLine ln = line(Count() - 1);
int pos_state = ln->state();
Parser* parser = gen_parser(1);
ln0->set_hiliting(parser, pos_state);
delete parser;
}
Add(ln0);
}
void Buffer::fill_hiliting(int start, int pos_state)
{
Parser* parser = gen_parser(1);
for(int i = start;i < Count(); i++)
{
PLine ln = line(i);
if(ln)
ln->set_hiliting(parser, pos_state);
}
delete parser;
}
void Buffer::check_hiliting()
{
if(!hiliting)
return;
PLine ln0 = abs_line();
int pos_state = ln0->state();
Parser* parser = gen_parser(1);
ln0->set_hiliting(parser, pos_state);
delete parser;
PLine ln1 = line(abs_row() + 1);
if(ln1 && ln1->state() != pos_state)
fill_hiliting(abs_row() + 1, pos_state);
}
void Buffer::flip_hiliting()
{
custom_syntax = 1;
hiliting++;
if(hiliting > HI_LAST)
hiliting = 0;
if(hiliting)
fill_hiliting(0, ST_INITIAL);
}
void Buffer::set_xlate(char *cp)
{
int i;
cur_cp[0] = 0;
for(i = 0; i < 256; i++)
cp_in[i] = cp_out[i] = i;
if(!cp)
return;
char cTmp[256];
for(i = 0; i < 256; i++)
cTmp[i] = i;
int rc1;
int rc2;
rc1 = cp2cp(cp, "", &cTmp[1], &cp_out[1], 255);
rc2 = cp2cp("", cp, &cTmp[1], &cp_in [1], 255);
if(rc1 || rc2)
{
for(i = 0; i < 256; i++)
cp_in[i] = cp_out[i] = i;
}
else
{
strcpy(cur_cp, cp);
}
}
//-----------------------------------------
// Word wrap
//-----------------------------------------
int Buffer::ww_need(int i)
{
PLine ln = line(i);
if(!ln)
return 0;
int slen = ln->len();
while(slen && __issp(ln->char_at(slen - 1)))
slen--;
if(slen > ww_width)
return 1;
return 0;
}
int Buffer::ww_perform(Rect& rect, int row)
{
PLine ln = line(row);
if(!ln)
return 0;
int break_pos = 0;
int i = 0;
int slen = ln->len();
while(slen && __issp(ln->char_at(slen - 1)))
slen--;
if(slen < ww_width)
return 0;
//Look for place where we will break line
for(i = ww_width - 1; i > 0; i--)
{
if(__issp(chr_out(ln->char_at(i))))
{
break_pos = i + 1;
break;
}
}
if(!break_pos) //Non-breakable line
{
//Try other way
for(i = ww_width; i < slen; i++)
{
if(__issp(chr_out(ln->char_at(i))))
{
break_pos = i + 1;
break;
}
}
if(!break_pos)
return 0;
}
int save_flags = word_wrap;
int save_row = abs_row();
int save_col = abs_col();
word_wrap = 0;
goto_line(rect, row);
goto_col (rect, break_pos);
if(save_flags & WW_MERGE)
{
line_end(rect);
del_char(rect);
if(__issp(chr_out(abs_line()->char_at(abs_col()))))
del_word_right(rect);
ins_char(rect,' ');
goto_col (rect, break_pos);
ins_char(rect, '\n');
}
else
ins_char(rect, '\n');
word_wrap = save_flags;
goto_line(rect, save_row);
goto_col(rect, save_col);
return break_pos;
}