|
|
/*
* The main edit loop as well as some other simple cursor movement routines. */
#include "stevie.h"
/*
* This flag is used to make auto-indent work right on lines where only * a <RETURN> or <ESC> is typed. It is set when an auto-indent is done, * and reset when any other editting is done on the line. If an <ESC> * or <RETURN> is received, and did_ai is TRUE, the line is truncated. */ bool_t did_ai = FALSE;
void edit() { extern bool_t need_redraw; int c; register char *p, *q;
Prenum = 0;
/* position the display and the cursor at the top of the file. */ *Topchar = *Filemem; *Curschar = *Filemem; Cursrow = Curscol = 0;
do_mlines(); /* check for mode lines before starting */
updatescreen();
for ( ;; ) {
/* Figure out where the cursor is based on Curschar. */ cursupdate();
if (need_redraw && !anyinput()) { updatescreen(); need_redraw = FALSE; }
if (!anyinput()) windgoto(Cursrow,Curscol);
c = vgetc();
if (State == NORMAL) {
/* We're in the normal (non-insert) mode. */
/* Pick up any leading digits and compute 'Prenum' */ if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){ Prenum = Prenum*10 + (c-'0'); continue; } /* execute the command */ normal(c); Prenum = 0;
} else {
/*
* Insert or Replace mode. */ switch (c) {
case ESC: /* an escape ends input mode */
/*
* If we just did an auto-indent, truncate the * line, and put the cursor back. */ if (did_ai) { Curschar->linep->s[0] = NUL; Curschar->index = 0; did_ai = FALSE; }
set_want_col = TRUE;
/* Don't end up on a '\n' if you can help it. */ if (gchar(Curschar) == NUL && Curschar->index != 0) dec(Curschar);
/*
* The cursor should end up on the last inserted * character. This is an attempt to match the real * 'vi', but it may not be quite right yet. */ if (Curschar->index != 0 && !endofline(Curschar)) dec(Curschar);
State = NORMAL; msg("");
/* construct the Redo buffer */ p = ralloc(Redobuff, Ninsert+2 < REDOBUFFMIN ? REDOBUFFMIN : Ninsert+2); if(p == NULL) { msg("Insufficient memory -- command not saved for redo"); } else { Redobuff=p; q=Insbuff; while ( q < Insptr ) *p++ = *q++; *p++ = ESC; *p = NUL; } updatescreen(); break;
case CTRL('D'): /*
* Control-D is treated as a backspace in insert * mode to make auto-indent easier. This isn't * completely compatible with vi, but it's a lot * easier than doing it exactly right, and the * difference isn't very noticeable. */ case BS: /* can't backup past starting point */ if (Curschar->linep == Insstart->linep && Curschar->index <= Insstart->index) { beep(); break; }
/* can't backup to a previous line */ if (Curschar->linep != Insstart->linep && Curschar->index <= 0) { beep(); break; }
did_ai = FALSE; dec(Curschar); if (State == INSERT) delchar(TRUE); /*
* It's a little strange to put backspaces into * the redo buffer, but it makes auto-indent a * lot easier to deal with. */ insertchar(BS); cursupdate(); updateline(); break;
case CR: case NL: insertchar(NL); opencmd(FORWARD, TRUE); /* open a new line */ break;
case TAB: if (!P(P_HT)) { /* fake TAB with spaces */ int i = P(P_TS) - (Curscol % P(P_TS)); did_ai = FALSE; while (i--) { inschar(' '); insertchar(' '); } updateline(); break; }
/* else fall through to normal case */
default: did_ai = FALSE; inschar(c); insertchar(c); updateline(); break; } } } }
void insertchar(c) int c; { char *p;
*Insptr++ = (char)c; Ninsert++;
if(Ninsert == InsbuffSize) { // buffer is full -- enlarge it
if((p = ralloc(Insbuff,InsbuffSize+INSERTSLOP)) != NULL) {
Insptr += p - Insbuff; Insbuff = p; InsbuffSize += INSERTSLOP;
} else { // could not get bigger buffer
stuffin(mkstr(ESC)); // just end insert mode
} } }
void getout() { windgoto(Rows-1,0); //putchar('\r');
putchar('\n'); windexit(0); }
void scrolldown(nlines) int nlines; { register LNPTR *p; register int done = 0; /* total # of physical lines done */
/* Scroll up 'nlines' lines. */ while (nlines--) { if ((p = prevline(Topchar)) == NULL) break; done += plines(p); *Topchar = *p; /*
* If the cursor is on the bottom line, we need to * make sure it gets moved up the appropriate number * of lines so it stays on the screen. */ if (Curschar->linep == Botchar->linep->prev) { int i = 0; while (i < done) { i += plines(Curschar); *Curschar = *prevline(Curschar); } } } s_ins(0, done); }
void scrollup(nlines) int nlines; { register LNPTR *p; register int done = 0; /* total # of physical lines done */ register int pl; /* # of plines for the current line */
/* Scroll down 'nlines' lines. */ while (nlines--) { pl = plines(Topchar); if ((p = nextline(Topchar)) == NULL) break; done += pl; if (Curschar->linep == Topchar->linep) *Curschar = *p; *Topchar = *p;
} s_del(0, done); }
/*
* oneright * oneleft * onedown * oneup * * Move one char {right,left,down,up}. Return TRUE when * sucessful, FALSE when we hit a boundary (of a line, or the file). */
bool_t oneright() { set_want_col = TRUE;
switch (inc(Curschar)) {
case 0: return TRUE;
case 1: dec(Curschar); /* crossed a line, so back up */ /* fall through */ case -1: return FALSE;
DEFAULT_UNREACHABLE; } /*NOTREACHED*/ }
bool_t oneleft() { set_want_col = TRUE;
switch (dec(Curschar)) {
case 0: return TRUE;
case 1: inc(Curschar); /* crossed a line, so back up */ /* fall through */ case -1: return FALSE;
DEFAULT_UNREACHABLE; } /*NOTREACHED*/ }
void beginline(flag) bool_t flag; { while ( oneleft() ) ; if (flag) { while (isspace(gchar(Curschar)) && oneright()) ; } set_want_col = TRUE; }
bool_t oneup(n) int n; { LNPTR p, *np; register int k;
p = *Curschar; for ( k=0; k<n; k++ ) { /* Look for the previous line */ if ( (np=prevline(&p)) == NULL ) { /* If we've at least backed up a little .. */ if ( k > 0 ) break; /* to update the cursor, etc. */ else return FALSE; } p = *np; } *Curschar = p; /* This makes sure Topchar gets updated so the complete line */ /* is one the screen. */ cursupdate(); /* try to advance to the column we want to be at */ *Curschar = *coladvance(&p, Curswant); return TRUE; }
bool_t onedown(n) int n; { LNPTR p, *np; register int k;
p = *Curschar; for ( k=0; k<n; k++ ) { /* Look for the next line */ if ( (np=nextline(&p)) == NULL ) { if ( k > 0 ) break; else return FALSE; } p = *np; } /* try to advance to the column we want to be at */ *Curschar = *coladvance(&p, Curswant); return TRUE; }
|