9506 lines · 229.1 KB · C
RawDownload
/* 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. * See README.txt for an overview of the Vim source code. */ /* * edit.c: functions for Insert mode */ #include "vim.h" #ifdef FEAT_INS_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 CTRL_X_THESAURUS	(10 + CTRL_X_WANT_IDENT)#define CTRL_X_CMDLINE		11#define CTRL_X_FUNCTION		12#define CTRL_X_OMNI		13#define CTRL_X_SPELL		14#define CTRL_X_LOCAL_MSG	15	/* only used in "ctrl_x_msgs" */ #define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT] static char *ctrl_x_msgs[] ={    N_(" Keyword completion (^N^P)"), /* ctrl_x_mode == 0, ^P/^N compl. */    N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"),    NULL,    N_(" Whole line completion (^L^N^P)"),    N_(" File name completion (^F^N^P)"),    N_(" Tag completion (^]^N^P)"),    N_(" Path pattern completion (^N^P)"),    N_(" Definition completion (^D^N^P)"),    NULL,    N_(" Dictionary completion (^K^N^P)"),    N_(" Thesaurus completion (^T^N^P)"),    N_(" Command-line completion (^V^N^P)"),    N_(" User defined completion (^U^N^P)"),    N_(" Omni completion (^O^N^P)"),    N_(" Spelling suggestion (s^N^P)"),    N_(" Keyword Local completion (^N^P)"),}; static char_u e_hitend[] = N_("Hit end of paragraph"); /* * Structure used to store one match for insert completion. */typedef struct compl_S compl_T;struct compl_S{    compl_T	*cp_next;    compl_T	*cp_prev;    char_u	*cp_str;	/* matched text */    char	cp_icase;	/* TRUE or FALSE: ignore case */    char_u	*(cp_text[CPT_COUNT]);	/* text for the menu */    char_u	*cp_fname;	/* file containing the match, allocated when				 * cp_flags has FREE_FNAME */    int		cp_flags;	/* ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME */    int		cp_number;	/* sequence number */}; #define ORIGINAL_TEXT	(1)   /* the original text when the expansion begun */#define FREE_FNAME	(2) /* * All the current matches are stored in a list. * "compl_first_match" points to the start of the list. * "compl_curr_match" points to the currently selected entry. * "compl_shown_match" is different from compl_curr_match during * ins_compl_get_exp(). */static compl_T    *compl_first_match = NULL;static compl_T    *compl_curr_match = NULL;static compl_T    *compl_shown_match = NULL; /* After using a cursor key <Enter> selects a match in the popup menu, * otherwise it inserts a line break. */static int	  compl_enter_selects = FALSE; /* When "compl_leader" is not NULL only matches that start with this string * are used. */static char_u	  *compl_leader = NULL; static int	  compl_get_longest = FALSE;	/* put longest common string						   in compl_leader */ static int	  compl_used_match;	/* Selected one of the matches.  When					   FALSE the match was edited or using					   the longest common string. */ static int	  compl_was_interrupted = FALSE;  /* didn't finish finding						     completions. */ static int	  compl_restarting = FALSE;	/* don't insert match */ /* When the first completion is done "compl_started" is set.  When it's * FALSE the word to be completed must be located. */static int	  compl_started = FALSE; static int	  compl_matches = 0;static char_u	  *compl_pattern = NULL;static int	  compl_direction = FORWARD;static int	  compl_shows_dir = FORWARD;static int	  compl_pending = 0;	    /* > 1 for postponed CTRL-N */static pos_T	  compl_startpos;static colnr_T	  compl_col = 0;	    /* column where the text starts					     * that is being completed */static char_u	  *compl_orig_text = NULL;  /* text as it was before					     * completion started */static int	  compl_cont_mode = 0;static expand_T	  compl_xp; static void ins_ctrl_x __ARGS((void));static int  has_compl_option __ARGS((int dict_opt));static int ins_compl_add __ARGS((char_u *str, int len, int icase, char_u *fname, char_u **cptext, int cdir, int flags, int adup));static int  ins_compl_equal __ARGS((compl_T *match, char_u *str, int len));static void ins_compl_longest_match __ARGS((compl_T *match));static void ins_compl_add_matches __ARGS((int num_matches, char_u **matches, int icase));static int  ins_compl_make_cyclic __ARGS((void));static void ins_compl_upd_pum __ARGS((void));static void ins_compl_del_pum __ARGS((void));static int  pum_wanted __ARGS((void));static int  pum_enough_matches __ARGS((void));static void ins_compl_dictionaries __ARGS((char_u *dict, char_u *pat, int flags, int thesaurus));static void ins_compl_files __ARGS((int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir));static char_u *find_line_end __ARGS((char_u *ptr));static void ins_compl_free __ARGS((void));static void ins_compl_clear __ARGS((void));static int  ins_compl_bs __ARGS((void));static void ins_compl_new_leader __ARGS((void));static void ins_compl_addleader __ARGS((int c));static void ins_compl_restart __ARGS((void));static void ins_compl_set_original_text __ARGS((char_u *str));static void ins_compl_addfrommatch __ARGS((void));static int  ins_compl_prep __ARGS((int c));static buf_T *ins_compl_next_buf __ARGS((buf_T *buf, int flag));#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)static void ins_compl_add_list __ARGS((list_T *list));#endifstatic int  ins_compl_get_exp __ARGS((pos_T *ini));static void ins_compl_delete __ARGS((void));static void ins_compl_insert __ARGS((void));static int  ins_compl_next __ARGS((int allow_get_expansion, int count, int insert_match));static int  ins_compl_key2dir __ARGS((int c));static int  ins_compl_pum_key __ARGS((int c));static int  ins_compl_key2count __ARGS((int c));static int  ins_compl_use_match __ARGS((int c));static int  ins_complete __ARGS((int c));static int  quote_meta __ARGS((char_u *dest, char_u *str, int len));#endif /* FEAT_INS_EXPAND */ #define BACKSPACE_CHAR		    1#define BACKSPACE_WORD		    2#define BACKSPACE_WORD_NOT_SPACE    3#define BACKSPACE_LINE		    4 static void ins_redraw __ARGS((int ready));static void ins_ctrl_v __ARGS((void));static void undisplay_dollar __ARGS((void));static void insert_special __ARGS((int, int, int));static void internal_format __ARGS((int textwidth, int second_indent, int flags, int format_only));static void check_auto_format __ARGS((int));static void redo_literal __ARGS((int c));static void start_arrow __ARGS((pos_T *end_insert_pos));#ifdef FEAT_SPELLstatic void check_spell_redraw __ARGS((void));static void spell_back_to_badword __ARGS((void));static int  spell_bad_len = 0;	/* length of located bad word */#endifstatic void stop_insert __ARGS((pos_T *end_insert_pos, int esc));static int  echeck_abbr __ARGS((int));#if 0static void replace_push_off __ARGS((int c));#endifstatic int  replace_pop __ARGS((void));static void replace_join __ARGS((int off));static void replace_pop_ins __ARGS((void));#ifdef FEAT_MBYTEstatic void mb_replace_pop_ins __ARGS((int cc));#endifstatic void replace_flush __ARGS((void));static void replace_do_bs __ARGS((void));#ifdef FEAT_CINDENTstatic int cindent_on __ARGS((void));#endifstatic void ins_reg __ARGS((void));static void ins_ctrl_g __ARGS((void));static void ins_ctrl_hat __ARGS((void));static int  ins_esc __ARGS((long *count, int cmdchar, int nomove));#ifdef FEAT_RIGHTLEFTstatic void ins_ctrl_ __ARGS((void));#endif#ifdef FEAT_VISUALstatic int ins_start_select __ARGS((int c));#endifstatic void ins_insert __ARGS((int replaceState));static void ins_ctrl_o __ARGS((void));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 FEAT_MOUSEstatic void ins_mouse __ARGS((int c));static void ins_mousescroll __ARGS((int up));#endif#if defined(FEAT_GUI_TABLINE) || defined(PROTO)static void ins_tabline __ARGS((int c));#endifstatic void ins_left __ARGS((void));static void ins_home __ARGS((int c));static void ins_end __ARGS((int c));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((int startcol));static void ins_pageup __ARGS((void));static void ins_down __ARGS((int startcol));static void ins_pagedown __ARGS((void));#ifdef FEAT_DNDstatic void ins_drop __ARGS((void));#endifstatic int  ins_tab __ARGS((void));static int  ins_eol __ARGS((int c));#ifdef FEAT_DIGRAPHSstatic int  ins_digraph __ARGS((void));#endifstatic int  ins_copychar __ARGS((linenr_T lnum));static int  ins_ctrl_ey __ARGS((int tc));#ifdef FEAT_SMARTINDENTstatic void ins_try_si __ARGS((int c));#endifstatic colnr_T get_nolist_virtcol __ARGS((void)); 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,					   K_SPECIAL and CSI are escaped */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 */static int	did_restart_edit;	/* "restart_edit" when calling edit() */ #ifdef FEAT_CINDENTstatic int	can_cindent;		/* may do cindenting on this line */#endif static int	old_indent = 0;		/* for ^^D command in insert mode */ #ifdef FEAT_RIGHTLEFTstatic int	revins_on;		/* reverse insert mode on */static int	revins_chars;		/* how much to skip after edit */static int	revins_legal;		/* was the last char 'legal'? */static int	revins_scol;		/* start column of revins session */#endif static int	ins_need_undo;		/* call u_save() before inserting a					   char.  Set when edit() is called.					   after that arrow_used is used. */ static int	did_add_space = FALSE;	/* auto_format() added an extra space					   under the cursor */ /* * edit(): Start inserting 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. * 'V'	"gR" command for Virtual Replace mode. * 'v'	"gr" command for single character Virtual Replace mode. * * 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). */    intedit(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;    int		i;    int		did_backspace = TRUE;	    /* previous char was backspace */#ifdef FEAT_CINDENT    int		line_is_white = FALSE;	    /* line is empty before insert */#endif    linenr_T	old_topline = 0;	    /* topline before insertion */#ifdef FEAT_DIFF    int		old_topfill = -1;#endif    int		inserted_space = FALSE;     /* just inserted a space */    int		replaceState = REPLACE;    int		nomove = FALSE;		    /* don't move cursor on return */     /* Remember whether editing was restarted after CTRL-O. */    did_restart_edit = restart_edit;     /* sleep before redrawing, needed for "CTRL-O :" that results in an     * error message */    check_for_delay(TRUE); #ifdef HAVE_SANDBOX    /* Don't allow inserting in the sandbox. */    if (sandbox != 0)    {	EMSG(_(e_sandbox));	return FALSE;    }#endif    /* Don't allow changes in the buffer while editing the cmdline.  The     * caller of getcmdline() may get confused. */    if (textlock != 0)    {	EMSG(_(e_secure));	return FALSE;    } #ifdef FEAT_INS_EXPAND    /* Don't allow recursive insert mode when busy with completion. */    if (compl_started || pum_visible())    {	EMSG(_(e_secure));	return FALSE;    }    ins_compl_clear();	    /* clear stuff for CTRL-X mode */#endif #ifdef FEAT_AUTOCMD    /*     * Trigger InsertEnter autocommands.  Do not do this for "r<CR>" or "grx".     */    if (cmdchar != 'r' && cmdchar != 'v')    {# ifdef FEAT_EVAL	if (cmdchar == 'R')	    ptr = (char_u *)"r";	else if (cmdchar == 'V')	    ptr = (char_u *)"v";	else	    ptr = (char_u *)"i";	set_vim_var_string(VV_INSERTMODE, ptr, 1);# endif	apply_autocmds(EVENT_INSERTENTER, NULL, NULL, FALSE, curbuf);    }#endif #ifdef FEAT_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 (!did_ai)	ai_col = 0;     if (cmdchar != NUL && restart_edit == 0)    {	ResetRedobuff();	AppendNumberToRedobuff(count);#ifdef FEAT_VREPLACE	if (cmdchar == 'V' || cmdchar == 'v')	{	    /* "gR" or "gr" command */	    AppendCharToRedobuff('g');	    AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R');	}	else#endif	{	    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 FEAT_FKMAP	if (p_fkmap && p_ri)	{	    beep_flush();	    EMSG(farsi_text_3);	    /* encoded in Farsi */	    State = INSERT;	}	else#endif	State = REPLACE;    }#ifdef FEAT_VREPLACE    else if (cmdchar == 'V' || cmdchar == 'v')    {	State = VREPLACE;	replaceState = VREPLACE;	orig_line_count = curbuf->b_ml.ml_line_count;	vr_lines_changed = 1;    }#endif    else	State = INSERT;     stop_insert_mode = FALSE;     /*     * Need to recompute the cursor position, it might move when the cursor is     * on a TAB or special character.     */    curs_columns(TRUE);     /*     * Enable langmap or IME, indicated by 'iminsert'.     * Note that IME may enabled/disabled without us noticing here, thus the     * 'iminsert' value may not reflect what is actually used.  It is updated     * when hitting <Esc>.     */    if (curbuf->b_p_iminsert == B_IMODE_LMAP)	State |= LANGMAP;#ifdef USE_IM_CONTROL    im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);#endif #ifdef FEAT_MOUSE    setmouse();#endif#ifdef FEAT_CMDL_INFO    clear_showcmd();#endif#ifdef FEAT_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     /*     * 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 != 0 && stuff_empty())    {#ifdef FEAT_MOUSE	/*	 * After a paste we consider text typed to be part of the insert for	 * the pasted text. You can backspace over the pasted 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|".	 */

Lines 1–500 of 9506.