home *** CD-ROM | disk | FTP | other *** search
- //=================================================================
- //
- // Copyright (C) 1995,1996,1997.1998 Bruce E. Wampler
- //
- // This file is part of the V C++ GUI Framework, and is covered
- // under the terms of the GNU Library General Public License,
- // Version 2. This library has NO WARRANTY. See the source file
- // vapp.cxx for more complete information about license terms.
- //
- // This code is based on Bruce Wampler's editor, See. I think a
- // bit of history about See will explain some things about the
- // reasons some of the code structure and variable names are
- // what they are. See end end of this file for the See history.
- //
- //
- //===============================================================
-
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
-
- #include <v/vwindow.h>
- #include <v/vkeys.h>
-
- #include <v/vtexted.h>
- #include <v/vfinddlg.h>
-
- /// Working notes:
- // allow line list to grow dynamically by adding lines and
- // copying old list to new one, then deleting old one.
-
- const long lineListSize = 5000; // allocation increment for lines
-
- // one static find pattern
- int vTextEditor::findCaseSensitive = 0;
- char vTextEditor::theFindPat[MAX_LINE + 2] = "";
-
- // =========================>>> vTextEditor::vTextEditor <<<================
- vTextEditor::vTextEditor(vBaseWindow* parent, int isCmdWindow)
- {
-
- _parent = parent; // remember who my parent was
- _isCmdWindow = isCmdWindow; // if our parent was a cmdwindow
- _TECInt = new vTextEdCmdInterp(this, (vCmdWindow*)parent);
-
- // default state flags
-
- state.findAtBeginning = // don't leave find at beginning of pat
- state.fixed_scroll = 0; // Not fixed scrolling
- state.tabspc = 8;
-
- // switches:
- state.readOnly =
- state.wraplm = // wrap limit
- use_wild = 0; // use wild cards in match
-
- oldcol = 1;
-
- state.ins_mode = 1; // insert (vs. overtype)
-
- b_lastln =
- leftmg = xoutcm =
- tvdlin = state.echof = lastLine = 1;
-
- linptr = 0;
-
- mouseMoveRow = mouseMoveCol =
- mouseCol = mouseRow = -1; // no mouse stuff yet
- scroll_lin = -1;
-
- for (int ix = 0 ; ix < 10 ; ++ix)
- noteloc[ix] = 0;
-
- _lines = 0; // make these null for smarter destructor
-
- initBuff() ; // initialize buffer routines
- resetBuff();
- }
-
- //=========================>>> vTextEditor::~vTextEditor <<<================
- vTextEditor::~vTextEditor()
- {
- if (_TECInt)
- delete _TECInt; // kill our command interp
- if (_lines)
- {
- for (long ix = 0 ; ix < _nextLine ; ++ix) // delete contents
- delete [] _lines[ix];
- delete [] _lines; // delete if created
- }
- }
-
- //=========================>>> vTextEditor::ChangeCmdInterp <<<================
- void vTextEditor::ChangeCmdInterp(vTextEdCmdInterp* newCI)
- {
- if (_TECInt)
- delete _TECInt; // delete current command interp
- if (newCI == 0) // use default CI
- _TECInt = new vTextEdCmdInterp(this, (vCmdWindow*)_parent);
- else
- _TECInt = newCI;
- }
-
- // #########################################################################
- //
- // buffer methods
- //
- // These are designed to be easily overriden to allow more complex
- // buffer management -- it should be possible to easily design a
- // package that allows unlimited file size, for example.
- //
- // #########################################################################
-
- //===========================>>> vTextEditor::initBuff <<<==================
- void vTextEditor::initBuff(void)
- {
- // initialize buffer routines - handled as a method so
- // can override
-
- _lines = new char*[lineListSize];
- _maxLines = lineListSize - 1; // safety factor
-
- _lines[0] = new char[2]; strcpy(_lines[0],"\n");
- _lines[1] = new char[2]; strcpy(_lines[1],"\n");
- for (long lx = 2 ; lx < lineListSize ; ++lx)
- _lines[lx] = 0;
- _nextLine = 2;
- lastLine = lastLineBF();
- }
-
- // =======================>>> vTextEditor::resetBuff <<<====================
- void vTextEditor::resetBuff() // open the buffer
- {
-
- // values used by buffer management
-
- if (_lines)
- {
- delete [] _lines[0];
- delete [] _lines[1];
- for (long ix = 2 ; ix < _nextLine ; ++ix) // delete contents
- {
- if (_lines[ix])
- delete [] _lines[ix];
- }
- _lines[0] = new char[2]; strcpy(_lines[0],"\n");
- _lines[1] = new char[2]; strcpy(_lines[1],"\n");
- }
- else
- {
- _lines = new char*[lineListSize];
- _maxLines = lineListSize - 1; // safety factor
-
- _lines[0] = new char[2]; strcpy(_lines[0],"\n");
- _lines[1] = new char[2]; strcpy(_lines[1],"\n");
- }
-
- _curLineBF =
- _nextLine = 1;
-
- wasColCmd = 0;
-
- // values used by editor code
-
- mark.beg_lin = mark.end_lin = /* manually clear mark range */
- mark.beg_col = mark.end_col = 0; /* DO NOT CALL ClearMarkRange() */
- mark.beg_chr = mark.end_chr = 0;
-
- curlin = lastLine = 1;
-
- curchr = _lines[1];
-
- last_col_out =
- state.counter =
- state.changes = 0;
-
- dsplin = ddline = 1;
- state.ins_mode = 1; // insert (vs. overtype)
- }
-
- // =========================>>> vTextEditor::addLine <<<====================
- int vTextEditor::addLine(char* line)
- {
- // This method adds the line to the end of the working buffer.
- // line numbers start at 1! This is logical - it corresponds
- // to how you would really number a text file. It does not
- // correspond to C 0 based array indexing. So it goes.
-
- if (!line)
- return 0;
-
- if (_nextLine >= _maxLines) // check for max lines
- if (!reallocLines())
- return 0;
-
- BUFFPTR bp = appendToBuff(line);
-
- if (!bp)
- return 0;
- if (curchr == _lines[_nextLine])
- {
- // When the very first line is added, curchr must be updated to
- // point to the new line instead of to the initial "\n"!
- curchr = bp;
- }
-
- _lines[_nextLine++] = bp; // point line array to beginning of line
- lastLine = lastLineBF(); // update
-
-
- return 1;
- }
-
- // ======================>>> vTextEditor::appendToBuff <<<==================
- BUFFPTR vTextEditor::appendToBuff(char* line)
- {
- // add text to the buffer -- allocate the spaced right here!
-
- BUFFPTR buff;
- BUFFPTR bp;
- int len = 0;
- char* cp;
-
- for (cp = line ; *cp && *cp != '\n' && *cp != '\r' ; ++cp) // break on eos or eol
- {
- ++len;
- }
-
- buff = (BUFFPTR) new char[len+2]; // the space for the line
-
- if (!buff) // did we get the space?
- return 0;
-
- for (bp = buff, cp = line ; *cp && *cp != '\n' && *cp != '\r' ; ) // break on eos or eol
- {
- *bp++ = *cp++;
- }
- *bp++ = '\n';
- *bp++ = 0;
-
- return buff;
- }
-
- // =========================>>> vTextEditor::insertLine <<<====================
- int vTextEditor::insertLine(char* line, long before)
- {
- // This method adds the line before line before.
- // line numbers start at 1! This is logical - it corresponds
- // to how you would really number a text file. It does not
- // correspond to C 0 based array indexing. So it goes.
-
- if (!line)
- return 0;
-
- if (_nextLine >= _maxLines) // check for max lines
- if (!reallocLines())
- return 0;
-
- BUFFPTR bp = appendToBuff(line); // allocate space for line
-
- if (!bp)
- return 0;
-
- if (curchr == _lines[_nextLine])
- {
- // When the very first line is added, curchr must be updated to
- // point to the new line instead of to the initial "\n"!
- curchr = bp;
- }
-
- for (long to = _nextLine++ ; to > before ; --to)
- {
- _lines[to] = _lines[to-1];
- }
-
- _lines[before] = bp; // point line array to beginning of line
- lastLine = lastLineBF();
- adjustLines(before,1);
-
- return 1;
- }
-
-
- // =====================>>> vTextEditor::getFirstLine <<<===================
- int vTextEditor::getFirstLine(char* line, int maxChars)
- {
- // return the first line in the buffer
-
- return getLine(line, maxChars,1);
- }
-
- // =========================>>> vTextEditor::getNextLine <<<================
- int vTextEditor::getNextLine(char* line, int maxChars)
- {
- // return the next line in the text buffer, not including end of line
- // returns the number of characters, -1 if at end of file
-
- return getLine(line, maxChars, _curLineBF +1);
- }
-
- // =========================>>> vTextEditor::getLine <<<===================
- int vTextEditor::getLine(char* line, int maxChars, long lineNum)
- {
- // return the next line in the text buffer, not including end of line
- // returns the number of characters, -1 if at end of file
-
- if (lineNum >= _nextLine || lineNum < 1) // at end!
- return -1;
-
- _curLineBF = lineNum; // Set _curlineBF
- int len = 0;
-
- for (char* ix = _lines[_curLineBF] ; *ix != 0 && *ix != '\n' && len < maxChars ; )
- {
- line[len++] = *ix++; // copy & track length
- }
- line[len] = 0; // terminate
- return len;
- }
-
- // ===================>>> vTextEditor::displayBuff <<<======================
- void vTextEditor::displayBuff(long lineNum, int paintIt)
- {
- // All lines added, so now display the buffer
-
-
- if (lineNum >= _nextLine)
- lineNum = _nextLine - 1;
- if (lineNum < 1)
- lineNum = 1;
-
- curlin = lineNum; // Internal stuff begins with line 1
- curchr = GLine(curlin); /* first char of buffer */
- lastLine = lastLineBF();
- int oldef = state.echof;
- state.echof = paintIt;
- ShowVScroll(1);
- Verify();
-
- state.echof = oldef;
- }
-
- // =========================>>> vTextEditor::GLine <<<======================
- BUFFPTR vTextEditor::GLine(long lineNum)
- {
- if (lineNum < 1 || lineNum >= _nextLine)
- {
- return _lines[1]; // something safe
- }
-
- return _lines[lineNum];
- }
-
- // =====================>>> vTextEditor::deleteCharBF <<<===================
- BUFFPTR vTextEditor::deleteCharBF(BUFFPTR charNum, long lineNum)
- {
- // First, shift everything up to next end of line left
- // This routine must not assume that lines are stored contiguously
-
-
- BUFFPTR ix;
- BUFFPTR newCurChar = charNum;
-
- char combine[MAX_LINE*2+2];
-
- char chrDeleted = GCh(charNum);
-
- if (lastLineBF() < 1)
- return 0;
-
- if (IsEndLine(chrDeleted)) // combine two lines?
- {
- if (lineNum < (_nextLine - 1)) // There IS a next line
- {
- BUFFPTR bp;
- int to;
- int offset;
-
- // combine this line with the next line
- to = 0;
- for (bp = _lines[lineNum] ; *bp && !IsEndLine(*bp) ; )
- combine[to++] = *bp++;
-
- offset = to; // track where we were
-
- for (bp = _lines[lineNum+1] ; *bp && !IsEndLine(*bp) ; )
- combine[to++] = *bp++;
- *bp = 0;
- combine[to] = 0;
-
- // create buffer for it
- bp = appendToBuff(combine);
- if (!bp)
- return 0;
-
- newCurChar = bp + offset; // this is new cur char
-
- // free the old space
- delete [] _lines[lineNum];
- delete [] _lines[lineNum+1];
- _lines[lineNum] = bp;
-
- // shift up the rest of the lines
- for (long lp = lineNum + 1 ; lp < _nextLine ; ++lp)
- _lines[lp] = _lines[lp + 1];
- --_nextLine;
- lastLine = lastLineBF();
- }
- adjustLines(lineNum,-1); // one line deleted
- }
- else
- {
- newCurChar = charNum;
- for (ix = charNum + 1 ; *ix && !IsEndLine(*ix) ; ++ix)
- *(ix-1) = *ix;
- *(ix-1) = *ix;
- *ix = 0;
- }
- return newCurChar;
- }
-
- // ===================>>> vTextEditor::deleteLinesBF <<<====================
- long vTextEditor::deleteLinesBF(long start, long end)
- {
- // delete the lines in the specified range,
- // return new last line of file
-
- long to, from;
-
- if (lastLineBF() < 1)
- return 0;
-
- for (to = start ; to <= end ; ++to)
- delete[] _lines[to];
-
- for (to = start, from = end+1 ; from < _nextLine ; ++to, ++from)
- {
- _lines[to] = _lines[from]; // shift
- }
- _lines[from] = 0;
- _nextLine -= (end - start + 1);
- adjustLines(start, -(end - start + 1));
- lastLine = lastLineBF();
-
- if (_nextLine <= 1)
- {
- _lines[1] = new char[2]; strcpy(_lines[1], "\n");
- return 1;
- }
-
- return _nextLine - 1;
- }
-
- // =====================>>> vTextEditor::insertCharBF <<<===================
- int vTextEditor::insertCharBF(int chr, BUFFPTR& curchar, long& curline)
- {
- // insert a char into the buffer at curline, curchar.
- // return new curchar, curline
-
- char ln1[MAX_LINE+2];
- char ln2[MAX_LINE+2];
- char* newLine;
- BUFFPTR origLine = _lines[curline]; // original full line
- int offSet;
- int ix;
- BUFFPTR fp;
-
-
- if (chr == 0) // don't allow this case
- return 0;
-
- offSet = 0;
- for (BUFFPTR bp = origLine ; bp != curchar ; ++bp, ++offSet)
- ;
-
- if (chr != '\n')
- {
- for (ix = 0, fp = origLine ; *fp != 0 && ix < MAX_LINE ; )
- {
- if (ix == offSet)
- ln1[ix++] = chr; // add the new char
- ln1[ix++] = *fp++; // copy original line
- }
- if (ix == offSet)
- ln1[ix++] = chr; // add the new char
- ln1[ix] = 0;
- newLine = appendToBuff(ln1);
- if (!newLine) // see if got the space
- return 0;
- delete [] _lines[curline]; // free the old space
- _lines[curline] = newLine; // point line to new space
- curchar = newLine + offSet + 1; // update curchar
- }
- else // adding newline
- {
- // we are inserting a newline!
- for (ix = 0, fp = origLine ; *fp != 0 && ix < MAX_LINE ; )
- {
- if (ix == offSet)
- ln1[ix++] = chr; // add the new char
- ln1[ix++] = *fp++; // copy original line
- }
- if (ix == offSet)
- ln1[ix++] = chr; // add the new char
- ln1[ix] = 0;
-
- // ln1 now has two lines in it, split em up.
-
- char* cp;
- for (cp = ln1 ; *cp != '\n' ; ++cp) // find first part
- ;
- *cp++ = 0;
-
- char *tp;
- for (tp = ln2 ; *cp ; ) // copy second part
- *tp++ = *cp++;
- *tp = 0;
-
- newLine = appendToBuff(ln1);
- if (!newLine) // see if got the space
- return 0;
- delete [] _lines[curline]; // free the old space
- _lines[curline] = newLine; // point line to new space
-
- if (_nextLine >= _maxLines) // check for max lines
- if (!reallocLines()) // add some more lines
- return 0;
-
- long lx;
- for (lx = _nextLine ; lx > curline ; --lx)
- _lines[lx] = _lines[lx - 1];
-
- newLine = appendToBuff(ln2);
- if (!newLine) // see if got the space
- return 0;
-
- ++curline; ++_nextLine;
- lastLine = lastLineBF();
- adjustLines(curline,1); // one more line
-
- _lines[curline] = newLine; // point line to new space
-
- curchar = _lines[curline]; // point to line beginning
- }
- return 1;
- }
-
- // ==========================>>> vTextEditor::lineLenBF <<<=================
- int vTextEditor::lineLenBF(long lineNum)
- {
- if (lineNum < 1 || lineNum >= (_nextLine - 1))
- return 0;
-
- int len = 0;
- for (BUFFPTR ix = _lines[lineNum] ; *ix != '\n' && *ix != 0 ; ++ix)
- ++len;
- return len;
- }
-
- // ===================>>> vTextEditor::adjustLines <<<======================
- void vTextEditor::adjustLines(long line_1, int by)
- {
- /* adjust starting line number int note locaetions */
-
- int ix;
-
- for (ix = 0 ; ix < 10 ; ++ix) /* adjust notes */
- {
- if (noteloc[ix] > line_1) /* page needs fixing */
- noteloc[ix] += (long) by;
- }
- }
-
- // #########################################################################
- //
- // Command Interface methods
- //
- // #########################################################################
-
- // ===================>>> vTextEditor::EditCommand <<<======================
- int vTextEditor::EditCommand(int id, long val)
- {
- // returns 1 if command succeeded, 0 if failed
- // or -1 if not processed
-
- int retval = 1; // assume OK
- switch (id)
- {
- case edCut: // ^X : Cut
- {
- EditCut();
- break;
- }
-
- case edCopy: // ^C : Copy
- {
- EditCopy();
- break;
- }
-
- case edPaste: // ^V: Paste
- {
- EditPaste();
- break;
- }
-
- case edVerify: // repaint screen
- Verify();
- break;
-
- case edFind: // find
- {
- vFindDialog fdlg(_parent);
- if (!fdlg.AskFindPat(theFindPat, MAX_LINE, findCaseSensitive))
- return 0;
- retval = Find(theFindPat,findCaseSensitive,0,0);
- break;
- }
-
- case edFindNext: // find again
- {
- if (*theFindPat) // something to find
- retval = FindNext(findCaseSensitive,0,0);
- else
- retval = 0;
- break;
- }
-
- case edBufferBottom: // move to bottom of file (no val)
- bufferBottom();
- break;
-
- case edCharDelete: // delete val chars
- retval = charDelete(val);
- break;
-
- case edCharFoldCase: // swap case of val letters
- retval = charFoldCase(val);
- break;
-
- case edCharInsert: // insert char val
- retval = charInsert(val);
- break;
-
- case edCharRight: // move val chars right
- retval = charRight(val);
- break;
-
- case edLineBeginning: // move to line beginning (no val)
- lineBeginning();
- break;
-
- case edLineDown: // move down val lines in column
- retval = lineDown(val);
- break;
-
- case edLineDownBeg: // move down val lines
- retval = lineDownBeg(val);
- break;
-
- case edLineDelete: // delete val lines
- lineDelete(val);
- break;
-
- case edLineDeleteFront: // delete to beginning of line (no val)
- retval = lineDeleteFront();
- break;
-
- case edLineDeleteToEnd: // delete to end of line (no val)
- retval = lineDeleteToEnd();
- break;
-
- case edLineEnd: // move to end of line (no val)
- lineEnd();
- break;
-
- case edLineGoto: // move cursor to line val
- retval = lineGoto(val);
- break;
-
- case edLineOpen: // open val new blank lines
- retval = lineOpen(val);
- break;
-
- case edFormatC: // format C code lines
- retval = formatC(val);
- break;
-
- case edNoteLocation: // note which line we are on
- if (val < 1 || val > 9)
- val = 0;
- noteloc[val] = GetCurLine();
- break;
-
- case edNoteGoto: // goto noted locateion
- if (val < 1 || val > 9)
- val = 0;
- retval = lineGoto(noteloc[val]);
- break;
-
- case edWordRight: // move cursor val words right
- wordRight(val);
- break;
-
- case edBalMatch: // find matching paren (up to val lines away)
- retval = BalMatch(val);
- break;
-
- case edScrollDown: // scroll val lines without changing cursor
- scrollDown(val);
- break;
-
- default: // editor can't handle
- retval = -1;
- break;
- }
- return retval;
- }
-
- // ======================>>> vTextEditor::EditKeyIn <<<=====================
- int vTextEditor::EditKeyIn(vKey key, unsigned int shift)
- {
- // process keystrokes -- return 1 if processed, 0 if
- // command fails, and -1 if not recognized
-
- return _TECInt->ProcessKey(key, shift);
-
- }
-
- // ===================>>> vTextEditor::defaultKeyIn <<<=====================
- int vTextEditor::defaultKeyIn(vKey key, unsigned int shift)
- {
- // this is a virtual function so that it would be possible
- // to override this method to implement a modal editor like
- // vi or see.
- // Returns -1 if not processed, 1 if successful, 0 if
- // command didn't succeed.
-
- int chr = (int)key;
-
- if ((shift & VKM_Alt || shift & VKM_Ctrl)
- && (chr < ' ' || chr > 0x7E))
- return -1;
-
- if (chr < ' ' && chr != '\r' && chr != '\t' && chr != '\n')
- return -1;
-
- if (chr > 0xFE) // ignore function and alt keys
- return -1;
-
- return charInsert(key);
- }
-
- // =======================>>> vTextEditor::Find <<<=========================
- int vTextEditor::Find(char* pat, int caseSensitive, int Down, int Wrap)
- {
- // Copy a new pattern to the pattern buffer
-
- char *fp = pat;
- int ix;
- for (ix = 0 ; *fp && ix < MAX_LINE ; )
- theFindPat[ix++] = *fp++;
- theFindPat[ix] = 0;
-
- return FindNext(caseSensitive, Down, Wrap); // now use findNext
- }
-
- // =====================>>> vTextEditor::FindNext <<<=======================
- int vTextEditor::FindNext(int caseSensitive, int Down, int Wrap)
- {
- // find a pattern = return 1 if found, 0 if not
-
- BUFFPTR findBP = curchr;
- char* foundAt;
- int ix;
- int lineOffset = 0;
-
- char workPat[MAX_LINE + 2]; // working pattern
- char workLine[MAX_LINE + 2]; // working line
-
- long findLine = curlin;
- long origLine = curlin;
-
- if (lastLineBF() < 1)
- return 0;
-
- int patLen = strlen(theFindPat);
-
- for (ix = 0 ; theFindPat[ix] != 0 ; ++ix)
- {
- if (caseSensitive)
- workPat[ix] = theFindPat[ix];
- else
- workPat[ix] = tolower(theFindPat[ix]);
- }
- workPat[ix] = 0;
-
- //@@@ just down for now...
-
- for ( ; ; )
- {
- lineOffset = findBP - GLine(findLine); // if not at beginning
- for (ix = 0 ; ix < MAX_LINE && GCh(findBP) != 0 ; ++findBP, ++ix)
- {
- if (caseSensitive)
- workLine[ix] = GCh(findBP);
- else
- workLine[ix] = tolower(GCh(findBP));
- }
- workLine[ix] = 0;
-
- foundAt = strstr(workLine,workPat); // see if in there
-
- if (foundAt != 0) // We found it!
- {
- ClearMarkRange(); /* no range now */
- curlin = findLine;
- int offset = foundAt - &workLine[0];
-
- curchr = GLine(curlin) + offset + lineOffset;
-
- // set up mark range
- mark.beg_lin = mark.end_lin = curlin;
- mark.beg_col = col_pos(curchr,0);
- mark.end_col = col_pos(curchr+patLen,0);
- mark.beg_chr = curchr;
- mark.end_chr = curchr + patLen;
-
- if (!state.findAtBeginning)
- curchr += patLen; // leave at end
-
- // need intelligent screen updating
- update(curlin - origLine);
- return 1;
- }
- if (findLine >= lastLine)
- {
- StatusMessage(" Pattern Not Found");
- return 0;
- }
- else
- {
- findLine++;
- findBP = GLine(findLine);
- }
-
- }
- StatusMessage(" Pattern Not Found");
- return 0;
- }
-
- // =======================>>> vTextEditor::HPage <<<========================
- void vTextEditor::HPage(int shown, int top)
- {
- vTextCanvasPane::HPage(shown, top);
- }
-
- // =======================>>> vTextEditor::VPage <<<========================
- void vTextEditor::VPage(int shown, int top)
- {
-
- #ifndef PAGEandMOVE
- long target;
- if (lastLineBF() < 1 || lastLine <= GetRows())
- {
- setScrollBar();
- return;
- }
- if ((top+shown) >= 100)
- target = lastLine;
- else if (top < 1)
- target = 1;
- else
- target = ((long)top * lastLine) / 100;
-
- if (target < 1)
- target = 1;
- if (target > lastLine)
- target = lastLine;
- if (scroll_lin < 0)
- scrollDown(target - curlin);
- else
- scrollDown(target-scroll_lin);
- #else
- // this code moves cursor on scroll bar page - not what we really want
-
- if (lastLineBF() < 1 || lastLine <= GetRows())
- {
- setScrollBar();
- return;
- }
- if ((top+shown) >= 100)
- curlin = lastLine;
- else if (top < 1)
- curlin = 1;
- else
- curlin = ((long)top * lastLine) / 100;
-
- if (curlin < 1)
- curlin = 1;
- if (curlin > lastLine)
- curlin = lastLine;
-
- curchr = GLine(curlin); // have to update this, too!
-
- // Some tricky stuff to put the cursor in the middle.
- int old_ddline = ddline;
- if (lastLine > GetRows())
- ddline = GetRows() / 2;
- else
- ddline = lastLine / 2;
- if (ddline < 1)
- ddline = 1;
- newscr();
- tvxy(findX(),tvy); /* reset cursor to current position */
- ddline = old_ddline;
-
- setScrollBar(); // MUST do this!
- ChangeLoc(curlin,col_pos(curchr,0));
- #endif
- }
-
- // =====================>>> vTextEditor::HScroll <<<========================
- void vTextEditor::HScroll(int step)
- {
- vTextCanvasPane::HScroll(step);
- }
-
- // =====================>>> vTextEditor::VScroll <<<========================
- void vTextEditor::VScroll(int step)
- {
- if (step < 0)
- scrollDown(-1);
- else
- scrollDown(1);
- }
-
- // =====================>>> vTextEditor::FontChanged <<<====================
- void vTextEditor::FontChanged(VCONST vFont& newFont)
- {
- vTextCanvasPane::FontChanged(newFont);
- }
-
- // ====================>>> vTextEditor::TextMouseDown <<<===================
- void vTextEditor::TextMouseDown(int row, int col, int button)
- {
-
- if (button != 1) // ignore right button moves
- {
- vTextCanvasPane::TextMouseDown(row, col, button);
- return;
- }
- mouseMoveRow = mouseRow = row + 1; // convert to 1,1 corner
- mouseMoveCol = mouseCol = col + 1;
- MouseMoveTo(mouseRow,mouseCol); // doing the move at mouse down
- // makes selections easier
- setScrollBar();
- ClearMarkRange(); // forces deselect
-
- }
-
- // ======================>>> vTextEditor::TextMouseUp <<<===================
- void vTextEditor::TextMouseUp(int r, int c, int button)
- {
- if (button != 1) // ignore right button moves
- {
- vTextCanvasPane::TextMouseUp(r, c, button);
- return;
- }
-
- if (mouseRow <= 0 || mouseCol <= 0)
- return;
-
- if (curlin < 1 || GetCols() < 1 || lastLineBF() < 1)
- return;
-
- int row = r + 1; // convert to 1,1 corner
- int col = c + 1;
-
-
- if (mouseRow != row || mouseCol != col) // selection
- {
- // @@@ This code actually needs to copy the selection
- // to the clipboard on X, and does nothing on Win
- // except enable the Cut/Copy menu item
- }
-
- }
-
- // ======================>>> vTextEditor::MouseMoveTo <<<=================
- void vTextEditor::MouseMoveTo(int row, int col)
- {
-
- // used by MouseUp and MouseMove to update cursor location
- if (scroll_lin < 0) // regular move
- {
- int cnt = row - tvdlin;
- if (cnt != 0) // difference
- lineDownBeg((long)cnt,0); // changing
- else
- lineBeginning(); // same row
- }
- else // switching position to scroll window
- {
- curlin = maxl((long)1,minl(scroll_lin + row - 1,lastLine));
- curchr = GLine(curlin);
- }
- // now move to column
-
- while (!IsEndLine(GCh(curchr)) && col > findX() )
- {
- ++curchr;
- }
- if (scroll_lin < 0) /* regular move */
- {
- tvhdln();
- }
- else /* need to verify since things can be off */
- {
- scroll_lin = -1;
- long old_ddline = ddline; // trick - terrible awful coding, but...
- ddline = row;
- newscr();
- int xf = findX();
- tvxy(xf,tvy); /* reset cursor to current position */
- ddline = old_ddline;
- }
- b_lastln = curlin;
- ChangeLoc(curlin,col_pos(curchr,0));
- }
-
- // ======================>>> vTextEditor::TextMouseMove <<<=================
- void vTextEditor::TextMouseMove(int r, int c, int button)
- {
-
- if (button != 1) // ignore right button moves
- {
- vTextCanvasPane::TextMouseMove(r, c, button);
- }
- else // highlighting text
- {
- if (mouseRow <= 0 || mouseCol <= 0)
- return;
-
- if (curlin < 1 || GetCols() < 1 || lastLineBF() < 1)
- return;
-
- int row = r + 1; // convert to 1,1 corner
- int col = c + 1;
-
- if (mouseMoveRow != row) // have moved a row down or up
- {
- if (row > mouseMoveRow) // moved down
- {
- int cnt = row - mouseMoveRow;
- AddToRangeRow(cnt, row, col); // add rows
- mouseMoveRow = row;
- // and update to columns
- AddToRangeCol(row, col);
- mouseMoveCol = col;
- }
- else // moving mouse up rows
- {
- int cnt = row - mouseMoveRow;
- AddToRangeRow(cnt, row, col); // add rows
- mouseMoveRow = row;
- // and update to columns
- AddToRangeCol(row, col);
- mouseMoveCol = col;
- }
-
- }
- else if (mouseMoveCol != col) // mouse to right of start
- {
- AddToRangeCol(row, col);
- mouseMoveCol = col;
- }
- }
- }
-
- // =========================>>> vTextEditor::AddToRangeCol <<<=================
- void vTextEditor::AddToRangeCol(int row, int col)
- {
-
- if (col_pos(curchr,0) < col) // add to right
- {
- if (mark.beg_lin == 0) /* no lines yet */
- {
- mark.end_lin = mark.beg_lin = curlin;
- mark.end_chr = mark.beg_chr = curchr;
- mark.end_col = mark.beg_col = col_pos(curchr,0);
- while (!IsEndLine(GCh(curchr))
- && col_pos(curchr,0) < col) // find new col
- charRight(1,0);
- mark.end_chr = curchr;
- mark.end_col = col_pos(curchr,0);
- }
- else if (mark.end_lin < curlin)
- {
- mark.end_lin = curlin;
- mark.end_chr = curchr;
- mark.end_col = col_pos(curchr,0);
- }
- else if (mark.beg_lin == curlin && mark.end_lin == curlin
- && col_pos(curchr,0) > mark.end_col)
- {
- mark.beg_col = mark.end_col;
- mark.beg_chr = mark.end_chr;
- mark.end_chr = curchr;
- mark.end_col = col_pos(curchr,0);
- }
- else if (mark.beg_lin == curlin && // some of this line marked
- ((mark.end_lin == curlin && col_pos(curchr,0) < mark.end_col)
- || mark.end_lin != mark.beg_lin))
- {
- while (!IsEndLine(GCh(curchr))
- && col_pos(curchr) < col) // find new col
- charRight(1,0);
- mark.beg_col = col_pos(curchr,0);
- mark.beg_chr = curchr;
- }
- else // normal add to marked
- {
- while (!IsEndLine(GCh(curchr))
- && col_pos(curchr) < col) // find new col
- charRight(1,0);
-
- mark.end_lin = curlin;
- mark.end_chr = curchr;
- mark.end_col = col_pos(curchr,0);
- }
- }
- else // add to left
- {
- if (mark.beg_lin == 0) // no lines yet, so note it
- {
- if (curchr == GLine(curlin))
- return; // No op at line beginning
- mark.end_lin = mark.beg_lin = curlin;
- mark.end_chr = mark.beg_chr = curchr;
- mark.end_col = mark.beg_col = col_pos(curchr,0);
- while (col_pos(curchr) > col) // find new col
- charRight(-1,0);
- mark.beg_chr = curchr;
- mark.beg_col = col_pos(curchr,0);
-
- }
- else if (mark.end_lin < curlin)
- {
- mark.end_lin = curlin;
- mark.end_chr = curchr;
- mark.end_col = col_pos(curchr,0);
- }
- else if (mark.end_lin == curlin && // some of this line marked
- ((mark.beg_lin == curlin && col_pos(curchr,0) > mark.beg_col)
- || mark.beg_lin != curlin))
- {
- // handles two cases: highlight on current line only,
- // or highlight starts on some line before
- while (col_pos(curchr) > col) // find new col
- charRight(-1,0);
- mark.end_col = col_pos(curchr,0);
- mark.end_chr = curchr;
- }
- else if (mark.end_lin == curlin // some of this line marked
- && col_pos(curchr,0) > mark.beg_col)
- {
- while (col_pos(curchr) > col) // find new col
- charRight(-1,0);
- mark.end_col = col_pos(curchr,0);
- mark.end_chr = curchr;
- }
- else // normal add to marked
- {
- while (col_pos(curchr) > col) // find new col
- charRight(-1,0);
-
- mark.beg_lin = curlin;
- mark.beg_chr = curchr;
- mark.beg_col = col_pos(curchr,0);
- }
- }
-
- tvxy(1,tvy); // Finally, fix up the highlight
- type_lines(curlin, 1); // by repainting current line
- tvhdln(); // and rehome cursor
- ((vWindow *)_parent)->SetValue(M_Cut, 1, Sensitive);
- ((vWindow *)_parent)->SetValue(M_Copy, 1, Sensitive);
- }
-
- // =========================>>> vTextEditor::AddToRangeRow <<<=================
- void vTextEditor::AddToRangeRow(long cnt, int row, int col)
- {
- /* add to mark range varaiable, update current line, then go down */
- if (cnt == 0)
- {
- ClearMarkRange(); /* no range now */
- return;
- }
-
- if (cnt > 0)
- {
- if (curlin + cnt > lastLine) /* past end? */
- cnt = lastLine - curlin + 1;
- if (mark.beg_lin == 0) /* no lines yet */
- {
- mark.beg_lin = curlin;
- mark.beg_chr = curchr;
- mark.beg_col = col_pos(curchr,0);
- }
- if (mark.end_lin == 0)
- {
- mark.end_lin = curlin + cnt - 1;
- }
- else if (mark.beg_lin == curlin // some of this line marked
- && mark.end_lin != mark.beg_lin)
- {
- if (mark.end_lin == curlin + cnt
- && col_pos(curchr,0) > mark.end_col)
- {
- mark.beg_lin = curlin + cnt;
- mark.beg_col = mark.end_col;
- mark.beg_chr = mark.end_chr;
- }
- else
- {
- mark.beg_col = col_pos(curchr,0);
- mark.beg_chr = GLine(curlin+cnt); // Something legal
- mark.beg_lin = curlin + cnt;
- }
- }
- else
- {
- mark.end_lin += cnt;
- mark.end_col = 1000; /* BIG */
- mark.end_chr = 0; /* end of line */
- }
-
- /* paint the lines to highlight */
- if (tvdlin+cnt-1 <= GetRows())
- {
- tvxy(1,tvy); /* fix it up */
- type_lines(curlin,(int)cnt);
- }
-
- if (curlin == lastLine && cnt > 0) /* down from last line? */
- {
- return;
- }
- lineDown(cnt,0);
-
- }
- else if (cnt < 0) // up lines
- {
- if (curlin + cnt < 1) // past start?
- cnt = -curlin;
- if (mark.end_lin == curlin && mark.beg_lin == curlin
- && mark.end_lin != 0)
- {
- mark.end_col = mark.beg_col;
- mark.end_chr = mark.beg_chr;
- lineDown(cnt,0);
- mark.beg_lin = curlin;
- mark.beg_col = col_pos(curchr,0);
- mark.beg_chr = curchr;
- }
- else
- {
- if (mark.end_lin == 0) //no lines yet
- {
- mark.beg_lin = mark.end_lin = curlin;
- mark.end_chr = curchr;
- mark.end_col = col_pos(curchr,0);
- mark.beg_col = 1;
- mark.beg_chr = GLine(curlin);
- }
-
- if (mark.end_lin == curlin // some of this line marked
- && mark.end_lin != mark.beg_lin)
- {
- if (mark.beg_lin == curlin + cnt
- && col_pos(curchr,0) < mark.beg_col)
- {
- mark.end_lin = curlin + cnt;
- mark.end_col = mark.beg_col;
- mark.end_chr = mark.beg_chr;
- lineDown(cnt,0);
- mark.beg_col = col_pos(curchr,0);
- mark.beg_chr = curchr;
- }
- else
- {
- lineDown(cnt,0);
- mark.end_col = col_pos(curchr,0);
- mark.end_chr = GLine(curlin+cnt); // Something legal
- mark.end_lin = curlin;
- }
- }
- else
- {
- // now move up specified number of lines, no clrRange
- lineDown(cnt, 0);
-
- mark.beg_lin = curlin;
- mark.beg_chr = curchr;
- mark.beg_col = col_pos(curchr,0);
- }
- }
-
- /* paint the lines to highlight */
- tvxy(1,tvy); /* fix it up */
- type_lines(curlin,(int)-cnt+1);
- tvhdln();
- }
- ((vWindow *)_parent)->SetValue(M_Cut, 1, Sensitive);
- ((vWindow *)_parent)->SetValue(M_Copy, 1, Sensitive);
- }
-
-
- // =========================>>> vTextEditor::Redraw <<<=====================
- void vTextEditor::Redraw(int x, int y, int w, int h)
- {
- vTextCanvasPane::Redraw(x,y,w,h);
- }
-
- // ======================>>> vTextEditor::ResizeText <<<====================
- void vTextEditor::ResizeText(const int rows, const int cols)
- {
- Verify();
- }
-
- // #########################################################################
- //
- // screen update stuff - maps old see/tv to vTextCanvasPane methods
- //
- // #########################################################################
-
- // =========================>>> vTextEditor::tvxy <<<=======================
- void vTextEditor::tvxy(int ix, int iy)
- {
- // tvxy - position cursor at position x,y
- // x=1 is left most column
- // y=1 is top most line
-
- tvx = ix;
- tvy = iy;
- if (!state.echof)
- return;
- GotoRC(iy-1,ix-1); // Convert to 0,0 based coords
- }
-
- // =========================>>> vTextEditor::tvplin <<<=====================
- void vTextEditor::tvplin(long lineNum, BUFFPTR chrptr, int whole_line,
- int hibeg, int hiend)
- { /* tvplin - put line beginning at chrptr
- will only type what will fit on screen (using xout) */
-
- char tmp;
- int linlen, origx, need_hi_end;
-
- int hiStart = -1;
- int hiLast = -1;
-
- BUFFPTR i;
-
- char linout[MAX_LINE+1];
-
- need_hi_end = 0;
-
- last_col_out = linptr = 0;
- origx = xoutcm; /* save x so can get true linelen */
- for (i = chrptr; !IsEndLine(GCh(i)) && xoutcm < MAX_LINE; ++i)
- {
- /* xoutcm has current column. If a hilite goes here,
- add to the linout array as 0x01 or 0x02.
- */
- if (xoutcm == hibeg)
- {
- hiStart = linptr; // where highlight starts
- need_hi_end = 1; /* will need a follow */
- }
- if (xoutcm == hiend)
- {
- hiLast = linptr; // where highlight ends
- need_hi_end = 0; /* don't need a follow now */
- }
- if (GCh(i) < ' ' && GCh(i) >= 0) /* control character? */
- {
- if (GCh(i) == '\t')
- {
- if (state.tabspc > 0)
- {
- do
- {
- linout[linptr++] = ' '; /* replace with blanks */
- ++xoutcm;
- }
- while ( ((xoutcm-1) % state.tabspc) != 0);
- }
- else
- {
- linout[linptr++] = '^';
- linout[linptr++] = 'I';
- xoutcm += 2;
- linout[linptr++] = '*';
- ++xoutcm;
- }
- continue;
- }
- else /* other control character */
- {
- linout[linptr++] = '^';
- ++xoutcm;
- if (xoutcm == GetCols() && !(IsEndLine(GCh(i))) )
- continue;
- tmp = GCh(i) + '@';
- linout[linptr++] = tmp;
-
- }
- } /*# end if control character */
- else
- {
- linout[linptr++] = GCh(i);
- }
- ++xoutcm;
- }
-
- if (need_hi_end)
- {
- hiLast = linptr;
- need_hi_end = 0; /* don't need a follow now */
- }
-
- linout[linptr] = 0; // terminate the line
-
- int lineStart = 0;
-
- // This whole line stuff is left over. I don't know exactly what it
- // did, but it breaks repainting when the margin is shifted, so just
- // ignore the whole_line value... BEW: 10/1/98
-
- //@ if (whole_line) /* write whole line */
- {
- last_col_out = linlen = mint(GetCols(),linptr-leftmg+1);
- lineStart = leftmg - 1;
- }
- #ifdef XXXXX
- else // just part of line
- {
- linlen = mint(GetCols()-origx+1,linptr);
- last_col_out = linlen + origx - 1;
- lineStart = 0;
- }
- #endif
-
- if (linlen > 0)
- paintLine(linout, lineStart, hiStart, hiLast, lineNum);
-
- }
-
- // ======================>>> vTextEditor::paintLine <<<=====================
- void vTextEditor::paintLine(char* linout, int lineStart,
- int hiStart, int hiLast, long lineNum)
- {
- // paint a line. This can be overridden (e.g., for syntax highlighting).
- // linout: the line to output with tabs converted to spaces, etc.
- // lineStart: where to begin printing the line (for hoiz. scrolling)
- // hiStart, hiLast: reverse text attribute
- // lineNum: the real line number in the buffer this is. This is unused
- // normally, but can be used for syntax highlighting to get
- // surrounding context.
-
- int linlen = strlen(linout);
- if (linlen > 0) // only draw if there!
- {
- char tmpChr; // to hold char
-
- if (hiStart < lineStart && hiLast < lineStart) // no highlight
- {
- DrawText(&linout[lineStart]); // simple case
- }
- else // has highlighting
- {
- if (hiStart > lineStart) // highlight from beginning
- {
- tmpChr = linout[hiStart]; // remember char
- linout[hiStart] = 0;
- DrawText(&linout[lineStart]); // normal part
- linout[hiStart] = tmpChr; // replace
- }
-
- tmpChr = linout[hiLast]; // remember char
- linout[hiLast] = 0; // make end of string
- DrawAttrText(&linout[hiStart],ChHighlight); // highlight part
- linout[hiLast] = tmpChr; // replace
-
- if (linlen > hiLast) // rest of line
- DrawText(&linout[hiLast]);
- }
- }
- }
-
-
- // ====================>>> vTextEditor::type_lines <<<======================
- void vTextEditor::type_lines(long ibeg, int icnt)
- { /* type_lines - type icnt lines starting at lines[ibeg]
- no cr/lf on the last line */
-
- long i, lim;
- int hibeg, hiend;
- BUFFPTR start;
-
- if (!state.echof)
- return;
- if (ibeg < 1 || ibeg > lastLine)
- return;
- xoutcm = tvx;
- lim = ibeg+icnt-1;
-
- for (i = ibeg ; i <= lim && i <= lastLine ; ++i)
- {
- /* simple check for whole line highlighting for now */
- if (i == mark.beg_lin)
- {
- hibeg = mark.beg_col;
- if (i == mark.end_lin)
- hiend = mark.end_col;
- else
- hiend = 1000;
- }
- else if (i >= mark.beg_lin && i <= mark.end_lin)
- {
- hibeg = 1;
- if (i == mark.end_lin)
- hiend = mark.end_col;
- else
- hiend = 1000;
- }
- else
- {
- hibeg = hiend = -1;
- }
-
- start = GLine(i);
- tvplin(i,start,1,hibeg, hiend); /* type out a wole line */
- xoutcm = 1;
- if (last_col_out < GetCols())
- tvelin(); /* erase rest of line */
- if ( i != lim )
- tvxy(1,++tvy);
- }
- }
-
- // =========================>>> vTextEditor::Verify <<<=====================
- void vTextEditor::Verify(void)
- { // Verify - rewrite the screen or type current line with cursor
-
- int xf, old_ddline;
-
- if (!state.echof)
- return;
-
- if (lastLineBF() < 1)
- {
- tvclr();
- return;
- }
- old_ddline = ddline;
- ddline = dsplin;
- newscr();
- xf = findX();
- tvxy(xf,tvy); /* reset cursor to current position */
- ddline = old_ddline;
- ChangeLoc(curlin,col_pos(curchr,0));
- setScrollBar();
- }
-
- // =====================>>> vTextEditor::tvbotb <<<=========================
- void vTextEditor::tvbotb(int n)
- { // tvbotb - make n blank lines at the bottom of the screen
-
- if (!state.echof)
- return;
- if (n >= GetRows())
- {
- tvclr();
- }
- else
- {
- tvxy(1,GetRows()); /* go to real last line */
-
- ScrollText(n);
- int j = GetRows()-n+1; /* home to virtual last line */
- tvxy(1,j); /* position at first new blank line */
- }
- }
-
- // ==========================>>> vTextEditor::tvclr <<<==========================
- void vTextEditor::tvclr(void)
- { // tvclr - clear the entire screen and home
-
- if (!state.echof)
- return;
- Clear();
- tvxy(1,1);
- tvx = tvy = 1;
- }
-
- // ========================>>> vTextEditor::tvelin <<<======================
- void vTextEditor::tvelin(void)
- { // tvelin - erase the rest of the current line
-
- if (!state.echof)
- return;
- int r,c;
- GetRC(r,c);
- ClearRow(r, c);
- }
-
- // ========================>>> vTextEditor::tvescr <<<======================
- void vTextEditor::tvescr(void)
- { // tvelin - erase from cursor to end of screen
-
- if (!state.echof)
- return;
- ClearToEnd(tvy-1, tvx - 1);
- }
-
- // ==========================>>> vTextEditor::tvtopb <<<====================
- void vTextEditor::tvtopb(int n)
- { // tvtopb - create n blank lines at the top of the screen
-
- if (!state.echof)
- return;
-
- tvxy(1,1); /* home first */
- if ( n >= GetRows())
- {
- tvescr(); /* simply erase the screen */
- }
- else
- {
- ScrollText(-n);
- }
- tvxy(1,1); /* home first */
- }
-
- // =======================>>> vTextEditor::bufferBottom <<<=================
- void vTextEditor::bufferBottom(void)
- { // bufferBottom - move cursor to bottom of current buffer
-
- if (lastLineBF() < 1)
- return;
-
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- curlin = lastLine; /* the last real line of text */
- curchr = GLine(curlin); /* the first char of that line */
- lineEnd(); /* goto end of the line */
- newscr(); /* update the screen */
- }
-
- // #########################################################################
- //
- // char methods
- //
- // #########################################################################
-
- // =======================>>> vTextEditor::charDelete <<<===================
- int vTextEditor::charDelete(long cnt)
- { // charDelete - delete next cnt characters
-
- static char chdel;
- int abscnt,newx;
- int i;
-
- if (state.readOnly || lastLineBF() < 1)
- return 0;
-
- checkIfScrolled();
- if (RemoveMarkRange()) /* there was a range to kill */
- return 1;
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- abscnt = (cnt > 0) ? cnt : (-cnt); /* remember absolute value of cnt */
-
- state.changes += abscnt; /* track changes */
-
- if (cnt < 0)
- charRight(cnt,0);
-
- for (i = 0 ; i < abscnt ; ++i)
- {
- chdel = GCh(curchr); /* remember the char we are deleting */
- curchr = deleteCharBF(curchr,curlin);
- if (curchr == 0)
- return 0;
- if (!IsEndLine(chdel))
- {
- retypeCurlin(1); // just retype current line
- }
- else
- {
- lastLine = lastLineBF();
- if (tvdlin < dsplin) // not at end
- {
- tvescr(); /* erase rest of screen */
- tvxy(1,tvy); /* fix it up */
- type_lines(curlin,mint((int)(GetRows() - tvdlin+1),
- (int)(lastLine - curlin)) );
- newx = findX(); /* where cursor will go */
- tvxy(newx,tvy); /* reposition cursor */
- }
- else /* at end of buffer */
- Verify();
- }
- }
-
- ChangeLoc(curlin,col_pos(curchr,0));
- return 1;
- }
-
- //=====================>>> vTextEditor::charFoldCase <<<====================
- int vTextEditor::charFoldCase(long cnt)
- {
- /* fold from upper to lower or lower to upper case if letter */
- int ni;
- char fchr;
-
- if (state.readOnly)
- return 0;
-
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- for (ni = 0 ; ni < cnt ; ++ni)
- {
- fchr = GCh(curchr); /* get current character */
- if (fchr >= 'a' && fchr <= 'z')
- fchr = cupper(fchr);
- else if (fchr >= 'A' && fchr <= 'Z')
- fchr = clower(fchr);
- if (IsEndLine(fchr))
- charRight((long)1,1);
- else
- {
- if (!charDelete((long) 1)) /* delete cur character */
- return 0;
- if (!charInsert((int)fchr)) /* and put back */
- return 0;
- }
- }
- return 1;
- }
-
- // ====================>>> vTextEditor::charInsert <<<======================
- int vTextEditor::charInsert(int ival)
- {
- int xf;
- int force_tidy;
- int chr;
-
- if (state.readOnly)
- return 0;
- checkIfScrolled();
- RemoveMarkRange(); /* no range now */
- wasColCmd = 0;
-
- chr = ival; /* use the passed value */
-
- ++state.changes; /* count changes */
-
- if (lastLineBF() == 0) // First actual insert!
- {
- char ln1[4];
- resetBuff();
- if (chr == '\n') // this effecitvely is two lines!
- {
- ln1[0] = 0;
- addLine(ln1);
- addLine(ln1);
- tvdlin = 2;
- displayBuff(1); // get a proper display
- }
- else
- {
- ln1[0] = chr;
- ln1[1] = 0;
- addLine(ln1);
- if (!_lines[1])
- return 0;
- curlin = 1;
- curchr = _lines[1] + 1;
- tvdlin = 1;
- displayBuff(1); // get a proper display
- lineEnd(); // move to end of the line
- }
- setScrollBar();
- return 1;
- }
-
- if (!state.ins_mode) // overtype mode?
- {
- if (!charDelete(1)) // delete nextchar
- return 0;
- }
-
- if (chr == '\r')
- chr = '\n'; // this is our convention
-
- if (chr == 0)
- chr = ' ';
-
- if (!insertCharBF(chr, curchr, curlin))
- return 0;
- lastLine = lastLineBF(); // update this one
-
- if (chr != '\n')
- {
- retypeCurlin(0); // just retype whole line
- }
- else
- {
- long dummy1; int dummy2;
- FindDispLine(dummy1,dummy2);
- if (tvdlin < dsplin) // not at end
- {
- tvescr(); /* erase rest of screen */
- tvxy(1,tvy); /* fix it up */
- type_lines(curlin,mint((int)(GetRows() - tvdlin + 1),
- (int)(lastLine - curlin)) );
- }
- else /* at end of buffer */
- Verify();
- setScrollBar();
- tvhdln(); /* home to display line */
- xf = findX();
- tvxy(xf,tvy); /* reset cursor to current position */
- }
-
- ChangeLoc(curlin,col_pos(curchr,0));
-
- return 1;
- }
-
- // ====================>>> vTextEditor::retypeCurlin <<<======================
- void vTextEditor::retypeCurlin(int eraseLine)
- {
- if (!state.echof)
- return;
- if (eraseLine)
- tvelin();
- tvxy(1,tvy);
- tvtyln(curlin,GLine(curlin), curchr == GLine(curlin));
- tvhdln(); // home to display line
- int xf = findX();
- tvxy(xf,tvy); // reset cursor to current position
- }
-
- // ====================>>> vTextEditor::charRight <<<======================
- int vTextEditor::charRight(long cnt, int clear_mark)
- { // charRight: move cursor right cnt characters
- // newlines count as one character
-
- long change;
- int i, rv;
-
- if (lastLineBF() < 1)
- return 0;
- if (cnt == 0)
- return 1;
-
- checkIfScrolled();
- if (clear_mark)
- ClearMarkRange(); /* no range now */
-
- wasColCmd = 0;
-
- rv = 1; /* assume success */
- change = 0; /* no change yet */
- if (cnt > 0) /* moving right */
- {
- for (i = 1 ; i <= cnt ; ++i)
- {
- if (IsEndLine(GCh(curchr))) /* at end of line */
- {
- if (curlin >= lastLine)
- {
- rv = 0;
- break; /* don't go beyond end! */
- }
- ++curlin;
- ++change; /* we've gone down one line */
- curchr = GLine(curlin);
- }
- else
- ++curchr;
- }
- }
- else if (cnt < 0) /* moving left */
- {
- cnt = (-cnt); /* fix this */
- for (i = 1 ; i <= cnt ; ++i)
- {
- if (curchr == GLine(curlin)) /* at front */
- {
- if (curlin > 1) /* can only go up on >= line 2 */
- {
- --curlin;
- --change;
- for (curchr = GLine(curlin) ;
- !IsEndLine(GCh(curchr)) ;
- ++curchr)
- ; /* bump curchr to end of the line */
- }
- else
- {
- rv = 0;
- break; /* don't go beyond front! */
- }
- }
- else
- --curchr;
- }
- }
- if (change != 0) /* don't do unnecessary change */
- update(change);
- if (clear_mark)
- ChangeLoc(curlin,col_pos(curchr,0));
- tvhdln();
- return rv;
- }
-
- // #########################################################################
- //
- // line methods
- //
- // #########################################################################
-
- // ===================>>> vTextEditor::lineBeginning <<<====================
- void vTextEditor::lineBeginning()
- { /* lineBeginning - move cursor to beginning of current line */
-
- int xf;
-
- if (lastLineBF() < 1)
- return;
-
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- curchr = GLine(curlin); /* point to current character */
- xf = findX(); /* this line needed to make the next */
- /* call eval order independent, if you wondered */
- tvxy(xf,tvy); /* and move cursor */
- ChangeLoc(curlin,col_pos(curchr,0));
- }
-
- // =====================>>> vTextEditor::lineDelete <<<=====================
- void vTextEditor::lineDelete(long cnt)
- { // lineDelete - delete cnt lines
-
- int ityp;
-
- long line_1, last_line; /* range of lines to kill */
- long istrt;
-
- if (state.readOnly || lastLineBF() < 1)
- return;
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- if (cnt == 0)
- return;
-
- if (cnt < 0) /* negative kill */
- {
- cnt = minl(-cnt,curlin-1); /* all upwards? */
- lineDownBeg(-cnt,0); /* go up that far */
- }
-
- if (cnt != 0)
- {
- range(cnt,&line_1,&last_line); /* calculate the line numbers to kill */
-
- curlin = line_1; /* remember new current line */
-
- SaveKillLine(last_line); /* save one line */
-
- ++state.changes; /* count changes */
- lastLine = deleteLinesBF(line_1,last_line); /* delete the lines from the buffer(s) */
-
- if (lastLine < curlin)
- curlin = lastLine; /* don't go past end */
-
- curchr = GLine(curlin); /* remember new current character */
-
- if (cnt >= 0 && curlin+(GetRows() - tvdlin) <= lastLine &&
- tvdlin < GetRows()) /* killing down */
- {
- tvxy(1,tvy); /* get to start of line */
- ityp = (int) minl((long)(GetRows()-tvdlin+1),lastLine - curlin + 1);
- tvescr(); /* erase the screen */
- istrt = curlin;
- type_lines(istrt, ityp);
- tvhdln(); /* home to display line */
- }
- else
- Verify(); /* kill up, retype screen */
- }
- ChangeLoc(curlin,col_pos(curchr,0));
- }
-
- // =====================>>> vTextEditor::lineDeleteFront <<<===============
- int vTextEditor::lineDeleteFront(void)
- { // lineDeleteFront - delete from cursor to beginning of line
-
- int chrs;
-
- if (state.readOnly || lastLineBF() < 1)
- return 0;
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- SaveKillLine(curlin); /* save one line */
- chrs = curchr - GLine(curlin); /* how much to delete */
- if (chrs > 0)
- return charDelete((long)(-chrs)); /* won't cause a combine, so don't worry */
- return 1;
- }
-
- // =====================>>> vTextEditor::lineDeleteToEnd <<<===============
- int vTextEditor::lineDeleteToEnd(void)
- { // lineDeleteToEnd:
- // kill the rest of the line, not including cursor and endLine
-
- int chrs;
- BUFFPTR i;
-
- if (state.readOnly || lastLineBF() < 1)
- return 0;
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- SaveKillLine(curlin); /* save one line */
- chrs = 0;
- for (i = curchr; !IsEndLine(GCh(i)) ; ++i)
- ++chrs; /* count how much to delete */
- if (chrs > 0)
- return charDelete((long) chrs); /* won't cause combine, so don't worry */
- return 1;
- }
-
- // ========================>>> vTextEditor::lineDown <<<====================
- int vTextEditor::lineDown(long cnt, int clrRange)
- { /* lineDown - move down in column */
-
- int curcol,l,oldef,needns,ic,ix,lim,rv;
-
- if (lastLineBF() < 1)
- return 0;
- if (clrRange)
- ClearMarkRange(); /* no range now */
-
- oldef = state.echof;
- needns = 0;
- if (leftmg > 1) /* handle right virtual screen different */
- {
- needns = 1;
- }
-
- if (wasColCmd) // going up/down columnwise
- curcol = oldcol;
- else
- oldcol = curcol = col_pos(curchr,1); /* calculate the current column */
-
- rv = lineDownBeg(cnt,0,clrRange); /* go down given lines, update screen */
-
- state.echof = 0;
-
- if (curlin >= 1 && curlin <= lastLine && curcol > 1) /* not at ends? */
- {
- l = lineLenBF(curlin);
- lim = mint(curcol-1,l);
- for (ix = 0, ic = col_pos(curchr,1) ; ix < lim && ic < curcol ;
- ++ix, ic = col_pos(curchr,1))
- ;
- charRight((long)ix,clrRange);
- }
-
- state.echof = oldef;
- if (needns) /* needed new screen */
- {
- Verify();
- }
- else
- tvhdln();
- ChangeLoc(curlin,col_pos(curchr,0));
- wasColCmd = 1;
- return rv;
- }
-
- // ====================>>> vTextEditor::lineDownBeg <<<=====================
- int vTextEditor::lineDownBeg(long cnt, int notify, int clrRange)
- { /* lineDownBeg - move dot down cnt lines */
-
- long oldlin,change;
-
- if (lastLineBF() < 1)
- return 0;
- if (clrRange)
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- if (curlin == lastLine && cnt > 0) /* down from last line? */
- {
- lineEnd();
- return 0; /* make loops fail */
- }
- oldlin = curlin; /* remember where we started from */
- if (curlin + cnt < 1)
- curlin = 1;
- else if (curlin + cnt > lastLine)
- curlin = lastLine;
- else
- curlin = curlin + cnt;
- curchr = GLine(curlin); /* point to the current character */
- change = curlin-oldlin; /* calculate how many lines changed */
- update(change); /* update the screen */
- if (notify)
- ChangeLoc(curlin,col_pos(curchr,0));
- return change != 0;
- }
-
- // =====================>>> vTextEditor::lineEnd <<<========================
- void vTextEditor::lineEnd(int clrRange)
- { // lineEnd - move cursor to end of the line
-
- int knt;
- BUFFPTR i;
-
- if (lastLineBF() < 1)
- return;
- if (clrRange)
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- knt = 0;
- for (i = curchr ; !IsEndLine(GCh(i)) ; ++i) /* find end of line */
- ++knt;
- charRight((long)knt,clrRange); /* move to end of line */
- ChangeLoc(curlin,col_pos(curchr,0));
- }
-
- // ======================>>> vTextEditor::lineOpen <<<======================
- int vTextEditor::lineOpen(long cnt)
- { // lineOpen - open a new line
-
- int i;
- long pcnt;
-
- if (state.readOnly || lastLineBF() < 1)
- return 0;
- pcnt = cnt >= 0 ? cnt : (-cnt); /* only allow positive opens */
-
- for (i=1; i<=pcnt; ++i)
- {
- if (!charInsert('\n')) /* insert right number of newlines */
- return 0;
- }
-
- lineDownBeg(-pcnt,0); /* and goto beginning of the opened line */
-
- lineEnd();
- return 1;
- }
-
- // ======================>>> vTextEditor::lineGoto <<<======================
- int vTextEditor::lineGoto(long cnt)
- { // lineGoto: move cursor to line cnt
-
- if (cnt < 0 || lastLineBF() < 1)
- return 0;
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- curlin = maxl(minl(cnt,lastLine),(long) 1); /* move to lines */
- curchr = GLine(curlin); /* point to the current character */
- Verify();
- return 1;
- }
-
- // =====================>>> vTextEditor::lineAutoFill <<<===================
- void vTextEditor::lineAutoFill(void)
- {
- BUFFPTR bx, startx;
- int lines, old_ef, old_y, ityp, go_right, cp, chr;
- long start_line, istrt;
-
- if (state.readOnly || lastLineBF() < 1)
- return;
-
- if (state.wraplm < 1)
- return; /* no auto-wrap going on */
-
- /* 1. Check if current line needs to be wrapped */
-
- startx = GLine(curlin); /* first char of line */
- bx = lastBX(curlin); /* index of last char of line */
- if (startx == bx)
- return; /* blank line, can't need tidy */
- if (col_pos(bx,0) <= state.wraplm) /* is last char beyond limit? */
- return; /* line doesn't need tidy */
-
- /* 2. If it does, figure out where the cursor is. */
-
- go_right = curchr - startx; /* where CURRENT char is */
- start_line = curlin;
- old_y = tvdlin; /* original line */
-
- /* 3. Echo off. */
-
- old_ef = state.echof;
- state.echof = 0;
-
- /* 4. Tidy down to PP or blank line or line beginning with white */
-
- for (lines = 1 ; lines < 50 && curlin <= lastLine ;
- ++lines )
- {
- lineFill((long) 1); /* fix current line */
- chr = GCh(curchr);
- if (chr == '.' || chr == ' ' || chr == '\t' || IsEndLine(chr))
- break;
- }
-
- /* 5. Restore echo */
-
- state.echof = old_ef;
-
- /* 6. Return to current line, making sure it stays where it was
- on the screen (or shift by one if it gets moved),
- and repaint the rest of the screen.
- */
-
- curlin = start_line;
- curchr = GLine(curlin);
- tvdlin = old_y;
-
- if (state.echof)
- {
- tvxy(1,old_y);
- istrt = curlin;
- ityp =(int) minl((long)(GetRows()-tvdlin+1),
- lastLine - curlin + 1);
- type_lines(istrt, ityp);
- }
-
- tvhdln(); /* home to display line */
-
- for ( ; ; )
- {
- bx = lastBX(curlin); /* see if still on this line */
- cp = col_pos(bx,0);
- if (go_right <= cp) /* on this line */
- {
- curchr = GLine(curlin) + go_right;
- break;
- }
- go_right -= cp; /* next line */
- if (!lineDownBeg((long) 1,0))
- break;
- }
- tvhdln(); /* home to display line */
- ChangeLoc(curlin,col_pos(curchr,0));
- }
-
- // =====================>>> vTextEditor::lineFill <<<=======================
- int vTextEditor::lineFill(long count)
- { // lineFill - fill lines to current margin
-
- char curline[40]; /* first part of current line */
- char* special[] = /* special keywords */
- { /* that shouldn't cause a wrap */
- " ", /* the usual non-breakers */
- "\t",
- ".",
- ""
- };
-
- int oldef, i, key_found;
- BUFFPTR linbeg, old_cc;
- int retval;
-
- if (state.readOnly || lastLineBF() < 1 || state.wraplm < 1)
- return 0; /* no auto-wrap going on */
-
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- retval = 1;
- oldef = state.echof;
- if (count > 1)
- state.echof = 0;
- if (state.wraplm <= 1 || curlin > lastLine)
- goto l900; /* work only if wrap limit turned on */
-
- for (i = 1 ; i <= count ; ++i)
- {
- lineBeginning(); /* start at beginning of line */
- if (curlin >= lastLine)
- goto l900;
-
- /* don't fill leading space, cr, period, tab, or latex keyword */
-
- getCurLine(curline,curlin); /* current line */
- key_found = 0;
- if (*curline)
- {
- for (int iy = 0 ; *special[iy] ; ++iy) /* search keyword list */
- {
- if (strstr(curline,special[iy]) == curline)
- {
- key_found = 1;
- break;
- }
- }
- }
- else
- key_found = 1;
- if (key_found)
- {
- lineDownBeg((long) 1,0);
- continue; /* skip dot commands */
- }
-
- while (curlin < lastLine)
- {
- if (IsEndLine(GCh(curchr)))
- {
- if (tvx+leftmg-1 < state.wraplm) /* combine lines! */
- {
- /* pt to first char of next line */
- linbeg = GLine(curlin+1);
- if (GCh(linbeg) == ' ' || IsEndLine(GCh(linbeg))
- || GCh(linbeg) == '\t' || GCh(linbeg) == '.')
- {
- lineDownBeg((long) 1);
- break; /* no more combining */
- }
- if (! Fill1(1,32))
- goto l990;
- /* fall thru to test for wrap */
- }
- else
- {
- lineDownBeg((long) 1); /* no more combining on line */
- break;
- }
- }
-
- old_cc = curchr;
- wordRight((long) 1);
- if (tvx+leftmg-1 > state.wraplm)
- {
- if (tvx+leftmg-2 == state.wraplm && IsEndLine(GCh(curchr)) )
- {
- lineDownBeg((long) 1);
- break;
- }
- else if ((tvx+leftmg-2 == state.wraplm ||
- tvx+leftmg-3 == state.wraplm) &&
- (GCh(curchr-1) == ' ' || GCh(curchr-1) == '\t'))
- {
- if (!Fill1(-1,'\n'))
- goto l990;
- }
- else if (GCh(old_cc-1) == ' ' ||
- GCh(old_cc-1) == '\t')
- {
- curchr = old_cc;
- if (!Fill1(-1,'\n'))
- goto l990;
- }
- else if (GCh(old_cc-2) == ' ' ||
- GCh(old_cc-2) == '\t')
- {
- curchr = old_cc-1;
- if (!Fill1(-1,'\n'))
- goto l990;
- }
- else if (IsEndLine(GCh(curchr)) )
- {
- lineDownBeg((long) 1);
- break;
- }
- else if (GCh(curchr-1) == ' ' ||
- GCh(curchr-1) == '\t')
- {
- if (!Fill1(-1,'\n'))
- goto l990;
- }
- else
- {
- for (wordRight((long) -1) ; /* go back a word, then break */
- (GCh(curchr-1) != ' ' && GCh(curchr-1) != '\t'
- && !IsEndLine(GCh(curchr-1)) ) ;
- wordRight((long) -1))
- {
- /* this line can't be filled - stop now */
- if (curchr == GLine(curlin))
- goto l990;
- }
- charInsert('\n');
- }
- break;
- }
-
- } /* end of for (;;) */
-
- } /*# end of the for (count) */
- l900:
- state.echof = oldef;
- if (oldef && count > 1)
- Verify();
-
- ChangeLoc(curlin,col_pos(curchr,0));
- return retval;
-
- l990: /* failure return */
- retval = 0;
- goto l900;
- }
-
- //===========================>>> vTextEditor::formatC <<<=====================
- int vTextEditor::formatC(long count)
- {
- /* format C code according to Bruce's style */
-
- int oldef, i, ij, ik, spaces, tabs, prev_key;
- long prev_lnum;
-
- char prev_line[40];
- char prev_prev_line[40];
-
- oldef = state.echof;
- if ( curlin >= _nextLine-1) /* can't do last line */
- return 0;
-
- if (count > 1)
- state.echof = 0;
-
- for (i = 1 ; i <= count ; ++i, lineDownBeg((long)1))
- {
- if ((prev_lnum = get_prev(prev_line,curlin)) <= 0) /* get the previous line */
- continue; /* handle 1st line of file! */
-
- (void) get_prev(prev_prev_line,prev_lnum); /* and the line before it */
-
- if (*prev_line != ' ' && *prev_line != '\t') /* funny line */
- {
- lineDownBeg((long)1);
- break; /* give up */
- }
-
- /* count previous tabs/spaces */
- tabs = spaces = 0;
- for (ij = 0 ; ij < 38 ; ++ij)
- {
- if (prev_line[ij] == '\t')
- {
- spaces = 0; /* skip embedded spaces */
- ++tabs;
- }
- else if (prev_line[ij] == ' ')
- ++spaces;
- else
- break; /* break on first non tab non blank */
- }
- if (tabs == 0 && spaces <= 2)
- {
- lineDownBeg((long) 1);
- break; /* give up on function heads */
- }
-
- /* now process current line */
- lineBeginning(); /* start at beginning of line */
-
- if (curlin >= _nextLine-1)
- break; /* done */
-
- /* don't fix blank lines */
-
- if (GCh(curchr) != ' ' && GCh(curchr) != '\t' )
- {
- lineDownBeg((long) 1);
- break; /* break on line I don't know about */
- }
-
- while (GCh(curchr) == ' ' || GCh(curchr) == '\t')
- charDelete((long)1); /* delete them */
-
- if (GCh(curchr) == '\n')
- continue; /* skip blank lines */
-
- /* determine spacing of current line based on prev line */
-
- prev_key = 0;
- if (is_key_word(&prev_line[ij],1)) /* a kew word! */
- {
- prev_key = 1; /* last line was key */
- if (GCh(curchr) == '{')
- spaces += 2;
- else
- spaces += 4;
- }
- else if (prev_line[ij] == '{')
- {
- spaces += 2;
- }
- else if (prev_line[ij] == '}')
- {
- spaces -= 2;
- }
-
- if (has_key((char*)curchr, "else"))
- {
- if (prev_line[ij] != '}')
- spaces -= 4;
- }
- else if (has_key((char *)curchr, "case") ||
- has_key((char*)curchr, "default:"))
- {
- if (prev_line[ij] != '{')
- spaces -= 4;
- }
- else if (!prev_key && prev_line[ij] != '{' &&
- prev_line[ij] != '}' && is_key_word(prev_prev_line,0))
- spaces -= 4;
-
- /* don't else next one, works with last else if */
- if (GCh(curchr) == '}') /* } */
- spaces -= 2;
-
- /* fix tab/space counts */
- if (spaces < 0)
- {
- if (--tabs < 0)
- tabs = 0;
- spaces = 8 + spaces;
- }
- while (spaces >= 8)
- {
- ++tabs;
- spaces -= 8;
- }
-
- for (ik = 0 ; ik < tabs ; ++ik)
- charInsert('\t');
- for (ik = 0 ; ik < spaces ; ++ik)
- charInsert(' ');
-
- } /* end of main for loop */
-
- state.echof = oldef;
- if (oldef && count > 1)
- Verify();
-
- return 1;
-
- }
-
- // =============================>>> vTextEditor::has_key <<<=======================
- int vTextEditor::has_key(char *buff_ptr, char *key)
- {
- while (*key)
- {
- if (*buff_ptr++ != *key++)
- return 0;
- }
- return 1; /* buff_ptr matches key up to key's EOS */
-
- }
-
- // ==========================>>> vTextEditor::is_key_word <<<======================
- int vTextEditor::is_key_word(char *bf, int case_def)
- {
- //char *strstr();
-
- while (*bf == ' ' || *bf == '\t') /* skip leading white */
- ++bf;
- if (strstr(bf,"if(") == bf)
- return 1;
- if (strstr(bf,"if (") == bf)
- return 1;
- if (strstr(bf,"for(") == bf)
- return 1;
- if (strstr(bf,"for (") == bf)
- return 1;
- if (strstr(bf,"while(") == bf)
- return 1;
- if (strstr(bf,"while (") == bf)
- return 1;
- if (strstr(bf,"else") == bf)
- return 1;
- if (strstr(bf,"typedef ") == bf)
- return 1;
- if (strstr(bf,"struct ") == bf)
- return 1;
- if (strstr(bf,"switch(") == bf)
- return 1;
- if (strstr(bf,"switch (") == bf)
- return 1;
- if (case_def && strstr(bf,"case ") == bf)
- return 1;
- if (case_def && strstr(bf,"default:") == bf)
- return 1;
- return 0;
- }
-
- //=============================>>> vTextEditor::get_prev <<<======================
- long vTextEditor::get_prev(char *prev_buff, long start)
- { // Get previous non-blank line in text buffer (BEW: 10/1/98)
- long pline;
- int ix, blank_line;
- BUFFPTR bi;
-
- *prev_buff = 0; /* empty line for sure */
- pline = start;
- GP_TOP:
- --pline; /* previous line */
-
- if (pline <= 1)
- return 0; /* there is no previous line */
-
- bi = GLine(pline); /* first char of buffer */
-
- blank_line = 1;
- for (ix = 0 ; ix < 38 ; ++ix)
- {
- if (GCh(bi+ix) == '\n')
- break;
- prev_buff[ix] = GCh(bi+ix); /* copy the char */
- if (prev_buff[ix] != ' ' || prev_buff[ix] != '\t')
- blank_line = 0; /* not a blank line */
- }
- prev_buff[ix] = 0; /* terminate the string */
- if (blank_line || prev_buff[0] == '#')
- goto GP_TOP; /* find previous non-blank line */
-
- return pline;
- }
-
-
- // ########################################################################
- //
- // Misc. methods
- //
- // ########################################################################
-
- // ======================>>> vTextEditor::EditCut <<<=================
- int vTextEditor::EditCut()
- {
- // Cut text to clipboard
-
- long sl = SelectionLen(); // length of selection
- if (sl < 0)
- return 0;
- char* cut = new char[sl+1]; // space for a copy
-
- CopySelection(cut, sl+1, 0); // copy the selection
- theApp->ClipboardSetText(cut); // set the clipboard
-
- delete [] cut; // free the space
-
- RemoveMarkRange(); // finally, cut it
- return 1;
- }
-
- // ======================>>> vTextEditor::EditCopy <<<=================
- int vTextEditor::EditCopy()
- {
- // Cut text to clipboard
-
- long sl = SelectionLen(); // length of selection
- if (sl < 0)
- return 0;
- char* cut = new char[sl+1]; // space for a copy
-
- CopySelection(cut, sl+1, 0); // copy the selection
- theApp->ClipboardSetText(cut); // set the clipboard
-
- delete [] cut; // free the space
-
- return 1;
- }
-
- // ======================>>> vTextEditor::EditPaste <<<=================
- int vTextEditor::EditPaste()
- {
- char* paste = theApp->ClipboardGetText(); // get the text
- if (!paste || !*paste)
- return 0;
- long pasteLen = strlen(paste);
- long orig_line = curlin;
-
- int old_echo = state.echof;
-
- if (pasteLen > 80)
- state.echof = 0;
-
- while (*paste) // dumb paste - char at a time insert
- {
- if (*paste != '\r') // ignore \r on both X and Windows
- {
- if (*paste == '\n')
- charInsert((int)'\r'); // this works for both X and Windows
- else
- charInsert((int)*paste);
- }
- ++paste;
- }
- if (state.echof == 0)
- {
- state.echof = old_echo;
- // Verify();
- }
-
- if (curlin != orig_line) /* refresh screen if moved */
- Verify();
- else
- tvhdln(); /* just fix the cursor */
- return 1;
- }
-
- // ======================>>> vTextEditor::SelectionLen <<<=================
- int vTextEditor::SelectionLen()
- {
- long lines;
- int len;
- MARK_RANGE r_mark;
-
- if (mark.beg_lin != 0) // we have some text to count
- {
- r_mark = mark; // use a copy
-
- // count the range
-
- lines = r_mark.end_lin - r_mark.beg_lin + 1;
-
- if (lines == 1) /* all on current line */
- {
- if (r_mark.end_chr) /* find type range */
- {
- len = r_mark.end_chr - r_mark.beg_chr;
- }
- else
- {
- for (len = 0 ; GCh(r_mark.beg_chr + len) != 0 ; ++len)
- ;
- }
- return len;
- }
- else // more than one line
- {
- // Count 1st line
- for (len = 0 ; GCh(r_mark.beg_chr + len) != 0 ; ++len)
- ;
- // Count middle lines
- for (long mid = r_mark.beg_lin + 1 ;
- mid < r_mark.end_lin ; ++mid)
- {
- int linlen;
- for (linlen = 0 ; GCh(GLine(mid) + linlen ) != 0 ;
- ++linlen)
- ; // count len of this line
- len += linlen; // add to total
- }
- // Count last line - count up to r_mark.end_chr, or
- // to the end of the line (some places we call end_chr
- // a big number that really isn't the end of the line
- int lastlen;
- for (lastlen = 0 ;
- GLine(r_mark.end_lin) + lastlen < r_mark.end_chr
- && GCh(GLine(r_mark.end_lin) + lastlen) != 0 ;
- ++lastlen)
- ;
- len += lastlen;
- return len;
- }
- }
- return 0;
- }
-
- // ======================>>> vTextEditor::CopySelection <<<=================
- int vTextEditor::CopySelection(char* buff, int max, int unmark)
- {
- long cnt;
- int ix;
- char *to;
- MARK_RANGE r_mark;
-
- to = buff;
-
- if (mark.beg_lin != 0) /* we have some text to kill */
- {
- if (max < SelectionLen() + 1) // make sure fits
- return 0;
-
- r_mark = mark; /* make copy to avoid recursion */
-
- /* now safe to kill off range */
- if (unmark)
- {
- mark.beg_lin = mark.end_lin =
- mark.beg_col = mark.end_col = 0;
- mark.beg_chr = mark.end_chr = 0;
- theApp->SetValueAll(M_Cut, 0, Sensitive); // zap menu
- theApp->SetValueAll(M_Copy, 0, Sensitive);
- }
-
-
- /* clean up screen */
- if (curlin != r_mark.beg_lin ||
- r_mark.end_lin - r_mark.beg_lin > 0)
- {
- Verify();
- }
- else
- {
- tvxy(1,tvdlin); /* fix it up */
- type_lines(curlin, 1);
- tvhdln();
- }
-
- /* copy the range */
-
- cnt = r_mark.end_lin - r_mark.beg_lin + 1;
-
- if (cnt == 1) /* all on current line */
- {
- if (r_mark.end_chr) /* find type range */
- {
- cnt = r_mark.end_chr - r_mark.beg_chr;
- }
- else
- {
- for (cnt = 0 ; GCh(r_mark.beg_chr + cnt) != 0 && cnt < (max - 1) ;
- ++cnt)
- ;
- }
- for (ix = 0 ; ix < cnt && ix < (max - 1) ; ++ix) /* copy directly */
- {
- *(to+ix) = GCh(r_mark.beg_chr+ix);
- if (*(to+ix) == 0)
- break;
- }
- *(to+ix) = 0;
- }
- else /* more than one line */
- {
- // Copy 1st line
- for (long len1 = 0 ; GCh(r_mark.beg_chr + len1) != 0 ; ++len1)
- *to++ = GCh(r_mark.beg_chr + len1);
- // Copy middle lines
- for (long mid = r_mark.beg_lin + 1 ;
- mid < r_mark.end_lin ; ++mid)
- {
- for (int linlen = 0 ; GCh(GLine(mid) + linlen) != 0 ;
- ++linlen)
- *to++ = GCh(GLine(mid) + linlen);
- }
- // Count last line - count up to r_mark.end_chr, or
- // to the end of the line (some places we call end_chr
- // a big number that really isn't the end of the line
- for (int lastlen = 0 ;
- GLine(r_mark.end_lin) + lastlen < r_mark.end_chr
- && GCh(GLine(r_mark.end_lin) + lastlen) != 0 ;
- ++lastlen)
- *to++ = GCh(GLine(r_mark.end_lin) + lastlen);
- *to++ = 0;
- }
- return 1;
- }
- return 0;
- }
-
- // ======================>>> vTextEditor::ClearMarkRange <<<================
- void vTextEditor::ClearMarkRange(void)
- {
-
- checkIfScrolled(); // can check for scroll here
-
- /* clear the range variables */
- if (mark.beg_lin != 0)
- {
- mark.beg_lin = mark.end_lin =
- mark.beg_col = mark.end_col = 0;
- mark.beg_chr = mark.end_chr = 0;
- Verify();
- }
- else /* just be sure we stay in phase */
- {
- mark.beg_lin = mark.end_lin =
- mark.beg_col = mark.end_col = 0;
- mark.beg_chr = mark.end_chr = 0;
- }
- theApp->SetValueAll(M_Cut, 0, Sensitive);
- theApp->SetValueAll(M_Copy, 0, Sensitive);
- }
-
- // =====================>>> vTextEditor::RemoveMarkRange <<<================
- int vTextEditor::RemoveMarkRange(void)
- {
- /* delete the text in the marked range
- return
- 0 : no text deleted
- 1 : text deleted
- */
-
- static int inHere = 0; // don't let it be recursive
- int retval = 0;
-
- long cnt, orig_line;
- MARK_RANGE r_mark;
- BUFFPTR orig_chr;
-
- if (inHere)
- return 0;
- inHere = 1;
- if (mark.beg_lin != 0) /* we have some text to kill */
- {
- r_mark = mark; /* make copy to avoid recursion */
-
- /* now safe to kill off range */
- mark.beg_lin = mark.end_lin =
- mark.beg_col = mark.end_col = 0;
- mark.beg_chr = mark.end_chr = 0;
-
- /* kill off range */
- orig_line = curlin;
- orig_chr = curchr;
- curlin = r_mark.beg_lin;
- curchr = r_mark.beg_chr;
- cnt = r_mark.end_lin - r_mark.beg_lin + 1;
-
- if (!state.readOnly && cnt == 1) /* all on current line */
- {
- if (r_mark.end_chr) /* find type range */
- {
- long dcnt = r_mark.end_chr - r_mark.beg_chr;
- charDelete(dcnt);
- }
- else /* ^M type range */
- {
- if (curchr == GLine(curlin))
- lineDelete(cnt); /* kill whole current line */
- else
- {
- lineDeleteToEnd(); /* past line beg, just kill rest */
- }
- }
- retval = 1;
- }
- else if (!state.readOnly) /* more than one line */
- {
- int oldef = state.echof;
- state.echof = 0; // turn off echo
- lineDeleteToEnd(); /* past line beg, just kill rest */
- lineDownBeg((long)1,0); /* and the end of line */
- --cnt; /* one less */
- lineDelete(cnt - 1); /* kill off all but last line */
- if (!r_mark.end_chr) /* kill whole last line */
- {
- lineDelete((long)1);
- }
- else
- {
- curchr = r_mark.end_chr; /* get last char */
- if (IsEndLine(GCh(curchr)))
- lineDelete((long)1);
- else
- lineDeleteFront(); /* kill last line */
- }
- charDelete((long)-1); /* and the lead cr */
- retval = 1;
- state.echof = oldef;
- }
- if (curlin != orig_line) /* refresh screen if moved */
- Verify();
- else
- tvhdln(); /* just fix the cursor */
-
- ChangeLoc(curlin,col_pos(curchr,0));
- }
-
- inHere = 0;
- return retval;
- }
-
- // ===========================>>> BalMatch <<<==============================
- int vTextEditor::BalMatch(long val)
- {
- /* Find balance of )]} or [{( */
-
- int orig_line, dir, nest, old_ef, echo_off;
- long limit, ix;
- BUFFPTR orig_chr;
- char start_c, match;
-
- if (lastLineBF() < 1)
- return 0;
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- old_ef = state.echof;
- echo_off = 0; /* haven't turned off echo */
-
- limit = ((long) val) * 4000L; /* limit for search */
-
- orig_chr = curchr;
- orig_line = curlin;
- start_c = GCh(curchr); /* original char */
- switch (start_c)
- {
- case '(':
- match = ')';
- dir = 1;
- break;
-
- case '{':
- match = '}';
- dir = 1;
- break;
-
- case '[':
- match = ']';
- dir = 1;
- break;
-
- case ')':
- match = '(';
- dir = -1;
- break;
-
- case '}':
- match = '{';
- dir = -1;
- break;
-
- case ']':
- match = '[';
- dir = -1;
- break;
-
- default:
- return 0; /* no op if not a paren thing */
-
- }
-
- for (ix = 1, nest = 0 ; ix < limit ; ++ix)
- {
- charRight((long)dir,1); /* go right */
- if (!echo_off && (curlin != orig_line))
- {
- state.echof = 0;
- echo_off = 1; /* disable echoing */
- StatusMessage("Scanning for matching paren");
- }
- if (GCh(curchr) == start_c)
- ++nest; /* bump nest */
- else if (GCh(curchr) == match)
- {
- if (nest)
- --nest; /* undo nest */
- else
- {
- if (echo_off) /* we've turned echo off */
- {
- if ((state.echof == old_ef)) /* update if it was on */
- Verify();
- }
- return 1; /* found the matching thing */
- }
- }
- }
-
- /* fall through ==> died */
- curchr = orig_chr;
- curlin = orig_line;
- state.echof = old_ef;
- newscr();
- ChangeLoc(curlin,col_pos(curchr,0));
- return 0;
- }
-
- // #########################################################################
- //
- // Private helper methods
- //
- // #########################################################################
-
- //========================>>> vTextEditor::reallocLines <<<======================
- int vTextEditor::reallocLines()
- {
- BUFFPTR* oldLines;
-
- oldLines = _lines; // remember old lines
- _lines = new char*[_maxLines + lineListSize];
- if (!_lines)
- {
- _lines = oldLines; // failed to get more lines
- return 0;
- }
-
- long lx;
- for (lx = 0 ; lx <= _maxLines ; ++lx) // copy old lines
- _lines[lx] = oldLines[lx];
-
- _maxLines = _maxLines + lineListSize - 1; // safety factor
-
- for (lx = 0 ; lx <= _maxLines ; ++lx) // null new lines
- _lines[lx] = 0;
-
- delete [] oldLines; // free the old lines
- return 1;
- }
-
- //========================>>> vTextEditor::col_pos <<<======================
- int vTextEditor::col_pos(BUFFPTR chr_pos, int do_shift)
- { /* col_pos - find the x position of the character chr_pos on current line
- handles spacing for tabs, control characters etc */
-
- BUFFPTR i;
- int pos;
-
- pos = 1;
- for (i = GLine(curlin) + 1 ; i <= chr_pos ; ++i)
- {
- if (GCh(i-1) < ' ' && GCh(i-1) > 0) /* cur pos depends on last chr */
- {
- if (GCh(i-1) == '\t' && state.tabspc > 0) /* handle tabs */
- {
- for (++pos ; ((pos-1) % state.tabspc) != 0; ++pos)
- ;
- }
- else /* control characters (echoed as ^X) */
- pos += 2; /* 2 spaces for other control character */
- }
- else /* normal character */
- ++pos;
- }
-
- while (do_shift)
- {
- if (pos < leftmg) /* won't fit on screen */
- {
- leftmg -= 16; /* shift left */
- }
- else if (pos >= GetCols() + leftmg)
- {
- leftmg += 16;
- }
- else
- break;
- }
-
- if (do_shift)
- return pos - leftmg + 1;
- else
- return pos;
- }
-
- // ===========================>>> vTextEditor::mint <<<=====================
- int vTextEditor::mint(int v1, int v2)
- {
- return (v1 > v2 ? v2 : v1);
- }
-
- // ============================>>> vTextEditor::maxt <<<====================
- int vTextEditor::maxt(int v1, int v2)
- {
- return (v1 > v2 ? v1 : v2);
- }
-
- // ===========================>>> vTextEditor::minl <<<=====================
- long vTextEditor::minl(long v1,long v2)
- {
- return (v1 > v2 ? v2 : v1);
- }
-
- // ===========================>>> vTextEditor::maxl <<<=====================
- long vTextEditor::maxl(long v1, long v2)
- {
- return (v1 > v2 ? v1 : v2);
- }
-
- // ===========================>>> vTextEditor::clower <<<===================
- int vTextEditor::clower(int ch)
- {
- return ((ch >='A' && ch<='Z') ? ch + ' ' : ch);
- }
-
- // ==========================>>> vTextEditor::cupper <<<===================
- int vTextEditor::cupper(int ch)
- {
- return ((ch >= 'a' && ch <= 'z') ? ch - ' ' : ch);
- }
-
- // ===================>>> vTextEditor::line_can_fit <<<=====================
- int vTextEditor::line_can_fit(long l)
- {
- /* if line can't fit onto screen width, we need to update deleted
- characters a bit differently.
- */
- BUFFPTR to;
- int len;
-
- for (to = GLine(l) + 1, len = 0 ; !IsEndLine(GCh(to)) ; ++to)
- {
- if (GCh(to) < ' ')
- return 0; /* ctrl chars mess it up, so false */
- ++len;
- }
- return (len < GetCols());
- }
-
- // =======================>>> vTextEditor::FindDispLine <<<=================
- void vTextEditor::FindDispLine(long& ibeg, int& cnt)
- { /* FindDispLine - find the display line
- known: current line, calculate where it would go on the screen */
-
- if (curlin <= dsplin)
- { /* it is in first part of the display */
- ibeg = 1;
- cnt = (int) minl((long)GetRows(),(long)(lastLine));
- tvdlin = (int)curlin; /* update the display line */
- }
- else if (lastLine-curlin < GetRows()-dsplin)
- { /* at bottom of display */
- ibeg = maxl((long)1,(long)(lastLine - GetRows() + 1));
- cnt = mint(GetRows(),(int) lastLine);
- tvdlin = minl(curlin,(long)(GetRows()-(lastLine-curlin+1)+1));
- }
- else /* normal case: in middle */
- {
- ibeg = maxl((long) 1,(long)(curlin-dsplin+1));
- cnt = minl((long)GetRows(),(long)(lastLine-(ibeg)+1));
- tvdlin = dsplin;
- }
- }
-
- // ======================>>> vTextEditor::findX <<<========================
- int vTextEditor::findX(void)
- { /* findX - find the x position of the current character
- handles spacing for tabs, control characters etc */
-
- BUFFPTR i;
- int pos, need_newscr;
-
- if (curlin < 1 || GetCols() < 1 || lastLineBF() < 1)
- return 1;
- need_newscr = 0;
- pos = 1;
-
- for (i = GLine(curlin)+1 ; i <= curchr ; ++i)
- {
- if (GCh(i-1) < ' ' && GCh(i-1) > 0) /* cur pos depends on last chr */
- {
- if (GCh(i-1) == '\t' && state.tabspc > 0) /* handle tabs */
- {
- for (++pos ; ((pos-1) % state.tabspc) != 0; ++pos)
- ;
- }
- else /* control characters (echoed as ^X) */
- pos += 2; /* 2 spaces for other control character */
- }
- else /* normal character */
- ++pos;
- }
-
- for (;;)
- {
- if (pos < leftmg) /* won't fit on screen */
- {
- leftmg -= 16; /* shift left */
- need_newscr = 1;
- }
- else if (pos >= GetCols()+leftmg)
- {
- leftmg += 16;
- need_newscr = 1;
- }
- else
- break;
- }
-
- if (need_newscr)
- {
- Verify();
- }
-
- return (pos-leftmg+1);
- }
-
- // ===================>>> vTextEditor::getCurLine <<<=======================
- void vTextEditor::getCurLine(char* buff, long start)
- {
- int ix;
- BUFFPTR bi;
-
- buff[0] = 0; /* empty line for sure */
-
- if (lastLineBF() < 1)
- return;
-
- bi = GLine(start); /* first char of buffer */
-
- for (ix = 0 ; ix < 38 ; ++ix) /* 38 chars max */
- {
- if (IsEndLine(GCh(bi+ix)))
- break;
- buff[ix] = GCh(bi+ix); /* copy the char */
- }
- buff[ix] = 0; /* terminate the string */
- }
-
- // ====================>>> vTextEditor::lastBX <<<==========================
- BUFFPTR vTextEditor::lastBX(long line)
- {
- /* return the buff index of the last char of the line */
- BUFFPTR bx;
-
- for (bx = GLine(line) ; !IsEndLine(GCh(bx)) ; ++bx)
- ; /* find last char in line */
- return bx;
- }
-
- // ====================>>> vTextEditor::Fill1 <<<==========================
- int vTextEditor::Fill1(int dir, int val)
- { /* change character dir to val */
-
- int oldwrp;
-
- if (state.readOnly)
- return 0;
- oldwrp = state.wraplm;
- state.wraplm = 0;
- if (! charDelete((long)dir))
- goto l900;
- if (! charInsert(val))
- goto l900;
- state.wraplm = oldwrp;
- return 1;
- l900:
- state.wraplm = oldwrp;
- return 0;
- }
-
- // ======================>>> vTextEditor::newscr <<<========================
- void vTextEditor::newscr(void)
- { /* newscr - retype entire screen, updating cursor position if necessary */
-
- long ibeg;
- int cnt;
-
- if (!state.echof)
- return;
-
- if (curlin < 1)
- {
- tvclr();
- tvxy(1,1);
- return;
- }
- if (lastLine < GetRows()) /* two kinds of screen rewrite */
- tvclr(); /* clear the screen and home */
- tvxy(1,1);
-
- dsplin = tvdlin = ddline; /* home to middle */
- FindDispLine(ibeg, cnt); /* calculate where it will go */
- type_lines(ibeg,cnt); /* type it out */
- tvhdln(); /* home to display line */
- }
-
- // =====================>>> vTextEditor::range <<<=========================
- void vTextEditor::range(long cnt, long *lbeg, long *lend)
- { /* determine a legal line number range given cnt */
-
- if (cnt <= 0)
- {
- if ((*lbeg = curlin + cnt) < 0)
- *lbeg = 1;
- *lend = curlin;
- if (cnt < 0)
- *lend = (*lend)-1;
- }
- else
- {
- *lbeg = curlin;
- if ((*lend = curlin+cnt-1) > lastLine)
- *lend = lastLine;
- }
- }
-
- // ====================>>> vTextEditor::setScrollBar <<<====================
- void vTextEditor::setScrollBar()
- {
- long shown;
- long top;
- long last = lastLine;
-
- if (!state.echof)
- return;
-
- if (last < 1)
- last = 1;
-
- if (lastLine <= (long)GetRows())
- shown = 100L;
- else
- shown = ((long) GetRows() * 100L) / last;
-
- if (shown < 1)
- shown = 1;
-
- long cur = (scroll_lin > 0) ? scroll_lin : curlin; // handle scrolling
-
- if (cur >= last)
- top = 100L;
- else if (cur == 1)
- top = 0;
- else
- top = (cur * 100L) / last;
-
- if (top < 0)
- top = 0;
-
- SetVScroll((int) shown, (int) top);
- }
-
- // ====================>>> vTextEditor::checkIfScrolled <<<=================
- void vTextEditor::checkIfScrolled()
- {
- // If we are scrolled, we need to restore screen
-
- if (!state.echof)
- return;
-
- if (scroll_lin > 0)
- {
- scroll_lin = -1;
- ShowTextCursor();
- Verify();
- }
- }
-
- // ====================>>> vTextEditor::scrollDown <<<======================
- void vTextEditor::scrollDown(long delta)
- { /* scroll screen without moving cursor either 1 line or screenful*/
-
- long change;
-
- if (!state.echof)
- return;
-
- if (lastLineBF() < 1 || delta == 0)
- return;
-
- if (!state.fixed_scroll && scroll_lin < 0) /* might be on same screen */
- {
- // this just adjusts the screen without really scrolling
- if (delta == 1 && dsplin > 1) /* scroll down */
- {
- if ((curlin+GetRows()-tvdlin) >= lastLine)
- return; // no where to go
- tvbotb(1); /* make room */
- tvxy(1,GetRows()); /* home to last line */
- dsplin = tvdlin = tvdlin - 1; /* change line */
- type_lines((long)(curlin+GetRows()-tvdlin),1); /* fix up screen */
- tvhdln(); /* home to display line */
- setScrollBar();
- return;
- }
- else if (delta == -1 && dsplin < GetRows())
- {
- if ((curlin-tvdlin) <= 0 )
- return;
- tvtopb(1); /* make blank lines at top */
- dsplin = tvdlin = tvdlin + 1; /* change line */
- type_lines((long)(curlin-tvdlin+1),1); /* fill in */
- tvhdln(); /* home to display line */
- setScrollBar();
- return;
- }
- }
-
- if (scroll_lin < 0) /* initial setup */
- {
- if (curlin <= dsplin) /* on first screen */
- {
- scroll_lin = 1; /* assume 1st line */
- }
- else if (lastLine - curlin < GetRows() - dsplin)
- { /* at bottom of display */
- scroll_lin = maxl((long)1,(long)(lastLine - GetRows() + 1));
- }
- else /* normal case: in middle */
- {
- scroll_lin = maxl((long)1,(long)(curlin-dsplin+1));
- }
- }
-
- if (delta < 0 && scroll_lin == 1) /* at top already */
- return;
-
- change = delta;
-
- if (change < 0) /* have to scroll screen down */
- {
- if (change == -1)
- {
- if (scroll_lin <= 1)
- return;
- scroll_lin -= 1;
- tvtopb(1); /* make blank lines at top */
- type_lines(scroll_lin,1); /* fill in */
- }
- else /* a screenful or so */
- {
- scroll_lin = maxl((long)1,(long)(scroll_lin + delta));
- newScrollScreen(scroll_lin);
- }
- }
- else if (change > 0) /* have to scroll screen up */
- {
- if ((scroll_lin+GetRows()) > lastLine)
- return; // no where to go
- if (change == 1)
- {
- scroll_lin += 1;
- tvbotb(1); /* make blank lines at top */
- type_lines((long)(scroll_lin+GetRows()-1),1); /* fill in */
- }
- else /* a screenful or so */
- {
- scroll_lin = minl(lastLine, (long)(scroll_lin + delta));
- newScrollScreen(scroll_lin);
- }
- }
-
- // now, if the curlin is on the new scrolled screen, we need to
- // repaint it so the cursor and highlight area show
-
-
- if (curlin >= scroll_lin && curlin < (scroll_lin + GetRows()))
- {
- scroll_lin = -1;
- ShowTextCursor();
- int xf = findX();
- tvxy(xf,tvdlin);
- }
- else
- HideTextCursor();
-
- setScrollBar();
-
- }
-
- // =================>>> vTextEditor::newScrollScreen <<<====================
- void vTextEditor::newScrollScreen(long ibeg)
- { /* newScrollScreen - retype entire screen,
- updating cursor position if necessary */
-
- if (!state.echof)
- return;
-
- tvclr(); /* clear the screen and home */
- type_lines(ibeg,(int)minl(lastLine,(long)GetRows())); /* type it out */
- }
-
- // ===================>>> vTextEditor::SaveKillLine <<<=====================
- void vTextEditor::SaveKillLine(long lin)
- { /* SaveKillLine - save one line that will be killed */
-
- BUFFPTR from;
- int to;
-
- to=0;
- for (from = GLine(lin); !IsEndLine(GCh(from)) ; ++from)
- {
- unkbuf[to]= GCh(from); /* put it in unkill buffer */
- to = mint(130,to+1);
- }
- unkbuf[to]=0;
- }
-
- // =====================>>> vTextEditor::tvhdln <<<=========================
- void vTextEditor::tvhdln(void)
- { /* tvhdln - home to display line */
-
- int xf;
-
- if (curlin < 1)
- tvxy(1,1);
- else
- {
- if (mark.beg_lin > 0)
- {
- tvxy(1,tvdlin);
- type_lines(curlin, 1);
- }
- xf = findX();
- tvxy(xf,tvdlin);
- }
- }
-
- // ========================>>> vTextEditor::tvtyln <<<======================
- void vTextEditor::tvtyln(long lineNum, BUFFPTR chrptr, int whole_line)
- { /* tvtyln - type a line on the screen without cr/lf */
-
- xoutcm = tvx;
- tvplin(lineNum,chrptr,whole_line,-1,-1);
- }
-
- // =======================>>> vTextEditor::unkill <<<=======================
- int vTextEditor::unkill(void)
- { /* unkill the single last line killed */
-
- char chrval;
- int i;
-
- if (state.readOnly)
- return 0;
- lineOpen((long)1); /* put the CR 1st - makes update pretty */
- for (i=0; unkbuf[i]; ++i)
- {
- chrval = unkbuf[i];
- if (! charInsert(chrval)) /* unkill slowly by using insert */
- {
- return 0;
- }
- }
- lineDownBeg((long)1); /* back to where we were */
- return 1;
- }
-
- // =======================>>> vTextEditor::update <<<=======================
- void vTextEditor::update(long change)
- { /* update - update the screen when line position has changed
- will not be used if any alterations have been made */
-
- if (change == 0)
- {
- tvhdln();
- return;
- }
- setScrollBar();
- if (state.fixed_scroll)
- updateScroll(change); /* cursor stays on fixed line */
- else
- updateNoScroll(change); /* cursor roams around screen */
- }
-
- // ===================>>> vTextEditor::updateScroll <<<=====================
- void vTextEditor::updateScroll(long change)
- { /* update - update the screen when line position has changed
- will not be used if any alterations have been made */
-
- long abschg;
-
- if (!state.echof)
- return;
- abschg = change;
-
- if (change < 0) /* have to scroll screen down */
- {
- abschg = (-change);
- if (tvdlin-abschg < 1)
- Verify();
- else if (curlin < tvdlin) /* won't fit exactly */
- {
- if (tvdlin >= dsplin && abschg != 1)
- {
- tvclr(); /* clear the screen */
- type_lines((long)1,GetRows()); /* type out a screen */
- }
- tvdlin = curlin;
- }
- else if (tvdlin - abschg >= dsplin)
- tvdlin -= abschg;
- else
- {
- if (tvdlin > dsplin)
- { /* moving up from below display line */
- abschg = dsplin-(tvdlin-abschg);
- tvdlin=dsplin; /* update */
- }
- tvtopb((int)abschg); /* make blank lines at top */
- type_lines((long)(curlin-tvdlin+1),(int)abschg); /* fill in */
- }
- }
- else if (change > 0) /* have to scroll screen up */
- {
- if (tvdlin+change > GetRows() && tvdlin < dsplin ||
- change >= GetRows())
- Verify();
- else if (tvdlin < dsplin || lastLine <= GetRows())
- if (tvdlin+change > dsplin && lastLine > GetRows())
- Verify();
- else
- tvdlin += change;
- else if (lastLine - curlin < GetRows() - tvdlin) /* on bottom part */
- {
- if (tvdlin<=dsplin && abschg != 1)
- {
- tvclr(); /* rewrite whole screen */
- type_lines((long)(lastLine - GetRows() + 1), GetRows());
- }
- tvdlin = (int) minl((long)GetRows(), (long)(lastLine))
- - (lastLine - curlin + 1) + 1;
- }
- else
- {
- tvbotb((int)abschg); /* make room */
- tvxy(1,(int)(GetRows()-abschg+1)); /* home to right line */
- type_lines((long)(curlin+GetRows()-tvdlin-abschg+1),(int)abschg); /* fix up screen */
- if (tvdlin < dsplin)
- tvdlin = dsplin;
- }
- }
- tvhdln();
- }
-
- // ==================>>> vTextEditor::updateNoScroll <<<====================
- void vTextEditor::updateNoScroll(long change)
- { /* update - update the screen when line position has changed
- will not be used if any alterations have been made */
-
- long abschg;
-
- if (!state.echof)
- return;
- abschg = change;
-
- if (change < 0) /* have to scroll screen down */
- {
- abschg = (-change);
- if (curlin + abschg < tvdlin && curlin < tvdlin) // won't fit exactly
- {
- dsplin = tvdlin = curlin;
- }
- else if (tvdlin - abschg >= 1)
- {
- dsplin = tvdlin -= (int)abschg;
- }
- else if (abschg == 1) /* simple case */
- {
- tvtopb((int)abschg); /* make blank lines at top */
- type_lines((long)(curlin-tvdlin+1),(int)abschg); /* fill in */
- dsplin = tvdlin = 1;
- }
- else /* scroll to above top line */
- {
- dsplin = tvdlin;
- Verify();
- }
- }
- else if (change > 0) /* have to scroll screen up */
- {
- if (tvdlin + change <= GetRows())
- {
- dsplin =
- tvdlin = tvdlin + change;
- }
- else if (change == 1)
- {
- tvbotb((int)abschg); /* make room */
- tvxy(1,(int)(GetRows()-abschg+1)); /* home to right line */
- type_lines((long)(curlin+GetRows()-tvdlin-abschg+1),(int)abschg);
- /* fix up screen */
- dsplin =
- tvdlin = GetRows();
- }
- else /* scroll to above top line */
- {
- dsplin = tvdlin;
- Verify();
- }
- }
- tvhdln();
- }
-
- // #########################################################################
- //
- // word methods
- //
- // #########################################################################
-
- // =====================>>> vTextEditor::wordRight <<<=====================
- int vTextEditor::wordRight(long cnt)
- { /* wordRight - move cursor over words */
-
- long lim, words, incr, lenmov;
- int rv;
-
- if (lastLineBF() < 1)
- return 0;
- ClearMarkRange(); /* no range now */
- wasColCmd = 0;
-
- rv = 1;
- lenmov = 0;
- if (cnt < 0)
- {
- incr = (-1); /* change */
- lim = (-cnt);
- }
- else if (cnt == 0)
- {
- incr = -1;
- lim = 0;
- }
- else
- {
- incr = 1;
- lim = cnt;
- }
-
- for (words = 1; words <= lim; ++words)
- {
- if ((IsEndLine(GCh(curchr)) && incr > 0) ||
- (curchr == GLine(curlin) && incr < 0) )
- {
- if (curlin + incr > lastLine || curlin + incr < 1)
- {
- rv = 0;
- break; /* at a buffer limit, so quit */
- }
- lineDownBeg((long)incr,0); /* move up or down */
- lenmov += incr;
- if (cnt<0)
- lineEnd();
- continue; /* move to next word */
- }
-
- /* ok, first, skip over word characters */
- while (IsWordChar(GCh(curchr)))
- {
- if (curchr == GLine(curlin) && incr < 0)
- goto l100;
- else
- {
- curchr += incr;
- lenmov += incr;
- }
- }
-
- /* now skip over remaining non word chars */
- while (! IsWordChar(GCh(curchr)))
- {
- if ((IsEndLine(GCh(curchr)) && incr > 0) ||
- (curchr == GLine(curlin) && incr < 0) )
- break;
- else
- {
- curchr += incr;
- lenmov += incr;
- }
- }
- l100: ;
- }
-
- if (incr < 0) /* move cursor to beginning of word */
- {
- while (IsWordChar(GCh(curchr-1)))
- {
- curchr += incr;
- lenmov += incr;
- }
- }
- tvhdln();
- oldlen = lenmov;
- ChangeLoc(curlin,col_pos(curchr,0));
- return rv;
- }
-
- // ====================>>> vTextEditor::IsWordChar <<<======================
- int vTextEditor::IsWordChar(int chr)
- { /* IsWordChar - determine if a character is a "word" type character */
-
- if ((chr>='a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') ||
- (chr >= '0' && chr <= '9') || chr == '_' || chr == '\\')
- return 1;
- else
- return 0;
- }
-
- // #########################################################################
- //
- // DEFAULT vTextEdCmdInterp
- //
- // #########################################################################
-
- // ==================>>> vTextEdCmdInterp::vTextEdCmdInterp <<<=================
- vTextEdCmdInterp::vTextEdCmdInterp(vTextEditor* textEd, vCmdWindow* cw)
- {
- _textEd = textEd;
- _myCmdWindow = cw;
- metaWait = 0;
- countWait = 0; // not waiting on meta cmd
- metaChar = 'A'-'@'; // ^A is default meta char
- cmdCount = 1;
-
- }
-
- // ==================>>> vTextEdCmdInterp::~vTextEdCmdInterp <<<================
- vTextEdCmdInterp::~vTextEdCmdInterp()
- {
- }
-
- // =====================>>> vTextEdCmdInterp::InitCmdInterp <<<====================
- void vTextEdCmdInterp::InitCmdInterp()
- {
- }
-
- // =====================>>> vTextEdCmdInterp::InitCmdInterp <<<====================
- void vTextEdCmdInterp::CmdInterpHelp()
- {
- }
-
- // =====================>>> vTextEdCmdInterp::ProcessKey <<<====================
- int vTextEdCmdInterp::ProcessKey(vKey key, unsigned int shift)
- {
- // Commands supported by default keyboard mapping:
- //
- // Most commands can be preceeded by a count, which is entered
- // with Esc followed by a value followed by the command. Negative
- // counts can be used for most commands as well. An n in front
- // of a command indicates it can use a count.
- //
- // Some commands have synonyms compatible with See and
- // touch typing shown in []'s (e.g., ^A, for Home).
- //
- // Commands that change text interact with highlighted text
- // by deleting it, but without copying it to the clipboard.
- // ^X and ^C interact with the clipboard.
- //
- //
- // ^A[ Balance match
- // ^ABackspace Delete to line beginngin [^A']
- // ^ADel Delete to line end [^A"]
- // n^AIns Insert character with value of count
- // ^Av Repaint screen
- // ^C Copy highlighted text to clipboard
- // nShift-^C Fold case
- // ^F Find pattern
- // Shift-^F Find next
- // n^G Goto line specified by count
- // n^K Kill line
- // n^O Open a new blank line
- // ^V Paste from clipboard
- // ^X Cut highlighted text to clipboard
- // nLeft Move left [^L]
- // nCtrl-Left Move left a word
- // nUp Move up [^U]
- // nShift-Up Move up to beginning of line
- // nRight Move right [^R]
- // nCtrl-Right Move right a word
- // nDown Move down [^D]
- // nShift-Down Move down to beginning of line
- // nBackspace Delete previous character
- // Esc Prefix for entering counts
- // nDel Delete next character
- // nShift-Del Delete line
- // Home Goto beginning of line [^A,]
- // Ctrl-Home Goto beginning of file
- // End Goto end of line [^A.]
- // Ctrl-End Goto end of file
- // nPgUp Move a screenful up
- // nCtrl-PgUp Scroll a screenful up
- // nPgDn Move a screenful down
- // nCtrl-PgDn Scroll a screenful down
- // Ins Toggle insert/overtype
-
- if (vk_IsModifier(key)) // ignore modifiers
- return -1;
-
- int retval = 1;
-
- if (countWait != 0)
- {
- if (key == '-')
- {
- countWait = -1;
- return 1;
- }
- else if (key >= '0' && key <= '9') // it is a count
- {
- cmdCount = (cmdCount * 10) + (key - '0');
- return 1;
- }
- else
- {
- cmdCount *= countWait; // negative?
- countWait = 0; // done building count
- }
- }
-
- if (metaWait) // waiting for meta cmd
- {
- metaWait = 0;
- switch (key)
- {
- case vk_KP_Insert:
- case vk_Insert:
- {
- retval = te()->charInsert(cmdCount);
- break;
- }
-
- case '\'':
- case vk_BackSpace:
- {
- retval = te()->lineDeleteFront();
- break;
- }
-
- case '"':
- case vk_Delete:
- case vk_KP_Delete:
- {
- retval = te()->lineDeleteToEnd();
- break;
- }
-
- case ',': // line beginning
- {
- te()->lineBeginning();
- break;
- }
-
- case '.': // line end
- {
- te()->lineEnd();
- break;
- }
-
- case '[': // ^A[ - bal match
- {
- retval = te()->BalMatch(cmdCount);
- break;
- }
-
- case 'v':
- case 'V':
- case 'V'-'@':
- {
- te()->Verify();
- break;
- }
-
- default:
- {
- retval = -1;
- break;
- }
- }
- cmdCount = 1;
- return retval;
- }
- else if (key == (vKey) metaChar)
- {
- metaWait = 1;
- return 1;
- }
-
- switch (key)
- {
- case 'C'-'@': // ^C : Copy ; Shift-^C: fold case
- {
- if (shift & VKM_Shift) // Shift-^F
- {
- retval = te()->charFoldCase(cmdCount);
- }
- else
- te()->EditCopy();
- break;
- }
-
- case 'F'-'@': // ^F: find, Shift-^F: find next
- {
- if (shift & VKM_Shift) // Shift-^F
- {
- retval = te()->EditCommand(edFindNext, cmdCount);
- }
- else
- {
- retval = te()->EditCommand(edFind, cmdCount);
- }
- break;
- }
-
- case 'G'-'@': // ^G: Goto line
- {
- retval = te()->lineGoto(cmdCount);
- break;
- }
-
- case 'K'-'@': // ^K: Kill line
- {
- te()->lineDelete(cmdCount);
- break;
- }
-
- case 'O'-'@': // ^O: Open line
- {
- retval = te()->lineOpen(cmdCount);
- break;
- }
-
- case 'V'-'@': // ^V: Paste
- {
- te()->EditPaste();
- break;
- }
-
- case 'X'-'@': // ^X : Cut
- {
- te()->EditCut();
- break;
- }
-
- case 'L'-'@':
- case vk_Left:
- case vk_KP_Left:
- {
- if (shift & VKM_Ctrl || shift & VKM_Shift)
- retval = te()->wordRight(-cmdCount);
- else
- retval = te()->charRight(-cmdCount,1);
- break;
- }
-
- case 'U'-'@':
- case vk_Up:
- case vk_KP_Up:
- {
- if (shift & VKM_Shift)
- retval = te()->lineDownBeg(-cmdCount);
- else
- retval = te()->lineDown(-cmdCount);
- break;
- }
-
- case 'R'-'@':
- case vk_Right:
- case vk_KP_Right:
- {
- if (shift & VKM_Ctrl ||shift & VKM_Shift)
- retval = te()->wordRight(cmdCount);
- else
- retval = te()->charRight(cmdCount,1);
- break;
- }
-
- case 'D'-'@':
- case vk_KP_Down:
- case vk_Down:
- {
- if (shift & VKM_Shift)
- retval = te()->lineDownBeg(cmdCount);
- else
- retval = te()->lineDown(cmdCount);
- break;
- }
-
- case vk_BackSpace:
- {
- retval = te()->charDelete(-cmdCount);
- break;
- }
-
- case vk_Tab:
- {
- retval = te()->defaultKeyIn('\t',shift);
- break;
- }
-
- case vk_Linefeed:
- {
- break;
- }
-
- case vk_Return:
- case vk_KP_Enter:
- {
- retval = te()->defaultKeyIn('\n',shift);
- break;
- }
-
- case vk_Escape:
- {
- countWait = 1;
- cmdCount = 0;
- return 1;
- }
-
- case vk_Delete:
- case vk_KP_Delete:
- {
- if (shift & VKM_Shift || shift & VKM_Ctrl)
- te()->lineDelete(cmdCount);
- else
- retval = te()->charDelete(cmdCount);
- break;
- }
-
- case vk_Home:
- case vk_KP_Home:
- {
- if (shift & VKM_Shift || shift & VKM_Ctrl)
- retval = te()->lineGoto(1);
- else
- te()->lineBeginning();
- break;
- }
-
- case vk_Page_Up:
- case vk_KP_Page_Up:
- {
- if (shift & VKM_Ctrl)
- te()->scrollDown(-cmdCount * te()->GetRows());
- else
- retval = te()->lineDown((long)(-cmdCount * te()->GetRows()));
- break;
- }
-
- case vk_Page_Down:
- case vk_KP_Page_Down:
- {
- if (shift & VKM_Ctrl)
- te()->scrollDown(cmdCount * te()->GetRows());
- else
- retval = te()->lineDown(
- (long) te()->minl((cmdCount * te()->GetRows()),
- (long)(te()->GetLines() - te()->GetCurLine() + 1)));
- break;
- }
-
- case vk_End:
- case vk_KP_End:
- {
- if (shift & VKM_Shift || shift & VKM_Ctrl)
- te()->bufferBottom();
- else
- te()->lineEnd();
- break;
- }
-
- case vk_KP_Insert:
- case vk_Insert:
- {
- te()->SetInsMode(!(te()->GetEdState().ins_mode));
- te()->ChangeInsMode(te()->GetEdState().ins_mode);
- break;
- }
-
- default:
- {
- retval = te()->defaultKeyIn(key,shift);
- break;
- }
- }
- cmdCount = 1;
- return retval;
- }
-
-
- //==================================================================
- // I wrote the original version of the See editor, called TVX, in
- // 1980 in a language called Ratfor, a preprocessor that gave
- // Fortran the syntax of C. At that time, much of the TVX command
- // structure was based on a Tenex editor called TV. The Ratfor
- // version of TVX actually worked quite will on a TRS-80 with 48K
- // (that's right, 48K) of RAM. I've been using some decendent of
- // TVX ever since. My fingers know the commands too well to
- // change much.
- //
- // TVX was character based, and ported to many platforms,
- // including CP/M, RT-11, RSX-11, VMS, and of course Unix. Much
- // of the organization of the edit updates are designed to work
- // over serial lines on a text terminal. This was accomplished
- // using either a custom terminal driver, or a package such as
- // TERMCAP on Unix. In fact, one could use the full screen editor
- // quite well over even 1200 Baud serial lines (visual editors
- // such as Vi really failed at much less than 9600 Baud).
- //
- // TVX was translated (semi-automatically) from Ratfor to C. Most
- // recently (about 1995) I converted it to C++, and finally this
- // C++ class for inclusion in the VGUI package. Somewhere along
- // the way, I changed the name to See, which stood for Simple
- // Enough Editor.
- //
- // Certainly, if I were designing an editor from scratch in C++,
- // it would be quite different in structure than this editor.
- // However, I always found it easier to port rather than rewrite.
- // Many of the specialized editor commands I developed for See
- // are still found in this code. A good emulation of many editor
- // command sets can be implemented with different command
- // parsers.
- //
- // What this goes to show is that old code never dies, it just
- // mutates. This code originated almost 20 years ago now. Many of
- // the 6 character variable names owe their origin to Fortran
- // variable name restrictions. Much of the seemingly complicated
- // screen update stuff owes its origin to the restrictions of
- // working with different terminals over slow baud rates.
- //==================================================================
-