home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
vos2-121.zip
/
v
/
srcos2
/
vtexted.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-11-09
|
126KB
|
4,322 lines
//=================================================================
//
// 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.
//==================================================================