home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD1.bin
/
useful
/
util
/
edit
/
vim
/
src
/
normal.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-13
|
41KB
|
1,935 lines
/* vi:ts=4:sw=4
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Read the file "credits.txt" for a list of people who contributed.
* Read the file "uganda.txt" for copying and usage conditions.
*/
/*
* Contains the main routine for processing characters in command mode.
* Communicates closely with the code in ops.c to handle the operators.
*/
#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "param.h"
#undef EXTERN
#undef INIT
#define EXTERN
#define INIT(x) x
#include "ops.h"
/*
* Generally speaking, every command in normal() should either clear any
* pending operator (with CLEAROP), or set the motion type variable.
*/
#define CLEAROP (operator = NOP) /* clear any pending operator */
#define CLEAROPBEEP clearopbeep() /* CLEAROP plus a beep() */
#define CHECKCLEAROP if (checkclearop()) break;
#define CHECKCLEAROPQ if (checkclearopq()) break;
/*
* If a count is given before the operator, it is saved in opnum.
*/
static linenr_t opnum = 0;
static linenr_t Prenum; /* The (optional) number before a command. */
int redo_Visual_busy = FALSE; /* TRUE when redo-ing a visual */
static void prep_redo __ARGS((long, int, int, int));
static int checkclearop __ARGS((void));
static int checkclearopq __ARGS((void));
static void clearopbeep __ARGS((void));
static void premsg __ARGS((int, int));
extern int restart_edit; /* this is in edit.c */
/*
* normal
*
* Execute a command in normal mode.
*
* This is basically a big switch with the cases arranged in rough categories
* in the following order:
*
* 0. Macros (q, @)
* 1. Screen positioning commands (^U, ^D, ^F, ^B, ^E, ^Y, z)
* 2. Control commands (:, <help>, ^L, ^G, ^^, ZZ, *, ^], ^T)
* 3. Cursor motions (G, H, M, L, l, K_RARROW, , h, K_LARROW, ^H, k, K_UARROW, ^P, +, CR, LF, j, K_DARROW, ^N, _, |, B, b, W, w, E, e, $, ^, 0)
* 4. Searches (?, /, n, N, T, t, F, f, ,, ;, ], [, %, (, ), {, })
* 5. Edits (., u, K_UNDO, ^R, U, r, J, p, P, ^A, ^S)
* 6. Inserts (A, a, I, i, o, O, R)
* 7. Operators (~, d, c, y, >, <, !, =, Q)
* 8. Abbreviations (x, X, D, C, s, S, Y, &)
* 9. Marks (m, ', `, ^O, ^I)
* 10. Buffer setting (")
* 11. Visual (v, V, ^V)
* 12. Suspend (^Z)
* 13. Window commands (^W)
* 14. extended commands (starting with 'g')
*/
void
normal()
{
register int c;
long n;
int flag = FALSE;
int flag2 = FALSE;
int type = 0; /* type of operation */
int dir = FORWARD; /* search direction */
int nchar = NUL;
int finish_op;
linenr_t Prenum1;
char_u searchbuff[CMDBUFFSIZE];/* buffer for search string */
FPOS *pos = NULL; /* init for gcc */
register char_u *ptr;
int command_busy = FALSE;
static int didwarn = FALSE; /* warned for broken inversion */
int modified = FALSE; /* changed current buffer */
int ctrl_w = FALSE; /* got CTRL-W command */
/* the visual area is remembered for reselection */
static linenr_t resel_Visual_nlines; /* number of lines */
static int resel_Visual_type = 0; /* type 'v', 'V' or CTRL-V */
static colnr_t resel_Visual_col; /* number of columns or end column */
/* the visual area is remembered for redo */
static linenr_t redo_Visual_nlines; /* number of lines */
static int redo_Visual_type = 0; /* type 'v', 'V' or CTRL-V */
static colnr_t redo_Visual_col; /* number of columns or end column */
static long redo_Visual_Prenum; /* Prenum for operator */
Prenum = 0;
/*
* If there is an operator pending, then the command we take this time
* will terminate it. Finish_op tells us to finish the operation before
* returning this time (unless the operation was cancelled).
*/
finish_op = (operator != NOP);
if (!finish_op && !yankbuffer)
opnum = 0;
if (p_sc && (vpeekc() == NUL || KeyTyped == TRUE))
premsg(NUL, NUL);
State = NORMAL_BUSY;
c = vgetc();
getcount:
/* Pick up any leading digits and compute 'Prenum' */
while ((c >= '1' && c <= '9') || (Prenum != 0 && (c == DEL || c == '0')))
{
if (c == DEL)
Prenum /= 10;
else
Prenum = Prenum * 10 + (c - '0');
if (Prenum < 0) /* got too large! */
Prenum = 999999999;
premsg(ctrl_w ? Ctrl('W') : ' ', NUL);
c = vgetc();
}
/*
* If we got CTRL-W there may be a/another count
*/
if (c == Ctrl('W') && !ctrl_w)
{
ctrl_w = TRUE;
opnum = Prenum; /* remember first count */
Prenum = 0;
State = ONLYKEY; /* no mapping for nchar, but keys */
premsg(c, NUL);
c = vgetc(); /* get next character */
goto getcount; /* jump back */
}
/*
* If we're in the middle of an operator (including after entering a yank
* buffer with ") AND we had a count before the
* operator, then that count overrides the current value of Prenum. What
* this means effectively, is that commands like "3dw" get turned into
* "d3w" which makes things fall into place pretty neatly.
* If you give a count before AND after the operator, they are multiplied.
*/
if (opnum != 0)
{
if (Prenum)
Prenum *= opnum;
else
Prenum = opnum;
opnum = 0;
}
Prenum1 = (Prenum == 0 ? 1 : Prenum); /* Prenum often defaults to 1 */
premsg(c, NUL);
/*
* get an additional character if we need one
* for CTRL-W we already got it when looking for a count
*/
if (ctrl_w)
{
nchar = c;
c = Ctrl('W');
premsg(c, nchar);
}
else if (strchr("@zZtTfF[]mg'`\"", c) || (c == 'q' && !Recording && !Exec_reg) ||
(c == 'r' && !VIsual.lnum))
{
State = NOMAPPING;
nchar = vgetc(); /* no macro mapping for this char */
premsg(c, nchar);
}
if (p_sc)
flushbuf(); /* flush the premsg() characters onto the screen so we can
see them while the command is being executed */
/*
* For commands that don't get another character we can put the State back to
* NORMAL and check for a window size change.
*/
if (STRCHR("z:/?", c) == NULL)
State = NORMAL;
if (nchar == ESC)
{
CLEAROP;
goto normal_end;
}
switch (c)
{
/*
* 0: Macros
*/
case 'q': /* (stop) recording into a named register */
CHECKCLEAROP;
/* command is ignored while executing a register */
if (!Exec_reg && dorecord(nchar) == FAIL)
CLEAROPBEEP;
break;
case '@': /* execute a named buffer */
CHECKCLEAROP;
while (Prenum1--)
{
if (doexecbuf(nchar) == FAIL)
{
CLEAROPBEEP;
break;
}
}
break;
/*
* 1: Screen positioning commands
*/
case Ctrl('D'):
flag = TRUE;
case Ctrl('U'):
CHECKCLEAROP;
if (Prenum)
curwin->w_p_scroll = (Prenum > curwin->w_height) ? curwin->w_height : Prenum;
n = (curwin->w_p_scroll <= curwin->w_height) ? curwin->w_p_scroll : curwin->w_height;
if (flag)
{
curwin->w_topline += n;
if (curwin->w_topline > curbuf->b_ml.ml_line_count)
curwin->w_topline = curbuf->b_ml.ml_line_count;
comp_Botline(curwin); /* compute curwin->w_botline */
(void)onedown(n);
}
else
{
if (n >= curwin->w_cursor.lnum)
n = curwin->w_cursor.lnum - 1;
Prenum1 = curwin->w_cursor.lnum - n;
scrolldown(n);
if (Prenum1 < curwin->w_cursor.lnum)
curwin->w_cursor.lnum = Prenum1;
}
beginline(TRUE);
updateScreen(VALID);
break;
case Ctrl('B'):
case K_SUARROW:
dir = BACKWARD;
case Ctrl('F'):
case K_SDARROW:
CHECKCLEAROP;
(void)onepage(dir, Prenum1);
break;
case Ctrl('E'):
CHECKCLEAROP;
scrollup(Prenum1);
/* We may have moved to another line -- webb */
coladvance(curwin->w_curswant);
updateScreen(VALID);
break;
case Ctrl('Y'):
CHECKCLEAROP;
scrolldown(Prenum1);
/* We may have moved to another line -- webb */
coladvance(curwin->w_curswant);
updateScreen(VALID);
break;
case 'z':
CHECKCLEAROP;
if (isdigit(nchar))
{
/*
* we misuse some variables to be able to call premsg()
*/
operator = c;
opnum = Prenum;
Prenum = nchar - '0';
for (;;)
{
premsg(' ', NUL);
nchar = vgetc();
State = NORMAL;
if (nchar == DEL)
Prenum /= 10;
else if (isdigit(nchar))
Prenum = Prenum * 10 + (nchar - '0');
else if (nchar == CR)
{
win_setheight((int)Prenum);
break;
}
else
{
CLEAROPBEEP;
break;
}
}
operator = NOP;