📄 ops.c
字号:
truncate_line(FALSE); /* delete the rest of the line */
/* leave cursor past last char in line */
}
else
{
del_lines(oap->line_count, TRUE, TRUE);
beginline(BL_WHITE | BL_FIX);
}
u_clearline(); /* "U" command should not be possible after "dd" */
}
else if (oap->line_count == 1) /* delete characters within one line */
{
if (u_save_cursor() == FAIL)
return FAIL;
/* if 'cpoptions' contains '$', display '$' at end of change */
if ( vim_strchr(p_cpo, CPO_DOLLAR) != NULL
&& oap->op_type == OP_CHANGE
&& oap->end.lnum == curwin->w_cursor.lnum
&& !oap->is_VIsual)
display_dollar(oap->end.col - !oap->inclusive);
n = oap->end.col - oap->start.col + 1 - !oap->inclusive;
(void)del_chars((long)n, restart_edit == NUL);
}
else /* delete characters between lines */
{
if (u_save_cursor() == FAIL) /* save first line for undo */
return FAIL;
#ifdef SYNTAX_HL
/* recompute syntax hl., starting with current line */
syn_changed(curwin->w_cursor.lnum);
#endif
truncate_line(TRUE); /* delete from cursor to end of line */
oap->start = curwin->w_cursor; /* remember curwin->w_cursor */
++curwin->w_cursor.lnum;
/* includes save for undo */
del_lines((long)(oap->line_count - 2), TRUE, TRUE);
if (u_save_cursor() == FAIL) /* save last line for undo */
return FAIL;
/* delete from start of line until op_end */
curwin->w_cursor.col = 0;
(void)del_chars((long)(oap->end.col + 1 - !oap->inclusive),
restart_edit == NUL);
curwin->w_cursor = oap->start; /* restore curwin->w_cursor */
(void)do_join(FALSE, TRUE);
}
/*
* For a change within one line, the screen is updated differently (to
* take care of 'dollar').
*/
if (oap->motion_type == MCHAR && oap->line_count == 1)
{
if (dollar_vcol)
must_redraw = 0; /* don't want a redraw now */
else
update_screenline();
}
else if (!global_busy) /* no need to update screen for :global */
{
update_topline();
update_screen(NOT_VALID);
}
msgmore(curbuf->b_ml.ml_line_count - old_lcount);
/*
* Set "'[" and "']" marks.
*/
curbuf->b_op_start = oap->start;
if (oap->block_mode)
{
curbuf->b_op_end.lnum = oap->end.lnum;
curbuf->b_op_end.col = oap->start.col;
}
else
curbuf->b_op_end = oap->start;
return OK;
}
/*
* op_tilde - handle the (non-standard vi) tilde operator
*/
void
op_tilde(oap)
OPARG *oap;
{
FPOS pos;
struct block_def bd;
if (u_save((linenr_t)(oap->start.lnum - 1),
(linenr_t)(oap->end.lnum + 1)) == FAIL)
return;
/*
* Set '[ and '] marks.
*/
curbuf->b_op_start = oap->start;
curbuf->b_op_end = oap->end;
pos = oap->start;
if (oap->block_mode) /* Visual block mode */
{
for (; pos.lnum <= oap->end.lnum; ++pos.lnum)
{
block_prep(oap, &bd, pos.lnum, FALSE);
pos.col = bd.textcol;
while (--bd.textlen >= 0)
{
swapchar(oap->op_type, &pos);
if (inc(&pos) == -1) /* at end of file */
break;
}
}
}
else /* not block mode */
{
if (oap->motion_type == MLINE)
{
pos.col = 0;
oap->end.col = STRLEN(ml_get(oap->end.lnum));
if (oap->end.col)
--oap->end.col;
}
else if (!oap->inclusive)
dec(&(oap->end));
while (ltoreq(pos, oap->end))
{
swapchar(oap->op_type, &pos);
if (inc(&pos) == -1) /* at end of file */
break;
}
}
if (oap->motion_type == MCHAR && oap->line_count == 1 && !oap->block_mode)
update_screenline();
else
{
#ifdef SYNTAX_HL
/* recompute syntax hl., starting with current line */
syn_changed(oap->start.lnum);
#endif
update_topline();
update_screen(NOT_VALID);
}
if (oap->line_count > p_report)
smsg((char_u *)"%ld line%s ~ed",
oap->line_count, plural(oap->line_count));
}
/*
* If op_type == OP_UPPER: make uppercase,
* if op_type == OP_LOWER: make lowercase,
* else swap case of character at 'pos'
*/
void
swapchar(op_type, pos)
int op_type;
FPOS *pos;
{
int c;
c = gchar(pos);
if (islower(c) && op_type != OP_LOWER)
{
pchar(*pos, TO_UPPER(c));
changed();
}
else if (isupper(c) && op_type != OP_UPPER)
{
pchar(*pos, TO_LOWER(c));
changed();
}
}
/*
* op_change - handle a change operation
*
* return TRUE if edit() returns because of a CTRL-O command
*/
int
op_change(oap)
OPARG *oap;
{
colnr_t l;
l = oap->start.col;
if (oap->motion_type == MLINE)
{
l = 0;
#ifdef SMARTINDENT
if (curbuf->b_p_si)
can_si = TRUE; /* It's like opening a new line, do si */
#endif
}
/* First delete the text in the region. In an empty buffer only need to
* save for undo */
if (curbuf->b_ml.ml_flags & ML_EMPTY)
{
if (u_save_cursor() == FAIL)
return FALSE;
}
else if (op_delete(oap) == FAIL)
return FALSE;
if ((l > curwin->w_cursor.col) && !lineempty(curwin->w_cursor.lnum))
inc_cursor();
#if defined(LISPINDENT) || defined(CINDENT)
if (oap->motion_type == MLINE)
{
# ifdef LISPINDENT
if (curbuf->b_p_lisp && curbuf->b_p_ai)
fixthisline(get_lisp_indent);
# endif
# if defined(LISPINDENT) && defined(CINDENT)
else
# endif
# ifdef CINDENT
if (curbuf->b_p_cin)
fixthisline(get_c_indent);
# endif
}
#endif
return edit(NUL, FALSE, (linenr_t)1);
}
/*
* set all the yank registers to empty (called from main())
*/
void
init_yank()
{
int i;
for (i = 0; i < NUM_REGISTERS; ++i)
y_regs[i].y_array = NULL;
}
/*
* Free "n" lines from the current yank register.
* Called for normal freeing and in case of error.
*/
static void
free_yank(n)
long n;
{
if (y_current->y_array != NULL)
{
long i;
for (i = n; --i >= 0; )
{
if ((i & 1023) == 1023) /* this may take a while */
{
/*
* This message should never cause a hit-return message.
* Overwrite this message with any next message.
*/
++no_wait_return;
smsg((char_u *)"freeing %ld lines", i + 1);
--no_wait_return;
msg_didout = FALSE;
msg_col = 0;
}
vim_free(y_current->y_array[i]);
}
vim_free(y_current->y_array);
y_current->y_array = NULL;
if (n >= 1000)
MSG("");
}
}
static void
free_yank_all()
{
free_yank(y_current->y_size);
}
/*
* Yank the text between curwin->w_cursor and startpos into a yank register.
* If we are to append (uppercase register), we first yank into a new yank
* register and then concatenate the old and the new one (so we keep the old
* one in case of out-of-memory).
*
* return FAIL for failure, OK otherwise
*/
int
op_yank(oap, deleting, mess)
OPARG *oap;
int deleting;
int mess;
{
long y_idx; /* index in y_array[] */
struct yankreg *curr; /* copy of y_current */
struct yankreg newreg; /* new yank register when appending */
char_u **new_ptr;
linenr_t lnum; /* current line number */
long j;
long len;
int yanktype = oap->motion_type;
long yanklines = oap->line_count;
linenr_t yankendlnum = oap->end.lnum;
char_u *p;
char_u *pnew;
struct block_def bd;
/* check for read-only register */
if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
{
beep_flush();
return FAIL;
}
if (oap->regname == '_') /* black hole: nothing to do */
return OK;
if (!deleting) /* op_delete() already set y_current */
get_yank_register(oap->regname, TRUE);
curr = y_current;
/* append to existing contents */
if (y_append && y_current->y_array != NULL)
y_current = &newreg;
else
free_yank_all(); /* free previously yanked lines */
/*
* If the cursor was in column 1 before and after the movement, and the
* operator is not inclusive, the yank is always linewise.
*/
if ( oap->motion_type == MCHAR
&& oap->start.col == 0
&& !oap->inclusive
&& (!oap->is_VIsual || *p_sel == 'o')
&& oap->end.col == 0
&& yanklines > 1)
{
yanktype = MLINE;
--yankendlnum;
--yanklines;
}
y_current->y_size = yanklines;
y_current->y_type = yanktype; /* set the yank register type */
y_current->y_array = (char_u **)lalloc_clear((long_u)(sizeof(char_u *) *
yanklines), TRUE);
if (y_current->y_array == NULL)
{
y_current = curr;
return FAIL;
}
y_idx = 0;
lnum = oap->start.lnum;
/*
* Visual block mode
*/
if (oap->block_mode)
{
y_current->y_type = MBLOCK; /* set the yank register type */
for ( ; lnum <= yankendlnum; ++lnum)
{
block_prep(oap, &bd, lnum, FALSE);
if ((pnew = alloc(bd.startspaces + bd.endspaces +
bd.textlen + 1)) == NULL)
goto fail;
y_current->y_array[y_idx++] = pnew;
copy_spaces(pnew, (size_t)bd.startspaces);
pnew += bd.startspaces;
mch_memmove(pnew, bd.textstart, (size_t)bd.textlen);
pnew += bd.textlen;
copy_spaces(pnew, (size_t)bd.endspaces);
pnew += bd.endspaces;
*pnew = NUL;
}
}
else
{
/*
* there are three parts for non-block mode:
* 1. if yanktype != MLINE yank last part of the top line
* 2. yank the lines between op_start and op_end, inclusive when
* yanktype == MLINE
* 3. if yanktype != MLINE yank first part of the bot line
*/
if (yanktype != MLINE)
{
if (yanklines == 1) /* op_start and op_end on same line */
{
j = oap->end.col - oap->start.col + 1 - !oap->inclusive;
/* Watch out for very big endcol (MAXCOL) */
p = ml_get(lnum) + oap->start.col;
len = STRLEN(p);
if (j > len || j < 0)
j = len;
if ((y_current->y_array[0] = vim_strnsave(p, (int)j)) == NULL)
{
fail:
free_yank(y_idx); /* free the allocated lines */
y_current = curr;
return FAIL;
}
goto success;
}
if ((y_current->y_array[0] =
vim_strsave(ml_get(lnum++) + oap->start.col)) == NULL)
goto fail;
++y_idx;
}
while (yanktype == MLINE ? (lnum <= yankendlnum) : (lnum < yankendlnum))
{
if ((y_current->y_array[y_idx] =
vim_strsave(ml_get(lnum++))) == NULL)
goto fail;
++y_idx;
}
if (yanktype != MLINE)
{
if ((y_current->y_array[y_idx] = vim_strnsave(ml_get(yankendlnum),
oap->end.col + 1 - !oap->inclusive)) == NULL)
goto fail;
}
}
success:
if (curr != y_current) /* append the new block to the old block */
{
new_ptr = (char_u **)lalloc((long_u)(sizeof(char_u *) *
(curr->y_size + y_current->y_size)), TRUE);
if (new_ptr == NULL)
goto fail;
for (j = 0; j < curr->y_size; ++j)
new_ptr[j] = curr->y_array[j];
vim_free(curr->y_array);
curr->y_array = new_ptr;
if (yanktype == MLINE) /* MLINE overrides MCHAR and MBLOCK */
curr->y_type = MLINE;
/* concatenate the last line of the old block with the first line of
* the new block */
if (curr->y_type == MCHAR)
{
pnew = lalloc((long_u)(STRLEN(curr->y_array[curr->y_size - 1])
+ STRLEN(y_current->y_array[0]) + 1), TRUE);
if (pnew == NULL)
{
y_idx = y_current->y_size - 1;
goto fail;
}
STRCPY(pnew, curr->y_array[--j]);
STRCAT(pnew, y_current->y_array[0]);
vim_free(curr->y_array[j]);
vim_free(y_current->y_array[0]);
curr->y_array[j++] = pnew;
y_idx = 1;
}
else
y_idx = 0;
while (y_idx < y_current->y_size)
curr->y_array[j++] = y_current->y_array[y_idx++];
curr->y_size = j;
vim_free(y_current->y_array);
y_current = curr;
}
if (mess) /* Display message about yank? */
{
if (yanktype == MCHAR && !oap->block_mode && yanklines == 1)
yanklines = 0;
/* Some versions of Vi use ">=" here, some don't... */
if (yanklines > p_report)
{
/* redisplay now, so message is not deleted */
update_topline_redraw();
smsg((char_u *)"%ld line%s yanked", yanklines, plural(yanklines));
}
}
/*
* Set "'[" and "']" marks.
*/
curbuf->b_op_start = oap->start;
curbuf->b_op_end = oap->end;
#ifdef USE_CLIPBOARD
/*
* If we were yanking to the clipboard register, send result to clipboard.
*/
if (curr == &(y_regs[CLIPBOARD_REGISTER]))
{
clip_own_selection();
clip_mch_set_selection();
}
#endif
return OK;
}
/*
* put contents of register "regname" into the text
* For ":put" command count == -1.
* flags: PUT_FIXINDENT make indent look nice
* PUT_CURSEND leave cursor after end of new text
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -