📄 edit.c
字号:
/* vi:set ts=8 sts=4 sw=4:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*/
/*
* edit.c: functions for Insert mode
*/
#include "vim.h"
#ifdef INSERT_EXPAND
/*
* definitions used for CTRL-X submode
*/
#define CTRL_X_WANT_IDENT 0x100
#define CTRL_X_NOT_DEFINED_YET (1)
#define CTRL_X_SCROLL (2)
#define CTRL_X_WHOLE_LINE (3)
#define CTRL_X_FILES (4)
#define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
#define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
#define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
#define CTRL_X_FINISHED (8)
#define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
#define C_X_SKIP (7) /* length of " Adding" */
char *ctrl_x_msgs[] =
{
" Adding Keyword completion (^N/^P)", /* ctrl_x_mode == 0, ^P/^N compl. */
" ^X mode (^E/^Y/^L/^]/^F/^I/^K/^D/^N/^P)",
/* Scroll has it's own msgs, in it's place there is the msg for local
* ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo */
" Adding Keyword Local completion (^N/^P)",
" Adding Whole line completion (^L/^N/^P)",
" Adding File name completion (^F/^N/^P)",
" Adding Tag completion (^]/^N/^P)",
" Adding Path pattern completion (^N/^P)",
" Adding Definition completion (^D/^N/^P)",
NULL,
" Adding Dictionary completion (^K/^N/^P)"
};
char_u e_hitend[] = "Hit end of paragraph";
char_u e_hitend_f[] = "Hit end of paragraph (forward)";
char_u e_hitend_b[] = "Hit end of paragraph (backward)";
char_u e_patnotf_f[] = "Pattern not found (forward)";
char_u e_patnotf_b[] = "Pattern not found (backward)";
/*
* Structure used to store one match for insert completion.
*/
struct Completion
{
struct Completion *next;
struct Completion *prev;
char_u *str; /* matched text */
char_u *fname; /* file containing the match */
int original; /* ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME */
};
/* the original text when the expansion begun */
#define ORIGINAL_TEXT (1)
#define FREE_FNAME (2)
/*
* All the current matches are stored in a list.
* "first_match" points to the start of the list.
* "curr_match" points to the currently selected entry.
*/
static struct Completion *first_match = NULL;
static struct Completion *curr_match = NULL;
static int started_completion;
static char_u *complete_pat;
static int save_sm;
static char_u *original_text = NULL; /* text before completion */
static int continue_mode = 0;
static int add_completion __ARGS((char_u *str, int len, char_u *, int dir, int reuse));
static int make_cyclic __ARGS((void));
static void complete_dictionaries __ARGS((char_u *dict, char_u *pat, int dir, int flags));
static void free_completions __ARGS((void));
static void clear_insexp __ARGS((void));
static int ins_expand_pre __ARGS((int c));
static BUF *next_buf __ARGS((BUF *buf, int flag));
static int get_expansion __ARGS((FPOS *ini, int dir));
static int ins_complete __ARGS((int c));
static int quote_meta __ARGS((char_u *dest, char_u *str, int len));
#endif /* INSERT_EXPAND */
#define BACKSPACE_CHAR 1
#define BACKSPACE_WORD 2
#define BACKSPACE_WORD_NOT_SPACE 3
#define BACKSPACE_LINE 4
static void edit_putchar __ARGS((int c, int highlight));
static void undisplay_dollar __ARGS((void));
static void change_indent __ARGS((int type, int amount, int round, int replaced));
static void insert_special __ARGS((int, int, int));
static void redo_literal __ARGS((int c));
static void start_arrow __ARGS((FPOS *end_insert_pos));
static void stop_insert __ARGS((FPOS *end_insert_pos));
static int echeck_abbr __ARGS((int));
static void replace_push_off __ARGS((int c));
static int replace_pop __ARGS((void));
static void replace_join __ARGS((int off));
static void replace_pop_ins __ARGS((void));
static void replace_flush __ARGS((void));
static void replace_do_bs __ARGS((void));
static int ins_reg __ARGS((void));
static int ins_esc __ARGS((long *count, int need_redraw, int cmdchar));
#ifdef RIGHTLEFT
static void ins_ctrl_ __ARGS((void));
#endif
static void ins_shift __ARGS((int c, int lastc));
static void ins_del __ARGS((void));
static int ins_bs __ARGS((int c, int mode, int *inserted_space_p));
#ifdef USE_MOUSE
static void ins_mouse __ARGS((int c));
#endif
static void ins_left __ARGS((void));
static void ins_home __ARGS((void));
static void ins_end __ARGS((void));
static void ins_s_left __ARGS((void));
static void ins_right __ARGS((void));
static void ins_s_right __ARGS((void));
static void ins_up __ARGS((void));
static void ins_pageup __ARGS((void));
static void ins_down __ARGS((void));
static void ins_pagedown __ARGS((void));
static int ins_tab __ARGS((void));
static int ins_eol __ARGS((int c));
#ifdef DIGRAPHS
static int ins_digraph __ARGS((void));
#endif
static int ins_copychar __ARGS((linenr_t lnum));
#ifdef SMARTINDENT
static void ins_try_si __ARGS((int c));
#endif
static colnr_t get_nolist_virtcol __ARGS((void));
static FPOS Insstart; /* This is where the latest
* insert/append mode started. */
static colnr_t Insstart_textlen; /* length of line when insert started */
static colnr_t Insstart_blank_vcol; /* vcol for first inserted blank */
static char_u *last_insert = NULL; /* the text of the previous insert */
static int last_insert_skip; /* nr of chars in front of previous insert */
static int new_insert_skip; /* nr of chars in front of current insert */
#ifdef CINDENT
static int can_cindent; /* may do cindenting on this line */
#endif
static int old_indent = 0; /* for ^^D command in insert mode */
#ifdef RIGHTLEFT
int revins_on; /* reverse insert mode on */
int revins_chars; /* how much to skip after edit */
int revins_legal; /* was the last char 'legal'? */
int revins_scol; /* start column of revins session */
#endif
/*
* edit(): Start insering text.
*
* "cmdchar" can be:
* 'i' normal insert command
* 'a' normal append command
* 'R' replace command
* 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
* but still only one <CR> is inserted. The <Esc> is not used for redo.
* 'g' "gI" command.
*
* This function is not called recursively. For CTRL-O commands, it returns
* and lets the caller handle the Normal-mode command.
*
* Return TRUE if a CTRL-O command caused the return (insert mode pending).
*/
int
edit(cmdchar, startln, count)
int cmdchar;
int startln; /* if set, insert at start of line */
long count;
{
int c = 0;
char_u *ptr;
int lastc;
colnr_t mincol;
static linenr_t o_lnum = 0;
static int o_eol = FALSE;
int need_redraw = FALSE;
int i;
int did_backspace = TRUE; /* previous char was backspace */
#ifdef CINDENT
int line_is_white = FALSE; /* line is empty before insert */
#endif
linenr_t old_topline = 0; /* topline before insertion */
int inserted_space = FALSE; /* just inserted a space */
int has_startsel; /* may start selection */
/* sleep before redrawing, needed for "CTRL-O :" that results in an
* error message */
check_for_delay(TRUE);
#ifdef INSERT_EXPAND
clear_insexp(); /* clear stuff for ctrl-x mode */
#endif
#ifdef USE_MOUSE
/*
* When doing a paste with the middle mouse button, Insstart is set to
* where the paste started.
*/
if (where_paste_started.lnum != 0)
Insstart = where_paste_started;
else
#endif
{
Insstart = curwin->w_cursor;
if (startln)
Insstart.col = 0;
}
Insstart_textlen = linetabsize(ml_get_curline());
Insstart_blank_vcol = MAXCOL;
if (cmdchar != NUL && !restart_edit)
{
ResetRedobuff();
AppendNumberToRedobuff(count);
AppendCharToRedobuff(cmdchar);
if (cmdchar == 'g') /* "gI" command */
AppendCharToRedobuff('I');
else if (cmdchar == 'r') /* "r<CR>" command */
count = 1; /* insert only one <CR> */
}
if (cmdchar == 'R')
{
#ifdef FKMAP
if (p_fkmap && p_ri)
{
beep_flush();
EMSG(farsi_text_3); /* encoded in Farsi */
State = INSERT;
}
else
#endif
State = REPLACE;
}
else
State = INSERT;
#if defined(USE_GUI_WIN32) && defined(MULTI_BYTE_IME)
ImeSetOriginMode();
#endif
/*
* Need to recompute the cursor position, it might move when the cursor is
* on a TAB or special character.
*/
curs_columns(TRUE);
#ifdef USE_MOUSE
setmouse();
#endif
#ifdef SHOWCMD
clear_showcmd();
#endif
#ifdef RIGHTLEFT
/* there is no reverse replace mode */
revins_on = (State == INSERT && p_ri);
if (revins_on)
undisplay_dollar();
revins_chars = 0;
revins_legal = 0;
revins_scol = -1;
#endif
/* if 'keymodel' contains "startsel", may start selection on shifted
* special key */
has_startsel = (vim_strchr(p_km, 'a') != NULL);
/*
* Handle restarting Insert mode.
* Don't do this for CTRL-O . (repeat an insert): we get here with
* restart_edit non-zero, and something in the stuff buffer.
*/
if (restart_edit && stuff_empty())
{
#ifdef USE_MOUSE
/*
* After a paste we consider text typed to be part of the insert for
* the pasted text. You can backspace over the paste text too.
*/
if (where_paste_started.lnum)
arrow_used = FALSE;
else
#endif
arrow_used = TRUE;
restart_edit = 0;
/*
* If the cursor was after the end-of-line before the CTRL-O and it is
* now at the end-of-line, put it after the end-of-line (this is not
* correct in very rare cases).
* Also do this if curswant is greater than the current virtual
* column. Eg after "^O$" or "^O80|".
*/
validate_virtcol();
update_curswant();
if ( ((o_eol && curwin->w_cursor.lnum == o_lnum)
|| curwin->w_curswant > curwin->w_virtcol)
&& *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL
&& *(ptr + 1) == NUL)
++curwin->w_cursor.col;
}
else
{
arrow_used = FALSE;
o_eol = FALSE;
}
#ifdef USE_MOUSE
where_paste_started.lnum = 0;
#endif
#ifdef CINDENT
can_cindent = TRUE;
#endif
/*
* If 'showmode' is set, show the current (insert/replace/..) mode.
* A warning message for changing a readonly file is given here, before
* actually changing anything. It's put after the mode, if any.
*/
i = 0;
if (p_smd)
i = showmode();
if (!p_im)
change_warning(i + 1);
#ifdef CURSOR_SHAPE
ui_cursor_shape(); /* may show different cursor shape */
#endif
#ifdef DIGRAPHS
do_digraph(-1); /* clear digraphs */
#endif
/*
* Get the current length of the redo buffer, those characters have to be
* skipped if we want to get to the inserted characters.
*/
ptr = get_inserted();
if (ptr == NULL)
new_insert_skip = 0;
else
{
new_insert_skip = STRLEN(ptr);
vim_free(ptr);
}
old_indent = 0;
for (;;)
{
#ifdef RIGHTLEFT
if (!revins_legal)
revins_scol = -1; /* reset on illegal motions */
else
revins_legal = 0;
#endif
if (arrow_used) /* don't repeat insert when arrow key used */
count = 0;
/* set curwin->w_curswant for next K_DOWN or K_UP */
if (!arrow_used)
curwin->w_set_curswant = TRUE;
/*
* When emsg() was called msg_scroll will have been set.
*/
msg_scroll = FALSE;
/*
* If we inserted a character at the last position of the last line in
* the window, scroll the window one line up. This avoids an extra
* redraw.
* This is detected when the cursor column is smaller after inserting
* something.
* Don't do this when the topline changed already, it has
* already been adjusted (by insertchar() calling open_line())).
*/
if (need_redraw && curwin->w_p_wrap && !did_backspace &&
curwin->w_topline == old_topline)
{
mincol = curwin->w_wcol;
validate_cursor_col();
if ((int)curwin->w_wcol < (int)mincol - curbuf->b_p_ts &&
curwin->w_wrow == curwin->w_winpos +
curwin->w_height - 1 - p_so &&
curwin->w_cursor.lnum != curwin->w_topline)
{
set_topline(curwin, curwin->w_topline + 1);
update_topline();
#ifdef SYNTAX_HL
/* recompute syntax hl., starting with current line */
syn_changed(curwin->w_cursor.lnum);
#endif
update_screen(VALID_TO_CURSCHAR);
need_redraw = FALSE;
}
else
update_topline();
}
else
update_topline();
did_backspace = FALSE;
/*
* redraw is postponed until here to make 'dollar' option work
* correctly.
*/
validate_cursor(); /* may set must_redraw */
if (need_redraw || must_redraw)
{
update_screenline();
if (curwin->w_redr_status == TRUE)
win_redr_status(curwin); /* display [+] if required */
need_redraw = FALSE;
}
else if (clear_cmdline || redraw_cmdline)
showmode(); /* clear cmdline, show mode and ruler */
showruler(FALSE);
setcursor();
update_curswant();
emsg_on_display = FALSE; /* may remove error message now */
old_topline = curwin->w_topline;
#ifdef USE_GUI_WIN32
dont_scroll = FALSE; /* allow scrolling here */
#endif
lastc = c; /* remember previous char for CTRL-D */
c = vgetc();
#ifdef RIGHTLEFT
if (p_hkmap && KeyTyped)
c = hkmap(c); /* Hebrew mode mapping */
#endif
#ifdef FKMAP
if (p_fkmap && KeyTyped)
c = fkmap(c); /* Farsi mode mapping */
#endif
#ifdef INSERT_EXPAND
/*
* Prepare for or stop ctrl-x mode.
*/
need_redraw |= ins_expand_pre(c);
#endif
#ifdef DIGRAPHS
c = do_digraph(c);
#endif
if (c == Ctrl('V') || c == Ctrl('Q'))
{
if (redrawing() && !char_avail())
edit_putchar('^', TRUE);
AppendToRedobuff((char_u *)"\026"); /* CTRL-V */
#ifdef SHOWCMD
add_to_showcmd_c(c);
#endif
c = get_literal();
#ifdef SHOWCMD
clear_showcmd();
#endif
insert_special(c, FALSE, TRUE);
need_redraw = TRUE;
#ifdef RIGHTLEFT
revins_chars++;
revins_legal++;
#endif
c = Ctrl('V'); /* pretend CTRL-V is last typed character */
continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -