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 >
C/C++ Source or Header  |  1998-11-09  |  126KB  |  4,322 lines

  1. //=================================================================
  2. //
  3. // Copyright (C) 1995,1996,1997.1998  Bruce E. Wampler
  4. //
  5. // This file is part of the V C++ GUI Framework, and is covered
  6. // under the terms of the GNU Library General Public License,
  7. // Version 2. This library has NO WARRANTY. See the source file
  8. // vapp.cxx for more complete information about license terms.
  9. //
  10. // This code is based on Bruce Wampler's editor, See. I think a
  11. // bit of history about See will explain some things about the
  12. // reasons some of the code structure and variable names are
  13. // what they are. See end end of this file for the See history.
  14. //
  15. //
  16. //===============================================================
  17.  
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21.  
  22. #include <v/vwindow.h>
  23. #include <v/vkeys.h>
  24.  
  25. #include <v/vtexted.h>
  26. #include <v/vfinddlg.h>
  27.  
  28. /// Working notes:
  29. //      allow line list to grow dynamically by adding lines and
  30. //      copying old list to new one, then deleting old one.
  31.  
  32.     const long lineListSize = 5000;     // allocation increment for lines
  33.  
  34.     // one static find pattern
  35.     int vTextEditor::findCaseSensitive = 0;
  36.     char vTextEditor::theFindPat[MAX_LINE + 2] = "";
  37.  
  38. // =========================>>> vTextEditor::vTextEditor <<<================
  39.   vTextEditor::vTextEditor(vBaseWindow* parent, int isCmdWindow)
  40.   {
  41.  
  42.     _parent = parent;                   // remember who my parent was
  43.     _isCmdWindow = isCmdWindow;         // if our parent was a cmdwindow
  44.     _TECInt = new vTextEdCmdInterp(this, (vCmdWindow*)parent);
  45.  
  46.     // default state flags
  47.  
  48.     state.findAtBeginning =             // don't leave find at beginning of pat
  49.     state.fixed_scroll = 0;             // Not fixed scrolling
  50.     state.tabspc = 8;
  51.  
  52.     // switches:
  53.     state.readOnly =
  54.     state.wraplm =                      // wrap limit
  55.     use_wild = 0;                       // use wild cards in match
  56.  
  57.     oldcol = 1;
  58.  
  59.     state.ins_mode = 1;                 // insert (vs. overtype)
  60.  
  61.     b_lastln =
  62.     leftmg = xoutcm =
  63.     tvdlin = state.echof = lastLine = 1;
  64.  
  65.     linptr = 0;
  66.  
  67.     mouseMoveRow = mouseMoveCol =
  68.     mouseCol = mouseRow = -1;   // no mouse stuff yet
  69.     scroll_lin = -1;
  70.  
  71.     for (int ix = 0 ; ix < 10 ; ++ix)
  72.         noteloc[ix] = 0;
  73.  
  74.     _lines = 0;                 // make these null for smarter destructor
  75.  
  76.     initBuff()  ;               // initialize buffer routines
  77.     resetBuff();
  78.   }
  79.  
  80. //=========================>>> vTextEditor::~vTextEditor <<<================
  81.   vTextEditor::~vTextEditor()
  82.   {
  83.     if (_TECInt)
  84.         delete _TECInt;        // kill our command interp
  85.     if (_lines)
  86.       {
  87.         for (long ix = 0 ; ix < _nextLine ; ++ix)       // delete contents
  88.             delete [] _lines[ix];
  89.         delete [] _lines;       // delete if created
  90.       }
  91.   }
  92.  
  93. //=========================>>> vTextEditor::ChangeCmdInterp <<<================
  94.   void vTextEditor::ChangeCmdInterp(vTextEdCmdInterp* newCI)
  95.   {
  96.     if (_TECInt)
  97.     delete _TECInt;        // delete current command interp
  98.     if (newCI == 0)        // use default CI
  99.     _TECInt = new vTextEdCmdInterp(this, (vCmdWindow*)_parent);
  100.     else
  101.     _TECInt = newCI;
  102.   }
  103.  
  104. // #########################################################################
  105. //
  106. // buffer methods
  107. //
  108. // These are designed to be easily overriden to allow more complex
  109. // buffer management -- it should be possible to easily design a
  110. // package that allows unlimited file size, for example.
  111. //
  112. // #########################################################################
  113.  
  114. //===========================>>> vTextEditor::initBuff <<<==================
  115.   void vTextEditor::initBuff(void)
  116.   {
  117.     // initialize buffer routines - handled as a method so
  118.     // can override
  119.  
  120.     _lines  = new char*[lineListSize];
  121.     _maxLines = lineListSize - 1;       // safety factor
  122.  
  123.     _lines[0] = new char[2]; strcpy(_lines[0],"\n");
  124.     _lines[1] = new char[2]; strcpy(_lines[1],"\n");
  125.     for (long lx = 2 ; lx < lineListSize ; ++lx)
  126.         _lines[lx] = 0;
  127.     _nextLine = 2;
  128.     lastLine = lastLineBF();
  129.   }
  130.  
  131. // =======================>>> vTextEditor::resetBuff <<<====================
  132.   void vTextEditor::resetBuff()                         // open the buffer
  133.   {
  134.  
  135.     // values used by buffer management
  136.  
  137.     if (_lines)
  138.       {
  139.         delete [] _lines[0];
  140.         delete [] _lines[1];
  141.     for (long ix = 2 ; ix < _nextLine ; ++ix)       // delete contents
  142.       {
  143.         if (_lines[ix])
  144.         delete [] _lines[ix];
  145.       }
  146.     _lines[0] = new char[2]; strcpy(_lines[0],"\n");
  147.         _lines[1] = new char[2]; strcpy(_lines[1],"\n");
  148.       }
  149.     else
  150.       {
  151.         _lines  = new char*[lineListSize];
  152.         _maxLines = lineListSize - 1;   // safety factor
  153.  
  154.         _lines[0] = new char[2]; strcpy(_lines[0],"\n");
  155.         _lines[1] = new char[2]; strcpy(_lines[1],"\n");
  156.       }
  157.  
  158.     _curLineBF =
  159.     _nextLine = 1;
  160.  
  161.     wasColCmd = 0;
  162.  
  163.     // values used by editor code
  164.  
  165.     mark.beg_lin = mark.end_lin =       /* manually clear mark range */
  166.     mark.beg_col = mark.end_col = 0;    /* DO NOT CALL ClearMarkRange() */
  167.     mark.beg_chr = mark.end_chr = 0;
  168.  
  169.     curlin = lastLine = 1;
  170.  
  171.     curchr = _lines[1];
  172.  
  173.     last_col_out =
  174.     state.counter =
  175.     state.changes = 0;
  176.  
  177.     dsplin = ddline = 1;
  178.     state.ins_mode = 1;                 // insert (vs. overtype)
  179.   }
  180.  
  181. // =========================>>> vTextEditor::addLine <<<====================
  182.   int vTextEditor::addLine(char* line)
  183.   {
  184.     // This method adds the line to the end of the working buffer.
  185.     // line numbers start at 1! This is logical - it corresponds
  186.     // to how you would really number a text file. It does not
  187.     // correspond to C 0 based array indexing. So it goes.
  188.  
  189.     if (!line)
  190.         return 0;
  191.  
  192.     if (_nextLine >= _maxLines)         // check for max lines
  193.       if (!reallocLines())
  194.         return 0;
  195.  
  196.     BUFFPTR bp = appendToBuff(line);
  197.  
  198.     if (!bp)
  199.         return 0;
  200.     if (curchr == _lines[_nextLine])
  201.       {
  202.         // When the very first line is added, curchr must be updated to
  203.         // point to the new line instead of to the initial "\n"!
  204.         curchr = bp;
  205.       }
  206.  
  207.     _lines[_nextLine++] = bp;   // point line array to beginning of line
  208.     lastLine = lastLineBF();    // update
  209.  
  210.  
  211.     return 1;
  212.   }
  213.  
  214. // ======================>>> vTextEditor::appendToBuff <<<==================
  215.   BUFFPTR vTextEditor::appendToBuff(char* line)
  216.   {
  217.     // add text to the buffer -- allocate the spaced right here!
  218.  
  219.     BUFFPTR buff;
  220.     BUFFPTR bp;
  221.     int len = 0;
  222.     char* cp;
  223.  
  224.     for (cp = line ; *cp && *cp != '\n' && *cp != '\r' ; ++cp) // break on eos or eol
  225.       {
  226.         ++len;
  227.       }
  228.  
  229.     buff = (BUFFPTR) new char[len+2];   // the space for the line
  230.  
  231.     if (!buff)                          // did we get the space?
  232.         return 0;
  233.  
  234.     for (bp = buff, cp = line ; *cp && *cp != '\n' && *cp != '\r' ; ) // break on eos or eol
  235.       {
  236.         *bp++ = *cp++;
  237.       }
  238.      *bp++ = '\n';
  239.      *bp++ = 0;
  240.  
  241.     return buff;
  242.   }
  243.  
  244. // =========================>>> vTextEditor::insertLine <<<====================
  245.   int vTextEditor::insertLine(char* line, long before)
  246.   {
  247.     // This method adds the line before line before.
  248.     // line numbers start at 1! This is logical - it corresponds
  249.     // to how you would really number a text file. It does not
  250.     // correspond to C 0 based array indexing. So it goes.
  251.  
  252.     if (!line)
  253.         return 0;
  254.  
  255.     if (_nextLine >= _maxLines)         // check for max lines
  256.       if (!reallocLines())
  257.         return 0;
  258.  
  259.     BUFFPTR bp = appendToBuff(line);    // allocate space for line
  260.  
  261.     if (!bp)
  262.         return 0;
  263.  
  264.     if (curchr == _lines[_nextLine])
  265.       {
  266.         // When the very first line is added, curchr must be updated to
  267.         // point to the new line instead of to the initial "\n"!
  268.         curchr = bp;
  269.       }
  270.  
  271.     for (long to = _nextLine++ ; to > before ; --to)
  272.       {
  273.         _lines[to] = _lines[to-1];
  274.       }
  275.  
  276.     _lines[before] = bp;   // point line array to beginning of line
  277.     lastLine = lastLineBF();
  278.     adjustLines(before,1);
  279.  
  280.     return 1;
  281.   }
  282.  
  283.  
  284. // =====================>>> vTextEditor::getFirstLine <<<===================
  285.   int vTextEditor::getFirstLine(char* line, int maxChars)
  286.   {
  287.     // return the first line in the buffer
  288.  
  289.     return getLine(line, maxChars,1);
  290.   }
  291.  
  292. // =========================>>> vTextEditor::getNextLine <<<================
  293.   int vTextEditor::getNextLine(char* line, int maxChars)
  294.   {
  295.     // return the next line in the text buffer, not including end of line
  296.     //    returns the number of characters, -1 if at end of file
  297.  
  298.     return getLine(line, maxChars, _curLineBF +1);
  299.   }
  300.  
  301. // =========================>>> vTextEditor::getLine <<<===================
  302.   int vTextEditor::getLine(char* line, int maxChars, long lineNum)
  303.   {
  304.     // return the next line in the text buffer, not including end of line
  305.     //    returns the number of characters, -1 if at end of file
  306.  
  307.     if (lineNum >= _nextLine || lineNum < 1)            // at end!
  308.         return -1;
  309.  
  310.     _curLineBF = lineNum;                       // Set _curlineBF
  311.     int len = 0;
  312.  
  313.     for (char* ix = _lines[_curLineBF] ; *ix != 0 && *ix != '\n' && len < maxChars ; )
  314.       {
  315.         line[len++] = *ix++;    // copy & track length
  316.       }
  317.     line[len] = 0;                      // terminate
  318.     return len;
  319.   }
  320.  
  321. // ===================>>> vTextEditor::displayBuff <<<======================
  322.   void vTextEditor::displayBuff(long lineNum, int paintIt)
  323.   {
  324.     // All lines added, so now display the buffer
  325.  
  326.  
  327.     if (lineNum >= _nextLine)
  328.         lineNum = _nextLine - 1;
  329.     if (lineNum < 1)
  330.         lineNum = 1;
  331.  
  332.     curlin = lineNum;   // Internal stuff begins with line 1
  333.     curchr = GLine(curlin);     /* first char of buffer */
  334.     lastLine = lastLineBF();
  335.     int oldef = state.echof;
  336.     state.echof = paintIt;
  337.     ShowVScroll(1);
  338.     Verify();
  339.  
  340.     state.echof = oldef;
  341.   }
  342.  
  343. // =========================>>> vTextEditor::GLine <<<======================
  344.   BUFFPTR vTextEditor::GLine(long lineNum)
  345.   {
  346.     if (lineNum < 1 || lineNum >= _nextLine)
  347.       {
  348.         return _lines[1];       // something safe
  349.       }
  350.  
  351.     return _lines[lineNum];
  352.   }
  353.  
  354. // =====================>>> vTextEditor::deleteCharBF <<<===================
  355.   BUFFPTR vTextEditor::deleteCharBF(BUFFPTR charNum, long lineNum)
  356.   {
  357.     // First, shift everything up to next end of line left
  358.     // This routine must not assume that lines are stored contiguously
  359.  
  360.  
  361.     BUFFPTR ix;
  362.     BUFFPTR newCurChar = charNum;
  363.  
  364.     char combine[MAX_LINE*2+2];
  365.  
  366.     char chrDeleted = GCh(charNum);
  367.  
  368.     if (lastLineBF() < 1)
  369.         return 0;
  370.  
  371.     if (IsEndLine(chrDeleted))          // combine two lines?
  372.       {
  373.         if (lineNum < (_nextLine - 1))  // There IS a next line
  374.           {
  375.             BUFFPTR bp;
  376.             int to;
  377.             int offset;
  378.  
  379.             // combine this line with the next line
  380.             to = 0;
  381.             for (bp = _lines[lineNum] ; *bp && !IsEndLine(*bp) ; )
  382.                 combine[to++] = *bp++;
  383.  
  384.             offset = to;                // track where we were
  385.  
  386.             for (bp = _lines[lineNum+1] ; *bp && !IsEndLine(*bp) ; )
  387.                 combine[to++] = *bp++;
  388.             *bp = 0;
  389.             combine[to] = 0;
  390.  
  391.             // create buffer for it
  392.             bp = appendToBuff(combine);
  393.             if (!bp)
  394.                 return 0;
  395.  
  396.             newCurChar = bp + offset;   // this is new cur char
  397.  
  398.             // free the old space
  399.             delete [] _lines[lineNum];
  400.             delete [] _lines[lineNum+1];
  401.             _lines[lineNum] = bp;
  402.  
  403.             // shift up the rest of the lines
  404.             for (long lp = lineNum + 1 ; lp < _nextLine ; ++lp)
  405.                 _lines[lp] = _lines[lp + 1];
  406.             --_nextLine;
  407.             lastLine = lastLineBF();
  408.           }
  409.         adjustLines(lineNum,-1);    // one line deleted
  410.       }
  411.     else
  412.       {
  413.         newCurChar = charNum;
  414.         for (ix = charNum + 1 ; *ix && !IsEndLine(*ix) ; ++ix)
  415.             *(ix-1) = *ix;
  416.         *(ix-1) = *ix;
  417.         *ix = 0;
  418.       }
  419.     return newCurChar;
  420.   }
  421.  
  422. // ===================>>> vTextEditor::deleteLinesBF <<<====================
  423.   long vTextEditor::deleteLinesBF(long start, long end)
  424.   {
  425.     // delete the lines in the specified range,
  426.     // return new last line of file
  427.  
  428.     long to, from;
  429.  
  430.     if (lastLineBF() < 1)
  431.         return 0;
  432.  
  433.     for (to = start ; to <= end ; ++to)
  434.         delete[] _lines[to];
  435.  
  436.     for (to = start, from = end+1 ; from < _nextLine ; ++to, ++from)
  437.       {
  438.         _lines[to] = _lines[from];  // shift
  439.       }
  440.     _lines[from] = 0;
  441.     _nextLine -= (end - start + 1);
  442.     adjustLines(start, -(end - start + 1));
  443.     lastLine = lastLineBF();
  444.  
  445.     if (_nextLine <= 1)
  446.       {
  447.         _lines[1] = new char[2]; strcpy(_lines[1], "\n");
  448.         return 1;
  449.       }
  450.  
  451.     return _nextLine - 1;
  452.   }
  453.  
  454. // =====================>>> vTextEditor::insertCharBF <<<===================
  455.   int vTextEditor::insertCharBF(int chr, BUFFPTR& curchar, long& curline)
  456.   {
  457.     // insert a char into the buffer at curline, curchar.
  458.     // return new curchar, curline
  459.  
  460.     char ln1[MAX_LINE+2];
  461.     char ln2[MAX_LINE+2];
  462.     char* newLine;
  463.     BUFFPTR origLine = _lines[curline];  // original full line
  464.     int offSet;
  465.     int ix;
  466.     BUFFPTR fp;
  467.  
  468.  
  469.     if (chr == 0)               // don't allow this case
  470.         return 0;
  471.  
  472.     offSet = 0;
  473.     for (BUFFPTR bp = origLine ; bp != curchar ; ++bp, ++offSet)
  474.         ;
  475.  
  476.     if (chr != '\n')
  477.       {
  478.         for (ix = 0, fp = origLine ; *fp != 0 && ix < MAX_LINE ; )
  479.           {
  480.              if (ix == offSet)
  481.                 ln1[ix++] = chr;                // add the new char
  482.              ln1[ix++] = *fp++;                 // copy original line
  483.           }
  484.         if (ix == offSet)
  485.             ln1[ix++] = chr;            // add the new char
  486.         ln1[ix] = 0;
  487.         newLine = appendToBuff(ln1);
  488.         if (!newLine)                           // see if got the space
  489.             return 0;
  490.         delete [] _lines[curline];               // free the old space
  491.         _lines[curline] = newLine;               // point line to new space
  492.         curchar = newLine + offSet + 1;          // update curchar
  493.       }
  494.     else                                        // adding newline
  495.       {
  496.         // we are inserting a newline!
  497.         for (ix = 0, fp = origLine ; *fp != 0 && ix < MAX_LINE ; )
  498.           {
  499.             if (ix == offSet)
  500.                 ln1[ix++] = chr;                // add the new char
  501.             ln1[ix++] = *fp++;                  // copy original line
  502.           }
  503.         if (ix == offSet)
  504.             ln1[ix++] = chr;                    // add the new char
  505.         ln1[ix] = 0;
  506.  
  507.         // ln1 now has two lines in it, split em up.
  508.  
  509.         char* cp;
  510.         for (cp = ln1 ; *cp != '\n' ; ++cp)     // find first part
  511.             ;
  512.         *cp++ = 0;
  513.  
  514.         char *tp;
  515.         for (tp = ln2 ; *cp ; )                 // copy second part
  516.             *tp++ = *cp++;
  517.         *tp = 0;
  518.  
  519.         newLine = appendToBuff(ln1);
  520.         if (!newLine)                           // see if got the space
  521.             return 0;
  522.         delete [] _lines[curline];               // free the old space
  523.         _lines[curline] = newLine;               // point line to new space
  524.  
  525.         if (_nextLine >= _maxLines)             // check for max lines
  526.             if (!reallocLines())                // add some more lines
  527.                 return 0;
  528.  
  529.         long lx;
  530.         for (lx = _nextLine ; lx > curline ; --lx)
  531.             _lines[lx] = _lines[lx - 1];
  532.  
  533.         newLine = appendToBuff(ln2);
  534.         if (!newLine)                           // see if got the space
  535.             return 0;
  536.  
  537.         ++curline; ++_nextLine;
  538.         lastLine = lastLineBF();
  539.         adjustLines(curline,1);            // one more line
  540.  
  541.         _lines[curline] = newLine;               // point line to new space
  542.  
  543.         curchar = _lines[curline];                // point to line beginning
  544.       }
  545.     return 1;
  546.   }
  547.  
  548. // ==========================>>> vTextEditor::lineLenBF <<<=================
  549.   int vTextEditor::lineLenBF(long lineNum)
  550.   {
  551.     if (lineNum < 1 || lineNum >= (_nextLine - 1))
  552.         return 0;
  553.  
  554.     int len = 0;
  555.     for (BUFFPTR ix = _lines[lineNum] ; *ix != '\n' && *ix != 0 ; ++ix)
  556.         ++len;
  557.     return len;
  558.   }
  559.  
  560. // ===================>>> vTextEditor::adjustLines <<<======================
  561.   void vTextEditor::adjustLines(long line_1, int by)
  562.   {
  563.     /* adjust starting line number int note locaetions */
  564.  
  565.     int ix;
  566.  
  567.     for (ix = 0 ; ix < 10 ; ++ix)        /* adjust notes */
  568.       {
  569.     if (noteloc[ix] > line_1)        /* page needs fixing */
  570.         noteloc[ix] += (long) by;
  571.       }
  572.   }
  573.  
  574. // #########################################################################
  575. //
  576. // Command Interface methods
  577. //
  578. // #########################################################################
  579.  
  580. // ===================>>> vTextEditor::EditCommand <<<======================
  581.   int vTextEditor::EditCommand(int id, long val)
  582.   {
  583.     // returns 1 if command succeeded, 0 if failed
  584.     // or -1 if not processed
  585.  
  586.     int retval = 1;             // assume OK
  587.     switch (id)
  588.       {
  589.         case edCut:             // ^X : Cut
  590.           {
  591.             EditCut();
  592.             break;
  593.           }
  594.  
  595.         case edCopy:            // ^C : Copy
  596.           {
  597.             EditCopy();
  598.             break;
  599.           }
  600.  
  601.         case edPaste:           // ^V: Paste
  602.           {
  603.             EditPaste();
  604.             break;
  605.           }
  606.           
  607.         case edVerify:          // repaint screen
  608.             Verify();
  609.             break;
  610.  
  611.         case edFind:            // find
  612.           {
  613.             vFindDialog fdlg(_parent);
  614.             if (!fdlg.AskFindPat(theFindPat, MAX_LINE, findCaseSensitive))
  615.                 return 0;
  616.             retval = Find(theFindPat,findCaseSensitive,0,0);
  617.             break;
  618.           }
  619.  
  620.         case edFindNext:        // find again
  621.           {
  622.             if (*theFindPat)            // something to find
  623.                 retval = FindNext(findCaseSensitive,0,0);
  624.             else
  625.                 retval = 0;
  626.             break;
  627.           }
  628.  
  629.         case edBufferBottom:    // move to bottom of file (no val)
  630.             bufferBottom();
  631.             break;
  632.  
  633.         case edCharDelete:      // delete val chars
  634.             retval = charDelete(val);
  635.             break;
  636.  
  637.         case edCharFoldCase:    // swap case of val letters
  638.             retval = charFoldCase(val);
  639.             break;
  640.  
  641.         case edCharInsert:      // insert char val
  642.             retval = charInsert(val);
  643.             break;
  644.  
  645.         case edCharRight:       // move val chars right
  646.             retval = charRight(val);
  647.             break;
  648.  
  649.         case edLineBeginning:   // move to line beginning (no val)
  650.             lineBeginning();
  651.             break;
  652.  
  653.         case edLineDown:        // move down val lines in column
  654.             retval = lineDown(val);
  655.             break;
  656.  
  657.         case edLineDownBeg:     // move down val lines
  658.             retval = lineDownBeg(val);
  659.             break;
  660.  
  661.         case edLineDelete:      // delete val lines
  662.             lineDelete(val);
  663.             break;
  664.  
  665.         case edLineDeleteFront: // delete to beginning of line (no val)
  666.             retval = lineDeleteFront();
  667.             break;
  668.  
  669.         case edLineDeleteToEnd: // delete to end of line (no val)
  670.             retval = lineDeleteToEnd();
  671.             break;
  672.  
  673.         case edLineEnd:         // move to end of line (no val)
  674.             lineEnd();
  675.             break;
  676.  
  677.         case edLineGoto:        // move cursor to line val
  678.             retval = lineGoto(val);
  679.             break;
  680.  
  681.         case edLineOpen:        // open val new blank lines
  682.             retval = lineOpen(val);
  683.             break;
  684.  
  685.     case edFormatC:        // format C code lines
  686.         retval = formatC(val);
  687.         break;
  688.  
  689.         case edNoteLocation:    // note which line we are on
  690.             if (val < 1 || val > 9)
  691.         val = 0;
  692.         noteloc[val] = GetCurLine();
  693.             break;
  694.  
  695.         case edNoteGoto:        // goto noted locateion
  696.             if (val < 1 || val > 9)
  697.         val = 0;
  698.         retval = lineGoto(noteloc[val]);
  699.             break;
  700.  
  701.         case edWordRight:       // move cursor val words right
  702.             wordRight(val);
  703.             break;
  704.  
  705.         case edBalMatch:        // find matching paren (up to val lines away)
  706.             retval = BalMatch(val);
  707.             break;
  708.  
  709.         case edScrollDown:      // scroll val lines without changing cursor
  710.             scrollDown(val);
  711.             break;
  712.  
  713.         default:                        // editor can't handle
  714.             retval = -1;
  715.             break;
  716.       }
  717.     return retval;
  718.   }
  719.  
  720. // ======================>>> vTextEditor::EditKeyIn <<<=====================
  721.   int vTextEditor::EditKeyIn(vKey key, unsigned int shift)
  722.   {
  723.      // process keystrokes -- return 1 if processed, 0 if
  724.      // command fails, and -1 if not recognized
  725.  
  726.     return _TECInt->ProcessKey(key, shift);
  727.  
  728.   }
  729.  
  730. // ===================>>> vTextEditor::defaultKeyIn <<<=====================
  731.   int vTextEditor::defaultKeyIn(vKey key, unsigned int shift)
  732.   {
  733.     // this is a virtual function so that it would be possible
  734.     // to override this method to implement a modal editor like
  735.     // vi or see.
  736.     // Returns -1 if not processed, 1 if successful, 0 if
  737.     // command didn't succeed.
  738.  
  739.     int chr = (int)key;
  740.  
  741.     if ((shift & VKM_Alt || shift & VKM_Ctrl)
  742.     && (chr < ' ' || chr > 0x7E))
  743.         return -1;
  744.  
  745.     if (chr < ' ' && chr != '\r' && chr != '\t' && chr != '\n')
  746.         return -1;
  747.  
  748.     if (chr > 0xFE)     // ignore function and alt keys
  749.         return -1;
  750.  
  751.     return charInsert(key);
  752.   }
  753.  
  754. // =======================>>> vTextEditor::Find <<<=========================
  755.   int vTextEditor::Find(char* pat, int caseSensitive, int Down, int Wrap)
  756.   {
  757.     // Copy a new pattern to the pattern buffer
  758.  
  759.     char *fp = pat;
  760.     int ix;
  761.     for (ix = 0 ; *fp && ix < MAX_LINE ; )
  762.         theFindPat[ix++] = *fp++;
  763.     theFindPat[ix] = 0;
  764.  
  765.     return FindNext(caseSensitive, Down, Wrap); // now use findNext
  766.   }
  767.  
  768. // =====================>>> vTextEditor::FindNext <<<=======================
  769.   int vTextEditor::FindNext(int caseSensitive, int Down, int Wrap)
  770.   {
  771.     // find a pattern = return 1 if found, 0 if not
  772.  
  773.     BUFFPTR findBP = curchr;
  774.     char* foundAt;
  775.     int ix;
  776.     int lineOffset = 0;
  777.  
  778.     char workPat[MAX_LINE + 2]; // working pattern
  779.     char workLine[MAX_LINE + 2];        // working line
  780.  
  781.     long findLine = curlin;
  782.     long origLine = curlin;
  783.  
  784.     if (lastLineBF() < 1)
  785.         return 0;
  786.  
  787.     int patLen = strlen(theFindPat);
  788.  
  789.     for (ix = 0 ; theFindPat[ix] != 0 ; ++ix)
  790.       {
  791.         if (caseSensitive)
  792.             workPat[ix] = theFindPat[ix];
  793.         else
  794.             workPat[ix] = tolower(theFindPat[ix]);
  795.       }
  796.     workPat[ix] = 0;
  797.  
  798.     //@@@  just down for now...
  799.  
  800.     for ( ; ; )
  801.       {
  802.         lineOffset = findBP - GLine(findLine);  // if not at beginning
  803.         for (ix = 0 ; ix < MAX_LINE && GCh(findBP) != 0 ; ++findBP, ++ix)
  804.           {
  805.             if (caseSensitive)
  806.                 workLine[ix] = GCh(findBP);
  807.             else
  808.                 workLine[ix] = tolower(GCh(findBP));
  809.           }
  810.         workLine[ix] = 0;
  811.  
  812.         foundAt = strstr(workLine,workPat);             // see if in there
  813.  
  814.         if (foundAt != 0)                       // We found it!
  815.           {
  816.             ClearMarkRange();                   /* no range now */
  817.             curlin = findLine;
  818.             int offset = foundAt - &workLine[0];
  819.  
  820.             curchr = GLine(curlin) + offset + lineOffset;
  821.  
  822.             // set up mark range
  823.             mark.beg_lin = mark.end_lin = curlin;
  824.             mark.beg_col = col_pos(curchr,0);
  825.             mark.end_col = col_pos(curchr+patLen,0);
  826.             mark.beg_chr = curchr;
  827.             mark.end_chr = curchr + patLen;
  828.  
  829.             if (!state.findAtBeginning)
  830.                 curchr += patLen;               // leave at end
  831.  
  832.             // need intelligent screen updating
  833.             update(curlin - origLine);
  834.             return 1;
  835.           }
  836.         if (findLine >= lastLine)
  837.           {
  838.             StatusMessage(" Pattern Not Found");
  839.             return 0;
  840.           }
  841.         else
  842.           {
  843.             findLine++;
  844.             findBP = GLine(findLine);
  845.           }
  846.  
  847.       }
  848.     StatusMessage(" Pattern Not Found");
  849.     return 0;
  850.   }
  851.  
  852. // =======================>>> vTextEditor::HPage <<<========================
  853.   void vTextEditor::HPage(int shown, int top)
  854.   {
  855.     vTextCanvasPane::HPage(shown, top);
  856.   }
  857.  
  858. // =======================>>> vTextEditor::VPage <<<========================
  859.   void vTextEditor::VPage(int shown, int top)
  860.   {
  861.  
  862. #ifndef PAGEandMOVE
  863.     long target;
  864.     if (lastLineBF() < 1 || lastLine <= GetRows())
  865.       {
  866.         setScrollBar();
  867.         return;
  868.       }
  869.     if ((top+shown) >= 100)
  870.         target = lastLine;
  871.     else if (top < 1)
  872.         target = 1;
  873.     else
  874.         target = ((long)top * lastLine) / 100;
  875.  
  876.     if (target < 1)
  877.         target = 1;
  878.     if (target > lastLine)
  879.         target = lastLine;
  880.     if (scroll_lin < 0)
  881.         scrollDown(target - curlin);
  882.     else
  883.         scrollDown(target-scroll_lin);
  884. #else
  885.     // this code moves cursor on scroll bar page - not what we really want
  886.  
  887.     if (lastLineBF() < 1 || lastLine <= GetRows())
  888.       {
  889.         setScrollBar();
  890.         return;
  891.       }
  892.     if ((top+shown) >= 100)
  893.         curlin = lastLine;
  894.     else if (top < 1)
  895.         curlin = 1;
  896.     else
  897.         curlin = ((long)top * lastLine) / 100;
  898.  
  899.     if (curlin < 1)
  900.         curlin = 1;
  901.     if (curlin > lastLine)
  902.         curlin = lastLine;
  903.  
  904.     curchr = GLine(curlin);             // have to update this, too!
  905.  
  906.     // Some tricky stuff to put the cursor in the middle.
  907.     int old_ddline = ddline;
  908.     if (lastLine > GetRows())
  909.         ddline = GetRows() / 2;
  910.     else
  911.         ddline = lastLine / 2;
  912.     if (ddline < 1)
  913.         ddline = 1;
  914.     newscr();
  915.     tvxy(findX(),tvy);          /* reset cursor to current position */
  916.     ddline = old_ddline;
  917.  
  918.     setScrollBar();                     // MUST do this!
  919.     ChangeLoc(curlin,col_pos(curchr,0));
  920. #endif
  921.   }
  922.  
  923. // =====================>>> vTextEditor::HScroll <<<========================
  924.   void vTextEditor::HScroll(int step)
  925.   {
  926.     vTextCanvasPane::HScroll(step);
  927.   }
  928.  
  929. // =====================>>> vTextEditor::VScroll <<<========================
  930.   void vTextEditor::VScroll(int step)
  931.   {
  932.     if (step < 0)
  933.         scrollDown(-1);
  934.     else
  935.         scrollDown(1);
  936.   }
  937.  
  938. // =====================>>> vTextEditor::FontChanged <<<====================
  939.   void vTextEditor::FontChanged(VCONST vFont& newFont)
  940.   {
  941.     vTextCanvasPane::FontChanged(newFont);
  942.   }
  943.  
  944. // ====================>>> vTextEditor::TextMouseDown <<<===================
  945.   void vTextEditor::TextMouseDown(int row, int col, int button)
  946.   {
  947.  
  948.      if (button != 1)            // ignore right button moves
  949.       {
  950.         vTextCanvasPane::TextMouseDown(row, col, button);
  951.         return;
  952.       }
  953.     mouseMoveRow = mouseRow = row + 1;  // convert to 1,1 corner
  954.     mouseMoveCol = mouseCol = col + 1;
  955.     MouseMoveTo(mouseRow,mouseCol);     // doing the move at mouse down
  956.                                         // makes selections easier
  957.     setScrollBar();
  958.     ClearMarkRange();                   // forces deselect
  959.  
  960.   }
  961.  
  962. // ======================>>> vTextEditor::TextMouseUp <<<===================
  963.   void vTextEditor::TextMouseUp(int r, int c, int button)
  964.   {
  965.     if (button != 1)            // ignore right button moves
  966.       {
  967.         vTextCanvasPane::TextMouseUp(r, c, button);
  968.         return;
  969.       }
  970.  
  971.     if (mouseRow <= 0 || mouseCol <= 0)
  972.         return;
  973.  
  974.     if (curlin < 1 || GetCols() < 1 || lastLineBF() < 1)
  975.         return;
  976.  
  977.     int row = r + 1;                    // convert to 1,1 corner
  978.     int col = c + 1;
  979.  
  980.  
  981.     if (mouseRow != row || mouseCol != col)     // selection
  982.       {
  983.         // @@@ This code actually needs to copy the selection
  984.         // to the clipboard on X, and does nothing on Win
  985.         // except enable the Cut/Copy menu item
  986.       }
  987.  
  988.     }
  989.  
  990. // ======================>>> vTextEditor::MouseMoveTo <<<=================
  991.   void vTextEditor::MouseMoveTo(int row, int col)
  992.   {
  993.  
  994.     // used by MouseUp and MouseMove to update cursor location
  995.     if (scroll_lin < 0)                     // regular move
  996.       {
  997.         int cnt = row - tvdlin;
  998.         if (cnt != 0)                       // difference
  999.             lineDownBeg((long)cnt,0);               // changing
  1000.         else
  1001.             lineBeginning();                // same row
  1002.       }
  1003.     else                    // switching position to scroll window
  1004.       {
  1005.         curlin = maxl((long)1,minl(scroll_lin + row - 1,lastLine));
  1006.         curchr = GLine(curlin);
  1007.       }
  1008.     // now move to column
  1009.  
  1010.     while (!IsEndLine(GCh(curchr)) && col > findX() )
  1011.       {
  1012.         ++curchr;
  1013.       }
  1014.     if (scroll_lin < 0)                     /* regular move */
  1015.       {
  1016.         tvhdln();
  1017.       }
  1018.     else                        /* need to verify since things can be off */
  1019.       {
  1020.         scroll_lin = -1;
  1021.         long old_ddline = ddline;   // trick - terrible awful coding, but...
  1022.         ddline = row;
  1023.         newscr();
  1024.         int xf = findX();
  1025.         tvxy(xf,tvy);       /* reset cursor to current position */
  1026.         ddline = old_ddline;
  1027.       }
  1028.     b_lastln = curlin;
  1029.     ChangeLoc(curlin,col_pos(curchr,0));
  1030.   }
  1031.  
  1032. // ======================>>> vTextEditor::TextMouseMove <<<=================
  1033.   void vTextEditor::TextMouseMove(int r, int c, int button)
  1034.   {
  1035.  
  1036.     if (button != 1)            // ignore right button moves
  1037.       {
  1038.         vTextCanvasPane::TextMouseMove(r, c, button);
  1039.       }
  1040.     else                // highlighting text
  1041.       {
  1042.         if (mouseRow <= 0 || mouseCol <= 0)
  1043.             return;
  1044.  
  1045.         if (curlin < 1 || GetCols() < 1 || lastLineBF() < 1)
  1046.             return;
  1047.  
  1048.         int row = r + 1;                // convert to 1,1 corner
  1049.         int col = c + 1;
  1050.  
  1051.         if (mouseMoveRow != row)        // have moved a row down or up
  1052.           {
  1053.             if (row > mouseMoveRow)     // moved down
  1054.               {
  1055.                 int cnt = row - mouseMoveRow;
  1056.                 AddToRangeRow(cnt, row, col);   // add rows
  1057.                 mouseMoveRow = row;
  1058.                 // and update to columns
  1059.                 AddToRangeCol(row, col);
  1060.                 mouseMoveCol = col;
  1061.               }
  1062.             else                        // moving mouse up rows
  1063.               {
  1064.                 int cnt = row - mouseMoveRow;
  1065.                 AddToRangeRow(cnt, row, col);   // add rows
  1066.                 mouseMoveRow = row;
  1067.                 // and update to columns
  1068.                 AddToRangeCol(row, col);
  1069.                 mouseMoveCol = col;
  1070.               }
  1071.  
  1072.           }
  1073.         else if (mouseMoveCol != col)   // mouse to right of start
  1074.           {
  1075.              AddToRangeCol(row, col);
  1076.              mouseMoveCol = col;
  1077.           }
  1078.       }
  1079.   }
  1080.  
  1081. // =========================>>> vTextEditor::AddToRangeCol <<<=================
  1082.   void vTextEditor::AddToRangeCol(int row, int col)
  1083.   {
  1084.  
  1085.     if (col_pos(curchr,0) < col)        // add to right
  1086.       {
  1087.         if (mark.beg_lin == 0)          /* no lines yet */
  1088.           {
  1089.             mark.end_lin = mark.beg_lin = curlin;
  1090.             mark.end_chr = mark.beg_chr = curchr;
  1091.             mark.end_col = mark.beg_col = col_pos(curchr,0);
  1092.             while (!IsEndLine(GCh(curchr))
  1093.                    && col_pos(curchr,0) < col)  // find new col
  1094.                 charRight(1,0);
  1095.             mark.end_chr = curchr;
  1096.             mark.end_col = col_pos(curchr,0);
  1097.           }
  1098.         else if (mark.end_lin < curlin)
  1099.           {
  1100.             mark.end_lin = curlin;
  1101.             mark.end_chr = curchr;
  1102.             mark.end_col = col_pos(curchr,0);
  1103.           }
  1104.         else if (mark.beg_lin == curlin && mark.end_lin == curlin
  1105.                  && col_pos(curchr,0) > mark.end_col)
  1106.           {
  1107.               mark.beg_col = mark.end_col;
  1108.               mark.beg_chr = mark.end_chr;
  1109.               mark.end_chr = curchr;
  1110.               mark.end_col = col_pos(curchr,0);
  1111.           }
  1112.         else if (mark.beg_lin == curlin &&  // some of this line marked
  1113.                  ((mark.end_lin == curlin && col_pos(curchr,0) < mark.end_col)
  1114.                  || mark.end_lin != mark.beg_lin))
  1115.           {
  1116.             while (!IsEndLine(GCh(curchr))
  1117.                    && col_pos(curchr) < col)    // find new col
  1118.                 charRight(1,0);
  1119.             mark.beg_col = col_pos(curchr,0);
  1120.             mark.beg_chr = curchr;
  1121.           }
  1122.         else                            // normal add to marked
  1123.           {
  1124.             while (!IsEndLine(GCh(curchr))
  1125.                    && col_pos(curchr) < col)    // find new col
  1126.                 charRight(1,0);
  1127.  
  1128.             mark.end_lin = curlin;
  1129.             mark.end_chr = curchr;
  1130.             mark.end_col = col_pos(curchr,0);
  1131.           }
  1132.       }
  1133.     else                                // add to left
  1134.       {
  1135.         if (mark.beg_lin == 0)          // no lines yet, so note it
  1136.           {
  1137.             if (curchr == GLine(curlin))
  1138.                 return;                 // No op at line beginning
  1139.             mark.end_lin = mark.beg_lin = curlin;
  1140.             mark.end_chr = mark.beg_chr = curchr;
  1141.             mark.end_col = mark.beg_col = col_pos(curchr,0);
  1142.             while (col_pos(curchr) > col)       // find new col
  1143.                 charRight(-1,0);
  1144.             mark.beg_chr = curchr;
  1145.             mark.beg_col = col_pos(curchr,0);
  1146.  
  1147.           }
  1148.         else if (mark.end_lin < curlin)
  1149.           {
  1150.             mark.end_lin = curlin;
  1151.             mark.end_chr = curchr;
  1152.             mark.end_col = col_pos(curchr,0);
  1153.           }
  1154.         else if (mark.end_lin == curlin &&  // some of this line marked
  1155.              ((mark.beg_lin == curlin && col_pos(curchr,0) > mark.beg_col)
  1156.               || mark.beg_lin != curlin))
  1157.           {
  1158.             // handles two cases: highlight on current line only,
  1159.             // or highlight starts on some line before
  1160.             while (col_pos(curchr) > col)       // find new col
  1161.                 charRight(-1,0);
  1162.             mark.end_col = col_pos(curchr,0);
  1163.             mark.end_chr = curchr;
  1164.           }
  1165.         else if (mark.end_lin == curlin  // some of this line marked
  1166.                  && col_pos(curchr,0) > mark.beg_col)
  1167.           {
  1168.             while (col_pos(curchr) > col)       // find new col
  1169.                 charRight(-1,0);
  1170.             mark.end_col = col_pos(curchr,0);
  1171.             mark.end_chr = curchr;
  1172.           }
  1173.         else                            // normal add to marked
  1174.           {
  1175.             while (col_pos(curchr) > col)       // find new col
  1176.                 charRight(-1,0);
  1177.  
  1178.             mark.beg_lin = curlin;
  1179.             mark.beg_chr = curchr;
  1180.             mark.beg_col = col_pos(curchr,0);
  1181.           }
  1182.       }
  1183.  
  1184.     tvxy(1,tvy);                // Finally, fix up the highlight
  1185.     type_lines(curlin, 1);      // by repainting current line
  1186.     tvhdln();                   // and rehome cursor
  1187.     ((vWindow *)_parent)->SetValue(M_Cut, 1, Sensitive);
  1188.     ((vWindow *)_parent)->SetValue(M_Copy, 1, Sensitive);
  1189.  }
  1190.  
  1191. // =========================>>> vTextEditor::AddToRangeRow <<<=================
  1192.   void vTextEditor::AddToRangeRow(long cnt, int row, int col)
  1193.   {
  1194.     /* add to mark range varaiable, update current line, then go down */
  1195.     if (cnt == 0)
  1196.       {
  1197.         ClearMarkRange();               /* no range now */
  1198.         return;
  1199.       }
  1200.  
  1201.     if (cnt > 0)
  1202.       {
  1203.         if (curlin + cnt > lastLine)    /* past end? */
  1204.             cnt = lastLine - curlin + 1;
  1205.         if (mark.beg_lin == 0)  /* no lines yet */
  1206.           {
  1207.             mark.beg_lin = curlin;
  1208.             mark.beg_chr = curchr;
  1209.             mark.beg_col = col_pos(curchr,0);
  1210.           }
  1211.         if (mark.end_lin == 0)
  1212.           {
  1213.             mark.end_lin = curlin + cnt - 1;
  1214.           }
  1215.         else if (mark.beg_lin == curlin   // some of this line marked
  1216.                  && mark.end_lin != mark.beg_lin)
  1217.           {
  1218.             if (mark.end_lin == curlin + cnt
  1219.                 && col_pos(curchr,0) > mark.end_col)
  1220.               {
  1221.                 mark.beg_lin = curlin + cnt;
  1222.                 mark.beg_col = mark.end_col;
  1223.                 mark.beg_chr = mark.end_chr;
  1224.               }
  1225.             else
  1226.               {
  1227.                 mark.beg_col = col_pos(curchr,0);
  1228.                 mark.beg_chr = GLine(curlin+cnt);       // Something legal
  1229.                 mark.beg_lin = curlin + cnt;
  1230.               }
  1231.           }
  1232.         else
  1233.           {
  1234.             mark.end_lin += cnt;
  1235.             mark.end_col = 1000;            /* BIG */
  1236.             mark.end_chr = 0;               /* end of line */
  1237.           }
  1238.  
  1239.         /* paint the lines to highlight */
  1240.         if (tvdlin+cnt-1 <= GetRows())
  1241.           {
  1242.             tvxy(1,tvy);        /* fix it up */
  1243.             type_lines(curlin,(int)cnt);
  1244.           }
  1245.  
  1246.         if (curlin == lastLine && cnt > 0)      /* down from last line? */
  1247.           {
  1248.             return;
  1249.           }
  1250.         lineDown(cnt,0);
  1251.  
  1252.       }
  1253.     else if (cnt < 0)                   // up lines
  1254.       {
  1255.         if (curlin + cnt < 1)           // past start?
  1256.             cnt = -curlin;
  1257.         if (mark.end_lin == curlin && mark.beg_lin == curlin
  1258.             && mark.end_lin != 0)
  1259.           {
  1260.                 mark.end_col = mark.beg_col;
  1261.                 mark.end_chr = mark.beg_chr;
  1262.                 lineDown(cnt,0);
  1263.                 mark.beg_lin = curlin;
  1264.                 mark.beg_col = col_pos(curchr,0);
  1265.                 mark.beg_chr = curchr;
  1266.           }
  1267.         else
  1268.           {
  1269.             if (mark.end_lin == 0)              //no lines yet
  1270.               {
  1271.                 mark.beg_lin = mark.end_lin = curlin;
  1272.                 mark.end_chr = curchr;
  1273.                 mark.end_col = col_pos(curchr,0);
  1274.                 mark.beg_col = 1;
  1275.                 mark.beg_chr = GLine(curlin);
  1276.               }
  1277.  
  1278.             if (mark.end_lin == curlin   // some of this line marked
  1279.                 && mark.end_lin != mark.beg_lin)
  1280.               {
  1281.                 if (mark.beg_lin == curlin + cnt
  1282.                    && col_pos(curchr,0) < mark.beg_col)
  1283.                   {
  1284.                     mark.end_lin = curlin + cnt;
  1285.                     mark.end_col = mark.beg_col;
  1286.                     mark.end_chr = mark.beg_chr;
  1287.                     lineDown(cnt,0);
  1288.                     mark.beg_col = col_pos(curchr,0);
  1289.                     mark.beg_chr = curchr;
  1290.                   }
  1291.                 else
  1292.                   {
  1293.                     lineDown(cnt,0);
  1294.                     mark.end_col = col_pos(curchr,0);
  1295.                     mark.end_chr = GLine(curlin+cnt);   // Something legal
  1296.                     mark.end_lin = curlin;
  1297.                   }
  1298.               }
  1299.             else
  1300.               {
  1301.                 // now move up specified number of lines, no clrRange
  1302.                 lineDown(cnt, 0);
  1303.  
  1304.                 mark.beg_lin = curlin;
  1305.                 mark.beg_chr = curchr;
  1306.                 mark.beg_col = col_pos(curchr,0);
  1307.               }
  1308.             }
  1309.  
  1310.             /* paint the lines to highlight */
  1311.           tvxy(1,tvy);        /* fix it up */
  1312.           type_lines(curlin,(int)-cnt+1);
  1313.           tvhdln();
  1314.       }
  1315.     ((vWindow *)_parent)->SetValue(M_Cut, 1, Sensitive);
  1316.     ((vWindow *)_parent)->SetValue(M_Copy, 1, Sensitive);
  1317.   }
  1318.  
  1319.  
  1320. // =========================>>> vTextEditor::Redraw <<<=====================
  1321.   void vTextEditor::Redraw(int x, int y, int w, int h)
  1322.   {
  1323.     vTextCanvasPane::Redraw(x,y,w,h);
  1324.   }
  1325.  
  1326. // ======================>>> vTextEditor::ResizeText <<<====================
  1327.   void vTextEditor::ResizeText(const int rows, const int cols)
  1328.   {
  1329.     Verify();
  1330.   }
  1331.  
  1332. // #########################################################################
  1333. //
  1334. // screen update stuff - maps old see/tv to vTextCanvasPane methods
  1335. //
  1336. // #########################################################################
  1337.  
  1338. // =========================>>> vTextEditor::tvxy <<<=======================
  1339.   void vTextEditor::tvxy(int ix, int iy)
  1340.   {
  1341.     // tvxy - position cursor at position x,y 
  1342.     //          x=1 is left most column
  1343.     //          y=1 is top most line
  1344.  
  1345.     tvx = ix;
  1346.     tvy = iy;
  1347.     if (!state.echof)
  1348.         return;
  1349.     GotoRC(iy-1,ix-1);  // Convert to 0,0 based coords
  1350.   }
  1351.  
  1352. // =========================>>> vTextEditor::tvplin <<<=====================
  1353.   void vTextEditor::tvplin(long lineNum, BUFFPTR chrptr, int whole_line,
  1354.                            int hibeg, int hiend)
  1355.   { /* tvplin - put line beginning at chrptr
  1356.                 will only type what will fit on screen (using xout) */
  1357.  
  1358.     char tmp;
  1359.     int linlen, origx, need_hi_end;
  1360.  
  1361.     int hiStart = -1;
  1362.     int hiLast = -1;
  1363.  
  1364.     BUFFPTR i;
  1365.  
  1366.     char linout[MAX_LINE+1];
  1367.  
  1368.     need_hi_end = 0;
  1369.  
  1370.     last_col_out = linptr = 0;
  1371.     origx = xoutcm;                     /* save x so can get true linelen */
  1372.     for (i =  chrptr; !IsEndLine(GCh(i)) && xoutcm < MAX_LINE; ++i)
  1373.       {
  1374.         /* xoutcm has current column.  If a hilite goes here,
  1375.            add to the linout array as 0x01 or 0x02.
  1376.         */
  1377.         if (xoutcm == hibeg)
  1378.           {
  1379.             hiStart = linptr;           // where highlight starts
  1380.             need_hi_end = 1;            /* will need a follow */
  1381.           }
  1382.         if (xoutcm == hiend)
  1383.           {
  1384.             hiLast = linptr;            // where highlight ends
  1385.             need_hi_end = 0;            /* don't need a follow now */
  1386.           }
  1387.         if (GCh(i) < ' ' && GCh(i) >= 0)        /* control character? */
  1388.           {
  1389.             if (GCh(i) == '\t')
  1390.               {
  1391.                 if (state.tabspc > 0)
  1392.                   {
  1393.                     do
  1394.                       {
  1395.                         linout[linptr++] = ' '; /* replace with blanks */
  1396.                         ++xoutcm;
  1397.                       }
  1398.                     while ( ((xoutcm-1) % state.tabspc) != 0);
  1399.                   }
  1400.                 else
  1401.                   {
  1402.                     linout[linptr++] = '^';
  1403.                     linout[linptr++] = 'I';
  1404.                     xoutcm += 2;
  1405.                     linout[linptr++] = '*';
  1406.                     ++xoutcm;
  1407.                   }
  1408.                 continue;
  1409.               }
  1410.             else                /*  other control character */
  1411.               {
  1412.                 linout[linptr++] = '^';
  1413.                 ++xoutcm;
  1414.                 if (xoutcm == GetCols() && !(IsEndLine(GCh(i))) )
  1415.                     continue;
  1416.                 tmp = GCh(i) + '@';
  1417.                 linout[linptr++] = tmp;
  1418.  
  1419.               }
  1420.           } /*# end if control character */
  1421.         else
  1422.           {
  1423.             linout[linptr++] = GCh(i);
  1424.           }
  1425.         ++xoutcm;
  1426.       }
  1427.  
  1428.     if (need_hi_end)
  1429.       {
  1430.         hiLast = linptr;
  1431.         need_hi_end = 0;        /* don't need a follow now */
  1432.       }
  1433.  
  1434.     linout[linptr] = 0;         // terminate the line
  1435.  
  1436.     int lineStart =  0;
  1437.  
  1438.     // This whole line stuff is left over. I don't know exactly what it
  1439.     // did, but it breaks repainting when the margin is shifted, so just
  1440.     // ignore the whole_line value...  BEW: 10/1/98
  1441.  
  1442. //@    if (whole_line)             /* write whole line */
  1443.       {
  1444.         last_col_out = linlen = mint(GetCols(),linptr-leftmg+1);
  1445.         lineStart = leftmg - 1;
  1446.       }
  1447. #ifdef XXXXX
  1448.     else                        // just part of line
  1449.       {
  1450.         linlen = mint(GetCols()-origx+1,linptr);
  1451.         last_col_out = linlen + origx - 1;
  1452.         lineStart = 0;
  1453.       }
  1454. #endif
  1455.  
  1456.     if (linlen > 0)
  1457.     paintLine(linout, lineStart, hiStart, hiLast, lineNum);
  1458.  
  1459.   }
  1460.  
  1461. // ======================>>> vTextEditor::paintLine <<<=====================
  1462.   void vTextEditor::paintLine(char* linout, int lineStart,
  1463.         int hiStart, int hiLast, long lineNum)
  1464.   {
  1465.     // paint a line. This can be overridden (e.g., for syntax highlighting).
  1466.     // linout: the line to output with tabs converted to spaces, etc.
  1467.     // lineStart: where to begin printing the line (for hoiz. scrolling)
  1468.     // hiStart, hiLast: reverse text attribute
  1469.     // lineNum: the real line number in the buffer this is. This is unused
  1470.     //          normally, but can be used for syntax highlighting to get
  1471.     //          surrounding context.
  1472.  
  1473.     int linlen = strlen(linout);
  1474.     if (linlen > 0)             // only draw if there!
  1475.       {
  1476.         char tmpChr;                // to hold char
  1477.  
  1478.         if (hiStart < lineStart && hiLast < lineStart)  // no highlight
  1479.           {
  1480.             DrawText(&linout[lineStart]);       // simple case
  1481.           }
  1482.         else                    // has highlighting
  1483.           {
  1484.             if (hiStart > lineStart)    // highlight from beginning
  1485.               {
  1486.                 tmpChr = linout[hiStart];       // remember char
  1487.                 linout[hiStart] = 0;
  1488.                 DrawText(&linout[lineStart]);  // normal part
  1489.                 linout[hiStart] = tmpChr;       // replace
  1490.               }
  1491.  
  1492.             tmpChr = linout[hiLast];    // remember char
  1493.             linout[hiLast] = 0;         // make end of string
  1494.             DrawAttrText(&linout[hiStart],ChHighlight); // highlight part
  1495.             linout[hiLast] = tmpChr;    // replace
  1496.  
  1497.             if (linlen > hiLast)        // rest of line
  1498.                 DrawText(&linout[hiLast]);
  1499.           }
  1500.       }
  1501.   }
  1502.  
  1503.  
  1504. // ====================>>> vTextEditor::type_lines <<<======================
  1505.   void vTextEditor::type_lines(long ibeg, int icnt)
  1506.   { /* type_lines - type icnt lines starting at lines[ibeg]
  1507.                 no cr/lf on the last line */
  1508.  
  1509.     long i, lim;
  1510.     int hibeg, hiend;
  1511.     BUFFPTR start;
  1512.  
  1513.     if (!state.echof)
  1514.         return;
  1515.     if (ibeg < 1 || ibeg > lastLine)
  1516.         return;
  1517.     xoutcm = tvx;
  1518.     lim = ibeg+icnt-1;
  1519.  
  1520.     for (i = ibeg ; i <= lim && i <= lastLine ; ++i)
  1521.       {
  1522.         /* simple check for whole line highlighting for now */
  1523.         if (i == mark.beg_lin)
  1524.           {
  1525.             hibeg = mark.beg_col;
  1526.             if (i == mark.end_lin)
  1527.                 hiend = mark.end_col;
  1528.             else
  1529.                 hiend = 1000;
  1530.           }
  1531.         else if (i >= mark.beg_lin && i <= mark.end_lin)
  1532.           {
  1533.             hibeg = 1;
  1534.             if (i == mark.end_lin)
  1535.                 hiend = mark.end_col;
  1536.             else
  1537.                 hiend = 1000;
  1538.           }
  1539.         else
  1540.           {
  1541.             hibeg = hiend = -1;
  1542.           }
  1543.  
  1544.         start = GLine(i);
  1545.         tvplin(i,start,1,hibeg, hiend); /* type out a wole line */
  1546.         xoutcm = 1;
  1547.         if (last_col_out < GetCols())
  1548.             tvelin();   /* erase rest of line */
  1549.         if ( i != lim )
  1550.             tvxy(1,++tvy);
  1551.       }
  1552.   }
  1553.  
  1554. // =========================>>> vTextEditor::Verify <<<=====================
  1555.   void vTextEditor::Verify(void)
  1556.   { // Verify - rewrite the screen or type current line with cursor
  1557.  
  1558.     int xf, old_ddline;
  1559.  
  1560.     if (!state.echof)
  1561.         return;
  1562.  
  1563.     if (lastLineBF() < 1)
  1564.       {
  1565.         tvclr();
  1566.         return;
  1567.       }
  1568.     old_ddline = ddline;
  1569.     ddline = dsplin;
  1570.     newscr();
  1571.     xf = findX();
  1572.     tvxy(xf,tvy);       /* reset cursor to current position */
  1573.     ddline = old_ddline;
  1574.     ChangeLoc(curlin,col_pos(curchr,0));
  1575.     setScrollBar();
  1576.   }
  1577.  
  1578. // =====================>>> vTextEditor::tvbotb <<<=========================
  1579.   void vTextEditor::tvbotb(int n)
  1580.   {  // tvbotb - make n blank lines at the bottom of the screen
  1581.  
  1582.     if (!state.echof)
  1583.         return;
  1584.     if (n >= GetRows())
  1585.       {
  1586.         tvclr();
  1587.       }
  1588.     else 
  1589.       {
  1590.         tvxy(1,GetRows());      /* go to real last line */
  1591.  
  1592.         ScrollText(n);
  1593.         int j = GetRows()-n+1;  /* home to virtual last line */
  1594.         tvxy(1,j);      /* position at first new blank line */
  1595.       }
  1596.   }
  1597.  
  1598. // ==========================>>> vTextEditor::tvclr  <<<==========================
  1599.   void vTextEditor::tvclr(void)
  1600.   {  // tvclr - clear the entire screen and home
  1601.  
  1602.     if (!state.echof)
  1603.         return;
  1604.     Clear();
  1605.     tvxy(1,1);
  1606.     tvx = tvy = 1;
  1607.   }
  1608.  
  1609. // ========================>>> vTextEditor::tvelin <<<======================
  1610.   void vTextEditor::tvelin(void)
  1611.   {  // tvelin - erase the rest of the current line 
  1612.  
  1613.     if (!state.echof)
  1614.         return;
  1615.     int r,c;
  1616.     GetRC(r,c);
  1617.     ClearRow(r, c);
  1618.   }
  1619.  
  1620. // ========================>>> vTextEditor::tvescr <<<======================
  1621.   void vTextEditor::tvescr(void)
  1622.   {  // tvelin - erase from cursor to end of screen
  1623.  
  1624.     if (!state.echof)
  1625.         return;
  1626.     ClearToEnd(tvy-1, tvx - 1);
  1627.   }
  1628.  
  1629. // ==========================>>> vTextEditor::tvtopb <<<====================
  1630.   void vTextEditor::tvtopb(int n)
  1631.   {  // tvtopb - create n blank lines at the top of the screen
  1632.  
  1633.     if (!state.echof)
  1634.         return;
  1635.  
  1636.     tvxy(1,1);          /* home first */
  1637.     if ( n >= GetRows())
  1638.       {
  1639.         tvescr();       /* simply erase the screen */
  1640.       }
  1641.     else
  1642.       {
  1643.         ScrollText(-n);
  1644.       }
  1645.     tvxy(1,1);          /* home first */
  1646.   }
  1647.  
  1648. // =======================>>> vTextEditor::bufferBottom <<<=================
  1649.   void vTextEditor::bufferBottom(void)
  1650.   { // bufferBottom - move cursor to bottom of current buffer
  1651.  
  1652.     if (lastLineBF() < 1)
  1653.         return;
  1654.  
  1655.     ClearMarkRange();           /* no range now */
  1656.     wasColCmd = 0;
  1657.  
  1658.     curlin = lastLine;          /* the last real line of text */
  1659.     curchr = GLine(curlin);     /* the first char of that line */
  1660.     lineEnd();                  /* goto end of the line */
  1661.     newscr();                   /* update the screen */
  1662.   }
  1663.  
  1664. // #########################################################################
  1665. //
  1666. // char methods
  1667. //
  1668. // #########################################################################
  1669.  
  1670. // =======================>>> vTextEditor::charDelete <<<===================
  1671.   int vTextEditor::charDelete(long cnt)
  1672.   {  // charDelete - delete next cnt characters
  1673.  
  1674.     static char chdel;
  1675.     int abscnt,newx;
  1676.     int i;
  1677.  
  1678.     if (state.readOnly || lastLineBF() < 1)
  1679.         return 0;
  1680.  
  1681.     checkIfScrolled();
  1682.     if (RemoveMarkRange())      /* there was a range to kill */
  1683.         return 1;
  1684.     ClearMarkRange();           /* no range now */
  1685.     wasColCmd = 0;
  1686.  
  1687.     abscnt = (cnt > 0) ? cnt : (-cnt);  /* remember absolute value of cnt */
  1688.  
  1689.     state.changes += abscnt;                    /* track changes */
  1690.  
  1691.     if (cnt < 0)
  1692.         charRight(cnt,0);
  1693.  
  1694.     for (i = 0 ; i < abscnt ; ++i)
  1695.       {
  1696.         chdel = GCh(curchr); /* remember the char we are deleting */
  1697.         curchr = deleteCharBF(curchr,curlin);
  1698.         if (curchr == 0)
  1699.             return 0;
  1700.         if (!IsEndLine(chdel))
  1701.           {
  1702.             retypeCurlin(1);            // just retype current line
  1703.           }
  1704.         else
  1705.           {
  1706.             lastLine = lastLineBF();
  1707.             if (tvdlin < dsplin)        // not at end
  1708.               {
  1709.                 tvescr();               /* erase rest of screen */
  1710.                 tvxy(1,tvy);            /* fix it up */
  1711.                 type_lines(curlin,mint((int)(GetRows() - tvdlin+1),
  1712.                                        (int)(lastLine - curlin))  );
  1713.                 newx = findX();         /* where cursor will go */
  1714.                 tvxy(newx,tvy);         /* reposition cursor */
  1715.               }
  1716.             else                        /* at end of buffer */
  1717.                 Verify(); 
  1718.           }
  1719.       }
  1720.  
  1721.     ChangeLoc(curlin,col_pos(curchr,0));
  1722.     return 1;
  1723.   }
  1724.  
  1725. //=====================>>> vTextEditor::charFoldCase <<<====================
  1726.   int vTextEditor::charFoldCase(long cnt)
  1727.   {
  1728.         /* fold from upper to lower or lower to upper case if letter */
  1729.     int ni;
  1730.     char fchr;
  1731.  
  1732.     if (state.readOnly)
  1733.         return 0;
  1734.  
  1735.     ClearMarkRange();           /* no range now */
  1736.     wasColCmd = 0;
  1737.  
  1738.     for (ni = 0 ; ni < cnt ; ++ni)
  1739.       {
  1740.         fchr = GCh(curchr);     /* get current character */
  1741.         if (fchr >= 'a' && fchr <= 'z')
  1742.             fchr = cupper(fchr);
  1743.         else if (fchr >= 'A' && fchr <= 'Z')
  1744.             fchr = clower(fchr);
  1745.         if (IsEndLine(fchr))
  1746.             charRight((long)1,1);
  1747.         else
  1748.           {
  1749.             if (!charDelete((long) 1))          /* delete cur character */
  1750.                 return 0;
  1751.             if (!charInsert((int)fchr))         /* and put back */
  1752.                 return 0;
  1753.           }
  1754.       }
  1755.     return 1;
  1756.   }
  1757.  
  1758. // ====================>>> vTextEditor::charInsert <<<======================
  1759.   int vTextEditor::charInsert(int ival)
  1760.   {
  1761.     int xf;
  1762.     int force_tidy;
  1763.     int chr;
  1764.  
  1765.     if (state.readOnly)
  1766.         return 0;
  1767.     checkIfScrolled();
  1768.     RemoveMarkRange();                   /* no range now */
  1769.     wasColCmd = 0;
  1770.  
  1771.     chr = ival;                         /* use the passed value */
  1772.  
  1773.     ++state.changes;                    /* count changes */
  1774.  
  1775.     if (lastLineBF() == 0)              // First actual insert!
  1776.       {
  1777.         char ln1[4];
  1778.         resetBuff();
  1779.         if (chr == '\n')        // this effecitvely is two lines!
  1780.           {
  1781.             ln1[0] = 0;
  1782.             addLine(ln1);
  1783.             addLine(ln1);
  1784.             tvdlin = 2;
  1785.             displayBuff(1);             // get a proper display
  1786.           }
  1787.         else
  1788.           {
  1789.             ln1[0] = chr;
  1790.             ln1[1] = 0;
  1791.             addLine(ln1);
  1792.             if (!_lines[1])
  1793.                 return 0;
  1794.             curlin = 1;
  1795.             curchr = _lines[1] + 1;
  1796.             tvdlin = 1;
  1797.             displayBuff(1);             // get a proper display
  1798.             lineEnd();          // move to end of the line
  1799.           }
  1800.         setScrollBar();
  1801.         return 1;
  1802.       }
  1803.  
  1804.     if (!state.ins_mode)                        // overtype mode?
  1805.       {
  1806.         if (!charDelete(1))             // delete nextchar
  1807.            return 0;
  1808.       }
  1809.  
  1810.     if (chr == '\r')
  1811.         chr = '\n';                     // this is our convention
  1812.  
  1813.     if (chr == 0)
  1814.         chr = ' ';
  1815.  
  1816.     if (!insertCharBF(chr, curchr, curlin))
  1817.         return 0;
  1818.     lastLine = lastLineBF();            // update this one
  1819.  
  1820.     if (chr != '\n')
  1821.       {
  1822.         retypeCurlin(0);                        // just retype whole line
  1823.       }
  1824.     else
  1825.       {
  1826.         long dummy1; int dummy2;
  1827.         FindDispLine(dummy1,dummy2);
  1828.         if (tvdlin < dsplin)    // not at end
  1829.           {
  1830.             tvescr();               /* erase rest of screen */
  1831.             tvxy(1,tvy);    /* fix it up */
  1832.             type_lines(curlin,mint((int)(GetRows() - tvdlin + 1),
  1833.             (int)(lastLine - curlin))  );
  1834.           }
  1835.         else                        /* at end of buffer */
  1836.             Verify();
  1837.         setScrollBar();
  1838.         tvhdln();   /* home to display line */
  1839.         xf = findX();
  1840.         tvxy(xf,tvy);       /* reset cursor to current position */
  1841.       }
  1842.  
  1843.     ChangeLoc(curlin,col_pos(curchr,0));
  1844.  
  1845.     return 1;
  1846.  }
  1847.  
  1848. // ====================>>> vTextEditor::retypeCurlin  <<<======================
  1849.   void vTextEditor::retypeCurlin(int eraseLine)
  1850.   {
  1851.     if (!state.echof)
  1852.         return;
  1853.     if (eraseLine)
  1854.         tvelin();
  1855.     tvxy(1,tvy);
  1856.     tvtyln(curlin,GLine(curlin), curchr == GLine(curlin));
  1857.     tvhdln();                   // home to display line
  1858.     int xf = findX();
  1859.     tvxy(xf,tvy);               // reset cursor to current position
  1860.   }
  1861.  
  1862. // ====================>>> vTextEditor::charRight  <<<======================
  1863.   int vTextEditor::charRight(long cnt, int clear_mark)
  1864.   {  // charRight: move cursor right cnt characters
  1865.      // newlines count as one character
  1866.  
  1867.     long change;
  1868.     int i, rv;
  1869.  
  1870.     if (lastLineBF() < 1)
  1871.         return 0;
  1872.     if (cnt == 0)
  1873.        return 1;
  1874.  
  1875.     checkIfScrolled();
  1876.     if (clear_mark)
  1877.         ClearMarkRange();               /* no range now */
  1878.  
  1879.     wasColCmd = 0;
  1880.  
  1881.     rv = 1;                     /* assume success */
  1882.     change = 0;                 /* no change yet */
  1883.     if (cnt > 0)                /* moving right */
  1884.       {
  1885.         for (i = 1 ; i <= cnt ; ++i)
  1886.           {
  1887.             if (IsEndLine(GCh(curchr))) /* at end of line */
  1888.               {
  1889.                 if (curlin >= lastLine)
  1890.                   {
  1891.                     rv = 0;
  1892.                     break;              /* don't go beyond end! */
  1893.                   }
  1894.                 ++curlin;
  1895.                 ++change;               /* we've gone down one line */
  1896.                 curchr = GLine(curlin);
  1897.               }
  1898.             else
  1899.                 ++curchr;
  1900.           }
  1901.       }
  1902.     else if (cnt < 0)           /* moving left */
  1903.       {
  1904.         cnt = (-cnt);           /* fix this */
  1905.         for (i = 1 ; i <= cnt ; ++i)
  1906.           {
  1907.             if (curchr == GLine(curlin)) /* at front */
  1908.               {
  1909.                 if (curlin > 1) /* can only go up on >= line 2 */
  1910.                   {
  1911.                     --curlin;
  1912.                     --change;
  1913.                     for (curchr = GLine(curlin) ;
  1914.                          !IsEndLine(GCh(curchr)) ;
  1915.                          ++curchr)
  1916.                         ;       /* bump curchr to end of the line */
  1917.                   }
  1918.                 else
  1919.                   {
  1920.                     rv = 0;
  1921.                     break;              /* don't go beyond front! */
  1922.                   }
  1923.               }
  1924.             else
  1925.                 --curchr;
  1926.           }
  1927.       }
  1928.     if (change != 0)            /* don't do unnecessary change */
  1929.         update(change);
  1930.     if (clear_mark)
  1931.         ChangeLoc(curlin,col_pos(curchr,0));
  1932.     tvhdln();
  1933.     return rv;
  1934.   }
  1935.  
  1936. // #########################################################################
  1937. //
  1938. // line methods
  1939. //
  1940. // #########################################################################
  1941.  
  1942. // ===================>>> vTextEditor::lineBeginning <<<====================
  1943.   void vTextEditor::lineBeginning()
  1944.   {  /* lineBeginning - move cursor to beginning of current line */
  1945.  
  1946.     int xf;
  1947.  
  1948.     if (lastLineBF() < 1)
  1949.         return;
  1950.  
  1951.     ClearMarkRange();           /* no range now */
  1952.     wasColCmd = 0;
  1953.  
  1954.     curchr = GLine(curlin);     /* point to current character */
  1955.     xf = findX();       /* this line needed to make the next */
  1956.                         /* call eval order independent, if you wondered */
  1957.     tvxy(xf,tvy);       /* and move cursor */
  1958.     ChangeLoc(curlin,col_pos(curchr,0));
  1959.   }
  1960.  
  1961. // =====================>>> vTextEditor::lineDelete <<<=====================
  1962.   void vTextEditor::lineDelete(long cnt)
  1963.   { // lineDelete - delete cnt lines
  1964.  
  1965.     int ityp;
  1966.  
  1967.     long line_1, last_line;     /* range of lines to kill */
  1968.     long istrt;
  1969.  
  1970.     if (state.readOnly || lastLineBF() < 1)
  1971.         return;
  1972.     ClearMarkRange();           /* no range now */
  1973.     wasColCmd = 0;
  1974.  
  1975.     if (cnt == 0)
  1976.         return;
  1977.  
  1978.     if (cnt < 0)                /* negative kill */
  1979.       {
  1980.         cnt = minl(-cnt,curlin-1);      /* all upwards? */
  1981.         lineDownBeg(-cnt,0);            /* go up that far */
  1982.       }
  1983.  
  1984.     if (cnt != 0)
  1985.       {
  1986.         range(cnt,&line_1,&last_line);  /* calculate the line numbers to kill */
  1987.  
  1988.         curlin = line_1;                /* remember new current line */
  1989.  
  1990.         SaveKillLine(last_line);        /* save one line */
  1991.  
  1992.         ++state.changes;                        /* count changes */
  1993.         lastLine = deleteLinesBF(line_1,last_line);     /* delete the lines from the buffer(s) */
  1994.  
  1995.         if (lastLine < curlin)
  1996.             curlin = lastLine;          /* don't go past end */
  1997.  
  1998.         curchr = GLine(curlin); /* remember new current character */
  1999.  
  2000.         if (cnt >= 0 && curlin+(GetRows() - tvdlin) <= lastLine &&
  2001.           tvdlin < GetRows())   /* killing down */
  2002.           {
  2003.             tvxy(1,tvy);        /* get to start of line */
  2004.             ityp = (int) minl((long)(GetRows()-tvdlin+1),lastLine - curlin + 1);
  2005.             tvescr();   /* erase the screen */
  2006.             istrt = curlin;
  2007.             type_lines(istrt, ityp);
  2008.             tvhdln();   /* home to display line */
  2009.           }
  2010.         else 
  2011.             Verify();                           /* kill up, retype screen */
  2012.       }
  2013.     ChangeLoc(curlin,col_pos(curchr,0));
  2014.   }
  2015.  
  2016. // =====================>>> vTextEditor::lineDeleteFront  <<<===============
  2017.   int vTextEditor::lineDeleteFront(void)
  2018.   { // lineDeleteFront - delete from cursor to beginning of line
  2019.  
  2020.     int chrs;
  2021.  
  2022.     if (state.readOnly || lastLineBF() < 1)
  2023.         return 0;
  2024.     ClearMarkRange();           /* no range now */
  2025.     wasColCmd = 0;
  2026.  
  2027.     SaveKillLine(curlin);                               /* save one line */
  2028.     chrs = curchr - GLine(curlin);      /* how much to delete */
  2029.     if (chrs > 0)
  2030.         return charDelete((long)(-chrs));       /* won't cause a combine, so don't worry */
  2031.     return 1;
  2032.   }
  2033.  
  2034. // =====================>>> vTextEditor::lineDeleteToEnd  <<<===============
  2035.   int vTextEditor::lineDeleteToEnd(void)
  2036.   { // lineDeleteToEnd:
  2037.     //       kill the rest of the line, not including cursor and endLine
  2038.  
  2039.     int chrs;
  2040.     BUFFPTR i;
  2041.  
  2042.     if (state.readOnly || lastLineBF() < 1)
  2043.         return 0;
  2044.     ClearMarkRange();           /* no range now */
  2045.     wasColCmd = 0;
  2046.  
  2047.     SaveKillLine(curlin);               /* save one line */
  2048.     chrs = 0;
  2049.     for (i = curchr; !IsEndLine(GCh(i)) ; ++i)
  2050.         ++chrs;                 /* count how much to delete */
  2051.     if (chrs > 0)
  2052.         return charDelete((long) chrs); /* won't cause combine, so don't worry */
  2053.     return 1;
  2054.   }
  2055.  
  2056. // ========================>>> vTextEditor::lineDown <<<====================
  2057.   int vTextEditor::lineDown(long cnt, int clrRange)
  2058.   { /* lineDown - move down in column */
  2059.  
  2060.     int curcol,l,oldef,needns,ic,ix,lim,rv;
  2061.  
  2062.     if (lastLineBF() < 1)
  2063.         return 0;
  2064.     if (clrRange)
  2065.         ClearMarkRange();           /* no range now */
  2066.  
  2067.     oldef = state.echof;
  2068.     needns = 0;
  2069.     if (leftmg > 1)             /* handle right virtual screen different */
  2070.       {
  2071.         needns = 1;
  2072.       }
  2073.  
  2074.     if (wasColCmd)      // going up/down columnwise
  2075.         curcol = oldcol;
  2076.     else
  2077.         oldcol = curcol = col_pos(curchr,1);    /* calculate the current column */
  2078.  
  2079.     rv = lineDownBeg(cnt,0,clrRange);    /* go down given lines, update screen */
  2080.  
  2081.     state.echof = 0;
  2082.  
  2083.     if (curlin >= 1 && curlin <= lastLine && curcol > 1)        /* not at ends? */
  2084.       {
  2085.         l = lineLenBF(curlin);
  2086.         lim = mint(curcol-1,l);
  2087.         for (ix = 0, ic = col_pos(curchr,1) ; ix < lim && ic < curcol ;
  2088.                 ++ix, ic = col_pos(curchr,1))
  2089.           ;
  2090.         charRight((long)ix,clrRange);
  2091.       }
  2092.  
  2093.     state.echof = oldef;
  2094.     if (needns)                 /* needed new screen */
  2095.       {
  2096.         Verify();
  2097.       }
  2098.     else
  2099.         tvhdln();
  2100.     ChangeLoc(curlin,col_pos(curchr,0));
  2101.     wasColCmd = 1;
  2102.     return rv;
  2103.   }
  2104.  
  2105. // ====================>>> vTextEditor::lineDownBeg <<<=====================
  2106.   int vTextEditor::lineDownBeg(long cnt, int notify, int clrRange)
  2107.   { /* lineDownBeg - move dot down cnt lines */
  2108.  
  2109.     long oldlin,change;
  2110.  
  2111.     if (lastLineBF() < 1)
  2112.         return 0;
  2113.     if (clrRange)
  2114.         ClearMarkRange();           /* no range now */
  2115.     wasColCmd = 0;
  2116.  
  2117.     if (curlin == lastLine && cnt > 0)  /* down from last line? */
  2118.       {
  2119.         lineEnd();
  2120.         return 0;               /* make loops fail */
  2121.       }
  2122.     oldlin = curlin;            /* remember where we started from */
  2123.     if (curlin + cnt < 1)
  2124.         curlin = 1;
  2125.     else if (curlin + cnt > lastLine)
  2126.         curlin = lastLine;
  2127.     else
  2128.         curlin = curlin + cnt;
  2129.     curchr = GLine(curlin);     /* point to the current character */
  2130.     change = curlin-oldlin;     /* calculate how many lines changed */
  2131.     update(change);             /* update the screen */
  2132.     if (notify)
  2133.         ChangeLoc(curlin,col_pos(curchr,0));
  2134.     return change != 0;
  2135.   }
  2136.  
  2137. // =====================>>> vTextEditor::lineEnd <<<========================
  2138.   void vTextEditor::lineEnd(int clrRange)
  2139.   { // lineEnd - move cursor to end of the line
  2140.  
  2141.     int knt;
  2142.     BUFFPTR i;
  2143.  
  2144.     if (lastLineBF() < 1)
  2145.         return;
  2146.     if (clrRange)
  2147.         ClearMarkRange();           /* no range now */
  2148.     wasColCmd = 0;
  2149.  
  2150.     knt = 0;
  2151.     for (i = curchr ; !IsEndLine(GCh(i)) ; ++i) /* find end of line */
  2152.         ++knt;
  2153.     charRight((long)knt,clrRange);             /* move to end of line */
  2154.     ChangeLoc(curlin,col_pos(curchr,0));
  2155.   }
  2156.  
  2157. // ======================>>> vTextEditor::lineOpen <<<======================
  2158.   int vTextEditor::lineOpen(long cnt)
  2159.   {  // lineOpen - open a new line
  2160.  
  2161.     int i;
  2162.     long pcnt;
  2163.  
  2164.     if (state.readOnly || lastLineBF() < 1)
  2165.         return 0;
  2166.     pcnt = cnt >= 0 ? cnt : (-cnt);     /* only allow positive opens */
  2167.  
  2168.     for (i=1; i<=pcnt; ++i)
  2169.       {
  2170.         if (!charInsert('\n'))          /* insert right number of newlines */
  2171.             return 0;
  2172.       }
  2173.  
  2174.     lineDownBeg(-pcnt,0);               /* and goto beginning of the opened line */
  2175.  
  2176.     lineEnd();
  2177.     return 1;
  2178.   }
  2179.  
  2180. // ======================>>> vTextEditor::lineGoto <<<======================
  2181.   int vTextEditor::lineGoto(long cnt)
  2182.   { // lineGoto: move cursor to line cnt
  2183.  
  2184.     if (cnt < 0 || lastLineBF() < 1)
  2185.         return 0;
  2186.     ClearMarkRange();           /* no range now */
  2187.     wasColCmd = 0;
  2188.  
  2189.     curlin = maxl(minl(cnt,lastLine),(long) 1); /* move to lines */
  2190.     curchr = GLine(curlin);     /* point to the current character */
  2191.     Verify();
  2192.     return 1;
  2193.   }
  2194.  
  2195. // =====================>>> vTextEditor::lineAutoFill <<<===================
  2196.   void vTextEditor::lineAutoFill(void)
  2197.   {
  2198.     BUFFPTR bx, startx;
  2199.     int lines, old_ef, old_y, ityp, go_right, cp, chr;
  2200.     long start_line, istrt;
  2201.  
  2202.     if (state.readOnly || lastLineBF() < 1)
  2203.         return;
  2204.  
  2205.     if (state.wraplm < 1)
  2206.         return;                 /* no auto-wrap going on */
  2207.  
  2208.     /*  1. Check if current line needs to be wrapped */
  2209.  
  2210.     startx = GLine(curlin);     /* first char of line */
  2211.     bx = lastBX(curlin);        /* index of last char of line */
  2212.     if (startx == bx)
  2213.         return;                 /* blank line, can't need tidy */
  2214.     if (col_pos(bx,0) <= state.wraplm) /* is last char beyond limit? */
  2215.         return;                 /* line doesn't need tidy */
  2216.  
  2217.     /*  2. If it does, figure out where the cursor is. */
  2218.  
  2219.     go_right = curchr - startx; /* where CURRENT char is */
  2220.     start_line = curlin;
  2221.     old_y = tvdlin;             /* original line */
  2222.  
  2223.     /*  3. Echo off. */
  2224.  
  2225.     old_ef = state.echof;
  2226.     state.echof = 0;
  2227.  
  2228.     /*  4. Tidy down to PP or blank line or line beginning with white */
  2229.  
  2230.     for (lines = 1 ; lines < 50 && curlin <= lastLine ;
  2231.          ++lines )
  2232.       {
  2233.         lineFill((long) 1);     /* fix current line */
  2234.         chr = GCh(curchr);
  2235.         if (chr == '.' || chr == ' ' || chr == '\t' || IsEndLine(chr))
  2236.             break;
  2237.       }
  2238.  
  2239.     /*  5. Restore echo */
  2240.  
  2241.     state.echof = old_ef;
  2242.  
  2243.     /*  6. Return to current line, making sure it stays where it was
  2244.            on the screen (or shift by one if it gets moved),
  2245.            and repaint the rest of the screen.
  2246.     */
  2247.  
  2248.     curlin = start_line;
  2249.     curchr = GLine(curlin);
  2250.     tvdlin = old_y;
  2251.  
  2252.     if (state.echof)
  2253.       {
  2254.         tvxy(1,old_y);
  2255.         istrt = curlin;
  2256.         ityp =(int) minl((long)(GetRows()-tvdlin+1),
  2257.                          lastLine - curlin + 1);
  2258.         type_lines(istrt, ityp);
  2259.       }
  2260.  
  2261.     tvhdln();   /* home to display line */
  2262.  
  2263.     for ( ; ; )
  2264.       {
  2265.         bx = lastBX(curlin);    /* see if still on this line */
  2266.         cp = col_pos(bx,0);
  2267.         if (go_right <= cp)     /* on this line */
  2268.           {
  2269.             curchr = GLine(curlin) + go_right;
  2270.             break;
  2271.           }
  2272.         go_right -= cp; /* next line */
  2273.         if (!lineDownBeg((long) 1,0))
  2274.             break;
  2275.       }
  2276.     tvhdln();   /* home to display line */
  2277.     ChangeLoc(curlin,col_pos(curchr,0));
  2278.   }
  2279.  
  2280. // =====================>>> vTextEditor::lineFill <<<=======================
  2281.   int vTextEditor::lineFill(long count)
  2282.   {  // lineFill - fill lines to current margin
  2283.  
  2284.     char curline[40];           /* first part of current line */
  2285.     char* special[] =           /* special keywords */
  2286.       {                         /* that shouldn't cause a wrap */
  2287.         " ",                    /* the usual non-breakers */
  2288.         "\t",
  2289.         ".",
  2290.         ""
  2291.       };
  2292.  
  2293.     int oldef, i, key_found;
  2294.     BUFFPTR linbeg, old_cc;
  2295.     int retval;
  2296.  
  2297.     if (state.readOnly || lastLineBF() < 1 || state.wraplm < 1)
  2298.         return 0;                       /* no auto-wrap going on */
  2299.  
  2300.     ClearMarkRange();           /* no range now */
  2301.     wasColCmd = 0;
  2302.  
  2303.     retval = 1;
  2304.     oldef = state.echof;
  2305.     if (count > 1)
  2306.         state.echof = 0;
  2307.     if (state.wraplm <= 1 || curlin > lastLine)
  2308.         goto l900;              /* work only if wrap limit turned on */
  2309.  
  2310.     for (i = 1 ; i <= count ; ++i)
  2311.       {
  2312.         lineBeginning();                /* start at beginning of line */
  2313.         if (curlin >= lastLine)
  2314.             goto l900;
  2315.  
  2316.         /* don't fill leading space, cr, period,  tab, or latex keyword */
  2317.  
  2318.         getCurLine(curline,curlin);     /* current line */
  2319.         key_found = 0;
  2320.         if (*curline)
  2321.           {
  2322.             for (int iy = 0 ; *special[iy] ; ++iy)      /* search keyword list */
  2323.               {
  2324.                 if (strstr(curline,special[iy]) == curline)
  2325.                   {
  2326.                     key_found = 1;
  2327.                     break;
  2328.                   }
  2329.               }
  2330.           }
  2331.         else
  2332.             key_found = 1;
  2333.         if (key_found)
  2334.           {
  2335.             lineDownBeg((long) 1,0);
  2336.             continue;           /* skip dot commands */
  2337.           }
  2338.  
  2339.         while (curlin < lastLine)
  2340.           {
  2341.             if (IsEndLine(GCh(curchr)))
  2342.               {
  2343.                 if (tvx+leftmg-1 < state.wraplm)        /* combine lines! */
  2344.                   {
  2345.                     /* pt to first char of next line */
  2346.                     linbeg = GLine(curlin+1);
  2347.                     if (GCh(linbeg) == ' ' || IsEndLine(GCh(linbeg))
  2348.                       || GCh(linbeg) == '\t' || GCh(linbeg) == '.')
  2349.                       {
  2350.                         lineDownBeg((long) 1);
  2351.                         break;  /* no more combining */
  2352.                       }
  2353.                     if (! Fill1(1,32))
  2354.                         goto l990;
  2355.                     /* fall thru to test for wrap */
  2356.                   }
  2357.                 else
  2358.                   {
  2359.                     lineDownBeg((long) 1);      /* no more combining on line */
  2360.                     break;
  2361.                   }
  2362.               }
  2363.  
  2364.             old_cc = curchr;
  2365.             wordRight((long) 1);
  2366.             if (tvx+leftmg-1 > state.wraplm)
  2367.               {
  2368.                 if (tvx+leftmg-2 == state.wraplm && IsEndLine(GCh(curchr)) )
  2369.                   {
  2370.                     lineDownBeg((long) 1);
  2371.                     break;
  2372.                   }
  2373.                 else if ((tvx+leftmg-2 == state.wraplm ||
  2374.                     tvx+leftmg-3 == state.wraplm) &&
  2375.                     (GCh(curchr-1) == ' ' || GCh(curchr-1) == '\t'))
  2376.                   {
  2377.                     if (!Fill1(-1,'\n'))
  2378.                         goto l990;
  2379.                   }
  2380.                 else if (GCh(old_cc-1) == ' ' ||
  2381.                     GCh(old_cc-1) == '\t')
  2382.                   {
  2383.                     curchr = old_cc;
  2384.                     if (!Fill1(-1,'\n'))
  2385.                         goto l990;
  2386.                   }
  2387.                 else if (GCh(old_cc-2) == ' ' ||
  2388.                     GCh(old_cc-2) == '\t')
  2389.                   {
  2390.                     curchr = old_cc-1;
  2391.                     if (!Fill1(-1,'\n'))
  2392.                         goto l990;
  2393.                   }
  2394.                 else if (IsEndLine(GCh(curchr)) )
  2395.                   {
  2396.                     lineDownBeg((long) 1);
  2397.                     break;
  2398.                   }
  2399.                 else if (GCh(curchr-1) == ' ' ||
  2400.                     GCh(curchr-1) == '\t')
  2401.                   {
  2402.                     if (!Fill1(-1,'\n'))
  2403.                         goto l990;
  2404.                   }
  2405.                 else
  2406.                   {
  2407.                     for (wordRight((long) -1) ;  /* go back a word, then break */
  2408.                         (GCh(curchr-1) != ' ' &&  GCh(curchr-1) != '\t'
  2409.                         && !IsEndLine(GCh(curchr-1)) ) ;
  2410.                         wordRight((long) -1))
  2411.                       {
  2412.                         /* this line can't be filled - stop now */
  2413.                         if (curchr == GLine(curlin))
  2414.                             goto l990;
  2415.                       }
  2416.                     charInsert('\n');
  2417.                   }
  2418.                 break;
  2419.               }
  2420.  
  2421.           } /* end of for (;;) */
  2422.  
  2423.       } /*# end of the for (count) */
  2424. l900:
  2425.     state.echof = oldef;
  2426.     if (oldef && count > 1)
  2427.         Verify();
  2428.  
  2429.     ChangeLoc(curlin,col_pos(curchr,0));
  2430.     return retval;
  2431.  
  2432. l990:                           /* failure return */
  2433.     retval = 0;
  2434.     goto l900;
  2435.   }
  2436.  
  2437. //===========================>>> vTextEditor::formatC <<<=====================
  2438.  int vTextEditor::formatC(long count)
  2439.   {
  2440.     /* format C code according to Bruce's style */
  2441.  
  2442.     int oldef, i, ij, ik, spaces, tabs, prev_key;
  2443.     long prev_lnum;
  2444.  
  2445.     char prev_line[40];
  2446.     char prev_prev_line[40];
  2447.  
  2448.     oldef = state.echof;
  2449.     if ( curlin >= _nextLine-1)    /* can't do last line */
  2450.     return 0;
  2451.  
  2452.     if (count > 1)
  2453.     state.echof = 0;
  2454.  
  2455.     for (i = 1 ; i <= count ; ++i, lineDownBeg((long)1))
  2456.       {
  2457.     if ((prev_lnum = get_prev(prev_line,curlin)) <= 0)    /* get the previous line */
  2458.         continue;            /* handle 1st line of file! */
  2459.  
  2460.     (void) get_prev(prev_prev_line,prev_lnum);    /* and the line before it */
  2461.  
  2462.     if (*prev_line != ' ' && *prev_line != '\t')    /* funny line */
  2463.       {
  2464.         lineDownBeg((long)1);
  2465.         break;            /* give up */
  2466.       }
  2467.  
  2468.     /* count previous tabs/spaces */
  2469.     tabs = spaces = 0;
  2470.     for (ij = 0 ; ij < 38 ; ++ij)
  2471.       {
  2472.         if (prev_line[ij] == '\t')
  2473.           {
  2474.         spaces = 0;        /* skip embedded spaces */
  2475.         ++tabs;
  2476.           }
  2477.         else if (prev_line[ij] == ' ')
  2478.         ++spaces;
  2479.         else
  2480.         break;            /* break on first non tab non blank */
  2481.       }
  2482.     if (tabs == 0 && spaces <= 2)
  2483.       {
  2484.         lineDownBeg((long) 1);
  2485.         break;            /* give up on function heads */
  2486.       }
  2487.  
  2488.     /* now process current line */
  2489.     lineBeginning();        /* start at beginning of line */
  2490.  
  2491.     if (curlin >= _nextLine-1)
  2492.         break;        /* done */
  2493.  
  2494.     /* don't fix blank lines */
  2495.  
  2496.     if (GCh(curchr) != ' ' && GCh(curchr) != '\t' )
  2497.       {
  2498.         lineDownBeg((long) 1);
  2499.         break;        /* break on line I don't know about */
  2500.       }
  2501.  
  2502.     while (GCh(curchr) == ' ' || GCh(curchr) == '\t')
  2503.         charDelete((long)1);        /* delete them */
  2504.  
  2505.     if (GCh(curchr) == '\n')
  2506.         continue;        /* skip blank lines */
  2507.  
  2508.     /* determine spacing of current line based on prev line */
  2509.  
  2510.     prev_key = 0;
  2511.     if (is_key_word(&prev_line[ij],1))    /* a kew word! */
  2512.       {
  2513.         prev_key = 1;            /* last line was key */
  2514.         if (GCh(curchr) == '{')
  2515.         spaces += 2;
  2516.         else
  2517.         spaces += 4;
  2518.       }
  2519.     else if (prev_line[ij] == '{')
  2520.       {
  2521.         spaces += 2;
  2522.       }
  2523.     else if (prev_line[ij] == '}')
  2524.       {
  2525.         spaces -= 2;
  2526.       }
  2527.  
  2528.     if (has_key((char*)curchr, "else"))
  2529.       {
  2530.         if (prev_line[ij] != '}')
  2531.         spaces -= 4;
  2532.       }
  2533.     else if (has_key((char *)curchr, "case") ||
  2534.       has_key((char*)curchr, "default:"))
  2535.       {
  2536.         if (prev_line[ij] != '{')
  2537.         spaces -= 4;
  2538.       }
  2539.     else if (!prev_key && prev_line[ij] != '{' && 
  2540.       prev_line[ij] != '}' && is_key_word(prev_prev_line,0))
  2541.         spaces -= 4;
  2542.  
  2543.     /* don't else next one, works with last else if */
  2544.     if (GCh(curchr) == '}')    /* } */
  2545.         spaces -= 2;
  2546.  
  2547.     /* fix tab/space counts */
  2548.     if (spaces < 0)
  2549.       {
  2550.         if (--tabs < 0)
  2551.         tabs = 0;
  2552.         spaces = 8 + spaces;
  2553.       }
  2554.     while (spaces >= 8)
  2555.       {
  2556.         ++tabs;
  2557.         spaces -= 8;
  2558.       }
  2559.  
  2560.     for (ik = 0 ; ik < tabs ; ++ik)
  2561.         charInsert('\t');
  2562.     for (ik = 0 ; ik < spaces ; ++ik)
  2563.         charInsert(' ');
  2564.  
  2565.       }    /* end of main for loop */
  2566.  
  2567.     state.echof = oldef;
  2568.     if (oldef && count > 1)
  2569.     Verify();
  2570.  
  2571.     return 1;
  2572.  
  2573.   }
  2574.  
  2575. // =============================>>> vTextEditor::has_key <<<=======================
  2576.   int vTextEditor::has_key(char *buff_ptr, char *key)
  2577.   {
  2578.     while (*key)
  2579.       {
  2580.     if (*buff_ptr++ != *key++)
  2581.         return 0;
  2582.       }
  2583.     return 1;    /* buff_ptr matches key up to key's EOS */
  2584.  
  2585.   }
  2586.  
  2587. // ==========================>>> vTextEditor::is_key_word <<<====================== 
  2588.   int vTextEditor::is_key_word(char *bf, int case_def)
  2589.   {
  2590.     //char *strstr();
  2591.  
  2592.     while (*bf == ' ' || *bf == '\t')    /* skip leading white */
  2593.     ++bf;
  2594.     if (strstr(bf,"if(") == bf)
  2595.     return 1;
  2596.     if (strstr(bf,"if (") == bf)
  2597.     return 1;
  2598.     if (strstr(bf,"for(") == bf)
  2599.     return 1;
  2600.     if (strstr(bf,"for (") == bf)
  2601.     return 1;
  2602.     if (strstr(bf,"while(") == bf)
  2603.     return 1;
  2604.     if (strstr(bf,"while (") == bf)
  2605.     return 1;
  2606.     if (strstr(bf,"else") == bf)
  2607.     return 1;
  2608.     if (strstr(bf,"typedef ") == bf)
  2609.     return 1;
  2610.     if (strstr(bf,"struct ") == bf)
  2611.     return 1;
  2612.     if (strstr(bf,"switch(") == bf)
  2613.     return 1;
  2614.     if (strstr(bf,"switch (") == bf)
  2615.     return 1;
  2616.     if (case_def && strstr(bf,"case ") == bf)
  2617.     return 1;
  2618.     if (case_def && strstr(bf,"default:") == bf)
  2619.     return 1;
  2620.     return 0;
  2621.   }
  2622.  
  2623. //=============================>>> vTextEditor::get_prev <<<======================
  2624.   long vTextEditor::get_prev(char *prev_buff, long start)
  2625.   {    // Get previous non-blank line in text buffer (BEW: 10/1/98)
  2626.     long pline;
  2627.     int ix, blank_line;
  2628.     BUFFPTR bi;
  2629.  
  2630.     *prev_buff = 0;            /* empty line for sure */
  2631.     pline = start;
  2632. GP_TOP:
  2633.     --pline;                /* previous line */
  2634.  
  2635.     if (pline <= 1)
  2636.     return 0;            /* there is no previous line */
  2637.  
  2638.     bi = GLine(pline);        /* first char of buffer */
  2639.  
  2640.     blank_line = 1;
  2641.     for (ix = 0 ; ix < 38 ; ++ix)
  2642.       {
  2643.     if (GCh(bi+ix) == '\n')
  2644.         break;
  2645.     prev_buff[ix] = GCh(bi+ix);    /* copy the char */
  2646.     if (prev_buff[ix] != ' ' || prev_buff[ix] != '\t')
  2647.        blank_line = 0;        /* not a blank line */
  2648.       }
  2649.     prev_buff[ix] = 0;            /* terminate the string */
  2650.     if (blank_line || prev_buff[0] == '#')
  2651.     goto GP_TOP;            /* find previous non-blank line */
  2652.  
  2653.     return pline;
  2654.   }
  2655.  
  2656.  
  2657. // ########################################################################
  2658. //
  2659. //  Misc. methods
  2660. //
  2661. // ########################################################################
  2662.  
  2663. // ======================>>> vTextEditor::EditCut <<<=================
  2664.   int vTextEditor::EditCut()
  2665.   {
  2666.     // Cut text to clipboard
  2667.  
  2668.     long sl = SelectionLen();           // length of selection
  2669.     if (sl < 0)
  2670.         return 0;
  2671.     char* cut = new char[sl+1];         // space for a copy
  2672.  
  2673.     CopySelection(cut, sl+1, 0);        // copy the selection
  2674.     theApp->ClipboardSetText(cut);      // set the clipboard
  2675.  
  2676.     delete [] cut;                      // free the space
  2677.  
  2678.     RemoveMarkRange();                  // finally, cut it
  2679.     return 1;
  2680.   }
  2681.  
  2682. // ======================>>> vTextEditor::EditCopy <<<=================
  2683.   int vTextEditor::EditCopy()
  2684.   {
  2685.     // Cut text to clipboard
  2686.  
  2687.     long sl = SelectionLen();           // length of selection
  2688.     if (sl < 0)
  2689.         return 0;
  2690.     char* cut = new char[sl+1];         // space for a copy
  2691.  
  2692.     CopySelection(cut, sl+1, 0);        // copy the selection
  2693.     theApp->ClipboardSetText(cut);      // set the clipboard
  2694.  
  2695.     delete [] cut;                      // free the space
  2696.  
  2697.     return 1;
  2698.   }
  2699.  
  2700. // ======================>>> vTextEditor::EditPaste <<<=================
  2701.   int vTextEditor::EditPaste()
  2702.   {
  2703.     char* paste = theApp->ClipboardGetText();   // get the text
  2704.     if (!paste || !*paste)
  2705.         return 0;
  2706.     long pasteLen = strlen(paste);
  2707.     long orig_line = curlin;
  2708.  
  2709.     int old_echo = state.echof;
  2710.  
  2711.     if (pasteLen > 80)
  2712.         state.echof = 0;
  2713.  
  2714.     while (*paste)              // dumb paste - char at a time insert
  2715.       {
  2716.         if (*paste != '\r')     // ignore \r on both X and Windows
  2717.           {
  2718.             if (*paste == '\n')
  2719.                 charInsert((int)'\r');  // this works for both X and Windows
  2720.             else
  2721.                 charInsert((int)*paste);
  2722.           }
  2723.         ++paste;
  2724.       }
  2725.     if (state.echof == 0)
  2726.       {
  2727.         state.echof = old_echo;
  2728.   //      Verify();
  2729.       }
  2730.  
  2731.     if (curlin != orig_line)        /* refresh screen if moved */
  2732.         Verify();
  2733.     else
  2734.         tvhdln();                   /* just fix the cursor */
  2735.     return 1;
  2736.   }
  2737.  
  2738. // ======================>>> vTextEditor::SelectionLen <<<=================
  2739.   int vTextEditor::SelectionLen()
  2740.   {
  2741.     long lines;
  2742.     int len;
  2743.     MARK_RANGE r_mark;
  2744.  
  2745.     if (mark.beg_lin != 0)              // we have some text to count
  2746.       {
  2747.         r_mark = mark;                  // use a copy
  2748.  
  2749.         // count the range
  2750.  
  2751.         lines = r_mark.end_lin - r_mark.beg_lin + 1;
  2752.  
  2753.         if (lines == 1)                   /* all on current line */
  2754.           {
  2755.             if (r_mark.end_chr) /* find type range */
  2756.               {
  2757.                 len = r_mark.end_chr - r_mark.beg_chr;
  2758.               }
  2759.             else
  2760.               {
  2761.                 for (len = 0 ; GCh(r_mark.beg_chr + len) != 0 ; ++len)
  2762.                     ;
  2763.               }
  2764.             return len;
  2765.           }
  2766.         else                    // more than one line
  2767.           {
  2768.             // Count 1st line
  2769.             for (len = 0 ; GCh(r_mark.beg_chr + len) != 0 ; ++len)
  2770.                ;
  2771.             // Count middle lines
  2772.             for (long mid = r_mark.beg_lin + 1 ;
  2773.                         mid < r_mark.end_lin ; ++mid)
  2774.               {
  2775.                 int linlen;
  2776.                 for (linlen = 0 ; GCh(GLine(mid) + linlen ) != 0 ;
  2777.                       ++linlen)
  2778.                   ;                     // count len of this line
  2779.                 len += linlen;          // add to total
  2780.               }
  2781.             // Count last line - count up to r_mark.end_chr, or
  2782.             // to the end of the line (some places we call end_chr
  2783.             // a big number that really isn't the end of the line
  2784.             int lastlen;
  2785.             for (lastlen = 0 ;
  2786.                  GLine(r_mark.end_lin) + lastlen < r_mark.end_chr
  2787.                  && GCh(GLine(r_mark.end_lin) + lastlen) != 0 ;
  2788.                  ++lastlen)
  2789.                 ;
  2790.             len += lastlen;
  2791.             return len;
  2792.           }
  2793.       }
  2794.     return 0;
  2795.   }
  2796.  
  2797. // ======================>>> vTextEditor::CopySelection <<<=================
  2798.   int vTextEditor::CopySelection(char* buff, int max, int unmark)
  2799.   {
  2800.     long cnt;
  2801.     int ix;
  2802.     char *to;
  2803.     MARK_RANGE r_mark;
  2804.  
  2805.     to = buff;
  2806.  
  2807.     if (mark.beg_lin != 0)              /* we have some text to kill */
  2808.       {
  2809.         if (max < SelectionLen() + 1)   // make sure fits
  2810.             return 0;
  2811.  
  2812.         r_mark = mark;                  /* make copy to avoid recursion */
  2813.  
  2814.         /* now safe to kill off range */
  2815.         if (unmark)
  2816.           {
  2817.             mark.beg_lin = mark.end_lin =
  2818.             mark.beg_col = mark.end_col = 0;
  2819.             mark.beg_chr = mark.end_chr = 0;
  2820.             theApp->SetValueAll(M_Cut, 0, Sensitive);   // zap menu
  2821.             theApp->SetValueAll(M_Copy, 0, Sensitive);
  2822.           }
  2823.  
  2824.  
  2825.         /* clean up screen */
  2826.         if (curlin != r_mark.beg_lin ||
  2827.             r_mark.end_lin - r_mark.beg_lin > 0)
  2828.           {
  2829.             Verify();
  2830.           }
  2831.         else
  2832.           {
  2833.             tvxy(1,tvdlin);     /* fix it up */
  2834.             type_lines(curlin, 1);
  2835.             tvhdln();
  2836.           }
  2837.  
  2838.         /* copy the range */
  2839.  
  2840.         cnt = r_mark.end_lin - r_mark.beg_lin + 1;
  2841.  
  2842.         if (cnt == 1)                   /* all on current line */
  2843.           {
  2844.             if (r_mark.end_chr) /* find type range */
  2845.               {
  2846.                 cnt = r_mark.end_chr - r_mark.beg_chr;
  2847.               }
  2848.             else
  2849.               {
  2850.                 for (cnt = 0 ; GCh(r_mark.beg_chr + cnt) != 0 && cnt < (max - 1) ;
  2851.                         ++cnt)
  2852.                     ;
  2853.               }
  2854.             for (ix = 0 ; ix < cnt && ix < (max - 1) ; ++ix)  /* copy directly */
  2855.               {
  2856.                 *(to+ix) = GCh(r_mark.beg_chr+ix);
  2857.                 if (*(to+ix) == 0)
  2858.                     break;
  2859.               }
  2860.             *(to+ix) = 0;
  2861.           }
  2862.         else                    /* more than one line */
  2863.           {
  2864.             // Copy 1st line
  2865.             for (long len1 = 0 ; GCh(r_mark.beg_chr + len1) != 0 ; ++len1)
  2866.                *to++ = GCh(r_mark.beg_chr + len1);
  2867.             // Copy middle lines
  2868.             for (long mid = r_mark.beg_lin + 1 ;
  2869.                         mid < r_mark.end_lin ; ++mid)
  2870.               {
  2871.                 for (int linlen = 0 ; GCh(GLine(mid) + linlen) != 0 ;
  2872.                       ++linlen)
  2873.                   *to++ = GCh(GLine(mid) + linlen);
  2874.               }
  2875.             // Count last line - count up to r_mark.end_chr, or
  2876.             // to the end of the line (some places we call end_chr
  2877.             // a big number that really isn't the end of the line
  2878.             for (int lastlen = 0 ;
  2879.                  GLine(r_mark.end_lin) + lastlen < r_mark.end_chr
  2880.                  && GCh(GLine(r_mark.end_lin) + lastlen) != 0 ;
  2881.                  ++lastlen)
  2882.                 *to++ = GCh(GLine(r_mark.end_lin) + lastlen);
  2883.             *to++ = 0;
  2884.           }
  2885.         return 1;
  2886.       }
  2887.     return 0;
  2888.   }
  2889.  
  2890. // ======================>>> vTextEditor::ClearMarkRange <<<================
  2891.   void vTextEditor::ClearMarkRange(void)
  2892.   {
  2893.  
  2894.     checkIfScrolled();                  // can check for scroll here
  2895.  
  2896.     /* clear the range variables */
  2897.     if (mark.beg_lin != 0)
  2898.       {
  2899.         mark.beg_lin = mark.end_lin =
  2900.         mark.beg_col = mark.end_col = 0;
  2901.         mark.beg_chr = mark.end_chr = 0;
  2902.         Verify();
  2903.       }
  2904.     else                        /* just be sure we stay in phase */
  2905.       {
  2906.         mark.beg_lin = mark.end_lin =
  2907.         mark.beg_col = mark.end_col = 0;
  2908.         mark.beg_chr = mark.end_chr = 0;
  2909.       }
  2910.     theApp->SetValueAll(M_Cut, 0, Sensitive);
  2911.     theApp->SetValueAll(M_Copy, 0, Sensitive);
  2912.   }
  2913.  
  2914. // =====================>>> vTextEditor::RemoveMarkRange <<<================
  2915.   int vTextEditor::RemoveMarkRange(void)
  2916.   {
  2917.      /* delete the text in the marked range
  2918.         return
  2919.             0 : no text deleted
  2920.             1 : text deleted
  2921.     */
  2922.  
  2923.     static int inHere = 0;                      // don't let it be recursive
  2924.     int retval = 0;
  2925.  
  2926.     long cnt, orig_line;
  2927.     MARK_RANGE r_mark;
  2928.     BUFFPTR orig_chr;
  2929.  
  2930.     if (inHere)
  2931.         return 0;
  2932.     inHere = 1;
  2933.     if (mark.beg_lin != 0)              /* we have some text to kill */
  2934.       {
  2935.         r_mark = mark;                  /* make copy to avoid recursion */
  2936.  
  2937.         /* now safe to kill off range */
  2938.         mark.beg_lin = mark.end_lin =
  2939.         mark.beg_col = mark.end_col = 0;
  2940.         mark.beg_chr = mark.end_chr = 0;
  2941.  
  2942.         /* kill off range */
  2943.         orig_line = curlin;
  2944.         orig_chr = curchr;
  2945.         curlin = r_mark.beg_lin;
  2946.         curchr = r_mark.beg_chr;
  2947.         cnt = r_mark.end_lin - r_mark.beg_lin + 1;
  2948.  
  2949.         if (!state.readOnly && cnt == 1)                        /* all on current line */
  2950.           {
  2951.             if (r_mark.end_chr)         /* find type range */
  2952.               {
  2953.                 long dcnt = r_mark.end_chr - r_mark.beg_chr;
  2954.                 charDelete(dcnt);
  2955.               }
  2956.             else                        /* ^M type range */
  2957.               {
  2958.                 if (curchr == GLine(curlin))
  2959.                     lineDelete(cnt);    /* kill whole current line */
  2960.                 else
  2961.                   {
  2962.                     lineDeleteToEnd();          /* past line beg, just kill rest */
  2963.                   }
  2964.               }
  2965.             retval = 1;
  2966.           }
  2967.         else if (!state.readOnly)       /* more than one line */
  2968.           {
  2969.             int oldef = state.echof;
  2970.             state.echof = 0;            // turn off echo
  2971.             lineDeleteToEnd();          /* past line beg, just kill rest */
  2972.             lineDownBeg((long)1,0);     /* and the end of line */
  2973.             --cnt;                      /* one less */
  2974.             lineDelete(cnt - 1);        /* kill off all but last line */
  2975.             if (!r_mark.end_chr)        /* kill whole last line */
  2976.               {
  2977.                 lineDelete((long)1);
  2978.               }
  2979.             else
  2980.               {
  2981.                 curchr = r_mark.end_chr;        /* get last char */
  2982.                 if (IsEndLine(GCh(curchr)))
  2983.                     lineDelete((long)1);
  2984.                 else
  2985.                     lineDeleteFront();          /* kill last line */
  2986.               }
  2987.             charDelete((long)-1);               /* and the lead cr */
  2988.             retval = 1;
  2989.             state.echof = oldef;
  2990.           }
  2991.         if (curlin != orig_line)        /* refresh screen if moved */
  2992.             Verify();
  2993.         else
  2994.             tvhdln();                   /* just fix the cursor */
  2995.  
  2996.         ChangeLoc(curlin,col_pos(curchr,0));
  2997.       }
  2998.  
  2999.     inHere = 0;
  3000.     return retval;
  3001.   }
  3002.  
  3003. // ===========================>>> BalMatch <<<==============================
  3004.   int vTextEditor::BalMatch(long val)
  3005.   {
  3006.     /* Find balance of )]} or [{( */
  3007.  
  3008.     int orig_line, dir, nest, old_ef, echo_off;
  3009.     long limit, ix;
  3010.     BUFFPTR orig_chr;
  3011.     char start_c, match;
  3012.  
  3013.     if (lastLineBF() < 1)
  3014.         return 0;
  3015.     ClearMarkRange();           /* no range now */
  3016.     wasColCmd = 0;
  3017.  
  3018.     old_ef = state.echof;
  3019.     echo_off = 0;               /* haven't turned off echo */
  3020.  
  3021.     limit = ((long) val) * 4000L;       /* limit for search */
  3022.  
  3023.     orig_chr = curchr;
  3024.     orig_line = curlin;
  3025.     start_c = GCh(curchr);              /* original char */
  3026.     switch (start_c)
  3027.       {
  3028.         case '(':
  3029.             match = ')';
  3030.             dir = 1;
  3031.             break;
  3032.  
  3033.         case '{':
  3034.             match = '}';
  3035.             dir = 1;
  3036.             break;
  3037.  
  3038.         case '[':
  3039.             match = ']';
  3040.             dir = 1;
  3041.             break;
  3042.  
  3043.         case ')':
  3044.             match = '(';
  3045.             dir = -1;
  3046.             break;
  3047.  
  3048.         case '}':
  3049.             match = '{';
  3050.             dir = -1;
  3051.             break;
  3052.  
  3053.         case ']':
  3054.             match = '[';
  3055.             dir = -1;
  3056.             break;
  3057.  
  3058.         default:
  3059.             return 0;           /* no op if not a paren thing */
  3060.  
  3061.       }
  3062.  
  3063.     for (ix = 1, nest = 0 ; ix < limit ; ++ix)
  3064.       {
  3065.         charRight((long)dir,1);         /* go right */
  3066.         if (!echo_off && (curlin != orig_line))
  3067.           {
  3068.             state.echof = 0;
  3069.             echo_off = 1;       /* disable echoing */
  3070.             StatusMessage("Scanning for matching paren");
  3071.           }
  3072.         if (GCh(curchr) == start_c)
  3073.             ++nest;             /* bump nest */
  3074.         else if (GCh(curchr) == match)
  3075.           {
  3076.             if (nest)
  3077.                 --nest;                 /* undo nest */
  3078.             else
  3079.               {
  3080.                 if (echo_off)           /* we've turned echo off */
  3081.                   {
  3082.                     if ((state.echof == old_ef)) /* update if it was on */
  3083.                         Verify();
  3084.                   }
  3085.                 return 1;                       /* found the matching thing */
  3086.               }
  3087.           }
  3088.       }
  3089.  
  3090.     /* fall through ==> died */
  3091.     curchr = orig_chr;
  3092.     curlin = orig_line;
  3093.     state.echof = old_ef;
  3094.     newscr();
  3095.     ChangeLoc(curlin,col_pos(curchr,0));
  3096.     return 0;
  3097.   }
  3098.  
  3099. // #########################################################################
  3100. //
  3101. // Private helper methods
  3102. //
  3103. // #########################################################################
  3104.  
  3105. //========================>>> vTextEditor::reallocLines <<<======================
  3106.   int vTextEditor::reallocLines()
  3107.   {
  3108.     BUFFPTR* oldLines;
  3109.  
  3110.     oldLines = _lines;                  // remember old lines
  3111.     _lines  = new char*[_maxLines + lineListSize];
  3112.     if (!_lines)
  3113.       {
  3114.         _lines = oldLines;              // failed to get more lines
  3115.         return 0;
  3116.       }
  3117.  
  3118.     long lx;
  3119.     for (lx = 0 ; lx <= _maxLines ; ++lx)  // copy old lines
  3120.         _lines[lx] = oldLines[lx];
  3121.  
  3122.     _maxLines = _maxLines + lineListSize - 1;       // safety factor
  3123.  
  3124.     for (lx = 0 ; lx <= _maxLines ; ++lx)  // null new lines
  3125.         _lines[lx] = 0;
  3126.  
  3127.     delete [] oldLines;                 // free the old lines
  3128.     return 1;
  3129.   }
  3130.  
  3131. //========================>>> vTextEditor::col_pos <<<======================
  3132.   int vTextEditor::col_pos(BUFFPTR chr_pos, int do_shift)
  3133.   {  /* col_pos - find the x position of the character chr_pos on current line
  3134.                 handles spacing for tabs, control characters etc */
  3135.  
  3136.     BUFFPTR i;
  3137.     int pos;
  3138.  
  3139.     pos = 1;
  3140.     for (i = GLine(curlin) + 1 ; i <= chr_pos ; ++i)
  3141.       {
  3142.         if (GCh(i-1) < ' ' && GCh(i-1) > 0)     /* cur pos depends on last chr */
  3143.           {
  3144.             if (GCh(i-1) == '\t' && state.tabspc > 0)   /* handle tabs */
  3145.               {
  3146.                 for (++pos ; ((pos-1) % state.tabspc) != 0; ++pos)
  3147.                     ;
  3148.               }
  3149.             else                /* control characters (echoed as ^X) */
  3150.                 pos += 2;       /* 2 spaces for other control character */
  3151.           }
  3152.         else                    /* normal character */
  3153.             ++pos;
  3154.       }
  3155.  
  3156.     while (do_shift)
  3157.       {
  3158.         if (pos < leftmg)       /* won't fit on screen */
  3159.           {
  3160.             leftmg -= 16;       /* shift left */
  3161.           }
  3162.         else if (pos >= GetCols() + leftmg)
  3163.           {
  3164.             leftmg += 16;
  3165.           }
  3166.         else
  3167.             break;
  3168.       }
  3169.  
  3170.     if (do_shift)
  3171.         return pos - leftmg + 1;
  3172.     else
  3173.         return pos;
  3174.   }
  3175.  
  3176. // ===========================>>> vTextEditor::mint <<<=====================
  3177.   int vTextEditor::mint(int v1, int v2)
  3178.   {
  3179.     return (v1 > v2 ? v2 : v1);
  3180.   }
  3181.  
  3182. // ============================>>> vTextEditor::maxt <<<====================
  3183.   int vTextEditor::maxt(int v1, int v2)
  3184.   {
  3185.     return (v1 > v2 ? v1 : v2);
  3186.   }
  3187.  
  3188. // ===========================>>> vTextEditor::minl <<<=====================
  3189.   long vTextEditor::minl(long v1,long v2)
  3190.   {
  3191.     return (v1 > v2 ? v2 : v1);
  3192.   }
  3193.  
  3194. // ===========================>>> vTextEditor::maxl <<<=====================
  3195.   long vTextEditor::maxl(long v1, long v2)
  3196.   {
  3197.     return (v1 > v2 ? v1 : v2);
  3198.   }
  3199.  
  3200. // ===========================>>> vTextEditor::clower <<<===================
  3201.   int vTextEditor::clower(int ch)
  3202.   {
  3203.     return ((ch >='A' && ch<='Z') ? ch + ' ' : ch);
  3204.   }
  3205.  
  3206. // ==========================>>> vTextEditor::cupper  <<<===================
  3207.   int vTextEditor::cupper(int ch)
  3208.   {
  3209.     return ((ch >= 'a' && ch <= 'z') ? ch - ' ' : ch);
  3210.   }
  3211.  
  3212. // ===================>>> vTextEditor::line_can_fit <<<=====================
  3213.   int vTextEditor::line_can_fit(long l)
  3214.   {
  3215.     /* if line can't fit onto screen width, we need to update deleted
  3216.         characters a bit differently.
  3217.     */
  3218.     BUFFPTR to;
  3219.     int len;
  3220.  
  3221.     for (to = GLine(l) + 1, len = 0 ; !IsEndLine(GCh(to)) ; ++to)
  3222.       {
  3223.         if (GCh(to) < ' ')
  3224.             return 0;                   /* ctrl chars mess it up, so false */
  3225.         ++len;
  3226.       }
  3227.     return (len < GetCols());
  3228.   }
  3229.  
  3230. // =======================>>> vTextEditor::FindDispLine <<<=================
  3231.   void vTextEditor::FindDispLine(long& ibeg, int& cnt)
  3232.   {  /* FindDispLine - find the display line
  3233.         known: current line, calculate where it would go on the screen */
  3234.  
  3235.     if (curlin <= dsplin)
  3236.       {                                 /* it is in first part of the display */
  3237.         ibeg = 1;
  3238.         cnt = (int) minl((long)GetRows(),(long)(lastLine));
  3239.         tvdlin = (int)curlin;           /* update the display line */
  3240.       }
  3241.     else if (lastLine-curlin < GetRows()-dsplin)
  3242.       {  /* at bottom of display */
  3243.         ibeg = maxl((long)1,(long)(lastLine - GetRows() + 1));
  3244.         cnt = mint(GetRows(),(int) lastLine);
  3245.         tvdlin = minl(curlin,(long)(GetRows()-(lastLine-curlin+1)+1));
  3246.       }
  3247.     else                        /* normal case: in middle */
  3248.       {
  3249.         ibeg = maxl((long) 1,(long)(curlin-dsplin+1));
  3250.         cnt = minl((long)GetRows(),(long)(lastLine-(ibeg)+1));
  3251.         tvdlin = dsplin;
  3252.       }
  3253.  }
  3254.  
  3255. // ======================>>> vTextEditor::findX  <<<========================
  3256.   int vTextEditor::findX(void)
  3257.   {  /* findX - find the x position of the current character
  3258.                 handles spacing for tabs, control characters etc */
  3259.  
  3260.     BUFFPTR i;
  3261.     int pos, need_newscr;
  3262.  
  3263.     if (curlin < 1 || GetCols() < 1 || lastLineBF() < 1)
  3264.         return 1;
  3265.     need_newscr = 0;
  3266.     pos = 1;
  3267.  
  3268.     for (i = GLine(curlin)+1 ; i <= curchr ; ++i)
  3269.       {
  3270.         if (GCh(i-1) < ' ' && GCh(i-1) > 0)     /* cur pos depends on last chr */
  3271.           {
  3272.             if (GCh(i-1) == '\t' && state.tabspc > 0)   /* handle tabs */
  3273.               {
  3274.                 for (++pos ; ((pos-1) % state.tabspc) != 0; ++pos)
  3275.                     ;
  3276.               }
  3277.             else                /* control characters (echoed as ^X) */
  3278.                 pos += 2;       /* 2 spaces for other control character */
  3279.           }
  3280.         else                    /* normal character */
  3281.             ++pos;
  3282.       }
  3283.  
  3284.     for (;;)
  3285.       {
  3286.         if (pos < leftmg)       /* won't fit on screen */
  3287.           {
  3288.             leftmg -= 16;       /* shift left */
  3289.             need_newscr = 1;
  3290.           }
  3291.         else if (pos >= GetCols()+leftmg)
  3292.           {
  3293.             leftmg += 16;
  3294.             need_newscr = 1;
  3295.           }
  3296.         else
  3297.             break;
  3298.       }
  3299.  
  3300.     if (need_newscr)
  3301.       {
  3302.         Verify();
  3303.       }
  3304.  
  3305.     return (pos-leftmg+1);
  3306.   }
  3307.  
  3308. // ===================>>> vTextEditor::getCurLine <<<=======================
  3309.   void vTextEditor::getCurLine(char* buff, long start)
  3310.   {
  3311.     int ix;
  3312.     BUFFPTR bi;
  3313.  
  3314.     buff[0] = 0;                /* empty line for sure */
  3315.  
  3316.     if (lastLineBF() < 1)
  3317.         return;
  3318.  
  3319.     bi = GLine(start);          /* first char of buffer */
  3320.  
  3321.     for (ix = 0 ; ix < 38 ; ++ix)       /* 38 chars max */
  3322.       {
  3323.         if (IsEndLine(GCh(bi+ix)))
  3324.             break;
  3325.         buff[ix] = GCh(bi+ix);  /* copy the char */
  3326.       }
  3327.     buff[ix] = 0;                       /* terminate the string */
  3328.   }
  3329.  
  3330. // ====================>>> vTextEditor::lastBX <<<==========================
  3331.   BUFFPTR vTextEditor::lastBX(long line)
  3332.   {
  3333.     /* return the buff index of the last char of the line */
  3334.     BUFFPTR bx;
  3335.  
  3336.     for (bx = GLine(line) ; !IsEndLine(GCh(bx)) ; ++bx)
  3337.         ;                       /* find last char in line */
  3338.     return bx;
  3339.   }
  3340.  
  3341. // ====================>>> vTextEditor::Fill1  <<<==========================
  3342.   int vTextEditor::Fill1(int dir, int val)
  3343.   {  /* change character dir to val */
  3344.  
  3345.     int oldwrp;
  3346.  
  3347.     if (state.readOnly)
  3348.         return 0;
  3349.     oldwrp = state.wraplm;
  3350.     state.wraplm = 0;
  3351.     if (! charDelete((long)dir))
  3352.         goto l900;
  3353.     if (! charInsert(val))
  3354.         goto l900;
  3355.     state.wraplm = oldwrp;
  3356.     return 1;
  3357. l900:
  3358.     state.wraplm = oldwrp;
  3359.     return 0;
  3360.   }
  3361.  
  3362. // ======================>>> vTextEditor::newscr <<<========================
  3363.   void vTextEditor::newscr(void)
  3364.   { /* newscr - retype entire screen, updating cursor position if necessary */
  3365.  
  3366.     long ibeg;
  3367.     int cnt;
  3368.  
  3369.     if (!state.echof)
  3370.         return;
  3371.  
  3372.     if (curlin < 1)
  3373.       {
  3374.         tvclr();
  3375.         tvxy(1,1);
  3376.         return;
  3377.       }
  3378.     if (lastLine < GetRows())   /* two kinds of screen rewrite */
  3379.         tvclr();                        /* clear the screen and home */
  3380.     tvxy(1,1);
  3381.  
  3382.     dsplin = tvdlin = ddline;   /* home to middle */
  3383.     FindDispLine(ibeg, cnt);    /* calculate where it will go */
  3384.     type_lines(ibeg,cnt);       /* type it out */
  3385.     tvhdln();                   /* home to display line */
  3386.   }
  3387.  
  3388. // =====================>>> vTextEditor::range  <<<=========================
  3389.   void vTextEditor::range(long cnt, long *lbeg, long *lend)
  3390.   { /* determine a legal line number range given cnt */
  3391.  
  3392.     if (cnt <= 0)
  3393.       {
  3394.         if ((*lbeg = curlin + cnt) < 0)
  3395.             *lbeg = 1;
  3396.         *lend = curlin;
  3397.         if (cnt < 0)
  3398.            *lend = (*lend)-1;
  3399.       }
  3400.     else
  3401.       {
  3402.         *lbeg = curlin;
  3403.         if ((*lend = curlin+cnt-1) > lastLine)
  3404.             *lend = lastLine;
  3405.       }
  3406.  }
  3407.  
  3408. // ====================>>> vTextEditor::setScrollBar <<<====================
  3409.   void vTextEditor::setScrollBar()
  3410.   {
  3411.     long shown;
  3412.     long top;
  3413.     long last = lastLine;
  3414.  
  3415.     if (!state.echof)
  3416.         return;
  3417.  
  3418.     if (last < 1)
  3419.         last = 1;
  3420.  
  3421.     if (lastLine <= (long)GetRows())
  3422.         shown = 100L;
  3423.     else
  3424.         shown = ((long) GetRows() * 100L) / last;
  3425.  
  3426.     if (shown < 1)
  3427.         shown = 1;
  3428.  
  3429.     long cur = (scroll_lin > 0) ? scroll_lin : curlin;  // handle scrolling
  3430.  
  3431.     if (cur >= last)
  3432.         top = 100L;
  3433.     else if (cur == 1)
  3434.         top = 0;
  3435.     else
  3436.         top = (cur * 100L) / last;
  3437.  
  3438.     if (top < 0)
  3439.         top = 0;
  3440.  
  3441.     SetVScroll((int) shown, (int) top);
  3442.   }
  3443.  
  3444. // ====================>>> vTextEditor::checkIfScrolled <<<=================
  3445.   void vTextEditor::checkIfScrolled()
  3446.   {
  3447.     // If we are scrolled, we need to restore screen
  3448.  
  3449.     if (!state.echof)
  3450.         return;
  3451.  
  3452.     if (scroll_lin > 0)
  3453.       {
  3454.         scroll_lin = -1;
  3455.         ShowTextCursor();
  3456.         Verify();
  3457.       }
  3458.   }
  3459.  
  3460. // ====================>>> vTextEditor::scrollDown <<<======================
  3461.   void vTextEditor::scrollDown(long delta)
  3462.   { /* scroll screen without moving cursor either 1 line or screenful*/
  3463.  
  3464.     long change;
  3465.  
  3466.     if (!state.echof)
  3467.         return;
  3468.  
  3469.     if (lastLineBF() < 1 || delta == 0)
  3470.         return;
  3471.  
  3472.     if (!state.fixed_scroll && scroll_lin < 0)  /* might be on same screen */
  3473.       {
  3474.         // this just adjusts the screen without really scrolling
  3475.         if (delta == 1 && dsplin > 1)           /* scroll down */
  3476.           {
  3477.             if ((curlin+GetRows()-tvdlin) >= lastLine)
  3478.                 return;                         // no where to go
  3479.             tvbotb(1);          /* make room */
  3480.             tvxy(1,GetRows());  /* home to last line */
  3481.             dsplin = tvdlin = tvdlin - 1;       /* change line */
  3482.             type_lines((long)(curlin+GetRows()-tvdlin),1);      /* fix up screen */
  3483.             tvhdln();   /* home to display line */
  3484.             setScrollBar();
  3485.             return;
  3486.           }
  3487.         else if (delta == -1 && dsplin < GetRows())
  3488.           {
  3489.             if ((curlin-tvdlin) <= 0 )
  3490.                 return;
  3491.             tvtopb(1);          /* make blank lines at top */
  3492.             dsplin = tvdlin = tvdlin + 1;       /* change line */
  3493.             type_lines((long)(curlin-tvdlin+1),1);      /* fill in */
  3494.             tvhdln();   /* home to display line */
  3495.             setScrollBar();
  3496.             return;
  3497.           }
  3498.       }
  3499.  
  3500.     if (scroll_lin < 0)         /* initial setup */
  3501.       {
  3502.         if (curlin <= dsplin)   /* on first screen */
  3503.           {
  3504.             scroll_lin = 1;             /* assume 1st line */
  3505.           }
  3506.         else if (lastLine - curlin < GetRows() - dsplin)
  3507.           {                             /* at bottom of display */
  3508.             scroll_lin = maxl((long)1,(long)(lastLine - GetRows() + 1));
  3509.           }
  3510.         else                    /* normal case: in middle */
  3511.           {
  3512.             scroll_lin = maxl((long)1,(long)(curlin-dsplin+1));
  3513.           }
  3514.       }
  3515.  
  3516.     if (delta < 0 && scroll_lin == 1)   /* at top already */
  3517.         return;
  3518.  
  3519.     change = delta;
  3520.  
  3521.     if (change < 0)                     /* have to scroll screen down */
  3522.       {
  3523.         if (change == -1)
  3524.           {
  3525.             if (scroll_lin <= 1)
  3526.                 return;
  3527.             scroll_lin -= 1;
  3528.             tvtopb(1);          /* make blank lines at top */
  3529.             type_lines(scroll_lin,1);   /* fill in */
  3530.           }
  3531.         else                    /* a screenful or so */
  3532.           {
  3533.             scroll_lin = maxl((long)1,(long)(scroll_lin + delta));
  3534.             newScrollScreen(scroll_lin);
  3535.           }
  3536.       }
  3537.     else if (change > 0)                /* have to scroll screen up */
  3538.       {
  3539.         if ((scroll_lin+GetRows()) > lastLine)
  3540.                 return;                         // no where to go
  3541.         if (change == 1)
  3542.           {
  3543.             scroll_lin += 1;
  3544.             tvbotb(1);          /* make blank lines at top */
  3545.             type_lines((long)(scroll_lin+GetRows()-1),1);       /* fill in */
  3546.           }
  3547.         else                    /* a screenful or so */
  3548.           {
  3549.             scroll_lin = minl(lastLine, (long)(scroll_lin + delta));
  3550.             newScrollScreen(scroll_lin);
  3551.           }
  3552.       }
  3553.  
  3554.     // now, if the curlin is on the new scrolled screen, we need to
  3555.     // repaint it so the cursor and highlight area show
  3556.  
  3557.  
  3558.     if (curlin >= scroll_lin  && curlin < (scroll_lin + GetRows()))
  3559.       {
  3560.         scroll_lin = -1;
  3561.         ShowTextCursor();
  3562.         int xf = findX();
  3563.         tvxy(xf,tvdlin);
  3564.       }
  3565.     else
  3566.         HideTextCursor();
  3567.  
  3568.     setScrollBar();
  3569.     
  3570.   }
  3571.  
  3572. // =================>>> vTextEditor::newScrollScreen <<<====================
  3573.   void vTextEditor::newScrollScreen(long ibeg)
  3574.   { /* newScrollScreen - retype entire screen,
  3575.         updating cursor position if necessary */
  3576.  
  3577.     if (!state.echof)
  3578.         return;
  3579.  
  3580.     tvclr();                    /* clear the screen and home */
  3581.     type_lines(ibeg,(int)minl(lastLine,(long)GetRows()));       /* type it out */
  3582.   }
  3583.  
  3584. // ===================>>> vTextEditor::SaveKillLine <<<=====================
  3585.   void vTextEditor::SaveKillLine(long lin)
  3586.   { /* SaveKillLine - save one line that will be killed */
  3587.  
  3588.     BUFFPTR from;
  3589.     int to;
  3590.  
  3591.     to=0;
  3592.     for (from = GLine(lin); !IsEndLine(GCh(from)) ; ++from)
  3593.       {
  3594.         unkbuf[to]= GCh(from);  /* put it in unkill buffer */
  3595.         to = mint(130,to+1);
  3596.       }
  3597.     unkbuf[to]=0;
  3598.   }
  3599.  
  3600. // =====================>>> vTextEditor::tvhdln <<<=========================
  3601.   void vTextEditor::tvhdln(void)
  3602.   { /* tvhdln - home to display line */
  3603.  
  3604.     int xf;
  3605.  
  3606.     if (curlin < 1)
  3607.         tvxy(1,1);
  3608.     else
  3609.       {
  3610.         if (mark.beg_lin > 0)
  3611.           {
  3612.             tvxy(1,tvdlin);
  3613.             type_lines(curlin, 1);
  3614.           }
  3615.         xf = findX();
  3616.         tvxy(xf,tvdlin);
  3617.       }
  3618.   }
  3619.  
  3620. // ========================>>> vTextEditor::tvtyln <<<======================
  3621.   void vTextEditor::tvtyln(long lineNum, BUFFPTR chrptr, int whole_line)
  3622.   { /* tvtyln - type a line on the screen without cr/lf */
  3623.  
  3624.     xoutcm = tvx;
  3625.     tvplin(lineNum,chrptr,whole_line,-1,-1);
  3626.   }
  3627.  
  3628. // =======================>>> vTextEditor::unkill <<<=======================
  3629.   int vTextEditor::unkill(void)
  3630.   { /* unkill the single last line killed */
  3631.  
  3632.     char chrval;
  3633.     int i;
  3634.  
  3635.     if (state.readOnly)
  3636.         return 0;
  3637.     lineOpen((long)1);          /* put the CR 1st - makes update pretty */
  3638.     for (i=0; unkbuf[i]; ++i)
  3639.       {
  3640.         chrval = unkbuf[i];
  3641.         if (! charInsert(chrval))       /* unkill slowly by using insert */
  3642.           {
  3643.             return 0;
  3644.           }
  3645.       }
  3646.     lineDownBeg((long)1);               /* back to where we were */
  3647.     return 1;
  3648.   }
  3649.  
  3650. // =======================>>> vTextEditor::update <<<=======================
  3651.   void vTextEditor::update(long change)
  3652.   { /* update - update the screen when line position has changed
  3653.                 will not be used if any alterations have been made */
  3654.  
  3655.     if (change == 0)
  3656.       {
  3657.         tvhdln();
  3658.         return;
  3659.       }
  3660.     setScrollBar();
  3661.     if (state.fixed_scroll)
  3662.         updateScroll(change);   /* cursor stays on fixed line */
  3663.     else
  3664.         updateNoScroll(change); /* cursor roams around screen */
  3665.   }
  3666.  
  3667. // ===================>>> vTextEditor::updateScroll <<<=====================
  3668.   void vTextEditor::updateScroll(long change)
  3669.   { /* update - update the screen when line position has changed
  3670.                 will not be used if any alterations have been made */
  3671.  
  3672.     long abschg;
  3673.  
  3674.     if (!state.echof)
  3675.         return;
  3676.     abschg =  change;
  3677.  
  3678.     if (change < 0)                     /* have to scroll screen down */
  3679.       {
  3680.         abschg = (-change);
  3681.         if (tvdlin-abschg < 1)
  3682.             Verify();
  3683.         else if (curlin < tvdlin)       /* won't fit exactly */
  3684.           {
  3685.             if (tvdlin >= dsplin && abschg != 1)
  3686.               {
  3687.                 tvclr();                /* clear the screen */
  3688.                 type_lines((long)1,GetRows());  /* type out a screen */
  3689.               }
  3690.             tvdlin = curlin;
  3691.           }
  3692.         else if (tvdlin - abschg >= dsplin)
  3693.             tvdlin -= abschg;
  3694.         else
  3695.           {
  3696.             if (tvdlin > dsplin)
  3697.               {                         /* moving up from below display line */
  3698.                 abschg = dsplin-(tvdlin-abschg);
  3699.                 tvdlin=dsplin;          /* update */
  3700.               }
  3701.             tvtopb((int)abschg);                /* make blank lines at top */
  3702.             type_lines((long)(curlin-tvdlin+1),(int)abschg);    /* fill in */
  3703.           }
  3704.       }
  3705.     else if (change > 0)                /* have to scroll screen up */
  3706.       {
  3707.         if (tvdlin+change > GetRows() && tvdlin < dsplin ||
  3708.                 change >= GetRows())
  3709.             Verify();
  3710.         else if (tvdlin < dsplin || lastLine <= GetRows())
  3711.             if (tvdlin+change > dsplin && lastLine > GetRows())
  3712.                 Verify();
  3713.             else
  3714.                 tvdlin += change;
  3715.         else if (lastLine - curlin < GetRows() - tvdlin)        /* on bottom part */
  3716.           {
  3717.             if (tvdlin<=dsplin && abschg != 1)
  3718.               {
  3719.                 tvclr();                /* rewrite whole screen */
  3720.                 type_lines((long)(lastLine - GetRows() + 1), GetRows());
  3721.               }
  3722.             tvdlin = (int) minl((long)GetRows(), (long)(lastLine))
  3723.                          - (lastLine - curlin + 1) + 1;
  3724.           }
  3725.         else
  3726.           {
  3727.             tvbotb((int)abschg);                /* make room */
  3728.             tvxy(1,(int)(GetRows()-abschg+1));  /* home to right line */
  3729.             type_lines((long)(curlin+GetRows()-tvdlin-abschg+1),(int)abschg);  /* fix up screen */
  3730.             if (tvdlin < dsplin)
  3731.                 tvdlin = dsplin;
  3732.           }
  3733.       }
  3734.     tvhdln();
  3735.   }
  3736.  
  3737. // ==================>>> vTextEditor::updateNoScroll <<<====================
  3738.   void vTextEditor::updateNoScroll(long change)
  3739.   { /* update - update the screen when line position has changed
  3740.                 will not be used if any alterations have been made */
  3741.  
  3742.     long abschg;
  3743.  
  3744.     if (!state.echof)
  3745.         return;
  3746.     abschg =  change;
  3747.  
  3748.     if (change < 0)                     /* have to scroll screen down */
  3749.       {
  3750.         abschg = (-change);
  3751.         if (curlin + abschg < tvdlin && curlin < tvdlin) // won't fit exactly
  3752.           {
  3753.             dsplin = tvdlin = curlin;
  3754.           }
  3755.         else if (tvdlin - abschg >= 1)
  3756.           {
  3757.             dsplin = tvdlin -= (int)abschg;
  3758.           }
  3759.         else if (abschg == 1) /* simple case */  
  3760.           {
  3761.             tvtopb((int)abschg);                /* make blank lines at top */
  3762.             type_lines((long)(curlin-tvdlin+1),(int)abschg);    /* fill in */
  3763.             dsplin = tvdlin = 1;
  3764.           }
  3765.         else            /* scroll to above top line */
  3766.           {
  3767.             dsplin = tvdlin;
  3768.             Verify();
  3769.           }
  3770.       }
  3771.     else if (change > 0)                /* have to scroll screen up */
  3772.       {
  3773.         if (tvdlin + change <= GetRows())
  3774.           {
  3775.             dsplin = 
  3776.             tvdlin = tvdlin + change;
  3777.           }
  3778.         else if (change == 1)
  3779.           {
  3780.             tvbotb((int)abschg);                /* make room */
  3781.             tvxy(1,(int)(GetRows()-abschg+1));  /* home to right line */
  3782.             type_lines((long)(curlin+GetRows()-tvdlin-abschg+1),(int)abschg);
  3783.             /* fix up screen */
  3784.             dsplin = 
  3785.             tvdlin = GetRows();
  3786.           }
  3787.         else            /* scroll to above top line */
  3788.           {
  3789.             dsplin = tvdlin;
  3790.             Verify();
  3791.           }
  3792.       }
  3793.     tvhdln();
  3794.   }
  3795.  
  3796. // #########################################################################
  3797. //
  3798. // word methods
  3799. //
  3800. // #########################################################################
  3801.  
  3802. // =====================>>> vTextEditor::wordRight  <<<=====================
  3803.   int vTextEditor::wordRight(long cnt)
  3804.   {  /* wordRight - move cursor over words */
  3805.  
  3806.     long lim, words, incr, lenmov;
  3807.     int rv;
  3808.  
  3809.     if (lastLineBF() < 1)
  3810.         return 0;
  3811.     ClearMarkRange();           /* no range now */
  3812.     wasColCmd = 0;
  3813.  
  3814.     rv = 1;
  3815.     lenmov = 0;
  3816.     if (cnt < 0)
  3817.       {
  3818.         incr = (-1);            /* change */
  3819.         lim = (-cnt);
  3820.       }
  3821.     else if (cnt == 0)
  3822.       {
  3823.         incr = -1;
  3824.         lim = 0;
  3825.       }
  3826.     else
  3827.       {
  3828.         incr = 1;
  3829.         lim = cnt;
  3830.       }
  3831.  
  3832.     for (words = 1; words <= lim; ++words)
  3833.       {
  3834.         if ((IsEndLine(GCh(curchr)) && incr > 0) ||
  3835.             (curchr == GLine(curlin) && incr < 0) )
  3836.           {
  3837.             if (curlin + incr > lastLine || curlin + incr < 1)
  3838.               {
  3839.                 rv = 0;
  3840.                 break;          /* at a buffer limit, so quit */
  3841.               }
  3842.             lineDownBeg((long)incr,0);  /* move up or down */
  3843.             lenmov += incr;
  3844.             if (cnt<0)
  3845.                 lineEnd();
  3846.             continue;           /* move to next word */
  3847.           }
  3848.  
  3849.     /* ok, first, skip over word characters */
  3850.         while (IsWordChar(GCh(curchr)))
  3851.           {
  3852.             if (curchr == GLine(curlin) && incr < 0)
  3853.                 goto l100;
  3854.             else
  3855.               {
  3856.                 curchr += incr;
  3857.                 lenmov += incr;
  3858.               }
  3859.           }
  3860.  
  3861.     /* now skip over remaining non word chars */
  3862.         while (! IsWordChar(GCh(curchr)))
  3863.            {
  3864.             if ((IsEndLine(GCh(curchr)) && incr > 0) ||
  3865.                 (curchr == GLine(curlin) && incr < 0) )
  3866.                 break;
  3867.             else
  3868.               {
  3869.                 curchr += incr;
  3870.                 lenmov += incr;
  3871.               }
  3872.           }
  3873. l100: ;
  3874.       }
  3875.  
  3876.     if (incr < 0)               /* move cursor to beginning of word */
  3877.       {
  3878.         while (IsWordChar(GCh(curchr-1)))
  3879.           {
  3880.             curchr += incr;
  3881.             lenmov += incr;
  3882.           }
  3883.       }
  3884.     tvhdln();
  3885.     oldlen = lenmov;
  3886.     ChangeLoc(curlin,col_pos(curchr,0));
  3887.     return rv;
  3888.   }
  3889.  
  3890. // ====================>>> vTextEditor::IsWordChar <<<======================
  3891.   int vTextEditor::IsWordChar(int chr)
  3892.   { /* IsWordChar - determine if a character is a "word" type character */
  3893.  
  3894.     if ((chr>='a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') ||
  3895.         (chr >= '0' && chr <= '9') || chr == '_' || chr == '\\')
  3896.         return 1;
  3897.     else
  3898.         return 0;
  3899.   }
  3900.  
  3901. // #########################################################################
  3902. //
  3903. // DEFAULT vTextEdCmdInterp
  3904. //
  3905. // #########################################################################
  3906.  
  3907. // ==================>>> vTextEdCmdInterp::vTextEdCmdInterp <<<=================
  3908.   vTextEdCmdInterp::vTextEdCmdInterp(vTextEditor* textEd, vCmdWindow* cw)
  3909.   {
  3910.       _textEd = textEd;
  3911.       _myCmdWindow = cw;
  3912.       metaWait = 0;
  3913.       countWait = 0;                // not waiting on meta cmd
  3914.       metaChar = 'A'-'@';           // ^A is default meta char
  3915.       cmdCount = 1;
  3916.  
  3917.   }
  3918.  
  3919. // ==================>>> vTextEdCmdInterp::~vTextEdCmdInterp <<<================
  3920.   vTextEdCmdInterp::~vTextEdCmdInterp()
  3921.   {
  3922.   }
  3923.  
  3924. // =====================>>> vTextEdCmdInterp::InitCmdInterp <<<====================
  3925.   void vTextEdCmdInterp::InitCmdInterp()
  3926.   {
  3927.   }
  3928.  
  3929. // =====================>>> vTextEdCmdInterp::InitCmdInterp <<<====================
  3930.   void vTextEdCmdInterp::CmdInterpHelp()
  3931.   {
  3932.   }
  3933.  
  3934. // =====================>>> vTextEdCmdInterp::ProcessKey <<<====================
  3935.   int vTextEdCmdInterp::ProcessKey(vKey key, unsigned int shift)
  3936.   {
  3937. // Commands supported by default keyboard mapping:
  3938. //
  3939. //      Most commands can be preceeded by a count, which is entered
  3940. //      with Esc followed by a value followed by the command. Negative
  3941. //      counts can be used for most commands as well. An n in front
  3942. //      of a command indicates it can use a count.
  3943. //
  3944. //      Some commands have synonyms compatible with See and
  3945. //      touch typing shown in []'s (e.g., ^A, for Home).
  3946. //
  3947. //      Commands that change text interact with highlighted text
  3948. //      by deleting it, but without copying it to the clipboard.
  3949. //      ^X and ^C interact with the clipboard.
  3950. //
  3951. //
  3952. //      ^A[             Balance match
  3953. //      ^ABackspace     Delete to line beginngin [^A']
  3954. //      ^ADel           Delete to line end [^A"]
  3955. //      n^AIns          Insert character with value of count
  3956. //      ^Av             Repaint screen
  3957. //      ^C              Copy highlighted text to clipboard
  3958. //      nShift-^C       Fold case
  3959. //      ^F              Find pattern
  3960. //      Shift-^F        Find next
  3961. //      n^G             Goto line specified by count
  3962. //      n^K             Kill line
  3963. //      n^O             Open a new blank line
  3964. //      ^V              Paste from clipboard
  3965. //      ^X              Cut highlighted text to clipboard
  3966. //      nLeft           Move left [^L]
  3967. //      nCtrl-Left      Move left a word
  3968. //      nUp             Move up [^U]
  3969. //      nShift-Up       Move up to beginning of line
  3970. //      nRight          Move right [^R]
  3971. //      nCtrl-Right     Move right a word
  3972. //      nDown           Move down [^D]
  3973. //      nShift-Down     Move down to beginning of line
  3974. //      nBackspace      Delete previous character
  3975. //      Esc             Prefix for entering counts
  3976. //      nDel            Delete next character
  3977. //      nShift-Del      Delete line
  3978. //      Home            Goto beginning of line [^A,]
  3979. //      Ctrl-Home       Goto beginning of file
  3980. //      End             Goto end of line [^A.]
  3981. //      Ctrl-End        Goto end of file
  3982. //      nPgUp           Move a screenful up
  3983. //      nCtrl-PgUp      Scroll a screenful up
  3984. //      nPgDn           Move a screenful down
  3985. //      nCtrl-PgDn      Scroll a screenful down
  3986. //      Ins             Toggle insert/overtype
  3987.  
  3988.     if (vk_IsModifier(key))             // ignore modifiers
  3989.         return -1;
  3990.  
  3991.     int retval = 1;
  3992.  
  3993.     if (countWait != 0)
  3994.       {
  3995.         if (key == '-')
  3996.           {
  3997.             countWait = -1;
  3998.             return 1;
  3999.           }
  4000.         else if (key >= '0' && key <= '9')      // it is a count
  4001.           {
  4002.             cmdCount = (cmdCount * 10) + (key - '0');
  4003.             return 1;
  4004.           }
  4005.         else
  4006.           {
  4007.             cmdCount *= countWait;        // negative?
  4008.             countWait = 0;                      // done building count
  4009.           }
  4010.       }
  4011.  
  4012.     if (metaWait)                       // waiting for meta cmd
  4013.       {
  4014.         metaWait = 0;
  4015.         switch (key)
  4016.           {
  4017.             case vk_KP_Insert:
  4018.             case vk_Insert:
  4019.               {
  4020.                 retval = te()->charInsert(cmdCount);
  4021.                 break;
  4022.               }
  4023.  
  4024.             case '\'':
  4025.             case vk_BackSpace:
  4026.               {
  4027.                 retval = te()->lineDeleteFront();
  4028.                 break;
  4029.               }
  4030.  
  4031.             case '"':
  4032.             case vk_Delete:
  4033.             case vk_KP_Delete:
  4034.               {
  4035.                 retval = te()->lineDeleteToEnd();
  4036.                 break;
  4037.               }
  4038.  
  4039.             case ',':                   // line beginning
  4040.               {
  4041.                 te()->lineBeginning();
  4042.                 break;
  4043.               }
  4044.  
  4045.             case '.':                   // line end
  4046.               {
  4047.                 te()->lineEnd();
  4048.                 break;
  4049.               }
  4050.  
  4051.             case '[':                   // ^A[ - bal match
  4052.               {
  4053.                 retval = te()->BalMatch(cmdCount);
  4054.                 break;
  4055.               }
  4056.  
  4057.             case 'v':
  4058.             case 'V':
  4059.             case 'V'-'@':
  4060.               {
  4061.                 te()->Verify();
  4062.                 break;
  4063.               }
  4064.  
  4065.             default:
  4066.               {
  4067.                 retval = -1;
  4068.                 break;
  4069.               }
  4070.           }
  4071.         cmdCount = 1;
  4072.         return retval;
  4073.       }
  4074.     else if (key == (vKey) metaChar)
  4075.       {
  4076.         metaWait = 1;
  4077.         return 1;
  4078.       }
  4079.  
  4080.     switch (key)
  4081.       {
  4082.         case 'C'-'@':           // ^C : Copy ; Shift-^C: fold case
  4083.           {
  4084.             if (shift & VKM_Shift)      // Shift-^F
  4085.               {
  4086.                 retval = te()->charFoldCase(cmdCount);
  4087.               }
  4088.             else
  4089.                 te()->EditCopy();
  4090.             break;
  4091.           }
  4092.  
  4093.         case 'F'-'@':           // ^F: find, Shift-^F: find next
  4094.           {
  4095.             if (shift & VKM_Shift)      // Shift-^F
  4096.               {
  4097.                 retval = te()->EditCommand(edFindNext, cmdCount);
  4098.               }
  4099.             else
  4100.               {
  4101.                 retval = te()->EditCommand(edFind, cmdCount);
  4102.               }
  4103.             break;
  4104.           }
  4105.  
  4106.         case 'G'-'@':           // ^G: Goto line
  4107.           {
  4108.             retval = te()->lineGoto(cmdCount);
  4109.             break;
  4110.           }
  4111.  
  4112.         case 'K'-'@':           // ^K: Kill line
  4113.           {
  4114.             te()->lineDelete(cmdCount);
  4115.             break;
  4116.           }
  4117.  
  4118.         case 'O'-'@':           // ^O: Open line
  4119.           {
  4120.             retval = te()->lineOpen(cmdCount);
  4121.             break;
  4122.           }
  4123.  
  4124.         case 'V'-'@':           // ^V: Paste
  4125.           {
  4126.             te()->EditPaste();
  4127.             break;
  4128.           }
  4129.  
  4130.         case 'X'-'@':           // ^X : Cut
  4131.           {
  4132.             te()->EditCut();
  4133.             break;
  4134.           }
  4135.  
  4136.         case 'L'-'@':
  4137.         case vk_Left:
  4138.         case vk_KP_Left:
  4139.           {
  4140.             if (shift & VKM_Ctrl || shift & VKM_Shift)
  4141.                 retval = te()->wordRight(-cmdCount);
  4142.             else
  4143.                 retval = te()->charRight(-cmdCount,1);
  4144.             break;
  4145.           }
  4146.  
  4147.         case 'U'-'@':
  4148.         case vk_Up:
  4149.         case vk_KP_Up:
  4150.           {
  4151.             if (shift & VKM_Shift)
  4152.                 retval = te()->lineDownBeg(-cmdCount);
  4153.             else
  4154.                 retval = te()->lineDown(-cmdCount);
  4155.             break;
  4156.           }
  4157.  
  4158.         case 'R'-'@':
  4159.         case vk_Right:
  4160.         case vk_KP_Right:
  4161.           {
  4162.             if (shift & VKM_Ctrl ||shift & VKM_Shift)
  4163.                 retval = te()->wordRight(cmdCount);
  4164.             else
  4165.                 retval = te()->charRight(cmdCount,1);
  4166.             break;
  4167.           }
  4168.  
  4169.         case 'D'-'@':
  4170.         case vk_KP_Down:
  4171.         case vk_Down:
  4172.           {
  4173.             if (shift & VKM_Shift)
  4174.                 retval = te()->lineDownBeg(cmdCount);
  4175.             else
  4176.                 retval = te()->lineDown(cmdCount);
  4177.             break;
  4178.           }
  4179.  
  4180.         case vk_BackSpace:
  4181.           {
  4182.             retval = te()->charDelete(-cmdCount);
  4183.             break;
  4184.           }
  4185.  
  4186.         case vk_Tab:
  4187.           {
  4188.             retval = te()->defaultKeyIn('\t',shift);
  4189.             break;
  4190.           }
  4191.  
  4192.         case vk_Linefeed:
  4193.           {
  4194.             break;
  4195.           }
  4196.  
  4197.         case vk_Return:
  4198.         case vk_KP_Enter:
  4199.           {
  4200.             retval = te()->defaultKeyIn('\n',shift);
  4201.             break;
  4202.           }
  4203.  
  4204.         case vk_Escape:
  4205.           {
  4206.             countWait = 1;
  4207.             cmdCount = 0;
  4208.             return 1;
  4209.           }
  4210.  
  4211.         case vk_Delete:
  4212.         case vk_KP_Delete:
  4213.           {
  4214.             if (shift & VKM_Shift || shift & VKM_Ctrl)
  4215.                 te()->lineDelete(cmdCount);
  4216.             else
  4217.                 retval = te()->charDelete(cmdCount);
  4218.             break;
  4219.           }
  4220.  
  4221.         case vk_Home:
  4222.         case vk_KP_Home:
  4223.           {
  4224.             if (shift & VKM_Shift || shift & VKM_Ctrl)
  4225.                 retval = te()->lineGoto(1);
  4226.             else
  4227.                 te()->lineBeginning();
  4228.             break;
  4229.           }
  4230.  
  4231.         case vk_Page_Up:
  4232.         case vk_KP_Page_Up:
  4233.           {
  4234.             if (shift & VKM_Ctrl)
  4235.                 te()->scrollDown(-cmdCount * te()->GetRows());
  4236.             else
  4237.                 retval = te()->lineDown((long)(-cmdCount * te()->GetRows()));
  4238.             break;
  4239.           }
  4240.  
  4241.         case vk_Page_Down:
  4242.         case vk_KP_Page_Down:
  4243.           {
  4244.             if (shift & VKM_Ctrl)
  4245.                 te()->scrollDown(cmdCount * te()->GetRows());
  4246.             else
  4247.                 retval = te()->lineDown(
  4248.             (long) te()->minl((cmdCount * te()->GetRows()), 
  4249.             (long)(te()->GetLines() - te()->GetCurLine() + 1)));
  4250.             break;
  4251.           }
  4252.  
  4253.         case vk_End:
  4254.         case vk_KP_End:
  4255.           {
  4256.             if (shift & VKM_Shift || shift & VKM_Ctrl)
  4257.                 te()->bufferBottom();
  4258.             else
  4259.                 te()->lineEnd();
  4260.             break;
  4261.           }
  4262.  
  4263.         case vk_KP_Insert:
  4264.         case vk_Insert:
  4265.           {
  4266.             te()->SetInsMode(!(te()->GetEdState().ins_mode));
  4267.             te()->ChangeInsMode(te()->GetEdState().ins_mode);
  4268.             break;
  4269.           }
  4270.  
  4271.         default:
  4272.           {
  4273.             retval = te()->defaultKeyIn(key,shift);
  4274.             break;
  4275.           }
  4276.       }
  4277.     cmdCount = 1;
  4278.     return retval;
  4279.   }
  4280.  
  4281.  
  4282. //==================================================================
  4283. // I wrote the original version of the See editor, called TVX, in
  4284. // 1980 in a language called Ratfor, a preprocessor that gave
  4285. // Fortran the syntax of C. At that time, much of the TVX command
  4286. // structure was based on a Tenex editor called TV. The Ratfor
  4287. // version of TVX actually worked quite will on a TRS-80 with 48K
  4288. // (that's right, 48K) of RAM. I've been using some decendent of
  4289. // TVX ever since. My fingers know the commands too well to
  4290. // change much.
  4291. //
  4292. // TVX was character based, and ported to many platforms,
  4293. // including CP/M, RT-11, RSX-11, VMS, and of course Unix. Much
  4294. // of the organization of the edit updates are designed to work
  4295. // over serial lines on a text terminal. This was accomplished
  4296. // using either a custom terminal driver, or a package such as
  4297. // TERMCAP on Unix. In fact, one could use the full screen editor
  4298. // quite well over even 1200 Baud serial lines (visual editors
  4299. // such as Vi really failed at much less than 9600 Baud).
  4300. // 
  4301. // TVX was translated (semi-automatically) from Ratfor to C. Most
  4302. // recently (about 1995) I converted it to C++, and finally this
  4303. // C++ class for inclusion in the VGUI package. Somewhere along
  4304. // the way, I changed the name to See, which stood for Simple
  4305. // Enough Editor.
  4306. //
  4307. // Certainly, if I were designing an editor from scratch in C++,
  4308. // it would be quite different in structure than this editor.
  4309. // However, I always found it easier to port rather than rewrite.
  4310. // Many of the specialized editor commands I developed for See
  4311. // are still found in this code. A good emulation of many editor
  4312. // command sets can be implemented with different command
  4313. // parsers.
  4314. // 
  4315. // What this goes to show is that old code never dies, it just
  4316. // mutates. This code originated almost 20 years ago now. Many of
  4317. // the 6 character variable names owe their origin to Fortran
  4318. // variable name restrictions. Much of the seemingly complicated
  4319. // screen update stuff owes its origin to the restrictions of
  4320. // working with different terminals over slow baud rates.
  4321. //==================================================================
  4322.