home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD2.bin
/
bbs
/
util
/
vim-3.0.lha
/
Vim
/
src
/
ops.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-09
|
39KB
|
1,736 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.
*/
/*
* ops.c: implementation of various operators: doshift, dodelete, dotilde,
* dochange, doyank, doput, dojoin
*/
#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "param.h"
#include "ops.h"
/*
* We have one yank buffer for normal yanks and puts, nine yank buffers for
* deletes and 26 yank buffers for use by name.
* Each yank buffer is an array of pointers to lines.
*/
static struct yankbuf
{
char_u **y_array; /* pointer to array of line pointers */
linenr_t y_size; /* number of lines in y_array */
char_u y_type; /* MLINE, MCHAR or MBLOCK */
} y_buf[36]; /* 0..9 = number buffers, 10..35 = char buffers */
static struct yankbuf *y_current; /* ptr to current yank buffer */
static int yankappend; /* TRUE when appending */
static struct yankbuf *y_previous = NULL; /* ptr to last written yank buffer */
static void get_yank_buffer __ARGS((int));
static int stuff_yank __ARGS((int, char_u *));
static void free_yank __ARGS((long));
static void free_yank_all __ARGS((void));
static void block_prep __ARGS((linenr_t, int));
/* variables use by block_prep, dodelete and doyank */
static int startspaces;
static int endspaces;
static int textlen;
static char_u *textstart;
static colnr_t textcol;
/*
* doshift - handle a shift operation
*/
void
doshift(op, curs_top, amount)
int op;
int curs_top;
int amount;
{
register long i;
int first_char;
if (!u_save((linenr_t)(curwin->w_cursor.lnum - 1), (linenr_t)(curwin->w_cursor.lnum + nlines)))
return;
for (i = nlines; --i >= 0; )
{
first_char = *ml_get(curwin->w_cursor.lnum);
if (first_char == NUL) /* empty line */
curwin->w_cursor.col = 0;
/*
* Don't move the line right if it starts with # and p_si is set.
*/
else if (!curbuf->b_p_si || first_char != '#')
{
/* if (Visual_block)
shift the block, not the whole line
else */
shift_line(op == LSHIFT, p_sr, amount);
}
++curwin->w_cursor.lnum;
}
if (curs_top) /* put cursor on first line, for ">>" */
curwin->w_cursor.lnum -= nlines;
else
--curwin->w_cursor.lnum; /* put cursor on last line, for ":>" */
updateScreen(CURSUPD);
if (nlines > p_report)
smsg((char_u *)"%ld line%s %ced", nlines, plural(nlines),
(op == RSHIFT) ? '>' : '<');
}
/*
* shift the current line one shiftwidth left (if left != 0) or right
* leaves cursor on first blank in the line
*/
void
shift_line(left, round, amount)
int left;
int round;
int amount;
{
register int count;
register int i, j;
int p_sw = (int)curbuf->b_p_sw;
count = get_indent(); /* get current indent */
if (round) /* round off indent */
{
i = count / p_sw; /* number of p_sw rounded down */
j = count % p_sw; /* extra spaces */
if (j && left) /* first remove extra spaces */
--amount;
if (left)
{
i -= amount;
if (i < 0)
i = 0;
}
else
i += amount;
count = i * p_sw;
}
else /* original vi indent */
{
if (left)
{
count -= p_sw * amount;
if (count < 0)
count = 0;
}
else
count += p_sw * amount;
}
set_indent(count, TRUE); /* set new indent */
}
/*
* check if character is name of yank buffer
* Note: There is no check for 0 (default register), caller should do this
*/
int
is_yank_buffer(c, write)
int c;
int write; /* if TRUE check for writable buffers */
{
if (isalnum(c) || (!write && strchr(".%:", c) != NULL) || c == '"')
return TRUE;
return FALSE;
}
/*
* Set y_current and yankappend, according to the value of yankbuffer.
*
* If yankbuffer is 0 and writing, use buffer 0
* If yankbuffer is 0 and reading, use previous buffer
*/
static void
get_yank_buffer(writing)
int writing;
{
register int i;
yankappend = FALSE;
if (((yankbuffer == 0 && !writing) || yankbuffer == '"') && y_previous != NULL)
{
y_current = y_previous;
return;
}
i = yankbuffer;
if (isdigit(i))
i -= '0';
else if (islower(i))
i -= 'a' - 10;
else if (isupper(i))
{
i -= 'A' - 10;
yankappend = TRUE;
}
else /* not 0-9, a-z or A-Z: use buffer 0 */
i = 0;
y_current = &(y_buf[i]);
if (writing) /* remember the buffer we write into for doput() */
y_previous = y_current;
}
/*
* start or stop recording into a yank buffer
*
* return FAIL for failure, OK otherwise
*/
int
dorecord(c)
int c;
{
char_u *p;
static int bufname;
int retval;
if (Recording == FALSE) /* start recording */
{
if (!isalnum(c) && c != '"') /* registers 0-9, a-z and " are allowed */
retval = FAIL;
else
{
Recording = TRUE;
showmode();
bufname = c;
retval = OK;
}
}
else /* stop recording */
{
Recording = FALSE;
MSG("");
/* the trailing 'q' command will not have been put in the buffer */
p = get_recorded();
if (p == NULL)
retval = FAIL;
else
retval = (stuff_yank(bufname, p));
}
return retval;
}
/*
* stuff string 'p' into yank buffer 'bufname' (append if uppercase)
* 'p' is assumed to be alloced.
*
* return FAIL for failure, OK otherwise
*/
static int
stuff_yank(bufname, p)
int bufname;
char_u *p;
{
char_u *lp;
char_u **pp;
yankbuffer = bufname;
/* check for read-only buffer */
if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, TRUE))
return FAIL;
get_yank_buffer(TRUE);
if (yankappend && y_current->y_array != NULL)
{
pp = &(y_current->y_array[y_current->y_size - 1]);
lp = lalloc((long_u)(STRLEN(*pp) + STRLEN(p) + 1), TRUE);
if (lp == NULL)
{
free(p);
return FAIL;
}
STRCPY(lp, *pp);
STRCAT(lp, p);
free(p);
free(*pp);
*pp = lp;
}
else
{
free_yank_all();
if ((y_current->y_array = (char_u **)alloc((unsigned)sizeof(char_u *))) == NULL)
{
free(p);
return FAIL;
}
y_current->y_array[0] = p;
y_current->y_size = 1;
y_current->y_type = MCHAR; /* used to be MLINE, why? */
}
return OK;
}
/*
* execute a yank buffer (register): copy it into the stuff buffer
*
* return FAIL for failure, OK otherwise
*/
int
doexecbuf(c)
int c;
{
static int lastc = NUL;
long i;
if (c == '@') /* repeat previous one */
c = lastc;
if (!is_yank_buffer(c, FALSE)) /* check for valid buffer */
return FAIL;
lastc = c;
if (c == ':') /* use last command line */
{
if (last_cmdline == NULL)
{
EMSG(e_nolastcmd);
return FAIL;
}
free(new_last_cmdline); /* don't keep the command line containing @: */
new_last_cmdline = NULL;
if (ins_typestr((char_u *)"\n", FALSE) == FAIL)
return FAIL;
if (ins_typestr(last_cmdline, FALSE) == FAIL)
return FAIL;
}
else
{
yankbuffer = c;
get_yank_buffer(FALSE);
if (y_current->y_array == NULL)
return FAIL;
for (i = y_current->y_size; --i >= 0; )
{
/* insert newline between lines and after last line if type is MLINE */
if (y_current->y_type == MLINE || i < y_current->y_size - 1)
{
if (ins_typestr((char_u *)"\n", FALSE) == FAIL)
return FAIL;
}
if (ins_typestr(y_current->y_array[i], FALSE) == FAIL)
return FAIL;
}
Exec_reg = TRUE; /* disable the 'q' command */
}
return OK;
}
/*
* insert a yank buffer: copy it into the Read buffer
* used by CTRL-R command in insert mode
*
* return FAIL for failure, OK otherwise
*/
int
insertbuf(c)
int c;
{
long i;
/*
* It is possible to get into an endless loop by having CTRL-R a in
* register a and then, in insert mode, doing CTRL-R a.
* If you hit CTRL-C, the loop will be broken here.
*/
breakcheck();
if (got_int)
return FAIL;
if (!is_yank_buffer(c, FALSE)) /* check for valid buffer */
return FAIL;
if (c == '.') /* insert last inserted text */
{
stuff_inserted(NUL, 1L, TRUE);
return OK;
}
if (c == '%') /* insert file name */
{
if (check_fname() == FAIL)
return FAIL;
stuffReadbuff(curbuf->b_xfilename);
return OK;
}
if (c == ':') /* insert last command line */
{
if (last_cmdline == NULL)
{
EMSG(e_nolastcmd);
return FAIL;
}
stuffReadbuff(last_cmdline);
return OK;
}
yankbuffer = c;
get_yank_buff