5067 lines · 118.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. */ /* * getchar.c * * functions related with getting a character from the user/mapping/redo/... * * manipulations with redo buffer and stuff buffer * mappings and abbreviations */ #include "vim.h" /* * These buffers are used for storing: * - stuffed characters: A command that is translated into another command. * - redo characters: will redo the last change. * - recorded chracters: for the "q" command. * * The bytes are stored like in the typeahead buffer: * - K_SPECIAL introduces a special key (two more bytes follow).  A literal *   K_SPECIAL is stored as K_SPECIAL KS_SPECIAL KE_FILLER. * - CSI introduces a GUI termcap code (also when gui.in_use is FALSE, *   otherwise switching the GUI on would make mappings invalid). *   A literal CSI is stored as CSI KS_EXTRA KE_CSI. * These translations are also done on multi-byte characters! * * Escaping CSI bytes is done by the system-specific input functions, called * by ui_inchar(). * Escaping K_SPECIAL is done by inchar(). * Un-escaping is done by vgetc(). */ #define MINIMAL_SIZE 20			/* minimal size for b_str */ static struct buffheader redobuff = {{NULL, {NUL}}, NULL, 0, 0};static struct buffheader old_redobuff = {{NULL, {NUL}}, NULL, 0, 0};#if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO)static struct buffheader save_redobuff = {{NULL, {NUL}}, NULL, 0, 0};static struct buffheader save_old_redobuff = {{NULL, {NUL}}, NULL, 0, 0};#endifstatic struct buffheader recordbuff = {{NULL, {NUL}}, NULL, 0, 0}; static int typeahead_char = 0;		/* typeahead char that's not flushed */ /* * when block_redo is TRUE redo buffer will not be changed * used by edit() to repeat insertions and 'V' command for redoing */static int	block_redo = FALSE; /* * Make a hash value for a mapping. * "mode" is the lower 4 bits of the State for the mapping. * "c1" is the first character of the "lhs". * Returns a value between 0 and 255, index in maphash. * Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode. */#define MAP_HASH(mode, c1) (((mode) & (NORMAL + VISUAL + SELECTMODE + OP_PENDING)) ? (c1) : ((c1) ^ 0x80)) /* * Each mapping is put in one of the 256 hash lists, to speed up finding it. */static mapblock_T	*(maphash[256]);static int		maphash_valid = FALSE; /* * List used for abbreviations. */static mapblock_T	*first_abbr = NULL; /* first entry in abbrlist */ static int		KeyNoremap = 0;	    /* remapping flags */ /* * variables used by vgetorpeek() and flush_buffers() * * typebuf.tb_buf[] contains all characters that are not consumed yet. * typebuf.tb_buf[typebuf.tb_off] is the first valid character. * typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1] is the last valid char. * typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len] must be NUL. * The head of the buffer may contain the result of mappings, abbreviations * and @a commands.  The length of this part is typebuf.tb_maplen. * typebuf.tb_silent is the part where <silent> applies. * After the head are characters that come from the terminal. * typebuf.tb_no_abbr_cnt is the number of characters in typebuf.tb_buf that * should not be considered for abbreviations. * Some parts of typebuf.tb_buf may not be mapped. These parts are remembered * in typebuf.tb_noremap[], which is the same length as typebuf.tb_buf and * contains RM_NONE for the characters that are not to be remapped. * typebuf.tb_noremap[typebuf.tb_off] is the first valid flag. * (typebuf has been put in globals.h, because check_termcode() needs it). */#define RM_YES		0	/* tb_noremap: remap */#define RM_NONE		1	/* tb_noremap: don't remap */#define RM_SCRIPT	2	/* tb_noremap: remap local script mappings */#define RM_ABBR		4	/* tb_noremap: don't remap, do abbrev. */ /* typebuf.tb_buf has three parts: room in front (for result of mappings), the * middle for typeahead and room for new characters (which needs to be 3 * * MAXMAPLEN) for the Amiga). */#define TYPELEN_INIT	(5 * (MAXMAPLEN + 3))static char_u	typebuf_init[TYPELEN_INIT];	/* initial typebuf.tb_buf */static char_u	noremapbuf_init[TYPELEN_INIT];	/* initial typebuf.tb_noremap */ static int	last_recorded_len = 0;	/* number of last recorded chars */ static char_u	*get_buffcont __ARGS((struct buffheader *, int));static void	add_buff __ARGS((struct buffheader *, char_u *, long n));static void	add_num_buff __ARGS((struct buffheader *, long));static void	add_char_buff __ARGS((struct buffheader *, int));static int	read_stuff __ARGS((int advance));static void	start_stuff __ARGS((void));static int	read_redo __ARGS((int, int));static void	copy_redo __ARGS((int));static void	init_typebuf __ARGS((void));static void	gotchars __ARGS((char_u *, int));static void	may_sync_undo __ARGS((void));static void	closescript __ARGS((void));static int	vgetorpeek __ARGS((int));static void	map_free __ARGS((mapblock_T **));static void	validate_maphash __ARGS((void));static void	showmap __ARGS((mapblock_T *mp, int local));#ifdef FEAT_EVALstatic char_u	*eval_map_expr __ARGS((char_u *str));#endif /* * Free and clear a buffer. */    voidfree_buff(buf)    struct buffheader	*buf;{    struct buffblock	*p, *np;     for (p = buf->bh_first.b_next; p != NULL; p = np)    {	np = p->b_next;	vim_free(p);    }    buf->bh_first.b_next = NULL;} /* * Return the contents of a buffer as a single string. * K_SPECIAL and CSI in the returned string are escaped. */    static char_u *get_buffcont(buffer, dozero)    struct buffheader	*buffer;    int			dozero;	    /* count == zero is not an error */{    long_u	    count = 0;    char_u	    *p = NULL;    char_u	    *p2;    char_u	    *str;    struct buffblock *bp;     /* compute the total length of the string */    for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)	count += (long_u)STRLEN(bp->b_str);     if ((count || dozero) && (p = lalloc(count + 1, TRUE)) != NULL)    {	p2 = p;	for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)	    for (str = bp->b_str; *str; )		*p2++ = *str++;	*p2 = NUL;    }    return (p);} /* * Return the contents of the record buffer as a single string * and clear the record buffer. * K_SPECIAL and CSI in the returned string are escaped. */    char_u *get_recorded(){    char_u	*p;    size_t	len;     p = get_buffcont(&recordbuff, TRUE);    free_buff(&recordbuff);     /*     * Remove the characters that were added the last time, these must be the     * (possibly mapped) characters that stopped the recording.     */    len = STRLEN(p);    if ((int)len >= last_recorded_len)    {	len -= last_recorded_len;	p[len] = NUL;    }     /*     * When stopping recording from Insert mode with CTRL-O q, also remove the     * CTRL-O.     */    if (len > 0 && restart_edit != 0 && p[len - 1] == Ctrl_O)	p[len - 1] = NUL;     return (p);} /* * Return the contents of the redo buffer as a single string. * K_SPECIAL and CSI in the returned string are escaped. */    char_u *get_inserted(){    return(get_buffcont(&redobuff, FALSE));} /* * Add string "s" after the current block of buffer "buf". * K_SPECIAL and CSI should have been escaped already. */    static voidadd_buff(buf, s, slen)    struct buffheader	*buf;    char_u		*s;    long		slen;	/* length of "s" or -1 */{    struct buffblock *p;    long_u	    len;     if (slen < 0)	slen = (long)STRLEN(s);    if (slen == 0)				/* don't add empty strings */	return;     if (buf->bh_first.b_next == NULL)	/* first add to list */    {	buf->bh_space = 0;	buf->bh_curr = &(buf->bh_first);    }    else if (buf->bh_curr == NULL)	/* buffer has already been read */    {	EMSG(_("E222: Add to read buffer"));	return;    }    else if (buf->bh_index != 0)	STRCPY(buf->bh_first.b_next->b_str,				 buf->bh_first.b_next->b_str + buf->bh_index);    buf->bh_index = 0;     if (buf->bh_space >= (int)slen)    {	len = (long_u)STRLEN(buf->bh_curr->b_str);	vim_strncpy(buf->bh_curr->b_str + len, s, (size_t)slen);	buf->bh_space -= slen;    }    else    {	if (slen < MINIMAL_SIZE)	    len = MINIMAL_SIZE;	else	    len = slen;	p = (struct buffblock *)lalloc((long_u)(sizeof(struct buffblock) + len),									TRUE);	if (p == NULL)	    return; /* no space, just forget it */	buf->bh_space = (int)(len - slen);	vim_strncpy(p->b_str, s, (size_t)slen); 	p->b_next = buf->bh_curr->b_next;	buf->bh_curr->b_next = p;	buf->bh_curr = p;    }    return;} /* * Add number "n" to buffer "buf". */    static voidadd_num_buff(buf, n)    struct buffheader *buf;    long	      n;{    char_u	number[32];     sprintf((char *)number, "%ld", n);    add_buff(buf, number, -1L);} /* * Add character 'c' to buffer "buf". * Translates special keys, NUL, CSI, K_SPECIAL and multibyte characters. */    static voidadd_char_buff(buf, c)    struct buffheader	*buf;    int			c;{#ifdef FEAT_MBYTE    char_u	bytes[MB_MAXBYTES + 1];    int		len;    int		i;#endif    char_u	temp[4]; #ifdef FEAT_MBYTE    if (IS_SPECIAL(c))	len = 1;    else	len = (*mb_char2bytes)(c, bytes);    for (i = 0; i < len; ++i)    {	if (!IS_SPECIAL(c))	    c = bytes[i];#endif 	if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL)	{	    /* translate special key code into three byte sequence */	    temp[0] = K_SPECIAL;	    temp[1] = K_SECOND(c);	    temp[2] = K_THIRD(c);	    temp[3] = NUL;	}#ifdef FEAT_GUI	else if (c == CSI)	{	    /* Translate a CSI to a CSI - KS_EXTRA - KE_CSI sequence */	    temp[0] = CSI;	    temp[1] = KS_EXTRA;	    temp[2] = (int)KE_CSI;	    temp[3] = NUL;	}#endif	else	{	    temp[0] = c;	    temp[1] = NUL;	}	add_buff(buf, temp, -1L);#ifdef FEAT_MBYTE    }#endif} /* * Get one byte from the stuff buffer. * If advance == TRUE go to the next char. * No translation is done K_SPECIAL and CSI are escaped. */    static intread_stuff(advance)    int		advance;{    char_u		c;    struct buffblock	*curr;     if (stuffbuff.bh_first.b_next == NULL)  /* buffer is empty */	return NUL;     curr = stuffbuff.bh_first.b_next;    c = curr->b_str[stuffbuff.bh_index];     if (advance)    {	if (curr->b_str[++stuffbuff.bh_index] == NUL)	{	    stuffbuff.bh_first.b_next = curr->b_next;	    vim_free(curr);	    stuffbuff.bh_index = 0;	}    }    return c;} /* * Prepare the stuff buffer for reading (if it contains something). */    static voidstart_stuff(){    if (stuffbuff.bh_first.b_next != NULL)    {	stuffbuff.bh_curr = &(stuffbuff.bh_first);	stuffbuff.bh_space = 0;    }} /* * Return TRUE if the stuff buffer is empty. */    intstuff_empty(){    return (stuffbuff.bh_first.b_next == NULL);} /* * Set a typeahead character that won't be flushed. */    voidtypeahead_noflush(c)    int		c;{    typeahead_char = c;} /* * Remove the contents of the stuff buffer and the mapped characters in the * typeahead buffer (used in case of an error).  If 'typeahead' is true, * flush all typeahead characters (used when interrupted by a CTRL-C). */    voidflush_buffers(typeahead)    int typeahead;{    init_typebuf();     start_stuff();    while (read_stuff(TRUE) != NUL)	;     if (typeahead)	    /* remove all typeahead */    {	/*	 * We have to get all characters, because we may delete the first part	 * of an escape sequence.	 * In an xterm we get one char at a time and we have to get them all.	 */	while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L,						  typebuf.tb_change_cnt) != 0)	    ;	typebuf.tb_off = MAXMAPLEN;	typebuf.tb_len = 0;    }    else		    /* remove mapped characters only */    {	typebuf.tb_off += typebuf.tb_maplen;	typebuf.tb_len -= typebuf.tb_maplen;    }    typebuf.tb_maplen = 0;    typebuf.tb_silent = 0;    cmd_silent = FALSE;    typebuf.tb_no_abbr_cnt = 0;} /* * The previous contents of the redo buffer is kept in old_redobuffer. * This is used for the CTRL-O <.> command in insert mode. */    voidResetRedobuff(){    if (!block_redo)    {	free_buff(&old_redobuff);	old_redobuff = redobuff;	redobuff.bh_first.b_next = NULL;    }} #if defined(FEAT_AUTOCMD) || defined(FEAT_EVAL) || defined(PROTO)/* * Save redobuff and old_redobuff to save_redobuff and save_old_redobuff. * Used before executing autocommands and user functions. */static int save_level = 0;     voidsaveRedobuff(){    char_u	*s;     if (save_level++ == 0)    {	save_redobuff = redobuff;	redobuff.bh_first.b_next = NULL;	save_old_redobuff = old_redobuff;	old_redobuff.bh_first.b_next = NULL; 	/* Make a copy, so that ":normal ." in a function works. */	s = get_buffcont(&save_redobuff, FALSE);	if (s != NULL)	{	    add_buff(&redobuff, s, -1L);	    vim_free(s);	}    }} 

Lines 1–500 of 5067.