⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 edit.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -