📄 ops.c
字号:
/*
* execute a yank register: copy it into the stuff buffer
*
* return FAIL for failure, OK otherwise
*/
int
do_execreg(regname, colon, addcr)
int regname;
int colon; /* insert ':' before each line */
int addcr; /* always add '\n' to end of line */
{
static int lastc = NUL;
long i;
char_u *p;
int retval = OK;
if (regname == '@') /* repeat previous one */
regname = lastc;
/* check for valid regname */
if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
return FAIL;
lastc = regname;
if (regname == '_') /* black hole: don't stuff anything */
return OK;
if (regname == ':') /* use last command line */
{
if (last_cmdline == NULL)
{
EMSG(e_nolastcmd);
return FAIL;
}
vim_free(new_last_cmdline); /* don't keep the cmdline containing @: */
new_last_cmdline = NULL;
retval = put_in_typebuf(last_cmdline, TRUE);
}
#ifdef WANT_EVAL
else if (regname == '=')
{
p = get_expr_line();
if (p == NULL)
return FAIL;
retval = put_in_typebuf(p, colon);
vim_free(p);
}
#endif
else if (regname == '.') /* use last inserted text */
{
p = get_last_insert_save();
if (p == NULL)
{
EMSG(e_noinstext);
return FAIL;
}
retval = put_in_typebuf(p, colon);
vim_free(p);
}
else
{
get_yank_register(regname, FALSE);
if (y_current->y_array == NULL)
return FAIL;
/*
* Insert lines into typeahead buffer, from last one to first one.
*/
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
|| addcr)
{
if (ins_typebuf((char_u *)"\n", FALSE, 0, TRUE) == FAIL)
return FAIL;
}
if (ins_typebuf(y_current->y_array[i], FALSE, 0, TRUE) == FAIL)
return FAIL;
if (colon && ins_typebuf((char_u *)":", FALSE, 0, TRUE) == FAIL)
return FAIL;
}
Exec_reg = TRUE; /* disable the 'q' command */
}
return retval;
}
static int
put_in_typebuf(s, colon)
char_u *s;
int colon; /* add ':' before the line */
{
int retval = OK;
if (colon)
retval = ins_typebuf((char_u *)"\n", FALSE, 0, TRUE);
if (retval == OK)
retval = ins_typebuf(s, FALSE, 0, TRUE);
if (colon && retval == OK)
retval = ins_typebuf((char_u *)":", FALSE, 0, TRUE);
return retval;
}
/*
* Insert a yank register: copy it into the Read buffer.
* Used by CTRL-R command and middle mouse button in insert mode.
*
* return FAIL for failure, OK otherwise
*/
int
insert_reg(regname, literally)
int regname;
int literally; /* insert literally, not as if typed */
{
long i;
int retval = OK;
char_u *arg;
int allocated;
/*
* 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.
*/
ui_breakcheck();
if (got_int)
return FAIL;
/* check for valid regname */
if (regname != NUL && !valid_yank_reg(regname, FALSE))
return FAIL;
#ifdef USE_CLIPBOARD
if (regname == '*')
clip_get_selection(); /* may fill * register */
#endif
if (regname == '.') /* insert last inserted text */
retval = stuff_inserted(NUL, 1L, TRUE);
else if (get_spec_reg(regname, &arg, &allocated, TRUE))
{
if (arg == NULL)
return FAIL;
if (literally)
stuffescaped(arg);
else
stuffReadbuff(arg);
if (allocated)
vim_free(arg);
}
else /* name or number register */
{
get_yank_register(regname, FALSE);
if (y_current->y_array == NULL)
retval = FAIL;
else
{
for (i = 0; i < y_current->y_size; ++i)
{
if (literally)
stuffescaped(y_current->y_array[i]);
else
stuffReadbuff(y_current->y_array[i]);
/*
* Insert a newline between lines and after last line if
* y_type is MLINE.
*/
if (y_current->y_type == MLINE || i < y_current->y_size - 1)
stuffcharReadbuff('\n');
}
}
}
return retval;
}
/*
* Stuff a string into the typeahead buffer, such that edit() will insert it
* literally.
*/
static void
stuffescaped(arg)
char_u *arg;
{
while (*arg)
{
if ((*arg < ' ' && *arg != TAB) || *arg > '~')
stuffcharReadbuff(Ctrl('V'));
stuffcharReadbuff(*arg++);
}
}
/*
* If "regname" is a special register, return a pointer to its value.
*/
static int
get_spec_reg(regname, argp, allocated, errmsg)
int regname;
char_u **argp;
int *allocated;
int errmsg; /* give error message when failing */
{
*argp = NULL;
*allocated = FALSE;
switch (regname)
{
case '%': /* file name */
if (errmsg)
check_fname(); /* will give emsg if not set */
*argp = curbuf->b_fname;
return TRUE;
case '#': /* alternate file name */
*argp = getaltfname(errmsg); /* may give emsg if not set */
return TRUE;
#ifdef WANT_EVAL
case '=': /* result of expression */
*argp = get_expr_line();
*allocated = TRUE;
return TRUE;
#endif
case ':': /* last command line */
if (last_cmdline == NULL && errmsg)
EMSG(e_nolastcmd);
*argp = last_cmdline;
return TRUE;
case '.': /* last inserted text */
*argp = get_last_insert_save();
*allocated = TRUE;
if (*argp == NULL && errmsg)
EMSG(e_noinstext);
return TRUE;
case '_': /* black hole: always empty */
*argp = (char_u *)"";
return TRUE;
}
return FALSE;
}
/*
* paste a yank register into the command line.
* used by CTRL-R command in command-line mode
* insert_reg() can't be used here, because special characters from the
* register contents will be interpreted as commands.
*
* return FAIL for failure, OK otherwise
*/
int
cmdline_paste(regname)
int regname;
{
long i;
char_u *arg;
int allocated;
if (!valid_yank_reg(regname, FALSE)) /* check for valid regname */
return FAIL;
#ifdef USE_CLIPBOARD
if (regname == '*')
clip_get_selection();
#endif
if (regname == '.') /* insert last inserted text */
return FAIL; /* Unimplemented */
if (get_spec_reg(regname, &arg, &allocated, TRUE))
{
if (arg == NULL)
return FAIL;
i = put_on_cmdline(arg, -1, TRUE);
if (allocated)
vim_free(arg);
return (int)i;
}
get_yank_register(regname, FALSE);
if (y_current->y_array == NULL)
return FAIL;
for (i = 0; i < y_current->y_size; ++i)
{
put_on_cmdline(y_current->y_array[i], -1, FALSE);
/* insert ^M between lines and after last line if type is MLINE */
if (y_current->y_type == MLINE || i < y_current->y_size - 1)
put_on_cmdline((char_u *)"\r", 1, FALSE);
}
return OK;
}
/*
* op_delete - handle a delete operation
*
* return FAIL if undo failed, OK otherwise.
*/
int
op_delete(oap)
OPARG *oap;
{
int n;
linenr_t lnum;
char_u *ptr;
char_u *newp, *oldp;
linenr_t old_lcount = curbuf->b_ml.ml_line_count;
int did_yank = FALSE;
struct block_def bd;
if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */
return OK;
/* Nothing to delete, return here. Do prepare undo, for op_change(). */
if (oap->empty)
{
return u_save_cursor();
}
#ifdef MULTI_BYTE
if (is_dbcs)
{
char_u *p;
if (oap->end.col >= oap->start.col)
{
p = ml_get(oap->end.lnum);
if (IsTrailByte(p, p + oap->end.col + oap->inclusive))
oap->end.col++;
}
else
{
p = ml_get(oap->start.lnum);
if (IsTrailByte(p, p + oap->start.col + oap->inclusive))
oap->start.col++;
}
}
#endif
/*
* Imitate the strange Vi behaviour: If the delete spans more than one line
* and motion_type == MCHAR and the result is a blank line, make the delete
* linewise. Don't do this for the change command or Visual mode.
*/
if ( oap->motion_type == MCHAR
&& !oap->is_VIsual
&& oap->line_count > 1
&& oap->op_type == OP_DELETE)
{
ptr = ml_get(oap->end.lnum) + oap->end.col + oap->inclusive;
ptr = skipwhite(ptr);
if (*ptr == NUL && inindent(0))
oap->motion_type = MLINE;
}
/*
* Check for trying to delete (e.g. "D") in an empty line.
* Note: For the change operator it is ok.
*/
if ( oap->motion_type == MCHAR
&& oap->line_count == 1
&& oap->op_type == OP_DELETE
&& *ml_get(oap->start.lnum) == NUL)
{
/*
* It's an error to operate on an empty region, when 'E' inclucded in
* 'cpoptions' (Vi compatible).
*/
if (vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL)
beep_flush();
return OK;
}
/*
* Do a yank of whatever we're about to delete.
* If a yank register was specified, put the deleted text into that register.
* For the black hole register '_' don't yank anything.
*/
if (oap->regname != '_')
{
if (oap->regname != 0)
{
/* check for read-only register */
if (!valid_yank_reg(oap->regname, TRUE))
{
beep_flush();
return OK;
}
get_yank_register(oap->regname, TRUE); /* yank into specif'd reg. */
if (op_yank(oap, TRUE, FALSE) == OK) /* yank without message */
did_yank = TRUE;
}
/*
* Put deleted text into register 1 and shift number registers if the
* delete contains a line break, or when a regname has been specified!
*/
if (oap->regname != 0 || oap->motion_type == MLINE
|| oap->line_count > 1)
{
y_current = &y_regs[9];
free_yank_all(); /* free register nine */
for (n = 9; n > 1; --n)
y_regs[n] = y_regs[n - 1];
y_previous = y_current = &y_regs[1];
y_regs[1].y_array = NULL; /* set register one to empty */
oap->regname = 0;
}
else if (oap->regname == 0) /* yank into unnamed register */
{
oap->regname = '-'; /* use special delete register */
get_yank_register(oap->regname, TRUE);
oap->regname = 0;
}
if (oap->regname == 0 && op_yank(oap, TRUE, FALSE) == OK)
did_yank = TRUE;
/*
* If there's too much stuff to fit in the yank register, then get a
* confirmation before doing the delete. This is crude, but simple.
* And it avoids doing a delete of something we can't put back if we
* want.
*/
if (!did_yank)
{
if (ask_yesno((char_u *)"cannot yank; delete anyway", TRUE) != 'y')
{
emsg(e_abort);
return FAIL;
}
}
}
/*
* block mode delete
*/
if (oap->block_mode)
{
if (u_save((linenr_t)(oap->start.lnum - 1),
(linenr_t)(oap->end.lnum + 1)) == FAIL)
return FAIL;
#ifdef SYNTAX_HL
/* recompute syntax hl., starting with this line */
syn_changed(curwin->w_cursor.lnum);
#endif
for (lnum = curwin->w_cursor.lnum;
curwin->w_cursor.lnum <= oap->end.lnum;
++curwin->w_cursor.lnum)
{
block_prep(oap, &bd, curwin->w_cursor.lnum, TRUE);
if (bd.textlen == 0) /* nothing to delete */
continue;
/* n == number of chars deleted
* If we delete a TAB, it may be replaced by several characters.
* Thus the number of characters may increase!
*/
n = bd.textlen - bd.startspaces - bd.endspaces;
oldp = ml_get_curline();
newp = alloc_check((unsigned)STRLEN(oldp) + 1 - n);
if (newp == NULL)
continue;
/* copy up to deleted part */
mch_memmove(newp, oldp, (size_t)bd.textcol);
/* insert spaces */
copy_spaces(newp + bd.textcol,
(size_t)(bd.startspaces + bd.endspaces));
/* copy the part after the deleted part */
oldp += bd.textcol + bd.textlen;
mch_memmove(newp + bd.textcol + bd.startspaces + bd.endspaces,
oldp, STRLEN(oldp) + 1);
/* replace the line */
ml_replace(curwin->w_cursor.lnum, newp, FALSE);
}
curwin->w_cursor.lnum = lnum;
changed_cline_bef_curs(); /* recompute cursor pos. on screen */
approximate_botline(); /* w_botline may be wrong now */
adjust_cursor();
changed();
update_screen(VALID_TO_CURSCHAR);
oap->line_count = 0; /* no lines deleted */
}
else if (oap->motion_type == MLINE)
{
if (oap->op_type == OP_CHANGE)
{
/* Delete the lines except the first one. Temporarily move the
* cursor to the next line. Save the current line number, if the
* last line is deleted it may be changed.
*/
if (oap->line_count > 1)
{
lnum = curwin->w_cursor.lnum;
++curwin->w_cursor.lnum;
del_lines((long)(oap->line_count - 1), TRUE, TRUE);
curwin->w_cursor.lnum = lnum;
}
if (u_save_cursor() == FAIL)
return FAIL;
if (curbuf->b_p_ai) /* don't delete indent */
{
beginline(BL_WHITE); /* cursor on first non-white */
did_ai = TRUE; /* delete the indent when ESC hit */
}
else
beginline(0); /* cursor in column 0 */
#ifdef SYNTAX_HL
/* recompute syntax hl., starting with current line */
syn_changed(curwin->w_cursor.lnum);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -