📄 normal.c
字号:
oap->line_count = oap->end.lnum - oap->start.lnum + 1;
if (VIsual_active || redo_VIsual_busy)
{
if (VIsual_mode == Ctrl('V')) /* block mode */
{
colnr_t start, end;
oap->block_mode = TRUE;
getvcol(curwin, &(oap->start),
&oap->start_vcol, NULL, &oap->end_vcol);
if (!redo_VIsual_busy)
{
getvcol(curwin, &(oap->end), &start, NULL, &end);
if (start < oap->start_vcol)
oap->start_vcol = start;
if (end > oap->end_vcol)
{
if (*p_sel == 'e' && start - 1 >= oap->end_vcol)
oap->end_vcol = start - 1;
else
oap->end_vcol = end;
}
}
/* if '$' was used, get oap->end_vcol from longest line */
if (curwin->w_curswant == MAXCOL)
{
curwin->w_cursor.col = MAXCOL;
oap->end_vcol = 0;
for (curwin->w_cursor.lnum = oap->start.lnum;
curwin->w_cursor.lnum <= oap->end.lnum;
++curwin->w_cursor.lnum)
{
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
if (end > oap->end_vcol)
oap->end_vcol = end;
}
}
else if (redo_VIsual_busy)
oap->end_vcol = oap->start_vcol + redo_VIsual_col - 1;
/*
* Correct oap->end.col and oap->start.col to be the
* upper-left and lower-right corner of the block area.
*/
curwin->w_cursor.lnum = oap->end.lnum;
coladvance(oap->end_vcol);
oap->end = curwin->w_cursor;
curwin->w_cursor = oap->start;
coladvance(oap->start_vcol);
oap->start = curwin->w_cursor;
}
if (!redo_VIsual_busy && !gui_yank)
{
/*
* Prepare to reselect and redo Visual: this is based on the
* size of the Visual text
*/
resel_VIsual_mode = VIsual_mode;
if (curwin->w_curswant == MAXCOL)
resel_VIsual_col = MAXCOL;
else if (VIsual_mode == Ctrl('V'))
resel_VIsual_col = oap->end_vcol - oap->start_vcol + 1;
else if (oap->line_count > 1)
resel_VIsual_col = oap->end.col;
else
resel_VIsual_col = oap->end.col - oap->start.col + 1;
resel_VIsual_line_count = oap->line_count;
}
/* can't redo yank (unless 'y' is in 'cpoptions') and ":" */
if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
&& oap->op_type != OP_COLON)
{
prep_redo(oap->regname, 0L, NUL, 'v', oap->op_prechar,
op_chars[oap->op_type - 1]);
redo_VIsual_mode = resel_VIsual_mode;
redo_VIsual_col = resel_VIsual_col;
redo_VIsual_line_count = resel_VIsual_line_count;
redo_VIsual_count = cap->count0;
}
/*
* oap->inclusive defaults to TRUE.
* If oap->end is on a NUL (empty line) oap->inclusive becomes
* FALSE. This makes "d}P" and "v}dP" work the same.
*/
oap->inclusive = TRUE;
if (VIsual_mode == 'V')
oap->motion_type = MLINE;
else
{
oap->motion_type = MCHAR;
if (VIsual_mode != Ctrl('V') && *ml_get_pos(&(oap->end)) == NUL)
{
oap->inclusive = FALSE;
/* Try to include the newline */
if (*p_sel != 'o'
&& oap->end.lnum < curbuf->b_ml.ml_line_count)
{
++oap->end.lnum;
oap->end.col = 0;
++oap->line_count;
}
}
}
redo_VIsual_busy = FALSE;
/*
* Switch Visual off now, so screen updating does
* not show inverted text when the screen is redrawn.
* With OP_YANK and sometimes with OP_COLON and OP_FILTER there is
* no screen redraw, so it is done here to remove the inverted
* part.
*/
if (!gui_yank)
{
VIsual_active = FALSE;
#ifdef USE_MOUSE
setmouse();
#endif
if (p_smd)
clear_cmdline = TRUE; /* unshow visual mode later */
if (oap->op_type == OP_YANK || oap->op_type == OP_COLON ||
oap->op_type == OP_FILTER)
update_curbuf(NOT_VALID);
}
}
curwin->w_set_curswant = TRUE;
/*
* oap->empty is set when start and end are the same. The inclusive
* flag affects this too, unless yanking and the end is on a NUL.
*/
oap->empty = (oap->motion_type == MCHAR
&& (!oap->inclusive
|| (oap->op_type == OP_YANK && gchar(&oap->end) == NUL))
&& equal(oap->start, oap->end));
/*
* For delete, change and yank, it's an error to operate on an
* empty region, when 'E' inclucded in 'cpoptions' (Vi compatible).
*/
empty_region_error = (oap->empty
&& vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL);
/* Force a redraw when operating on an empty Visual region */
if (oap->is_VIsual && oap->empty)
redraw_curbuf_later(NOT_VALID);
/*
* If the end of an operator is in column one while oap->motion_type is
* MCHAR and oap->inclusive is FALSE, we put op_end after the last character
* in the previous line. If op_start is on or before the first non-blank
* in the line, the operator becomes linewise (strange, but that's the way
* vi does it).
*/
if ( oap->motion_type == MCHAR
&& oap->inclusive == FALSE
&& !dont_adjust_op_end
&& oap->end.col == 0
&& (!oap->is_VIsual || *p_sel == 'o')
&& oap->line_count > 1)
{
oap->end_adjusted = TRUE; /* remember that we did this */
--oap->line_count;
--oap->end.lnum;
if (inindent(0))
oap->motion_type = MLINE;
else
{
oap->end.col = STRLEN(ml_get(oap->end.lnum));
if (oap->end.col)
{
--oap->end.col;
oap->inclusive = TRUE;
}
}
}
else
oap->end_adjusted = FALSE;
switch (oap->op_type)
{
case OP_LSHIFT:
case OP_RSHIFT:
op_shift(oap, TRUE, oap->is_VIsual ? (int)cap->count1 : 1);
break;
case DO_JOIN:
if (oap->line_count < 2)
oap->line_count = 2;
if (curwin->w_cursor.lnum + oap->line_count - 1 >
curbuf->b_ml.ml_line_count)
beep_flush();
else
do_do_join(oap->line_count, !oap->op_prechar, TRUE);
break;
case OP_DELETE:
VIsual_reselect = FALSE; /* don't reselect now */
if (empty_region_error)
vim_beep();
else
(void)op_delete(oap);
break;
case OP_YANK:
if (empty_region_error)
{
if (!gui_yank)
vim_beep();
}
else
(void)op_yank(oap, FALSE, !gui_yank);
break;
case OP_CHANGE:
VIsual_reselect = FALSE; /* don't reselect now */
if (empty_region_error)
vim_beep();
else
{
/* don't restart edit after typing <Esc> in edit() */
restart_edit = 0;
*command_busy = op_change(oap); /* will call edit() */
}
break;
case OP_FILTER:
if (vim_strchr(p_cpo, CPO_FILTER) != NULL)
AppendToRedobuff((char_u *)"!\r"); /* use any last used !cmd */
else
bangredo = TRUE; /* do_bang() will put cmd in redo buffer */
case OP_INDENT:
case OP_COLON:
#if defined(LISPINDENT) || defined(CINDENT)
/*
* If 'equalprg' is empty, do the indenting internally.
*/
if (oap->op_type == OP_INDENT && *p_ep == NUL)
{
# ifdef LISPINDENT
if (curbuf->b_p_lisp)
{
op_reindent(oap, get_lisp_indent);
break;
}
# endif
# ifdef CINDENT
op_reindent(oap, get_c_indent);
break;
# endif
}
#endif /* defined(LISPINDENT) || defined(CINDENT) */
op_colon(oap);
break;
case OP_TILDE:
case OP_UPPER:
case OP_LOWER:
if (empty_region_error)
vim_beep();
else
op_tilde(oap);
break;
case OP_FORMAT:
if (*p_fp != NUL)
op_colon(oap); /* use external command */
else
op_format(oap); /* use internal function */
break;
default:
clearopbeep(oap);
}
oap->op_prechar = NUL;
if (!gui_yank)
{
/*
* if 'sol' not set, go back to old column for some commands
*/
if (!p_sol && oap->motion_type == MLINE && !oap->end_adjusted
&& (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT
|| oap->op_type == OP_DELETE))
coladvance(curwin->w_curswant = old_col);
oap->op_type = OP_NOP;
}
else
curwin->w_cursor = old_cursor;
oap->block_mode = FALSE;
oap->regname = 0;
}
}
/*
* Handle indent and format operators and visual mode ":".
*/
static void
op_colon(oap)
OPARG *oap;
{
stuffcharReadbuff(':');
if (oap->is_VIsual)
stuffReadbuff((char_u *)"'<,'>");
else
{
/*
* Make the range look nice, so it can be repeated.
*/
if (oap->start.lnum == curwin->w_cursor.lnum)
stuffcharReadbuff('.');
else
stuffnumReadbuff((long)oap->start.lnum);
if (oap->end.lnum != oap->start.lnum)
{
stuffcharReadbuff(',');
if (oap->end.lnum == curwin->w_cursor.lnum)
stuffcharReadbuff('.');
else if (oap->end.lnum == curbuf->b_ml.ml_line_count)
stuffcharReadbuff('$');
else if (oap->start.lnum == curwin->w_cursor.lnum)
{
stuffReadbuff((char_u *)".+");
stuffnumReadbuff((long)oap->line_count - 1);
}
else
stuffnumReadbuff((long)oap->end.lnum);
}
}
if (oap->op_type != OP_COLON)
stuffReadbuff((char_u *)"!");
if (oap->op_type == OP_INDENT)
{
#ifndef CINDENT
if (*p_ep == NUL)
stuffReadbuff((char_u *)"indent");
else
#endif
stuffReadbuff(p_ep);
stuffReadbuff((char_u *)"\n");
}
else if (oap->op_type == OP_FORMAT)
{
if (*p_fp == NUL)
stuffReadbuff((char_u *)"fmt");
else
stuffReadbuff(p_fp);
stuffReadbuff((char_u *)"\n");
}
/*
* do_cmdline() does the rest
*/
}
#ifdef USE_MOUSE
/*
* Do the appropriate action for the current mouse click in the current mode.
*
* Normal Mode:
* event modi- position visual change action
* fier cursor window
* left press - yes end yes
* left press C yes end yes "^]" (2)
* left press S yes end yes "*" (2)
* left drag - yes start if moved no
* left relse - yes start if moved no
* middle press - yes if not active no put register
* middle press - yes if active no yank and put
* right press - yes start or extend yes
* right press S yes no change yes "#" (2)
* right drag - yes extend no
* right relse - yes extend no
*
* Insert or Replace Mode:
* event modi- position visual change action
* fier cursor window
* left press - yes (cannot be active) yes
* left press C yes (cannot be active) yes "CTRL-O^]" (2)
* left press S yes (cannot be active) yes "CTRL-O*" (2)
* left drag - yes start or extend (1) no CTRL-O (1)
* left relse - yes start or extend (1) no CTRL-O (1)
* middle press - no (cannot be active) no put register
* right press - yes start or extend yes CTRL-O
* right press S yes (cannot be active) yes "CTRL-O#" (2)
*
* (1) only if mouse pointer moved since press
* (2) only if click is in same buffer
*
* Return TRUE if start_arrow() should be called for edit mode.
*/
int
do_mouse(oap, c, dir, count, fix_indent)
OPARG *oap; /* operator argument, can be NULL */
int c; /* K_LEFTMOUSE, etc */
int dir; /* Direction to 'put' if necessary */
long count;
int fix_indent; /* PUT_FIXINDENT if fixing indent necessary */
{
static FPOS orig_cursor;
static int do_always = FALSE; /* ignore 'mouse' setting next time */
static int got_click = FALSE; /* got a click some time back */
int which_button; /* MOUSE_LEFT, _MIDDLE or _RIGHT */
int is_click; /* If FALSE it's a drag or release event */
int is_drag; /* If TRUE it's a drag event */
int jump_flags = 0; /* flags for jump_to_mouse() */
FPOS start_visual;
FPOS end_visual;
int diff;
int moved; /* Has cursor moved? */
int in_status_line; /* mouse in status line */
int c1, c2;
int VIsual_was_active = VIsual_active;
int regname;
/*
* When GUI is active, always recognize mouse events, otherwise:
* - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
* - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
* - For command line and insert mode 'mouse' is checked before calling
* do_mouse().
*/
if (do_always)
do_always = FALSE;
else
#ifdef USE_GUI
if (!gui.in_use)
#endif
{
if (VIsual_active)
{
if (!mouse_has(MOUSE_VISUAL))
return FALSE;
}
else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
return FALSE;
}
which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
/*
* Ignore drag and release events if we didn't get a click.
*/
if (is_click)
got_click = TRUE;
else
{
if (!got_click) /* didn't get click, ignore */
return FALSE;
if (!is_drag) /* release, reset got_click */
got_click = FALSE;
}
/*
* ALT is currently ignored
*/
if ((mod_mask & MOD_MASK_ALT))
return FALSE;
/*
* CTRL right mouse button does CTRL-T
*/
if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
{
if (State & INSERT)
stuffcharReadbuff(Ctrl('O'));
stuffcharReadbuff(Ctrl('T'));
got_click = FALSE; /* ignore drag&release now */
return FALSE;
}
/*
* CTRL only works with left mouse button
*/
if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
return FALSE;
/*
* When a modifier is down, ignore drag and release events, as well as
* multiple clicks and the middle mouse button.
* Accept shift-leftmouse drags when 'M' option is in 'mouse'.
*/
if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT))
&& (!is_click
|| (mod_mask & MOD_MASK_MULTI_CLICK)
|| which_button == MOUSE_MIDDLE)
&& !((mod_mask & MOD_MASK_SHIFT)
&& mouse_model_popup()
&& which_button == MOUSE_LEFT)
)
return FALSE;
/*
* If the button press was used as the movement command for an operator
* (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
* drag/release events.
*/
if (!is_click && which_button == MOUSE_MIDDLE)
return FALSE;
if (oap != NULL)
regname = oap->regname;
else
regname = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -