home *** CD-ROM | disk | FTP | other *** search
- /*
- ** 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;
- }
-
-