445 lines
8.8 KiB
C
445 lines
8.8 KiB
C
/*
|
||
* LEVEE, or Captain Video; A vi clone
|
||
*
|
||
* Copyright (c) 1982-2007 David L Parsons
|
||
* All rights reserved.
|
||
*
|
||
* Redistribution and use in source and binary forms, without or
|
||
* without modification, are permitted provided that the above
|
||
* copyright notice and this paragraph are duplicated in all such
|
||
* forms and that any documentation, advertising materials, and
|
||
* other materials related to such distribution and use acknowledge
|
||
* that the software was developed by David L Parsons (orc@pell.chi.il.us).
|
||
* My name may not be used to endorse or promote products derived
|
||
* from this software without specific prior written permission.
|
||
* THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR
|
||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
|
||
* PURPOSE.
|
||
*/
|
||
#include "levee.h"
|
||
#include "extern.h"
|
||
|
||
int PROC findcol();
|
||
int PROC moveword();
|
||
int PROC sentence();
|
||
int PROC match();
|
||
int PROC fchar(), bchar();
|
||
|
||
/* driver for movement commands */
|
||
|
||
findstates PROC
|
||
findCP(curp,newpos,cmd)
|
||
int curp, *newpos;
|
||
cmdtype cmd;
|
||
{
|
||
static char chars[2] = {'/','?'};
|
||
char tsearch;
|
||
|
||
*newpos = ERR;
|
||
switch (cmd) { /* move around */
|
||
|
||
case GO_LEFT:
|
||
*newpos = max(lstart, curp-max(count,1));
|
||
break;
|
||
|
||
case GO_RIGHT:
|
||
*newpos = min(lend, curp+max(count,1));
|
||
break;
|
||
|
||
case GO_UP:
|
||
case GO_DOWN:
|
||
*newpos = nextline(cmd==GO_DOWN, curp, count);
|
||
if (*newpos >= 0 && *newpos < bufmax)
|
||
*newpos = findcol(*newpos,xp);
|
||
break;
|
||
|
||
case FORWD:
|
||
case TO_WD:
|
||
case BACK_WD:
|
||
case BTO_WD:
|
||
*newpos = moveword(curp,(cmd <= TO_WD),(cmd==TO_WD || cmd==BTO_WD));
|
||
break;
|
||
|
||
case NOTWHITE:
|
||
*newpos = skipws(bseekeol(curp));
|
||
break;
|
||
|
||
case TO_COL:
|
||
*newpos = findcol(curp, count);
|
||
break;
|
||
|
||
case TO_EOL:
|
||
while ( (count-- > 1) && (curp < bufmax) )
|
||
curp = 1+fseekeol(curp);
|
||
*newpos = fseekeol(curp);
|
||
break;
|
||
|
||
case PARA_FWD:
|
||
do
|
||
curp = findfwd("^*[ \t$",curp+1,bufmax-1);
|
||
while (curp != ERR && --count > 0);
|
||
*newpos = (curp==ERR)?bufmax:curp;
|
||
break;
|
||
|
||
case PARA_BACK:
|
||
do
|
||
curp = findback("^*[ \t$",curp-1,0);
|
||
while (curp != ERR && --count > 0);
|
||
*newpos = (curp==ERR)?0:curp;
|
||
break;
|
||
|
||
case SENT_FWD:
|
||
case SENT_BACK:
|
||
*newpos = sentence(curp, cmd==SENT_FWD);
|
||
break;
|
||
|
||
case MATCHEXPR:
|
||
*newpos = match(curp);
|
||
break;
|
||
|
||
case TO_CHAR:
|
||
case UPTO_CHAR:
|
||
case BACK_CHAR:
|
||
case BACKTO_CHAR:
|
||
ch = readchar();
|
||
if (ch == ESC)
|
||
return ESCAPED;
|
||
if (cmd<=UPTO_CHAR) {
|
||
*newpos = fchar(curp,*newpos);
|
||
if (cmd==UPTO_CHAR && *newpos>=0)
|
||
*newpos = max(curp, *newpos-1);
|
||
}
|
||
else {
|
||
*newpos = bchar(curp,*newpos);
|
||
if (cmd==BACKTO_CHAR && *newpos>=0)
|
||
*newpos = min(curp, *newpos+1);
|
||
}
|
||
break;
|
||
|
||
case PAGE_BEGIN:
|
||
*newpos = ptop;
|
||
break;
|
||
|
||
case PAGE_END:
|
||
*newpos = pend;
|
||
break;
|
||
|
||
case PAGE_MIDDLE:
|
||
curp = ptop;
|
||
count = 12;
|
||
while (count-- > 0 && curp < bufmax)
|
||
curp = 1+fseekeol(curp);
|
||
*newpos = skipws(curp);
|
||
break;
|
||
|
||
case GLOBAL_LINE:
|
||
if (count <= 0)
|
||
*newpos = bufmax-1;
|
||
else
|
||
*newpos = to_index(count);
|
||
break;
|
||
|
||
case TO_MARK:
|
||
case TO_MARK_LINE:
|
||
*newpos = getcontext((char)tolower(readchar()), cmd==TO_MARK_LINE);
|
||
break;
|
||
|
||
case CR_FWD:
|
||
case CR_BACK:
|
||
curp = nextline(cmd==CR_FWD, curp, count);
|
||
if (cmd==CR_BACK && curp > 0)
|
||
curp = bseekeol(curp);
|
||
*newpos = skipws(curp);
|
||
break;
|
||
|
||
case PATT_FWD:
|
||
case PATT_BACK: /* search for pattern */
|
||
case FSEARCH:
|
||
case BSEARCH:
|
||
clrprompt();
|
||
if (cmd == PATT_FWD || cmd == PATT_BACK) {
|
||
printch(tsearch = instring[0] = chars[cmd-PATT_FWD]);
|
||
if (!getline(&instring[1]))
|
||
return ESCAPED; /* needs to skip later tests */
|
||
}
|
||
else {
|
||
if (!lsearch)
|
||
return BADMOVE;
|
||
tsearch = lsearch;
|
||
printch(instring[0] = (cmd==FSEARCH)?lsearch:((lsearch=='?')?'/':'?') );
|
||
prints(lastpatt);
|
||
instring[1] = 0;
|
||
}
|
||
if (*findparse(instring, newpos, curp)) { /* croaked patt */
|
||
*newpos = ERR;
|
||
prompt(TRUE,"bad pattern");
|
||
}
|
||
else if (*newpos == ERR)
|
||
prompt(FALSE,"no match");
|
||
lsearch = tsearch; /* fixup for N, n */
|
||
break;
|
||
}
|
||
if ( ((*newpos) >= 0) && ((*newpos) <= bufmax) )
|
||
return LEGALMOVE;
|
||
return BADMOVE;
|
||
}
|
||
|
||
/* this procedure handles all movement in visual mode */
|
||
|
||
VOID PROC
|
||
movearound(cmd)
|
||
cmdtype cmd;
|
||
{
|
||
int cp;
|
||
|
||
switch (findCP(curr, &cp, cmd)) {
|
||
case LEGALMOVE:
|
||
if (cp < bufmax) {
|
||
if (cmd >= PATT_FWD) /* absolute move */
|
||
contexts[0] = curr; /* so save old position... */
|
||
curr = cp; /* goto new position */
|
||
if (cmd==GO_UP || cmd==GO_DOWN) /* reset Xpos */
|
||
deranged = TRUE;
|
||
else
|
||
xp = setX(cp); /* just reset XP */
|
||
if (cp < lstart || cp > lend) {
|
||
lstart = bseekeol(curr);
|
||
lend = fseekeol(curr);
|
||
if (curr < ptop) {
|
||
if (canUPSCROLL && ok_to_scroll(curr, ptop)) {
|
||
scrollback(curr);
|
||
yp = 0;
|
||
}
|
||
else {
|
||
yp = settop(LINES / 2);
|
||
redisplay(TRUE);
|
||
}
|
||
}
|
||
else if (curr > pend) {
|
||
if (ok_to_scroll(pend, curr)) {
|
||
scrollforward(curr);
|
||
yp = LINES-2;
|
||
}
|
||
else {
|
||
yp = settop(LINES / 2);
|
||
redisplay(TRUE);
|
||
}
|
||
}
|
||
else
|
||
yp = setY(curr);
|
||
}
|
||
}
|
||
else
|
||
error();
|
||
break;
|
||
case BADMOVE:
|
||
error();
|
||
break;
|
||
}
|
||
mvcur(yp, xp);
|
||
}
|
||
|
||
int PROC
|
||
findcol(ip, col)
|
||
int ip, col;
|
||
{
|
||
int tcol, endd;
|
||
|
||
ip = bseekeol(ip); /* start search here */
|
||
endd = fseekeol(ip); /* end search here */
|
||
|
||
tcol = 0;
|
||
while (tcol < col && ip < endd)
|
||
switch (cclass(core[ip++])) {
|
||
case 0: tcol++; break;
|
||
case 1: tcol += 2; break;
|
||
case 3: tcol += 3; break;
|
||
case 2: tcol = tabsize*(1+(tcol/tabsize)); break;
|
||
}
|
||
return(ip);
|
||
}
|
||
|
||
char dstpatt[]="[](){}", srcpatt[]="][)(}{";
|
||
|
||
/* find matching [], (), {} */
|
||
|
||
int PROC
|
||
match(p)
|
||
int p;
|
||
{
|
||
char srcchar, dstchar;
|
||
int lev, step;
|
||
|
||
while((lev = scan(6,'=',core[p],srcpatt)) >= 6 && core[p] != EOL)
|
||
p++;
|
||
if (lev < 6) {
|
||
srcchar = srcpatt[lev];
|
||
dstchar = dstpatt[lev];
|
||
step = setstep[lev&1];
|
||
lev = 0;
|
||
while (p >= 0 && p < bufmax) {
|
||
p += step;
|
||
if (core[p] == srcchar)
|
||
lev++;
|
||
else if (core[p] == dstchar)
|
||
if(--lev < 0)
|
||
return p;
|
||
}
|
||
}
|
||
return (-1);
|
||
}
|
||
|
||
char * PROC
|
||
class(c)
|
||
/* find the character class of a char -- for word movement */
|
||
char c;
|
||
{
|
||
if (strchr(wordset,c))
|
||
return wordset;
|
||
else if (strchr(spaces,c))
|
||
return spaces;
|
||
else
|
||
return (char*)NULL;
|
||
}
|
||
|
||
int PROC
|
||
skip(chars,cp,step)
|
||
/* skip past characters in a character class */
|
||
char *chars;
|
||
register int cp;
|
||
int step;
|
||
{
|
||
while (cp >= 0 && cp < bufmax && strchr(chars,core[cp]))
|
||
cp += step;
|
||
return cp;
|
||
}
|
||
|
||
int PROC
|
||
tow(cp,step)
|
||
/* skip to the start of the next word */
|
||
register int cp;
|
||
register int step;
|
||
{
|
||
while (cp >= 0 && cp < bufmax
|
||
&& !(strchr(wordset,core[cp]) || strchr(spaces,core[cp])))
|
||
cp += step;
|
||
return cp;
|
||
}
|
||
|
||
int PROC
|
||
moveword(cp,forwd,toword)
|
||
/* word movement */
|
||
int cp;
|
||
bool forwd, toword;
|
||
{
|
||
int step;
|
||
char *ccl;
|
||
|
||
step = setstep[forwd]; /* set direction to move.. */
|
||
if (!toword)
|
||
cp += step; /* advance one character */
|
||
count = max(1,count);
|
||
ccl = class(core[cp]);
|
||
if (toword && ccl == spaces) { /* skip to start of word */
|
||
count--;
|
||
cp = skip(spaces,cp,step);
|
||
ccl = class(core[cp]);
|
||
}
|
||
|
||
while (cp >= 0 && cp < bufmax && count-- > 0) {
|
||
if (ccl == spaces) {
|
||
cp = skip(spaces,cp,step);
|
||
ccl = class(core[cp]);
|
||
}
|
||
cp = (ccl)?skip(ccl,cp,step):tow(cp,step);
|
||
ccl = class(core[cp]);
|
||
}
|
||
if (toword) { /* past whitespace? */
|
||
if (ccl == spaces)
|
||
cp = skip(spaces,cp,step);
|
||
return cp;
|
||
}
|
||
return cp-step; /* sit on last character. */
|
||
}
|
||
|
||
/* find a character forward on current line */
|
||
|
||
int PROC
|
||
fchar(pos,npos)
|
||
int pos,npos;
|
||
{
|
||
do
|
||
pos += scan(lend-pos-1,'=',ch, &core[pos+1]) + 1;
|
||
while (--count>0 && pos<lend);
|
||
if (pos<lend)
|
||
return(pos);
|
||
return(npos);
|
||
}
|
||
|
||
/* find a character backward on the current line */
|
||
|
||
int PROC
|
||
bchar(pos,npos)
|
||
int pos,npos;
|
||
{
|
||
do
|
||
pos += scan(-pos+lstart+1,'=',ch, &core[pos-1]) - 1;
|
||
while (--count>0 && pos>=lstart);
|
||
if (pos>=lstart)
|
||
return(pos);
|
||
return(npos);
|
||
}
|
||
|
||
/* look for the end of a sentence forward */
|
||
|
||
int PROC
|
||
ahead(i)
|
||
int i;
|
||
{
|
||
char c;
|
||
|
||
do {
|
||
if ((c=core[i]) == '.' || c == '?' || c == '!')
|
||
if (i == bufmax-1 || (c=core[1+i]) == TAB || c == EOL || c == ' ')
|
||
return i;
|
||
|
||
} while (++i < bufmax);
|
||
return -1;
|
||
}
|
||
|
||
/* look for the end of a sentence backwards. */
|
||
|
||
int PROC
|
||
back(i)
|
||
int i;
|
||
{
|
||
char c;
|
||
|
||
do {
|
||
if ((c=core[i]) == '.' || c == '?' || c == '!')
|
||
if ((c=core[1+i]) == TAB || c == EOL || c == ' ')
|
||
return i;
|
||
|
||
} while (--i >= 0);
|
||
return -1;
|
||
}
|
||
|
||
/* find the end of the next/last sentence.
|
||
Sentences are delimited by ., !, or ? followed by a space.
|
||
*/
|
||
|
||
int PROC
|
||
sentence(start,forwd)
|
||
int start;
|
||
bool forwd;
|
||
{
|
||
do {
|
||
if (forwd)
|
||
start = ahead(start+1);
|
||
else
|
||
start = back(start-1);
|
||
} while (--count > 0 && start >= 0);
|
||
return start;
|
||
}
|