diff options
Diffstat (limited to 'edit.cpp')
-rw-r--r-- | edit.cpp | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/edit.cpp b/edit.cpp new file mode 100644 index 0000000..740a0f3 --- /dev/null +++ b/edit.cpp @@ -0,0 +1,515 @@ +// edit.cpp +// Revision 7-feb-2005 + +//#include "cursor.h" +#include "graphics.h" +#include "error.h" +#include "trace.h" +#include "util.h" +#include "sysvar.h" + +#include "edit.h" + +using util::to_string; + +#include <sstream> +#include <deque> + +#include <cassert> +#define ASSERT assert + +namespace sysvar= blassic::sysvar; +using namespace blassic::file; + + +namespace { + +std::deque <std::string> history; + +size_t getmaxhistory () +{ + return sysvar::get16 (sysvar::MaxHistory); +} + +void showstring (BlFile & bf, const std::string & str) +{ + for (size_t i= 0, l= str.size (); i < l; ++i) + { + unsigned char c= str [i]; + if (c < 32) + bf << '\\' << char (c + 'A'); + else + bf << static_cast <char> (c); + } + bf.flush (); +} + +class Edit { +public: + Edit (BlFile & bf, std::string & str, + size_t npos, size_t inicol, bool lineend); + ~Edit (); + bool do_it (); +private: + BlFile & bf; + std::string & str; + size_t npos; + size_t inicol; + size_t width; + bool textwindow; + size_t histsize; + size_t histpos; + bool intagmode; + bool lineend; + + std::string savestr; + + //void getwidth (); + void back (); + void forward (); + void deletechar (); + void showrest (); + void showinitial (); + void up (); + void down (); +}; + +Edit::Edit (BlFile & bf, std::string & str, + size_t npos, size_t inicol, bool lineend) : + bf (bf), + str (str), + npos (npos), + inicol (inicol), + width (bf.getwidth () ), + textwindow (bf.istextwindow () ), + histsize (history.size () ), + histpos (histsize), + intagmode (bf.istagactive () ), + lineend (lineend) +{ + TRACEFUNC (tr, "Edit::~Edit"); + TRMESSAGE (tr, "lineend: " + to_string (lineend) ); + + if (textwindow) + graphics::synchronize_suspend (); + if (intagmode) + bf.tagoff (); +} + +Edit::~Edit () +{ + TRACEFUNC (tr, "Edit::~Edit"); + + if (textwindow) + graphics::synchronize_restart (); + if (intagmode) + bf.tag (); +} + +void Edit::back () +{ + if (textwindow) + { + --npos; + bf.movecharback (); + return; + } + if ( (npos-- + inicol) % width != 0) + bf.movecharback (); + else + { + bf.movecharup (); + bf.movecharforward (width - 1); + } +} + +void Edit::forward () +{ + ++npos; + if (textwindow) + { + bf.movecharforward (); + return; + } + if ( (npos + inicol) % width != 0) + bf.movecharforward (); + else + { + if (npos == str.size () ) + { + //bf.movecharforward (); + //bf << '\n'; + bf.endline (); + bf.flush (); + } + else + { + //bf << '\r'; + //bf.flush (); + bf.movecharback (width - 1); + bf.movechardown (); + } + } +} + +void Edit::deletechar () +{ + if (npos < str.size () ) + { + str.erase (npos, 1); + // Vil chapuza. + str+= ' '; + showrest (); + str.erase (str.size () - 1); + } +} + +void Edit::showrest () +{ + //TRACEFUNC (tr, "Edit::showrest"); + + if (npos == str.size () ) + return; + //bf << str.substr (npos); + //bf.flush (); + showstring (bf, str.substr (npos) ); + + size_t l= str.size (); + size_t nlines= (l + inicol) / width; + size_t actualline= (npos + inicol) / width; + size_t actualcol= (npos + inicol) % width; + size_t lastcol= (l + inicol) % width; + if (lastcol == 0 && nlines > 0) + { + if (! textwindow) + { + #ifndef __WIN32__ + --nlines; + // The cursor position remains + // in the last valid column. + lastcol= width - 1; + //lastcol= width; + #endif + } + } + bf.movecharup (nlines - actualline); + if (actualcol < lastcol) + { + //TRMESSAGE (tr, std::string ("moving back " + + // to_string (lastcol - actualcol) ) ); + bf.movecharback (lastcol - actualcol); + } + else if (actualcol > lastcol) + { + //TRMESSAGE (tr, "moving forward"); + bf.movecharforward (actualcol - lastcol); + } + else if (actualcol == width - 1) + { + // Without this the cursor sometimes keep in the next line. + bf.movecharback (); + bf.movecharforward (); + } +} + +void Edit::showinitial () +{ + //TRACEFUNC (tr, "Edit::showinitial"); + + //bf << '\r' << str; + //bf.flush (); + + //bf << '\r'; + //bf.movecharforward (inicol); + + showstring (bf, str); + + size_t l= str.size () + inicol; + size_t nlines= l / width; + size_t actualline= (npos + inicol) / width; + size_t actualcol= (npos + inicol) % width; + size_t lastcol= l % width; + + #ifndef __WIN32__ + if (lastcol == 0 && nlines > 0) + { + --nlines; + lastcol= width - 1; + } + #endif + + bf.movecharup (nlines - actualline); + if (actualcol < lastcol) + bf.movecharback (lastcol - actualcol); + else + bf.movecharforward (actualcol - lastcol); + //bf << '\r'; + //bf.flush (); + //movecharforward (npos); +} + +void Edit::up () +{ + if (histpos > 0) + { + if (histpos == histsize) + savestr= str; + std::string::size_type oldsize= str.size (); + --histpos; + str= history [histpos]; + while (npos > 0) + back (); + std::string::size_type + actualsize= str.size (); + if (oldsize > actualsize) + { + showstring (bf, std::string (oldsize, ' ') ); + npos= oldsize; + for (size_t i= 0; i < oldsize; ++i) + back (); + } + //showinitial (); + showstring (bf, str); + npos= actualsize; + } +} + +void Edit::down () +{ + if (histpos < histsize) + { + std::string::size_type oldsize= str.size (); + ++histpos; + if (histpos < histsize) + str= history [histpos]; + else + str= savestr; + while (npos > 0) + back (); + std::string::size_type + actualsize= str.size (); + if (oldsize > actualsize) + { + showstring (bf, std::string (oldsize, ' ') ); + npos= oldsize; + for (size_t i= 0; i < oldsize; ++i) + back (); + } + //showinitial (); + showstring (bf, str); + npos= actualsize; + } +} + +bool Edit::do_it () +{ + TRACEFUNC (tr, "Edit::do_it"); + + showinitial (); + + bool editing= true; + bool retval= true; + while (editing) + { + bf.showcursor (); + //TRMESSAGE (tr, "Waiting key"); + std::string key= bf.getkey (); + //TRMESSAGE (tr, "Received key"); + bf.hidecursor (); + if (key.size () == 1) + { + unsigned char c= key [0]; + switch (c) + { + case '\r': case '\n': + editing= false; + break; + case '\x1B': + editing= false; + retval= false; + break; + case '\t': + { + //size_t n= npos + 1; + //n+= 7 - (n % 8); + //n-= npos ; + size_t n= 8 - npos % 8; + str.insert (npos, n, ' '); + showrest (); + for (size_t i= 0; i < n; ++i) + forward (); + } + break; + case '\3': // Ctrl-C + editing= false; + retval= false; + break; + case '\5': // Ctrl-E, test debug + //bf << str.substr (npos) << '\n'; + //bf.flush (); + showstring (bf, str.substr (npos) ); + //bf << '\n'; + bf.endline (); + bf.flush (); + showinitial (); + break; + case '\x8': + case '\x7F': + if (npos > 0) + { + back (); + deletechar (); + } + break; + default: + if (c >= ' ') + { + str.insert (npos, 1, c); + showrest (); + forward (); + } + } + } + else if (key == "RIGHT") + { + if (npos < str.size () ) + { + forward (); + } + } + else if (key == "LEFT") + { + if (npos > 0) + { + back (); + } + } + else if (key == "DELETE") + { + if (npos < str.size () ) + deletechar (); + } + else if (key == "HOME") + { + while (npos > 0) + back (); + } + else if (key == "END") + { + const size_t l= str.size (); + while (npos < l) + forward (); + } + else if (key == "UP") + up (); + else if (key == "DOWN") + down (); + } + //hidecursor (); + + if (lineend) + { + // After exit, cursor must be positioned after the line edited. + //bf << str.substr (npos) << '\n'; + bf << str.substr (npos); + bf.endline (); + bf.flush (); + } + + if (retval) + { + size_t maxhist= getmaxhistory (); + if (maxhist == 0) + maxhist= 1; + if (histsize >= maxhist) + { + history.erase (history.begin (), + history.begin () + histsize - maxhist + 1); + } + if (! str.empty () && (history.empty () || + history [history.size () - 1] != str) ) + history.push_back (str); + } + + return retval; +} + +} // namespace + +bool blassic::edit::editline (BlFile & bf, std::string & str, + size_t npos, size_t inicol, bool lineend) +{ + TRACEFUNC (tr, "editline - string"); + { + std::ostringstream oss; + oss << "Inicol: " << inicol; + TRMESSAGE (tr, oss.str () ); + } + + Edit edit (bf, str, npos, inicol, lineend); + return edit.do_it (); +} + +#if 0 + +bool editline (BlFile & bf, Program & program, BlLineNumber bln, + std::string & str) +{ + TRACEFUNC (tr, "editline - line number->string"); + + std::string buffer; + { + BlFileOutString bfos; + program.list (bln, bln, bfos); + buffer= bfos.str (); + if (buffer.empty () ) + { + //bfos << bln << " \n"; + bfos << bln << ' '; + bfos.endline (); + buffer= bfos.str (); + } + } + buffer.erase (buffer.size () - 1); + TRMESSAGE (tr, std::string (1, '\'') + buffer + '\''); + + static const std::string number ("01234567890"); + size_t inipos= buffer.find_first_of (number); + ASSERT (inipos != std::string::npos); + inipos= buffer.find_first_not_of (number, inipos); + ASSERT (inipos != std::string::npos); + ++inipos; + + bool r; + if ( (r= editline (bf, buffer, inipos) ) == true) + str= buffer; + return r; +} + +bool editline (BlFile & bf, Program & program, BlLineNumber bln) +{ + TRACEFUNC (tr, "editline - line number"); + + std::string buffer; + bool r; + if ( (r= editline (bf, program, bln, buffer) ) == true) + { + CodeLine code; + code.scan (buffer); + BlLineNumber nline= code.number (); + if (nline == LineDirectCommand) + throw ErrBlassicInternal; + else + { + if (code.empty () ) + program.deletelines (nline, nline); + else + program.insert (code); + } + } + return r; +} + +#endif + +// End of edit.cpp |