xref: /vim-8.2.3635/src/register.c (revision 3075a455)
14aea03ebSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
24aea03ebSBram Moolenaar  *
34aea03ebSBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
44aea03ebSBram Moolenaar  *
54aea03ebSBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
64aea03ebSBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
74aea03ebSBram Moolenaar  * See README.txt for an overview of the Vim source code.
84aea03ebSBram Moolenaar  */
94aea03ebSBram Moolenaar 
104aea03ebSBram Moolenaar /*
114aea03ebSBram Moolenaar  * register.c: functions for managing registers
124aea03ebSBram Moolenaar  */
134aea03ebSBram Moolenaar 
144aea03ebSBram Moolenaar #include "vim.h"
154aea03ebSBram Moolenaar 
164aea03ebSBram Moolenaar /*
174aea03ebSBram Moolenaar  * Registers:
184aea03ebSBram Moolenaar  *	0 = unnamed register, for normal yanks and puts
194aea03ebSBram Moolenaar  *   1..9 = registers '1' to '9', for deletes
204aea03ebSBram Moolenaar  * 10..35 = registers 'a' to 'z' ('A' to 'Z' for appending)
214aea03ebSBram Moolenaar  *     36 = delete register '-'
224aea03ebSBram Moolenaar  *     37 = Selection register '*'. Only if FEAT_CLIPBOARD defined
234aea03ebSBram Moolenaar  *     38 = Clipboard register '+'. Only if FEAT_CLIPBOARD and FEAT_X11 defined
244aea03ebSBram Moolenaar  */
254aea03ebSBram Moolenaar static yankreg_T	y_regs[NUM_REGISTERS];
264aea03ebSBram Moolenaar 
274aea03ebSBram Moolenaar static yankreg_T	*y_current;	    // ptr to current yankreg
284aea03ebSBram Moolenaar static int		y_append;	    // TRUE when appending
294aea03ebSBram Moolenaar static yankreg_T	*y_previous = NULL; // ptr to last written yankreg
304aea03ebSBram Moolenaar 
314aea03ebSBram Moolenaar static int	stuff_yank(int, char_u *);
324aea03ebSBram Moolenaar static void	put_reedit_in_typebuf(int silent);
334aea03ebSBram Moolenaar static int	put_in_typebuf(char_u *s, int esc, int colon,
344aea03ebSBram Moolenaar 								 int silent);
35544a38e4SChristian Brabandt static int	yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space);
364aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
374aea03ebSBram Moolenaar static void	copy_yank_reg(yankreg_T *reg);
384aea03ebSBram Moolenaar #endif
394aea03ebSBram Moolenaar static void	dis_msg(char_u *p, int skip_esc);
404aea03ebSBram Moolenaar 
414aea03ebSBram Moolenaar     yankreg_T *
get_y_regs(void)424aea03ebSBram Moolenaar get_y_regs(void)
434aea03ebSBram Moolenaar {
444aea03ebSBram Moolenaar     return y_regs;
454aea03ebSBram Moolenaar }
464aea03ebSBram Moolenaar 
474aea03ebSBram Moolenaar     yankreg_T *
get_y_register(int reg)4845fffdf1SBram Moolenaar get_y_register(int reg)
4945fffdf1SBram Moolenaar {
5045fffdf1SBram Moolenaar     return &y_regs[reg];
5145fffdf1SBram Moolenaar }
5245fffdf1SBram Moolenaar 
5345fffdf1SBram Moolenaar     yankreg_T *
get_y_current(void)544aea03ebSBram Moolenaar get_y_current(void)
554aea03ebSBram Moolenaar {
564aea03ebSBram Moolenaar     return y_current;
574aea03ebSBram Moolenaar }
584aea03ebSBram Moolenaar 
594aea03ebSBram Moolenaar     yankreg_T *
get_y_previous(void)604aea03ebSBram Moolenaar get_y_previous(void)
614aea03ebSBram Moolenaar {
624aea03ebSBram Moolenaar     return y_previous;
634aea03ebSBram Moolenaar }
644aea03ebSBram Moolenaar 
654aea03ebSBram Moolenaar     void
set_y_current(yankreg_T * yreg)6645fffdf1SBram Moolenaar set_y_current(yankreg_T *yreg)
6745fffdf1SBram Moolenaar {
6845fffdf1SBram Moolenaar     y_current = yreg;
6945fffdf1SBram Moolenaar }
7045fffdf1SBram Moolenaar 
7145fffdf1SBram Moolenaar     void
set_y_previous(yankreg_T * yreg)724aea03ebSBram Moolenaar set_y_previous(yankreg_T *yreg)
734aea03ebSBram Moolenaar {
744aea03ebSBram Moolenaar     y_previous = yreg;
754aea03ebSBram Moolenaar }
764aea03ebSBram Moolenaar 
7778eb9cceSChristian Brabandt     void
reset_y_append(void)7878eb9cceSChristian Brabandt reset_y_append(void)
7978eb9cceSChristian Brabandt {
8078eb9cceSChristian Brabandt     y_append = FALSE;
8178eb9cceSChristian Brabandt }
8278eb9cceSChristian Brabandt 
8378eb9cceSChristian Brabandt 
844aea03ebSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
854aea03ebSBram Moolenaar /*
864aea03ebSBram Moolenaar  * Keep the last expression line here, for repeating.
874aea03ebSBram Moolenaar  */
884aea03ebSBram Moolenaar static char_u	*expr_line = NULL;
89b4bcea47SBram Moolenaar static exarg_T	*expr_eap = NULL;
904aea03ebSBram Moolenaar 
914aea03ebSBram Moolenaar /*
924aea03ebSBram Moolenaar  * Get an expression for the "\"=expr1" or "CTRL-R =expr1"
934aea03ebSBram Moolenaar  * Returns '=' when OK, NUL otherwise.
944aea03ebSBram Moolenaar  */
954aea03ebSBram Moolenaar     int
get_expr_register(void)964aea03ebSBram Moolenaar get_expr_register(void)
974aea03ebSBram Moolenaar {
984aea03ebSBram Moolenaar     char_u	*new_line;
994aea03ebSBram Moolenaar 
1004aea03ebSBram Moolenaar     new_line = getcmdline('=', 0L, 0, TRUE);
1014aea03ebSBram Moolenaar     if (new_line == NULL)
1024aea03ebSBram Moolenaar 	return NUL;
1034aea03ebSBram Moolenaar     if (*new_line == NUL)	// use previous line
1044aea03ebSBram Moolenaar 	vim_free(new_line);
1054aea03ebSBram Moolenaar     else
106b4bcea47SBram Moolenaar 	set_expr_line(new_line, NULL);
1074aea03ebSBram Moolenaar     return '=';
1084aea03ebSBram Moolenaar }
1094aea03ebSBram Moolenaar 
1104aea03ebSBram Moolenaar /*
1114aea03ebSBram Moolenaar  * Set the expression for the '=' register.
1124aea03ebSBram Moolenaar  * Argument must be an allocated string.
113b4bcea47SBram Moolenaar  * "eap" may be used if the next line needs to be checked when evaluating the
114b4bcea47SBram Moolenaar  * expression.
1154aea03ebSBram Moolenaar  */
1164aea03ebSBram Moolenaar     void
set_expr_line(char_u * new_line,exarg_T * eap)117b4bcea47SBram Moolenaar set_expr_line(char_u *new_line, exarg_T *eap)
1184aea03ebSBram Moolenaar {
1194aea03ebSBram Moolenaar     vim_free(expr_line);
1204aea03ebSBram Moolenaar     expr_line = new_line;
121b4bcea47SBram Moolenaar     expr_eap = eap;
1224aea03ebSBram Moolenaar }
1234aea03ebSBram Moolenaar 
1244aea03ebSBram Moolenaar /*
1254aea03ebSBram Moolenaar  * Get the result of the '=' register expression.
1264aea03ebSBram Moolenaar  * Returns a pointer to allocated memory, or NULL for failure.
1274aea03ebSBram Moolenaar  */
1284aea03ebSBram Moolenaar     char_u *
get_expr_line(void)1294aea03ebSBram Moolenaar get_expr_line(void)
1304aea03ebSBram Moolenaar {
1314aea03ebSBram Moolenaar     char_u	*expr_copy;
1324aea03ebSBram Moolenaar     char_u	*rv;
1334aea03ebSBram Moolenaar     static int	nested = 0;
1344aea03ebSBram Moolenaar 
1354aea03ebSBram Moolenaar     if (expr_line == NULL)
1364aea03ebSBram Moolenaar 	return NULL;
1374aea03ebSBram Moolenaar 
1384aea03ebSBram Moolenaar     // Make a copy of the expression, because evaluating it may cause it to be
1394aea03ebSBram Moolenaar     // changed.
1404aea03ebSBram Moolenaar     expr_copy = vim_strsave(expr_line);
1414aea03ebSBram Moolenaar     if (expr_copy == NULL)
1424aea03ebSBram Moolenaar 	return NULL;
1434aea03ebSBram Moolenaar 
1444aea03ebSBram Moolenaar     // When we are invoked recursively limit the evaluation to 10 levels.
1454aea03ebSBram Moolenaar     // Then return the string as-is.
1464aea03ebSBram Moolenaar     if (nested >= 10)
1474aea03ebSBram Moolenaar 	return expr_copy;
1484aea03ebSBram Moolenaar 
1494aea03ebSBram Moolenaar     ++nested;
150b4bcea47SBram Moolenaar     rv = eval_to_string_eap(expr_copy, TRUE, expr_eap);
1514aea03ebSBram Moolenaar     --nested;
1524aea03ebSBram Moolenaar     vim_free(expr_copy);
1534aea03ebSBram Moolenaar     return rv;
1544aea03ebSBram Moolenaar }
1554aea03ebSBram Moolenaar 
1564aea03ebSBram Moolenaar /*
1574aea03ebSBram Moolenaar  * Get the '=' register expression itself, without evaluating it.
1584aea03ebSBram Moolenaar  */
1594aea03ebSBram Moolenaar     static char_u *
get_expr_line_src(void)1604aea03ebSBram Moolenaar get_expr_line_src(void)
1614aea03ebSBram Moolenaar {
1624aea03ebSBram Moolenaar     if (expr_line == NULL)
1634aea03ebSBram Moolenaar 	return NULL;
1644aea03ebSBram Moolenaar     return vim_strsave(expr_line);
1654aea03ebSBram Moolenaar }
1664aea03ebSBram Moolenaar #endif // FEAT_EVAL
1674aea03ebSBram Moolenaar 
1684aea03ebSBram Moolenaar /*
1694aea03ebSBram Moolenaar  * Check if 'regname' is a valid name of a yank register.
1704aea03ebSBram Moolenaar  * Note: There is no check for 0 (default register), caller should do this
1714aea03ebSBram Moolenaar  */
1724aea03ebSBram Moolenaar     int
valid_yank_reg(int regname,int writing)1734aea03ebSBram Moolenaar valid_yank_reg(
1744aea03ebSBram Moolenaar     int	    regname,
1754aea03ebSBram Moolenaar     int	    writing)	    // if TRUE check for writable registers
1764aea03ebSBram Moolenaar {
1774aea03ebSBram Moolenaar     if (       (regname > 0 && ASCII_ISALNUM(regname))
1784aea03ebSBram Moolenaar 	    || (!writing && vim_strchr((char_u *)
1794aea03ebSBram Moolenaar #ifdef FEAT_EVAL
1804aea03ebSBram Moolenaar 				    "/.%:="
1814aea03ebSBram Moolenaar #else
1824aea03ebSBram Moolenaar 				    "/.%:"
1834aea03ebSBram Moolenaar #endif
1844aea03ebSBram Moolenaar 					, regname) != NULL)
1854aea03ebSBram Moolenaar 	    || regname == '#'
1864aea03ebSBram Moolenaar 	    || regname == '"'
1874aea03ebSBram Moolenaar 	    || regname == '-'
1884aea03ebSBram Moolenaar 	    || regname == '_'
1894aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
1904aea03ebSBram Moolenaar 	    || regname == '*'
1914aea03ebSBram Moolenaar 	    || regname == '+'
1924aea03ebSBram Moolenaar #endif
1934aea03ebSBram Moolenaar #ifdef FEAT_DND
1944aea03ebSBram Moolenaar 	    || (!writing && regname == '~')
1954aea03ebSBram Moolenaar #endif
1964aea03ebSBram Moolenaar 							)
1974aea03ebSBram Moolenaar 	return TRUE;
1984aea03ebSBram Moolenaar     return FALSE;
1994aea03ebSBram Moolenaar }
2004aea03ebSBram Moolenaar 
2014aea03ebSBram Moolenaar /*
2024aea03ebSBram Moolenaar  * Set y_current and y_append, according to the value of "regname".
2034aea03ebSBram Moolenaar  * Cannot handle the '_' register.
2044aea03ebSBram Moolenaar  * Must only be called with a valid register name!
2054aea03ebSBram Moolenaar  *
2064aea03ebSBram Moolenaar  * If regname is 0 and writing, use register 0
2074aea03ebSBram Moolenaar  * If regname is 0 and reading, use previous register
2084aea03ebSBram Moolenaar  *
2094aea03ebSBram Moolenaar  * Return TRUE when the register should be inserted literally (selection or
2104aea03ebSBram Moolenaar  * clipboard).
2114aea03ebSBram Moolenaar  */
2124aea03ebSBram Moolenaar     int
get_yank_register(int regname,int writing)2134aea03ebSBram Moolenaar get_yank_register(int regname, int writing)
2144aea03ebSBram Moolenaar {
2154aea03ebSBram Moolenaar     int	    i;
2164aea03ebSBram Moolenaar     int	    ret = FALSE;
2174aea03ebSBram Moolenaar 
2184aea03ebSBram Moolenaar     y_append = FALSE;
2194aea03ebSBram Moolenaar     if ((regname == 0 || regname == '"') && !writing && y_previous != NULL)
2204aea03ebSBram Moolenaar     {
2214aea03ebSBram Moolenaar 	y_current = y_previous;
2224aea03ebSBram Moolenaar 	return ret;
2234aea03ebSBram Moolenaar     }
2244aea03ebSBram Moolenaar     i = regname;
2254aea03ebSBram Moolenaar     if (VIM_ISDIGIT(i))
2264aea03ebSBram Moolenaar 	i -= '0';
2274aea03ebSBram Moolenaar     else if (ASCII_ISLOWER(i))
2284aea03ebSBram Moolenaar 	i = CharOrdLow(i) + 10;
2294aea03ebSBram Moolenaar     else if (ASCII_ISUPPER(i))
2304aea03ebSBram Moolenaar     {
2314aea03ebSBram Moolenaar 	i = CharOrdUp(i) + 10;
2324aea03ebSBram Moolenaar 	y_append = TRUE;
2334aea03ebSBram Moolenaar     }
2344aea03ebSBram Moolenaar     else if (regname == '-')
2354aea03ebSBram Moolenaar 	i = DELETION_REGISTER;
2364aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
2374aea03ebSBram Moolenaar     // When selection is not available, use register 0 instead of '*'
2384aea03ebSBram Moolenaar     else if (clip_star.available && regname == '*')
2394aea03ebSBram Moolenaar     {
2404aea03ebSBram Moolenaar 	i = STAR_REGISTER;
2414aea03ebSBram Moolenaar 	ret = TRUE;
2424aea03ebSBram Moolenaar     }
2434aea03ebSBram Moolenaar     // When clipboard is not available, use register 0 instead of '+'
2444aea03ebSBram Moolenaar     else if (clip_plus.available && regname == '+')
2454aea03ebSBram Moolenaar     {
2464aea03ebSBram Moolenaar 	i = PLUS_REGISTER;
2474aea03ebSBram Moolenaar 	ret = TRUE;
2484aea03ebSBram Moolenaar     }
2494aea03ebSBram Moolenaar #endif
2504aea03ebSBram Moolenaar #ifdef FEAT_DND
2514aea03ebSBram Moolenaar     else if (!writing && regname == '~')
2524aea03ebSBram Moolenaar 	i = TILDE_REGISTER;
2534aea03ebSBram Moolenaar #endif
2544aea03ebSBram Moolenaar     else		// not 0-9, a-z, A-Z or '-': use register 0
2554aea03ebSBram Moolenaar 	i = 0;
2564aea03ebSBram Moolenaar     y_current = &(y_regs[i]);
2574aea03ebSBram Moolenaar     if (writing)	// remember the register we write into for do_put()
2584aea03ebSBram Moolenaar 	y_previous = y_current;
2594aea03ebSBram Moolenaar     return ret;
2604aea03ebSBram Moolenaar }
2614aea03ebSBram Moolenaar 
2624aea03ebSBram Moolenaar /*
2634aea03ebSBram Moolenaar  * Obtain the contents of a "normal" register. The register is made empty.
2644aea03ebSBram Moolenaar  * The returned pointer has allocated memory, use put_register() later.
2654aea03ebSBram Moolenaar  */
2664aea03ebSBram Moolenaar     void *
get_register(int name,int copy)2674aea03ebSBram Moolenaar get_register(
2684aea03ebSBram Moolenaar     int		name,
2694aea03ebSBram Moolenaar     int		copy)	// make a copy, if FALSE make register empty.
2704aea03ebSBram Moolenaar {
2714aea03ebSBram Moolenaar     yankreg_T	*reg;
2724aea03ebSBram Moolenaar     int		i;
2734aea03ebSBram Moolenaar 
2744aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
2754aea03ebSBram Moolenaar     // When Visual area changed, may have to update selection.  Obtain the
2764aea03ebSBram Moolenaar     // selection too.
2774aea03ebSBram Moolenaar     if (name == '*' && clip_star.available)
2784aea03ebSBram Moolenaar     {
2794aea03ebSBram Moolenaar 	if (clip_isautosel_star())
2804aea03ebSBram Moolenaar 	    clip_update_selection(&clip_star);
2814aea03ebSBram Moolenaar 	may_get_selection(name);
2824aea03ebSBram Moolenaar     }
2834aea03ebSBram Moolenaar     if (name == '+' && clip_plus.available)
2844aea03ebSBram Moolenaar     {
2854aea03ebSBram Moolenaar 	if (clip_isautosel_plus())
2864aea03ebSBram Moolenaar 	    clip_update_selection(&clip_plus);
2874aea03ebSBram Moolenaar 	may_get_selection(name);
2884aea03ebSBram Moolenaar     }
2894aea03ebSBram Moolenaar #endif
2904aea03ebSBram Moolenaar 
2914aea03ebSBram Moolenaar     get_yank_register(name, 0);
2924aea03ebSBram Moolenaar     reg = ALLOC_ONE(yankreg_T);
2934aea03ebSBram Moolenaar     if (reg != NULL)
2944aea03ebSBram Moolenaar     {
2954aea03ebSBram Moolenaar 	*reg = *y_current;
2964aea03ebSBram Moolenaar 	if (copy)
2974aea03ebSBram Moolenaar 	{
2984aea03ebSBram Moolenaar 	    // If we run out of memory some or all of the lines are empty.
2994aea03ebSBram Moolenaar 	    if (reg->y_size == 0)
3004aea03ebSBram Moolenaar 		reg->y_array = NULL;
3014aea03ebSBram Moolenaar 	    else
3024aea03ebSBram Moolenaar 		reg->y_array = ALLOC_MULT(char_u *, reg->y_size);
3034aea03ebSBram Moolenaar 	    if (reg->y_array != NULL)
3044aea03ebSBram Moolenaar 	    {
3054aea03ebSBram Moolenaar 		for (i = 0; i < reg->y_size; ++i)
3064aea03ebSBram Moolenaar 		    reg->y_array[i] = vim_strsave(y_current->y_array[i]);
3074aea03ebSBram Moolenaar 	    }
3084aea03ebSBram Moolenaar 	}
3094aea03ebSBram Moolenaar 	else
3104aea03ebSBram Moolenaar 	    y_current->y_array = NULL;
3114aea03ebSBram Moolenaar     }
3124aea03ebSBram Moolenaar     return (void *)reg;
3134aea03ebSBram Moolenaar }
3144aea03ebSBram Moolenaar 
3154aea03ebSBram Moolenaar /*
3164aea03ebSBram Moolenaar  * Put "reg" into register "name".  Free any previous contents and "reg".
3174aea03ebSBram Moolenaar  */
3184aea03ebSBram Moolenaar     void
put_register(int name,void * reg)3194aea03ebSBram Moolenaar put_register(int name, void *reg)
3204aea03ebSBram Moolenaar {
3214aea03ebSBram Moolenaar     get_yank_register(name, 0);
3224aea03ebSBram Moolenaar     free_yank_all();
3234aea03ebSBram Moolenaar     *y_current = *(yankreg_T *)reg;
3244aea03ebSBram Moolenaar     vim_free(reg);
3254aea03ebSBram Moolenaar 
3264aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
3274aea03ebSBram Moolenaar     // Send text written to clipboard register to the clipboard.
3284aea03ebSBram Moolenaar     may_set_selection();
3294aea03ebSBram Moolenaar #endif
3304aea03ebSBram Moolenaar }
3314aea03ebSBram Moolenaar 
332fccbf068SBram Moolenaar #if defined(FEAT_CLIPBOARD) || defined(PROTO)
3334aea03ebSBram Moolenaar     void
free_register(void * reg)3344aea03ebSBram Moolenaar free_register(void *reg)
3354aea03ebSBram Moolenaar {
3364aea03ebSBram Moolenaar     yankreg_T tmp;
3374aea03ebSBram Moolenaar 
3384aea03ebSBram Moolenaar     tmp = *y_current;
3394aea03ebSBram Moolenaar     *y_current = *(yankreg_T *)reg;
3404aea03ebSBram Moolenaar     free_yank_all();
3414aea03ebSBram Moolenaar     vim_free(reg);
3424aea03ebSBram Moolenaar     *y_current = tmp;
3434aea03ebSBram Moolenaar }
3444aea03ebSBram Moolenaar #endif
3454aea03ebSBram Moolenaar 
3464aea03ebSBram Moolenaar /*
3474aea03ebSBram Moolenaar  * return TRUE if the current yank register has type MLINE
3484aea03ebSBram Moolenaar  */
3494aea03ebSBram Moolenaar     int
yank_register_mline(int regname)3504aea03ebSBram Moolenaar yank_register_mline(int regname)
3514aea03ebSBram Moolenaar {
3524aea03ebSBram Moolenaar     if (regname != 0 && !valid_yank_reg(regname, FALSE))
3534aea03ebSBram Moolenaar 	return FALSE;
3544aea03ebSBram Moolenaar     if (regname == '_')		// black hole is always empty
3554aea03ebSBram Moolenaar 	return FALSE;
3564aea03ebSBram Moolenaar     get_yank_register(regname, FALSE);
3574aea03ebSBram Moolenaar     return (y_current->y_type == MLINE);
3584aea03ebSBram Moolenaar }
3594aea03ebSBram Moolenaar 
3604aea03ebSBram Moolenaar /*
3614aea03ebSBram Moolenaar  * Start or stop recording into a yank register.
3624aea03ebSBram Moolenaar  *
3634aea03ebSBram Moolenaar  * Return FAIL for failure, OK otherwise.
3644aea03ebSBram Moolenaar  */
3654aea03ebSBram Moolenaar     int
do_record(int c)3664aea03ebSBram Moolenaar do_record(int c)
3674aea03ebSBram Moolenaar {
3684aea03ebSBram Moolenaar     char_u	    *p;
3694aea03ebSBram Moolenaar     static int	    regname;
3704aea03ebSBram Moolenaar     yankreg_T	    *old_y_previous, *old_y_current;
3714aea03ebSBram Moolenaar     int		    retval;
3724aea03ebSBram Moolenaar 
3734aea03ebSBram Moolenaar     if (reg_recording == 0)	    // start recording
3744aea03ebSBram Moolenaar     {
3754aea03ebSBram Moolenaar 	// registers 0-9, a-z and " are allowed
3764aea03ebSBram Moolenaar 	if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
3774aea03ebSBram Moolenaar 	    retval = FAIL;
3784aea03ebSBram Moolenaar 	else
3794aea03ebSBram Moolenaar 	{
3804aea03ebSBram Moolenaar 	    reg_recording = c;
3814aea03ebSBram Moolenaar 	    showmode();
3824aea03ebSBram Moolenaar 	    regname = c;
3834aea03ebSBram Moolenaar 	    retval = OK;
3844aea03ebSBram Moolenaar 	}
3854aea03ebSBram Moolenaar     }
3864aea03ebSBram Moolenaar     else			    // stop recording
3874aea03ebSBram Moolenaar     {
3884aea03ebSBram Moolenaar 	// Get the recorded key hits.  K_SPECIAL and CSI will be escaped, this
3894aea03ebSBram Moolenaar 	// needs to be removed again to put it in a register.  exec_reg then
3904aea03ebSBram Moolenaar 	// adds the escaping back later.
3914aea03ebSBram Moolenaar 	reg_recording = 0;
3924aea03ebSBram Moolenaar 	msg("");
3934aea03ebSBram Moolenaar 	p = get_recorded();
3944aea03ebSBram Moolenaar 	if (p == NULL)
3954aea03ebSBram Moolenaar 	    retval = FAIL;
3964aea03ebSBram Moolenaar 	else
3974aea03ebSBram Moolenaar 	{
3984aea03ebSBram Moolenaar 	    // Remove escaping for CSI and K_SPECIAL in multi-byte chars.
3994aea03ebSBram Moolenaar 	    vim_unescape_csi(p);
4004aea03ebSBram Moolenaar 
4014aea03ebSBram Moolenaar 	    // We don't want to change the default register here, so save and
4024aea03ebSBram Moolenaar 	    // restore the current register name.
4034aea03ebSBram Moolenaar 	    old_y_previous = y_previous;
4044aea03ebSBram Moolenaar 	    old_y_current = y_current;
4054aea03ebSBram Moolenaar 
4064aea03ebSBram Moolenaar 	    retval = stuff_yank(regname, p);
4074aea03ebSBram Moolenaar 
4084aea03ebSBram Moolenaar 	    y_previous = old_y_previous;
4094aea03ebSBram Moolenaar 	    y_current = old_y_current;
4104aea03ebSBram Moolenaar 	}
4114aea03ebSBram Moolenaar     }
4124aea03ebSBram Moolenaar     return retval;
4134aea03ebSBram Moolenaar }
4144aea03ebSBram Moolenaar 
4154aea03ebSBram Moolenaar /*
4164aea03ebSBram Moolenaar  * Stuff string "p" into yank register "regname" as a single line (append if
4174aea03ebSBram Moolenaar  * uppercase).	"p" must have been alloced.
4184aea03ebSBram Moolenaar  *
4194aea03ebSBram Moolenaar  * return FAIL for failure, OK otherwise
4204aea03ebSBram Moolenaar  */
4214aea03ebSBram Moolenaar     static int
stuff_yank(int regname,char_u * p)4224aea03ebSBram Moolenaar stuff_yank(int regname, char_u *p)
4234aea03ebSBram Moolenaar {
4244aea03ebSBram Moolenaar     char_u	*lp;
4254aea03ebSBram Moolenaar     char_u	**pp;
4264aea03ebSBram Moolenaar 
4274aea03ebSBram Moolenaar     // check for read-only register
4284aea03ebSBram Moolenaar     if (regname != 0 && !valid_yank_reg(regname, TRUE))
4294aea03ebSBram Moolenaar     {
4304aea03ebSBram Moolenaar 	vim_free(p);
4314aea03ebSBram Moolenaar 	return FAIL;
4324aea03ebSBram Moolenaar     }
4334aea03ebSBram Moolenaar     if (regname == '_')		    // black hole: don't do anything
4344aea03ebSBram Moolenaar     {
4354aea03ebSBram Moolenaar 	vim_free(p);
4364aea03ebSBram Moolenaar 	return OK;
4374aea03ebSBram Moolenaar     }
4384aea03ebSBram Moolenaar     get_yank_register(regname, TRUE);
4394aea03ebSBram Moolenaar     if (y_append && y_current->y_array != NULL)
4404aea03ebSBram Moolenaar     {
4414aea03ebSBram Moolenaar 	pp = &(y_current->y_array[y_current->y_size - 1]);
4424aea03ebSBram Moolenaar 	lp = alloc(STRLEN(*pp) + STRLEN(p) + 1);
4434aea03ebSBram Moolenaar 	if (lp == NULL)
4444aea03ebSBram Moolenaar 	{
4454aea03ebSBram Moolenaar 	    vim_free(p);
4464aea03ebSBram Moolenaar 	    return FAIL;
4474aea03ebSBram Moolenaar 	}
4484aea03ebSBram Moolenaar 	STRCPY(lp, *pp);
4494aea03ebSBram Moolenaar 	STRCAT(lp, p);
4504aea03ebSBram Moolenaar 	vim_free(p);
4514aea03ebSBram Moolenaar 	vim_free(*pp);
4524aea03ebSBram Moolenaar 	*pp = lp;
4534aea03ebSBram Moolenaar     }
4544aea03ebSBram Moolenaar     else
4554aea03ebSBram Moolenaar     {
4564aea03ebSBram Moolenaar 	free_yank_all();
4574aea03ebSBram Moolenaar 	if ((y_current->y_array = ALLOC_ONE(char_u *)) == NULL)
4584aea03ebSBram Moolenaar 	{
4594aea03ebSBram Moolenaar 	    vim_free(p);
4604aea03ebSBram Moolenaar 	    return FAIL;
4614aea03ebSBram Moolenaar 	}
4624aea03ebSBram Moolenaar 	y_current->y_array[0] = p;
4634aea03ebSBram Moolenaar 	y_current->y_size = 1;
4644aea03ebSBram Moolenaar 	y_current->y_type = MCHAR;  // used to be MLINE, why?
4654aea03ebSBram Moolenaar #ifdef FEAT_VIMINFO
4664aea03ebSBram Moolenaar 	y_current->y_time_set = vim_time();
4674aea03ebSBram Moolenaar #endif
4684aea03ebSBram Moolenaar     }
4694aea03ebSBram Moolenaar     return OK;
4704aea03ebSBram Moolenaar }
4714aea03ebSBram Moolenaar 
47241a7f82dSYegappan Lakshmanan /*
47341a7f82dSYegappan Lakshmanan  * Last executed register (@ command)
47441a7f82dSYegappan Lakshmanan  */
4754aea03ebSBram Moolenaar static int execreg_lastc = NUL;
4764aea03ebSBram Moolenaar 
4774aea03ebSBram Moolenaar     int
get_execreg_lastc(void)4784aea03ebSBram Moolenaar get_execreg_lastc(void)
4794aea03ebSBram Moolenaar {
4804aea03ebSBram Moolenaar     return execreg_lastc;
4814aea03ebSBram Moolenaar }
4824aea03ebSBram Moolenaar 
4834aea03ebSBram Moolenaar     void
set_execreg_lastc(int lastc)4844aea03ebSBram Moolenaar set_execreg_lastc(int lastc)
4854aea03ebSBram Moolenaar {
4864aea03ebSBram Moolenaar     execreg_lastc = lastc;
4874aea03ebSBram Moolenaar }
4884aea03ebSBram Moolenaar 
4894aea03ebSBram Moolenaar /*
490856c1110SBram Moolenaar  * When executing a register as a series of ex-commands, if the
491856c1110SBram Moolenaar  * line-continuation character is used for a line, then join it with one or
492856c1110SBram Moolenaar  * more previous lines. Note that lines are processed backwards starting from
493856c1110SBram Moolenaar  * the last line in the register.
494856c1110SBram Moolenaar  *
495856c1110SBram Moolenaar  * Arguments:
496856c1110SBram Moolenaar  *   lines - list of lines in the register
497856c1110SBram Moolenaar  *   idx - index of the line starting with \ or "\. Join this line with all the
498856c1110SBram Moolenaar  *	   immediate predecessor lines that start with a \ and the first line
499856c1110SBram Moolenaar  *	   that doesn't start with a \. Lines that start with a comment "\
500856c1110SBram Moolenaar  *	   character are ignored.
501856c1110SBram Moolenaar  *
502856c1110SBram Moolenaar  * Returns the concatenated line. The index of the line that should be
503856c1110SBram Moolenaar  * processed next is returned in idx.
504856c1110SBram Moolenaar  */
505856c1110SBram Moolenaar     static char_u *
execreg_line_continuation(char_u ** lines,long * idx)506856c1110SBram Moolenaar execreg_line_continuation(char_u **lines, long *idx)
507856c1110SBram Moolenaar {
508856c1110SBram Moolenaar     garray_T	ga;
509856c1110SBram Moolenaar     long	i = *idx;
510856c1110SBram Moolenaar     char_u	*p;
511856c1110SBram Moolenaar     int		cmd_start;
512856c1110SBram Moolenaar     int		cmd_end = i;
513856c1110SBram Moolenaar     int		j;
514856c1110SBram Moolenaar     char_u	*str;
515856c1110SBram Moolenaar 
516856c1110SBram Moolenaar     ga_init2(&ga, (int)sizeof(char_u), 400);
517856c1110SBram Moolenaar 
518856c1110SBram Moolenaar     // search backwards to find the first line of this command.
519856c1110SBram Moolenaar     // Any line not starting with \ or "\ is the start of the
520856c1110SBram Moolenaar     // command.
521856c1110SBram Moolenaar     while (--i > 0)
522856c1110SBram Moolenaar     {
523856c1110SBram Moolenaar 	p = skipwhite(lines[i]);
524856c1110SBram Moolenaar 	if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' '))
525856c1110SBram Moolenaar 	    break;
526856c1110SBram Moolenaar     }
527856c1110SBram Moolenaar     cmd_start = i;
528856c1110SBram Moolenaar 
529856c1110SBram Moolenaar     // join all the lines
530856c1110SBram Moolenaar     ga_concat(&ga, lines[cmd_start]);
531856c1110SBram Moolenaar     for (j = cmd_start + 1; j <= cmd_end; j++)
532856c1110SBram Moolenaar     {
533856c1110SBram Moolenaar 	p = skipwhite(lines[j]);
534856c1110SBram Moolenaar 	if (*p == '\\')
535856c1110SBram Moolenaar 	{
536856c1110SBram Moolenaar 	    // Adjust the growsize to the current length to
537856c1110SBram Moolenaar 	    // speed up concatenating many lines.
538856c1110SBram Moolenaar 	    if (ga.ga_len > 400)
539856c1110SBram Moolenaar 	    {
540856c1110SBram Moolenaar 		if (ga.ga_len > 8000)
541856c1110SBram Moolenaar 		    ga.ga_growsize = 8000;
542856c1110SBram Moolenaar 		else
543856c1110SBram Moolenaar 		    ga.ga_growsize = ga.ga_len;
544856c1110SBram Moolenaar 	    }
545856c1110SBram Moolenaar 	    ga_concat(&ga, p + 1);
546856c1110SBram Moolenaar 	}
547856c1110SBram Moolenaar     }
548856c1110SBram Moolenaar     ga_append(&ga, NUL);
549856c1110SBram Moolenaar     str = vim_strsave(ga.ga_data);
550856c1110SBram Moolenaar     ga_clear(&ga);
551856c1110SBram Moolenaar 
552856c1110SBram Moolenaar     *idx = i;
553856c1110SBram Moolenaar     return str;
554856c1110SBram Moolenaar }
555856c1110SBram Moolenaar 
556856c1110SBram Moolenaar /*
5574aea03ebSBram Moolenaar  * Execute a yank register: copy it into the stuff buffer.
5584aea03ebSBram Moolenaar  *
5594aea03ebSBram Moolenaar  * Return FAIL for failure, OK otherwise.
5604aea03ebSBram Moolenaar  */
5614aea03ebSBram Moolenaar     int
do_execreg(int regname,int colon,int addcr,int silent)5624aea03ebSBram Moolenaar do_execreg(
5634aea03ebSBram Moolenaar     int	    regname,
5644aea03ebSBram Moolenaar     int	    colon,		// insert ':' before each line
5654aea03ebSBram Moolenaar     int	    addcr,		// always add '\n' to end of line
5664aea03ebSBram Moolenaar     int	    silent)		// set "silent" flag in typeahead buffer
5674aea03ebSBram Moolenaar {
5684aea03ebSBram Moolenaar     long	i;
5694aea03ebSBram Moolenaar     char_u	*p;
5704aea03ebSBram Moolenaar     int		retval = OK;
5714aea03ebSBram Moolenaar     int		remap;
5724aea03ebSBram Moolenaar 
5734aea03ebSBram Moolenaar     // repeat previous one
5744aea03ebSBram Moolenaar     if (regname == '@')
5754aea03ebSBram Moolenaar     {
5764aea03ebSBram Moolenaar 	if (execreg_lastc == NUL)
5774aea03ebSBram Moolenaar 	{
5784aea03ebSBram Moolenaar 	    emsg(_("E748: No previously used register"));
5794aea03ebSBram Moolenaar 	    return FAIL;
5804aea03ebSBram Moolenaar 	}
5814aea03ebSBram Moolenaar 	regname = execreg_lastc;
5824aea03ebSBram Moolenaar     }
5834aea03ebSBram Moolenaar     // check for valid regname
5844aea03ebSBram Moolenaar     if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
5854aea03ebSBram Moolenaar     {
5864aea03ebSBram Moolenaar 	emsg_invreg(regname);
5874aea03ebSBram Moolenaar 	return FAIL;
5884aea03ebSBram Moolenaar     }
5894aea03ebSBram Moolenaar     execreg_lastc = regname;
5904aea03ebSBram Moolenaar 
5914aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
5924aea03ebSBram Moolenaar     regname = may_get_selection(regname);
5934aea03ebSBram Moolenaar #endif
5944aea03ebSBram Moolenaar 
5954aea03ebSBram Moolenaar     // black hole: don't stuff anything
5964aea03ebSBram Moolenaar     if (regname == '_')
5974aea03ebSBram Moolenaar 	return OK;
5984aea03ebSBram Moolenaar 
5994aea03ebSBram Moolenaar     // use last command line
6004aea03ebSBram Moolenaar     if (regname == ':')
6014aea03ebSBram Moolenaar     {
6024aea03ebSBram Moolenaar 	if (last_cmdline == NULL)
6034aea03ebSBram Moolenaar 	{
604e29a27f6SBram Moolenaar 	    emsg(_(e_no_previous_command_line));
6054aea03ebSBram Moolenaar 	    return FAIL;
6064aea03ebSBram Moolenaar 	}
6074aea03ebSBram Moolenaar 	// don't keep the cmdline containing @:
6084aea03ebSBram Moolenaar 	VIM_CLEAR(new_last_cmdline);
6094aea03ebSBram Moolenaar 	// Escape all control characters with a CTRL-V
6104aea03ebSBram Moolenaar 	p = vim_strsave_escaped_ext(last_cmdline,
6114aea03ebSBram Moolenaar 		    (char_u *)"\001\002\003\004\005\006\007"
6124aea03ebSBram Moolenaar 			  "\010\011\012\013\014\015\016\017"
6134aea03ebSBram Moolenaar 			  "\020\021\022\023\024\025\026\027"
6144aea03ebSBram Moolenaar 			  "\030\031\032\033\034\035\036\037",
6154aea03ebSBram Moolenaar 		    Ctrl_V, FALSE);
6164aea03ebSBram Moolenaar 	if (p != NULL)
6174aea03ebSBram Moolenaar 	{
6184aea03ebSBram Moolenaar 	    // When in Visual mode "'<,'>" will be prepended to the command.
6194aea03ebSBram Moolenaar 	    // Remove it when it's already there.
6204aea03ebSBram Moolenaar 	    if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0)
6214aea03ebSBram Moolenaar 		retval = put_in_typebuf(p + 5, TRUE, TRUE, silent);
6224aea03ebSBram Moolenaar 	    else
6234aea03ebSBram Moolenaar 		retval = put_in_typebuf(p, TRUE, TRUE, silent);
6244aea03ebSBram Moolenaar 	}
6254aea03ebSBram Moolenaar 	vim_free(p);
6264aea03ebSBram Moolenaar     }
6274aea03ebSBram Moolenaar #ifdef FEAT_EVAL
6284aea03ebSBram Moolenaar     else if (regname == '=')
6294aea03ebSBram Moolenaar     {
6304aea03ebSBram Moolenaar 	p = get_expr_line();
6314aea03ebSBram Moolenaar 	if (p == NULL)
6324aea03ebSBram Moolenaar 	    return FAIL;
6334aea03ebSBram Moolenaar 	retval = put_in_typebuf(p, TRUE, colon, silent);
6344aea03ebSBram Moolenaar 	vim_free(p);
6354aea03ebSBram Moolenaar     }
6364aea03ebSBram Moolenaar #endif
6374aea03ebSBram Moolenaar     else if (regname == '.')		// use last inserted text
6384aea03ebSBram Moolenaar     {
6394aea03ebSBram Moolenaar 	p = get_last_insert_save();
6404aea03ebSBram Moolenaar 	if (p == NULL)
6414aea03ebSBram Moolenaar 	{
642e29a27f6SBram Moolenaar 	    emsg(_(e_no_inserted_text_yet));
6434aea03ebSBram Moolenaar 	    return FAIL;
6444aea03ebSBram Moolenaar 	}
6454aea03ebSBram Moolenaar 	retval = put_in_typebuf(p, FALSE, colon, silent);
6464aea03ebSBram Moolenaar 	vim_free(p);
6474aea03ebSBram Moolenaar     }
6484aea03ebSBram Moolenaar     else
6494aea03ebSBram Moolenaar     {
6504aea03ebSBram Moolenaar 	get_yank_register(regname, FALSE);
6514aea03ebSBram Moolenaar 	if (y_current->y_array == NULL)
6524aea03ebSBram Moolenaar 	    return FAIL;
6534aea03ebSBram Moolenaar 
6544b96df5aSBram Moolenaar 	// Disallow remapping for ":@r".
6554aea03ebSBram Moolenaar 	remap = colon ? REMAP_NONE : REMAP_YES;
6564aea03ebSBram Moolenaar 
6574aea03ebSBram Moolenaar 	// Insert lines into typeahead buffer, from last one to first one.
6584aea03ebSBram Moolenaar 	put_reedit_in_typebuf(silent);
6594aea03ebSBram Moolenaar 	for (i = y_current->y_size; --i >= 0; )
6604aea03ebSBram Moolenaar 	{
6614aea03ebSBram Moolenaar 	    char_u *escaped;
662856c1110SBram Moolenaar 	    char_u *str;
663856c1110SBram Moolenaar 	    int	    free_str = FALSE;
6644aea03ebSBram Moolenaar 
6654aea03ebSBram Moolenaar 	    // insert NL between lines and after last line if type is MLINE
6664aea03ebSBram Moolenaar 	    if (y_current->y_type == MLINE || i < y_current->y_size - 1
6674aea03ebSBram Moolenaar 								     || addcr)
6684aea03ebSBram Moolenaar 	    {
6694aea03ebSBram Moolenaar 		if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
6704aea03ebSBram Moolenaar 		    return FAIL;
6714aea03ebSBram Moolenaar 	    }
672856c1110SBram Moolenaar 
673856c1110SBram Moolenaar 	    // Handle line-continuation for :@<register>
674856c1110SBram Moolenaar 	    str = y_current->y_array[i];
675856c1110SBram Moolenaar 	    if (colon && i > 0)
676856c1110SBram Moolenaar 	    {
677856c1110SBram Moolenaar 		p = skipwhite(str);
678856c1110SBram Moolenaar 		if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))
679856c1110SBram Moolenaar 		{
680856c1110SBram Moolenaar 		    str = execreg_line_continuation(y_current->y_array, &i);
681856c1110SBram Moolenaar 		    if (str == NULL)
682856c1110SBram Moolenaar 			return FAIL;
683856c1110SBram Moolenaar 		    free_str = TRUE;
684856c1110SBram Moolenaar 		}
685856c1110SBram Moolenaar 	    }
686856c1110SBram Moolenaar 	    escaped = vim_strsave_escape_csi(str);
687856c1110SBram Moolenaar 	    if (free_str)
688856c1110SBram Moolenaar 		vim_free(str);
6894aea03ebSBram Moolenaar 	    if (escaped == NULL)
6904aea03ebSBram Moolenaar 		return FAIL;
6914aea03ebSBram Moolenaar 	    retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
6924aea03ebSBram Moolenaar 	    vim_free(escaped);
6934aea03ebSBram Moolenaar 	    if (retval == FAIL)
6944aea03ebSBram Moolenaar 		return FAIL;
6954aea03ebSBram Moolenaar 	    if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
6964aea03ebSBram Moolenaar 								      == FAIL)
6974aea03ebSBram Moolenaar 		return FAIL;
6984aea03ebSBram Moolenaar 	}
6994aea03ebSBram Moolenaar 	reg_executing = regname == 0 ? '"' : regname; // disable "q" command
7004aea03ebSBram Moolenaar     }
7014aea03ebSBram Moolenaar     return retval;
7024aea03ebSBram Moolenaar }
7034aea03ebSBram Moolenaar 
7044aea03ebSBram Moolenaar /*
7054aea03ebSBram Moolenaar  * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
7064aea03ebSBram Moolenaar  * used only after other typeahead has been processed.
7074aea03ebSBram Moolenaar  */
7084aea03ebSBram Moolenaar     static void
put_reedit_in_typebuf(int silent)7094aea03ebSBram Moolenaar put_reedit_in_typebuf(int silent)
7104aea03ebSBram Moolenaar {
7114aea03ebSBram Moolenaar     char_u	buf[3];
7124aea03ebSBram Moolenaar 
7134aea03ebSBram Moolenaar     if (restart_edit != NUL)
7144aea03ebSBram Moolenaar     {
7154aea03ebSBram Moolenaar 	if (restart_edit == 'V')
7164aea03ebSBram Moolenaar 	{
7174aea03ebSBram Moolenaar 	    buf[0] = 'g';
7184aea03ebSBram Moolenaar 	    buf[1] = 'R';
7194aea03ebSBram Moolenaar 	    buf[2] = NUL;
7204aea03ebSBram Moolenaar 	}
7214aea03ebSBram Moolenaar 	else
7224aea03ebSBram Moolenaar 	{
7234aea03ebSBram Moolenaar 	    buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
7244aea03ebSBram Moolenaar 	    buf[1] = NUL;
7254aea03ebSBram Moolenaar 	}
7264aea03ebSBram Moolenaar 	if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
7274aea03ebSBram Moolenaar 	    restart_edit = NUL;
7284aea03ebSBram Moolenaar     }
7294aea03ebSBram Moolenaar }
7304aea03ebSBram Moolenaar 
7314aea03ebSBram Moolenaar /*
7324aea03ebSBram Moolenaar  * Insert register contents "s" into the typeahead buffer, so that it will be
7334aea03ebSBram Moolenaar  * executed again.
7344aea03ebSBram Moolenaar  * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
7354aea03ebSBram Moolenaar  * no remapping.
7364aea03ebSBram Moolenaar  */
7374aea03ebSBram Moolenaar     static int
put_in_typebuf(char_u * s,int esc,int colon,int silent)7384aea03ebSBram Moolenaar put_in_typebuf(
7394aea03ebSBram Moolenaar     char_u	*s,
7404aea03ebSBram Moolenaar     int		esc,
7414aea03ebSBram Moolenaar     int		colon,	    // add ':' before the line
7424aea03ebSBram Moolenaar     int		silent)
7434aea03ebSBram Moolenaar {
7444aea03ebSBram Moolenaar     int		retval = OK;
7454aea03ebSBram Moolenaar 
7464aea03ebSBram Moolenaar     put_reedit_in_typebuf(silent);
7474aea03ebSBram Moolenaar     if (colon)
7484aea03ebSBram Moolenaar 	retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
7494aea03ebSBram Moolenaar     if (retval == OK)
7504aea03ebSBram Moolenaar     {
7514aea03ebSBram Moolenaar 	char_u	*p;
7524aea03ebSBram Moolenaar 
7534aea03ebSBram Moolenaar 	if (esc)
7544aea03ebSBram Moolenaar 	    p = vim_strsave_escape_csi(s);
7554aea03ebSBram Moolenaar 	else
7564aea03ebSBram Moolenaar 	    p = s;
7574aea03ebSBram Moolenaar 	if (p == NULL)
7584aea03ebSBram Moolenaar 	    retval = FAIL;
7594aea03ebSBram Moolenaar 	else
7604aea03ebSBram Moolenaar 	    retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
7614aea03ebSBram Moolenaar 							     0, TRUE, silent);
7624aea03ebSBram Moolenaar 	if (esc)
7634aea03ebSBram Moolenaar 	    vim_free(p);
7644aea03ebSBram Moolenaar     }
7654aea03ebSBram Moolenaar     if (colon && retval == OK)
7664aea03ebSBram Moolenaar 	retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
7674aea03ebSBram Moolenaar     return retval;
7684aea03ebSBram Moolenaar }
7694aea03ebSBram Moolenaar 
7704aea03ebSBram Moolenaar /*
7714aea03ebSBram Moolenaar  * Insert a yank register: copy it into the Read buffer.
7724aea03ebSBram Moolenaar  * Used by CTRL-R command and middle mouse button in insert mode.
7734aea03ebSBram Moolenaar  *
7744aea03ebSBram Moolenaar  * return FAIL for failure, OK otherwise
7754aea03ebSBram Moolenaar  */
7764aea03ebSBram Moolenaar     int
insert_reg(int regname,int literally_arg)7774aea03ebSBram Moolenaar insert_reg(
7784aea03ebSBram Moolenaar     int		regname,
7794aea03ebSBram Moolenaar     int		literally_arg)	// insert literally, not as if typed
7804aea03ebSBram Moolenaar {
7814aea03ebSBram Moolenaar     long	i;
7824aea03ebSBram Moolenaar     int		retval = OK;
7834aea03ebSBram Moolenaar     char_u	*arg;
7844aea03ebSBram Moolenaar     int		allocated;
7854aea03ebSBram Moolenaar     int		literally = literally_arg;
7864aea03ebSBram Moolenaar 
7874aea03ebSBram Moolenaar     // It is possible to get into an endless loop by having CTRL-R a in
7884aea03ebSBram Moolenaar     // register a and then, in insert mode, doing CTRL-R a.
7894aea03ebSBram Moolenaar     // If you hit CTRL-C, the loop will be broken here.
7904aea03ebSBram Moolenaar     ui_breakcheck();
7914aea03ebSBram Moolenaar     if (got_int)
7924aea03ebSBram Moolenaar 	return FAIL;
7934aea03ebSBram Moolenaar 
7944aea03ebSBram Moolenaar     // check for valid regname
7954aea03ebSBram Moolenaar     if (regname != NUL && !valid_yank_reg(regname, FALSE))
7964aea03ebSBram Moolenaar 	return FAIL;
7974aea03ebSBram Moolenaar 
7984aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
7994aea03ebSBram Moolenaar     regname = may_get_selection(regname);
8004aea03ebSBram Moolenaar #endif
8014aea03ebSBram Moolenaar 
8024aea03ebSBram Moolenaar     if (regname == '.')			// insert last inserted text
8034aea03ebSBram Moolenaar 	retval = stuff_inserted(NUL, 1L, TRUE);
8044aea03ebSBram Moolenaar     else if (get_spec_reg(regname, &arg, &allocated, TRUE))
8054aea03ebSBram Moolenaar     {
8064aea03ebSBram Moolenaar 	if (arg == NULL)
8074aea03ebSBram Moolenaar 	    return FAIL;
8084aea03ebSBram Moolenaar 	stuffescaped(arg, literally);
8094aea03ebSBram Moolenaar 	if (allocated)
8104aea03ebSBram Moolenaar 	    vim_free(arg);
8114aea03ebSBram Moolenaar     }
8124aea03ebSBram Moolenaar     else				// name or number register
8134aea03ebSBram Moolenaar     {
8144aea03ebSBram Moolenaar 	if (get_yank_register(regname, FALSE))
8154aea03ebSBram Moolenaar 	    literally = TRUE;
8164aea03ebSBram Moolenaar 	if (y_current->y_array == NULL)
8174aea03ebSBram Moolenaar 	    retval = FAIL;
8184aea03ebSBram Moolenaar 	else
8194aea03ebSBram Moolenaar 	{
8204aea03ebSBram Moolenaar 	    for (i = 0; i < y_current->y_size; ++i)
8214aea03ebSBram Moolenaar 	    {
822032a2d05SBram Moolenaar 		if (regname == '-')
823032a2d05SBram Moolenaar 		{
824032a2d05SBram Moolenaar 		    AppendCharToRedobuff(Ctrl_R);
825032a2d05SBram Moolenaar 		    AppendCharToRedobuff(regname);
826032a2d05SBram Moolenaar 		    do_put(regname, NULL, BACKWARD, 1L, PUT_CURSEND);
827032a2d05SBram Moolenaar 		}
828032a2d05SBram Moolenaar 		else
8294aea03ebSBram Moolenaar 		    stuffescaped(y_current->y_array[i], literally);
8304aea03ebSBram Moolenaar 		// Insert a newline between lines and after last line if
8314aea03ebSBram Moolenaar 		// y_type is MLINE.
8324aea03ebSBram Moolenaar 		if (y_current->y_type == MLINE || i < y_current->y_size - 1)
8334aea03ebSBram Moolenaar 		    stuffcharReadbuff('\n');
8344aea03ebSBram Moolenaar 	    }
8354aea03ebSBram Moolenaar 	}
8364aea03ebSBram Moolenaar     }
8374aea03ebSBram Moolenaar 
8384aea03ebSBram Moolenaar     return retval;
8394aea03ebSBram Moolenaar }
8404aea03ebSBram Moolenaar 
8414aea03ebSBram Moolenaar /*
8424aea03ebSBram Moolenaar  * If "regname" is a special register, return TRUE and store a pointer to its
8434aea03ebSBram Moolenaar  * value in "argp".
8444aea03ebSBram Moolenaar  */
8454aea03ebSBram Moolenaar     int
get_spec_reg(int regname,char_u ** argp,int * allocated,int errmsg)8464aea03ebSBram Moolenaar get_spec_reg(
8474aea03ebSBram Moolenaar     int		regname,
8484aea03ebSBram Moolenaar     char_u	**argp,
8494aea03ebSBram Moolenaar     int		*allocated,	// return: TRUE when value was allocated
8504aea03ebSBram Moolenaar     int		errmsg)		// give error message when failing
8514aea03ebSBram Moolenaar {
8524aea03ebSBram Moolenaar     int		cnt;
8534aea03ebSBram Moolenaar 
8544aea03ebSBram Moolenaar     *argp = NULL;
8554aea03ebSBram Moolenaar     *allocated = FALSE;
8564aea03ebSBram Moolenaar     switch (regname)
8574aea03ebSBram Moolenaar     {
8584aea03ebSBram Moolenaar 	case '%':		// file name
8594aea03ebSBram Moolenaar 	    if (errmsg)
8604aea03ebSBram Moolenaar 		check_fname();	// will give emsg if not set
8614aea03ebSBram Moolenaar 	    *argp = curbuf->b_fname;
8624aea03ebSBram Moolenaar 	    return TRUE;
8634aea03ebSBram Moolenaar 
8644aea03ebSBram Moolenaar 	case '#':		// alternate file name
8654aea03ebSBram Moolenaar 	    *argp = getaltfname(errmsg);	// may give emsg if not set
8664aea03ebSBram Moolenaar 	    return TRUE;
8674aea03ebSBram Moolenaar 
8684aea03ebSBram Moolenaar #ifdef FEAT_EVAL
8694aea03ebSBram Moolenaar 	case '=':		// result of expression
8704aea03ebSBram Moolenaar 	    *argp = get_expr_line();
8714aea03ebSBram Moolenaar 	    *allocated = TRUE;
8724aea03ebSBram Moolenaar 	    return TRUE;
8734aea03ebSBram Moolenaar #endif
8744aea03ebSBram Moolenaar 
8754aea03ebSBram Moolenaar 	case ':':		// last command line
8764aea03ebSBram Moolenaar 	    if (last_cmdline == NULL && errmsg)
877e29a27f6SBram Moolenaar 		emsg(_(e_no_previous_command_line));
8784aea03ebSBram Moolenaar 	    *argp = last_cmdline;
8794aea03ebSBram Moolenaar 	    return TRUE;
8804aea03ebSBram Moolenaar 
8814aea03ebSBram Moolenaar 	case '/':		// last search-pattern
8824aea03ebSBram Moolenaar 	    if (last_search_pat() == NULL && errmsg)
883e29a27f6SBram Moolenaar 		emsg(_(e_no_previous_regular_expression));
8844aea03ebSBram Moolenaar 	    *argp = last_search_pat();
8854aea03ebSBram Moolenaar 	    return TRUE;
8864aea03ebSBram Moolenaar 
8874aea03ebSBram Moolenaar 	case '.':		// last inserted text
8884aea03ebSBram Moolenaar 	    *argp = get_last_insert_save();
8894aea03ebSBram Moolenaar 	    *allocated = TRUE;
8904aea03ebSBram Moolenaar 	    if (*argp == NULL && errmsg)
891e29a27f6SBram Moolenaar 		emsg(_(e_no_inserted_text_yet));
8924aea03ebSBram Moolenaar 	    return TRUE;
8934aea03ebSBram Moolenaar 
8944aea03ebSBram Moolenaar #ifdef FEAT_SEARCHPATH
8954aea03ebSBram Moolenaar 	case Ctrl_F:		// Filename under cursor
8964aea03ebSBram Moolenaar 	case Ctrl_P:		// Path under cursor, expand via "path"
8974aea03ebSBram Moolenaar 	    if (!errmsg)
8984aea03ebSBram Moolenaar 		return FALSE;
8994aea03ebSBram Moolenaar 	    *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP
9004aea03ebSBram Moolenaar 			    | (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL);
9014aea03ebSBram Moolenaar 	    *allocated = TRUE;
9024aea03ebSBram Moolenaar 	    return TRUE;
9034aea03ebSBram Moolenaar #endif
9044aea03ebSBram Moolenaar 
9054aea03ebSBram Moolenaar 	case Ctrl_W:		// word under cursor
9064aea03ebSBram Moolenaar 	case Ctrl_A:		// WORD (mnemonic All) under cursor
9074aea03ebSBram Moolenaar 	    if (!errmsg)
9084aea03ebSBram Moolenaar 		return FALSE;
9094aea03ebSBram Moolenaar 	    cnt = find_ident_under_cursor(argp, regname == Ctrl_W
9104aea03ebSBram Moolenaar 				   ?  (FIND_IDENT|FIND_STRING) : FIND_STRING);
9114aea03ebSBram Moolenaar 	    *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
9124aea03ebSBram Moolenaar 	    *allocated = TRUE;
9134aea03ebSBram Moolenaar 	    return TRUE;
9144aea03ebSBram Moolenaar 
9154aea03ebSBram Moolenaar 	case Ctrl_L:		// Line under cursor
9164aea03ebSBram Moolenaar 	    if (!errmsg)
9174aea03ebSBram Moolenaar 		return FALSE;
9184aea03ebSBram Moolenaar 
9194aea03ebSBram Moolenaar 	    *argp = ml_get_buf(curwin->w_buffer,
9204aea03ebSBram Moolenaar 			curwin->w_cursor.lnum, FALSE);
9214aea03ebSBram Moolenaar 	    return TRUE;
9224aea03ebSBram Moolenaar 
9234aea03ebSBram Moolenaar 	case '_':		// black hole: always empty
9244aea03ebSBram Moolenaar 	    *argp = (char_u *)"";
9254aea03ebSBram Moolenaar 	    return TRUE;
9264aea03ebSBram Moolenaar     }
9274aea03ebSBram Moolenaar 
9284aea03ebSBram Moolenaar     return FALSE;
9294aea03ebSBram Moolenaar }
9304aea03ebSBram Moolenaar 
9314aea03ebSBram Moolenaar /*
9324aea03ebSBram Moolenaar  * Paste a yank register into the command line.
9334aea03ebSBram Moolenaar  * Only for non-special registers.
9344aea03ebSBram Moolenaar  * Used by CTRL-R command in command-line mode
9354aea03ebSBram Moolenaar  * insert_reg() can't be used here, because special characters from the
9364aea03ebSBram Moolenaar  * register contents will be interpreted as commands.
9374aea03ebSBram Moolenaar  *
9384aea03ebSBram Moolenaar  * return FAIL for failure, OK otherwise
9394aea03ebSBram Moolenaar  */
9404aea03ebSBram Moolenaar     int
cmdline_paste_reg(int regname,int literally_arg,int remcr)9414aea03ebSBram Moolenaar cmdline_paste_reg(
9424aea03ebSBram Moolenaar     int regname,
9434aea03ebSBram Moolenaar     int literally_arg,	// Insert text literally instead of "as typed"
9444aea03ebSBram Moolenaar     int remcr)		// don't add CR characters
9454aea03ebSBram Moolenaar {
9464aea03ebSBram Moolenaar     long	i;
9474aea03ebSBram Moolenaar     int		literally = literally_arg;
9484aea03ebSBram Moolenaar 
9494aea03ebSBram Moolenaar     if (get_yank_register(regname, FALSE))
9504aea03ebSBram Moolenaar 	literally = TRUE;
9514aea03ebSBram Moolenaar     if (y_current->y_array == NULL)
9524aea03ebSBram Moolenaar 	return FAIL;
9534aea03ebSBram Moolenaar 
9544aea03ebSBram Moolenaar     for (i = 0; i < y_current->y_size; ++i)
9554aea03ebSBram Moolenaar     {
9564aea03ebSBram Moolenaar 	cmdline_paste_str(y_current->y_array[i], literally);
9574aea03ebSBram Moolenaar 
9584aea03ebSBram Moolenaar 	// Insert ^M between lines and after last line if type is MLINE.
9594aea03ebSBram Moolenaar 	// Don't do this when "remcr" is TRUE.
9604aea03ebSBram Moolenaar 	if ((y_current->y_type == MLINE || i < y_current->y_size - 1) && !remcr)
9614aea03ebSBram Moolenaar 	    cmdline_paste_str((char_u *)"\r", literally);
9624aea03ebSBram Moolenaar 
9634aea03ebSBram Moolenaar 	// Check for CTRL-C, in case someone tries to paste a few thousand
9644aea03ebSBram Moolenaar 	// lines and gets bored.
9654aea03ebSBram Moolenaar 	ui_breakcheck();
9664aea03ebSBram Moolenaar 	if (got_int)
9674aea03ebSBram Moolenaar 	    return FAIL;
9684aea03ebSBram Moolenaar     }
9694aea03ebSBram Moolenaar     return OK;
9704aea03ebSBram Moolenaar }
9714aea03ebSBram Moolenaar 
9724aea03ebSBram Moolenaar /*
9734aea03ebSBram Moolenaar  * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
9744aea03ebSBram Moolenaar  */
9754aea03ebSBram Moolenaar     void
shift_delete_registers()9764aea03ebSBram Moolenaar shift_delete_registers()
9774aea03ebSBram Moolenaar {
9784aea03ebSBram Moolenaar     int		n;
9794aea03ebSBram Moolenaar 
9804aea03ebSBram Moolenaar     y_current = &y_regs[9];
9814aea03ebSBram Moolenaar     free_yank_all();			// free register nine
9824aea03ebSBram Moolenaar     for (n = 9; n > 1; --n)
9834aea03ebSBram Moolenaar 	y_regs[n] = y_regs[n - 1];
9844aea03ebSBram Moolenaar     y_current = &y_regs[1];
9854aea03ebSBram Moolenaar     if (!y_append)
9864aea03ebSBram Moolenaar 	y_previous = y_current;
9874aea03ebSBram Moolenaar     y_regs[1].y_array = NULL;		// set register one to empty
9884aea03ebSBram Moolenaar }
9894aea03ebSBram Moolenaar 
9904aea03ebSBram Moolenaar #if defined(FEAT_EVAL)
9914aea03ebSBram Moolenaar     void
yank_do_autocmd(oparg_T * oap,yankreg_T * reg)9924aea03ebSBram Moolenaar yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
9934aea03ebSBram Moolenaar {
9944aea03ebSBram Moolenaar     static int	    recursive = FALSE;
9954aea03ebSBram Moolenaar     dict_T	    *v_event;
9964aea03ebSBram Moolenaar     list_T	    *list;
9974aea03ebSBram Moolenaar     int		    n;
9984aea03ebSBram Moolenaar     char_u	    buf[NUMBUFLEN + 2];
9994aea03ebSBram Moolenaar     long	    reglen = 0;
1000*3075a455SBram Moolenaar     save_v_event_T  save_v_event;
10014aea03ebSBram Moolenaar 
10024aea03ebSBram Moolenaar     if (recursive)
10034aea03ebSBram Moolenaar 	return;
10044aea03ebSBram Moolenaar 
1005*3075a455SBram Moolenaar     v_event = get_v_event(&save_v_event);
10064aea03ebSBram Moolenaar 
10074aea03ebSBram Moolenaar     list = list_alloc();
10084aea03ebSBram Moolenaar     if (list == NULL)
10094aea03ebSBram Moolenaar 	return;
10104aea03ebSBram Moolenaar     for (n = 0; n < reg->y_size; n++)
10114aea03ebSBram Moolenaar 	list_append_string(list, reg->y_array[n], -1);
10124aea03ebSBram Moolenaar     list->lv_lock = VAR_FIXED;
10136d90c61cSBram Moolenaar     (void)dict_add_list(v_event, "regcontents", list);
10144aea03ebSBram Moolenaar 
10154aea03ebSBram Moolenaar     buf[0] = (char_u)oap->regname;
10164aea03ebSBram Moolenaar     buf[1] = NUL;
10176d90c61cSBram Moolenaar     (void)dict_add_string(v_event, "regname", buf);
10184aea03ebSBram Moolenaar 
10194aea03ebSBram Moolenaar     buf[0] = get_op_char(oap->op_type);
10204aea03ebSBram Moolenaar     buf[1] = get_extra_op_char(oap->op_type);
10214aea03ebSBram Moolenaar     buf[2] = NUL;
10226d90c61cSBram Moolenaar     (void)dict_add_string(v_event, "operator", buf);
10234aea03ebSBram Moolenaar 
10244aea03ebSBram Moolenaar     buf[0] = NUL;
10254aea03ebSBram Moolenaar     buf[1] = NUL;
10264aea03ebSBram Moolenaar     switch (get_reg_type(oap->regname, &reglen))
10274aea03ebSBram Moolenaar     {
10284aea03ebSBram Moolenaar 	case MLINE: buf[0] = 'V'; break;
10294aea03ebSBram Moolenaar 	case MCHAR: buf[0] = 'v'; break;
10304aea03ebSBram Moolenaar 	case MBLOCK:
10314aea03ebSBram Moolenaar 		vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
10324aea03ebSBram Moolenaar 			     reglen + 1);
10334aea03ebSBram Moolenaar 		break;
10344aea03ebSBram Moolenaar     }
10356d90c61cSBram Moolenaar     (void)dict_add_string(v_event, "regtype", buf);
10364aea03ebSBram Moolenaar 
10376d90c61cSBram Moolenaar     (void)dict_add_bool(v_event, "visual", oap->is_VIsual);
103837d1673cSBram Moolenaar 
10394aea03ebSBram Moolenaar     // Lock the dictionary and its keys
10404aea03ebSBram Moolenaar     dict_set_items_ro(v_event);
10414aea03ebSBram Moolenaar 
10424aea03ebSBram Moolenaar     recursive = TRUE;
10436adb9ea0SBram Moolenaar     textwinlock++;
10444aea03ebSBram Moolenaar     apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
10456adb9ea0SBram Moolenaar     textwinlock--;
10464aea03ebSBram Moolenaar     recursive = FALSE;
10474aea03ebSBram Moolenaar 
10484aea03ebSBram Moolenaar     // Empty the dictionary, v:event is still valid
1049*3075a455SBram Moolenaar     restore_v_event(v_event, &save_v_event);
10504aea03ebSBram Moolenaar }
10514aea03ebSBram Moolenaar #endif
10524aea03ebSBram Moolenaar 
10534aea03ebSBram Moolenaar /*
10544aea03ebSBram Moolenaar  * set all the yank registers to empty (called from main())
10554aea03ebSBram Moolenaar  */
10564aea03ebSBram Moolenaar     void
init_yank(void)10574aea03ebSBram Moolenaar init_yank(void)
10584aea03ebSBram Moolenaar {
10594aea03ebSBram Moolenaar     int		i;
10604aea03ebSBram Moolenaar 
10614aea03ebSBram Moolenaar     for (i = 0; i < NUM_REGISTERS; ++i)
10624aea03ebSBram Moolenaar 	y_regs[i].y_array = NULL;
10634aea03ebSBram Moolenaar }
10644aea03ebSBram Moolenaar 
10654aea03ebSBram Moolenaar #if defined(EXITFREE) || defined(PROTO)
10664aea03ebSBram Moolenaar     void
clear_registers(void)10674aea03ebSBram Moolenaar clear_registers(void)
10684aea03ebSBram Moolenaar {
10694aea03ebSBram Moolenaar     int		i;
10704aea03ebSBram Moolenaar 
10714aea03ebSBram Moolenaar     for (i = 0; i < NUM_REGISTERS; ++i)
10724aea03ebSBram Moolenaar     {
10734aea03ebSBram Moolenaar 	y_current = &y_regs[i];
10744aea03ebSBram Moolenaar 	if (y_current->y_array != NULL)
10754aea03ebSBram Moolenaar 	    free_yank_all();
10764aea03ebSBram Moolenaar     }
10774aea03ebSBram Moolenaar }
10784aea03ebSBram Moolenaar #endif
10794aea03ebSBram Moolenaar 
10804aea03ebSBram Moolenaar /*
10814aea03ebSBram Moolenaar  * Free "n" lines from the current yank register.
10824aea03ebSBram Moolenaar  * Called for normal freeing and in case of error.
10834aea03ebSBram Moolenaar  */
10844aea03ebSBram Moolenaar     static void
free_yank(long n)10854aea03ebSBram Moolenaar free_yank(long n)
10864aea03ebSBram Moolenaar {
10874aea03ebSBram Moolenaar     if (y_current->y_array != NULL)
10884aea03ebSBram Moolenaar     {
10894aea03ebSBram Moolenaar 	long	    i;
10904aea03ebSBram Moolenaar 
10914aea03ebSBram Moolenaar 	for (i = n; --i >= 0; )
10924aea03ebSBram Moolenaar 	{
10934aea03ebSBram Moolenaar #ifdef AMIGA	    // only for very slow machines
10944aea03ebSBram Moolenaar 	    if ((i & 1023) == 1023)  // this may take a while
10954aea03ebSBram Moolenaar 	    {
10964aea03ebSBram Moolenaar 		// This message should never cause a hit-return message.
10974aea03ebSBram Moolenaar 		// Overwrite this message with any next message.
10984aea03ebSBram Moolenaar 		++no_wait_return;
10994aea03ebSBram Moolenaar 		smsg(_("freeing %ld lines"), i + 1);
11004aea03ebSBram Moolenaar 		--no_wait_return;
11014aea03ebSBram Moolenaar 		msg_didout = FALSE;
11024aea03ebSBram Moolenaar 		msg_col = 0;
11034aea03ebSBram Moolenaar 	    }
11044aea03ebSBram Moolenaar #endif
11054aea03ebSBram Moolenaar 	    vim_free(y_current->y_array[i]);
11064aea03ebSBram Moolenaar 	}
11074aea03ebSBram Moolenaar 	VIM_CLEAR(y_current->y_array);
11084aea03ebSBram Moolenaar #ifdef AMIGA
11094aea03ebSBram Moolenaar 	if (n >= 1000)
11104aea03ebSBram Moolenaar 	    msg("");
11114aea03ebSBram Moolenaar #endif
11124aea03ebSBram Moolenaar     }
11134aea03ebSBram Moolenaar }
11144aea03ebSBram Moolenaar 
111545fffdf1SBram Moolenaar     void
free_yank_all(void)11164aea03ebSBram Moolenaar free_yank_all(void)
11174aea03ebSBram Moolenaar {
11184aea03ebSBram Moolenaar     free_yank(y_current->y_size);
11194aea03ebSBram Moolenaar }
11204aea03ebSBram Moolenaar 
11214aea03ebSBram Moolenaar /*
11224aea03ebSBram Moolenaar  * Yank the text between "oap->start" and "oap->end" into a yank register.
11234aea03ebSBram Moolenaar  * If we are to append (uppercase register), we first yank into a new yank
11244aea03ebSBram Moolenaar  * register and then concatenate the old and the new one (so we keep the old
11254aea03ebSBram Moolenaar  * one in case of out-of-memory).
11264aea03ebSBram Moolenaar  *
11274aea03ebSBram Moolenaar  * Return FAIL for failure, OK otherwise.
11284aea03ebSBram Moolenaar  */
11294aea03ebSBram Moolenaar     int
op_yank(oparg_T * oap,int deleting,int mess)11304aea03ebSBram Moolenaar op_yank(oparg_T *oap, int deleting, int mess)
11314aea03ebSBram Moolenaar {
11324aea03ebSBram Moolenaar     long		y_idx;		// index in y_array[]
11334aea03ebSBram Moolenaar     yankreg_T		*curr;		// copy of y_current
11344aea03ebSBram Moolenaar     yankreg_T		newreg;		// new yank register when appending
11354aea03ebSBram Moolenaar     char_u		**new_ptr;
11364aea03ebSBram Moolenaar     linenr_T		lnum;		// current line number
11374aea03ebSBram Moolenaar     long		j;
11384aea03ebSBram Moolenaar     int			yanktype = oap->motion_type;
11394aea03ebSBram Moolenaar     long		yanklines = oap->line_count;
11404aea03ebSBram Moolenaar     linenr_T		yankendlnum = oap->end.lnum;
11414aea03ebSBram Moolenaar     char_u		*p;
11424aea03ebSBram Moolenaar     char_u		*pnew;
11434aea03ebSBram Moolenaar     struct block_def	bd;
11444aea03ebSBram Moolenaar #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
11454aea03ebSBram Moolenaar     int			did_star = FALSE;
11464aea03ebSBram Moolenaar #endif
11474aea03ebSBram Moolenaar 
11484aea03ebSBram Moolenaar 				    // check for read-only register
11494aea03ebSBram Moolenaar     if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
11504aea03ebSBram Moolenaar     {
11514aea03ebSBram Moolenaar 	beep_flush();
11524aea03ebSBram Moolenaar 	return FAIL;
11534aea03ebSBram Moolenaar     }
11544aea03ebSBram Moolenaar     if (oap->regname == '_')	    // black hole: nothing to do
11554aea03ebSBram Moolenaar 	return OK;
11564aea03ebSBram Moolenaar 
11574aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
11584aea03ebSBram Moolenaar     if (!clip_star.available && oap->regname == '*')
11594aea03ebSBram Moolenaar 	oap->regname = 0;
11604aea03ebSBram Moolenaar     else if (!clip_plus.available && oap->regname == '+')
11614aea03ebSBram Moolenaar 	oap->regname = 0;
11624aea03ebSBram Moolenaar #endif
11634aea03ebSBram Moolenaar 
11644aea03ebSBram Moolenaar     if (!deleting)		    // op_delete() already set y_current
11654aea03ebSBram Moolenaar 	get_yank_register(oap->regname, TRUE);
11664aea03ebSBram Moolenaar 
11674aea03ebSBram Moolenaar     curr = y_current;
11684aea03ebSBram Moolenaar 				    // append to existing contents
11694aea03ebSBram Moolenaar     if (y_append && y_current->y_array != NULL)
11704aea03ebSBram Moolenaar 	y_current = &newreg;
11714aea03ebSBram Moolenaar     else
11724aea03ebSBram Moolenaar 	free_yank_all();	    // free previously yanked lines
11734aea03ebSBram Moolenaar 
11744aea03ebSBram Moolenaar     // If the cursor was in column 1 before and after the movement, and the
11754aea03ebSBram Moolenaar     // operator is not inclusive, the yank is always linewise.
11764aea03ebSBram Moolenaar     if (       oap->motion_type == MCHAR
11774aea03ebSBram Moolenaar 	    && oap->start.col == 0
11784aea03ebSBram Moolenaar 	    && !oap->inclusive
11794aea03ebSBram Moolenaar 	    && (!oap->is_VIsual || *p_sel == 'o')
11804aea03ebSBram Moolenaar 	    && !oap->block_mode
11814aea03ebSBram Moolenaar 	    && oap->end.col == 0
11824aea03ebSBram Moolenaar 	    && yanklines > 1)
11834aea03ebSBram Moolenaar     {
11844aea03ebSBram Moolenaar 	yanktype = MLINE;
11854aea03ebSBram Moolenaar 	--yankendlnum;
11864aea03ebSBram Moolenaar 	--yanklines;
11874aea03ebSBram Moolenaar     }
11884aea03ebSBram Moolenaar 
11894aea03ebSBram Moolenaar     y_current->y_size = yanklines;
11904aea03ebSBram Moolenaar     y_current->y_type = yanktype;   // set the yank register type
11914aea03ebSBram Moolenaar     y_current->y_width = 0;
11924aea03ebSBram Moolenaar     y_current->y_array = lalloc_clear(sizeof(char_u *) * yanklines, TRUE);
11934aea03ebSBram Moolenaar     if (y_current->y_array == NULL)
11944aea03ebSBram Moolenaar     {
11954aea03ebSBram Moolenaar 	y_current = curr;
11964aea03ebSBram Moolenaar 	return FAIL;
11974aea03ebSBram Moolenaar     }
11984aea03ebSBram Moolenaar #ifdef FEAT_VIMINFO
11994aea03ebSBram Moolenaar     y_current->y_time_set = vim_time();
12004aea03ebSBram Moolenaar #endif
12014aea03ebSBram Moolenaar 
12024aea03ebSBram Moolenaar     y_idx = 0;
12034aea03ebSBram Moolenaar     lnum = oap->start.lnum;
12044aea03ebSBram Moolenaar 
12054aea03ebSBram Moolenaar     if (oap->block_mode)
12064aea03ebSBram Moolenaar     {
12074aea03ebSBram Moolenaar 	// Visual block mode
12084aea03ebSBram Moolenaar 	y_current->y_type = MBLOCK;	    // set the yank register type
12094aea03ebSBram Moolenaar 	y_current->y_width = oap->end_vcol - oap->start_vcol;
12104aea03ebSBram Moolenaar 
12114aea03ebSBram Moolenaar 	if (curwin->w_curswant == MAXCOL && y_current->y_width > 0)
12124aea03ebSBram Moolenaar 	    y_current->y_width--;
12134aea03ebSBram Moolenaar     }
12144aea03ebSBram Moolenaar 
12154aea03ebSBram Moolenaar     for ( ; lnum <= yankendlnum; lnum++, y_idx++)
12164aea03ebSBram Moolenaar     {
12174aea03ebSBram Moolenaar 	switch (y_current->y_type)
12184aea03ebSBram Moolenaar 	{
12194aea03ebSBram Moolenaar 	    case MBLOCK:
12204aea03ebSBram Moolenaar 		block_prep(oap, &bd, lnum, FALSE);
1221544a38e4SChristian Brabandt 		if (yank_copy_line(&bd, y_idx, oap->excl_tr_ws) == FAIL)
12224aea03ebSBram Moolenaar 		    goto fail;
12234aea03ebSBram Moolenaar 		break;
12244aea03ebSBram Moolenaar 
12254aea03ebSBram Moolenaar 	    case MLINE:
12264aea03ebSBram Moolenaar 		if ((y_current->y_array[y_idx] =
12274aea03ebSBram Moolenaar 					    vim_strsave(ml_get(lnum))) == NULL)
12284aea03ebSBram Moolenaar 		    goto fail;
12294aea03ebSBram Moolenaar 		break;
12304aea03ebSBram Moolenaar 
12314aea03ebSBram Moolenaar 	    case MCHAR:
12324aea03ebSBram Moolenaar 		{
12334aea03ebSBram Moolenaar 		    colnr_T startcol = 0, endcol = MAXCOL;
12344aea03ebSBram Moolenaar 		    int	    is_oneChar = FALSE;
12354aea03ebSBram Moolenaar 		    colnr_T cs, ce;
12364aea03ebSBram Moolenaar 
12374aea03ebSBram Moolenaar 		    p = ml_get(lnum);
12384aea03ebSBram Moolenaar 		    bd.startspaces = 0;
12394aea03ebSBram Moolenaar 		    bd.endspaces = 0;
12404aea03ebSBram Moolenaar 
12414aea03ebSBram Moolenaar 		    if (lnum == oap->start.lnum)
12424aea03ebSBram Moolenaar 		    {
12434aea03ebSBram Moolenaar 			startcol = oap->start.col;
12444aea03ebSBram Moolenaar 			if (virtual_op)
12454aea03ebSBram Moolenaar 			{
12464aea03ebSBram Moolenaar 			    getvcol(curwin, &oap->start, &cs, NULL, &ce);
12474aea03ebSBram Moolenaar 			    if (ce != cs && oap->start.coladd > 0)
12484aea03ebSBram Moolenaar 			    {
12494aea03ebSBram Moolenaar 				// Part of a tab selected -- but don't
12504aea03ebSBram Moolenaar 				// double-count it.
12514aea03ebSBram Moolenaar 				bd.startspaces = (ce - cs + 1)
12524aea03ebSBram Moolenaar 							  - oap->start.coladd;
12534aea03ebSBram Moolenaar 				startcol++;
12544aea03ebSBram Moolenaar 			    }
12554aea03ebSBram Moolenaar 			}
12564aea03ebSBram Moolenaar 		    }
12574aea03ebSBram Moolenaar 
12584aea03ebSBram Moolenaar 		    if (lnum == oap->end.lnum)
12594aea03ebSBram Moolenaar 		    {
12604aea03ebSBram Moolenaar 			endcol = oap->end.col;
12614aea03ebSBram Moolenaar 			if (virtual_op)
12624aea03ebSBram Moolenaar 			{
12634aea03ebSBram Moolenaar 			    getvcol(curwin, &oap->end, &cs, NULL, &ce);
12644aea03ebSBram Moolenaar 			    if (p[endcol] == NUL || (cs + oap->end.coladd < ce
12654aea03ebSBram Moolenaar 					// Don't add space for double-wide
12664aea03ebSBram Moolenaar 					// char; endcol will be on last byte
12674aea03ebSBram Moolenaar 					// of multi-byte char.
12684aea03ebSBram Moolenaar 					&& (*mb_head_off)(p, p + endcol) == 0))
12694aea03ebSBram Moolenaar 			    {
12704aea03ebSBram Moolenaar 				if (oap->start.lnum == oap->end.lnum
12714aea03ebSBram Moolenaar 					    && oap->start.col == oap->end.col)
12724aea03ebSBram Moolenaar 				{
12734aea03ebSBram Moolenaar 				    // Special case: inside a single char
12744aea03ebSBram Moolenaar 				    is_oneChar = TRUE;
12754aea03ebSBram Moolenaar 				    bd.startspaces = oap->end.coladd
12764aea03ebSBram Moolenaar 					 - oap->start.coladd + oap->inclusive;
12774aea03ebSBram Moolenaar 				    endcol = startcol;
12784aea03ebSBram Moolenaar 				}
12794aea03ebSBram Moolenaar 				else
12804aea03ebSBram Moolenaar 				{
12814aea03ebSBram Moolenaar 				    bd.endspaces = oap->end.coladd
12824aea03ebSBram Moolenaar 							     + oap->inclusive;
12834aea03ebSBram Moolenaar 				    endcol -= oap->inclusive;
12844aea03ebSBram Moolenaar 				}
12854aea03ebSBram Moolenaar 			    }
12864aea03ebSBram Moolenaar 			}
12874aea03ebSBram Moolenaar 		    }
12884aea03ebSBram Moolenaar 		    if (endcol == MAXCOL)
12894aea03ebSBram Moolenaar 			endcol = (colnr_T)STRLEN(p);
12904aea03ebSBram Moolenaar 		    if (startcol > endcol || is_oneChar)
12914aea03ebSBram Moolenaar 			bd.textlen = 0;
12924aea03ebSBram Moolenaar 		    else
12934aea03ebSBram Moolenaar 			bd.textlen = endcol - startcol + oap->inclusive;
12944aea03ebSBram Moolenaar 		    bd.textstart = p + startcol;
1295544a38e4SChristian Brabandt 		    if (yank_copy_line(&bd, y_idx, FALSE) == FAIL)
12964aea03ebSBram Moolenaar 			goto fail;
12974aea03ebSBram Moolenaar 		    break;
12984aea03ebSBram Moolenaar 		}
12994aea03ebSBram Moolenaar 		// NOTREACHED
13004aea03ebSBram Moolenaar 	}
13014aea03ebSBram Moolenaar     }
13024aea03ebSBram Moolenaar 
13034aea03ebSBram Moolenaar     if (curr != y_current)	// append the new block to the old block
13044aea03ebSBram Moolenaar     {
13054aea03ebSBram Moolenaar 	new_ptr = ALLOC_MULT(char_u *, curr->y_size + y_current->y_size);
13064aea03ebSBram Moolenaar 	if (new_ptr == NULL)
13074aea03ebSBram Moolenaar 	    goto fail;
13084aea03ebSBram Moolenaar 	for (j = 0; j < curr->y_size; ++j)
13094aea03ebSBram Moolenaar 	    new_ptr[j] = curr->y_array[j];
13104aea03ebSBram Moolenaar 	vim_free(curr->y_array);
13114aea03ebSBram Moolenaar 	curr->y_array = new_ptr;
13124aea03ebSBram Moolenaar #ifdef FEAT_VIMINFO
13134aea03ebSBram Moolenaar 	curr->y_time_set = vim_time();
13144aea03ebSBram Moolenaar #endif
13154aea03ebSBram Moolenaar 
13164aea03ebSBram Moolenaar 	if (yanktype == MLINE)	// MLINE overrides MCHAR and MBLOCK
13174aea03ebSBram Moolenaar 	    curr->y_type = MLINE;
13184aea03ebSBram Moolenaar 
13194aea03ebSBram Moolenaar 	// Concatenate the last line of the old block with the first line of
13204aea03ebSBram Moolenaar 	// the new block, unless being Vi compatible.
13214aea03ebSBram Moolenaar 	if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL)
13224aea03ebSBram Moolenaar 	{
13234aea03ebSBram Moolenaar 	    pnew = alloc(STRLEN(curr->y_array[curr->y_size - 1])
13244aea03ebSBram Moolenaar 					  + STRLEN(y_current->y_array[0]) + 1);
13254aea03ebSBram Moolenaar 	    if (pnew == NULL)
13264aea03ebSBram Moolenaar 	    {
13274aea03ebSBram Moolenaar 		y_idx = y_current->y_size - 1;
13284aea03ebSBram Moolenaar 		goto fail;
13294aea03ebSBram Moolenaar 	    }
13304aea03ebSBram Moolenaar 	    STRCPY(pnew, curr->y_array[--j]);
13314aea03ebSBram Moolenaar 	    STRCAT(pnew, y_current->y_array[0]);
13324aea03ebSBram Moolenaar 	    vim_free(curr->y_array[j]);
13334aea03ebSBram Moolenaar 	    vim_free(y_current->y_array[0]);
13344aea03ebSBram Moolenaar 	    curr->y_array[j++] = pnew;
13354aea03ebSBram Moolenaar 	    y_idx = 1;
13364aea03ebSBram Moolenaar 	}
13374aea03ebSBram Moolenaar 	else
13384aea03ebSBram Moolenaar 	    y_idx = 0;
13394aea03ebSBram Moolenaar 	while (y_idx < y_current->y_size)
13404aea03ebSBram Moolenaar 	    curr->y_array[j++] = y_current->y_array[y_idx++];
13414aea03ebSBram Moolenaar 	curr->y_size = j;
13424aea03ebSBram Moolenaar 	vim_free(y_current->y_array);
13434aea03ebSBram Moolenaar 	y_current = curr;
13444aea03ebSBram Moolenaar     }
13454aea03ebSBram Moolenaar     if (curwin->w_p_rnu)
13464aea03ebSBram Moolenaar 	redraw_later(SOME_VALID);	// cursor moved to start
13474aea03ebSBram Moolenaar     if (mess)			// Display message about yank?
13484aea03ebSBram Moolenaar     {
13494aea03ebSBram Moolenaar 	if (yanktype == MCHAR
13504aea03ebSBram Moolenaar 		&& !oap->block_mode
13514aea03ebSBram Moolenaar 		&& yanklines == 1)
13524aea03ebSBram Moolenaar 	    yanklines = 0;
13534aea03ebSBram Moolenaar 	// Some versions of Vi use ">=" here, some don't...
13544aea03ebSBram Moolenaar 	if (yanklines > p_report)
13554aea03ebSBram Moolenaar 	{
13564aea03ebSBram Moolenaar 	    char namebuf[100];
13574aea03ebSBram Moolenaar 
13584aea03ebSBram Moolenaar 	    if (oap->regname == NUL)
13594aea03ebSBram Moolenaar 		*namebuf = NUL;
13604aea03ebSBram Moolenaar 	    else
13614aea03ebSBram Moolenaar 		vim_snprintf(namebuf, sizeof(namebuf),
13624aea03ebSBram Moolenaar 						_(" into \"%c"), oap->regname);
13634aea03ebSBram Moolenaar 
13644aea03ebSBram Moolenaar 	    // redisplay now, so message is not deleted
13654aea03ebSBram Moolenaar 	    update_topline_redraw();
13664aea03ebSBram Moolenaar 	    if (oap->block_mode)
13674aea03ebSBram Moolenaar 	    {
13684aea03ebSBram Moolenaar 		smsg(NGETTEXT("block of %ld line yanked%s",
13694aea03ebSBram Moolenaar 				     "block of %ld lines yanked%s", yanklines),
13704aea03ebSBram Moolenaar 			yanklines, namebuf);
13714aea03ebSBram Moolenaar 	    }
13724aea03ebSBram Moolenaar 	    else
13734aea03ebSBram Moolenaar 	    {
13744aea03ebSBram Moolenaar 		smsg(NGETTEXT("%ld line yanked%s",
13754aea03ebSBram Moolenaar 					      "%ld lines yanked%s", yanklines),
13764aea03ebSBram Moolenaar 			yanklines, namebuf);
13774aea03ebSBram Moolenaar 	    }
13784aea03ebSBram Moolenaar 	}
13794aea03ebSBram Moolenaar     }
13804aea03ebSBram Moolenaar 
1381e1004401SBram Moolenaar     if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
1382f4a1d1c0SBram Moolenaar     {
13834aea03ebSBram Moolenaar 	// Set "'[" and "']" marks.
13844aea03ebSBram Moolenaar 	curbuf->b_op_start = oap->start;
13854aea03ebSBram Moolenaar 	curbuf->b_op_end = oap->end;
13864aea03ebSBram Moolenaar 	if (yanktype == MLINE && !oap->block_mode)
13874aea03ebSBram Moolenaar 	{
13884aea03ebSBram Moolenaar 	    curbuf->b_op_start.col = 0;
13894aea03ebSBram Moolenaar 	    curbuf->b_op_end.col = MAXCOL;
13904aea03ebSBram Moolenaar 	}
1391f4a1d1c0SBram Moolenaar     }
13924aea03ebSBram Moolenaar 
13934aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
13944aea03ebSBram Moolenaar     // If we were yanking to the '*' register, send result to clipboard.
13954aea03ebSBram Moolenaar     // If no register was specified, and "unnamed" in 'clipboard', make a copy
13964aea03ebSBram Moolenaar     // to the '*' register.
13974aea03ebSBram Moolenaar     if (clip_star.available
13984aea03ebSBram Moolenaar 	    && (curr == &(y_regs[STAR_REGISTER])
13994aea03ebSBram Moolenaar 		|| (!deleting && oap->regname == 0
14004aea03ebSBram Moolenaar 		   && ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
14014aea03ebSBram Moolenaar     {
14024aea03ebSBram Moolenaar 	if (curr != &(y_regs[STAR_REGISTER]))
14034aea03ebSBram Moolenaar 	    // Copy the text from register 0 to the clipboard register.
14044aea03ebSBram Moolenaar 	    copy_yank_reg(&(y_regs[STAR_REGISTER]));
14054aea03ebSBram Moolenaar 
14064aea03ebSBram Moolenaar 	clip_own_selection(&clip_star);
14074aea03ebSBram Moolenaar 	clip_gen_set_selection(&clip_star);
14084aea03ebSBram Moolenaar # ifdef FEAT_X11
14094aea03ebSBram Moolenaar 	did_star = TRUE;
14104aea03ebSBram Moolenaar # endif
14114aea03ebSBram Moolenaar     }
14124aea03ebSBram Moolenaar 
14134aea03ebSBram Moolenaar # ifdef FEAT_X11
14144aea03ebSBram Moolenaar     // If we were yanking to the '+' register, send result to selection.
141537096afdSBram Moolenaar     // Also copy to the '*' register, in case auto-select is off.  But not when
141637096afdSBram Moolenaar     // 'clipboard' has "unnamedplus" and not "unnamed".
14174aea03ebSBram Moolenaar     if (clip_plus.available
14184aea03ebSBram Moolenaar 	    && (curr == &(y_regs[PLUS_REGISTER])
14194aea03ebSBram Moolenaar 		|| (!deleting && oap->regname == 0
14204aea03ebSBram Moolenaar 		  && ((clip_unnamed | clip_unnamed_saved) &
14214aea03ebSBram Moolenaar 							  CLIP_UNNAMED_PLUS))))
14224aea03ebSBram Moolenaar     {
14234aea03ebSBram Moolenaar 	if (curr != &(y_regs[PLUS_REGISTER]))
14244aea03ebSBram Moolenaar 	    // Copy the text from register 0 to the clipboard register.
14254aea03ebSBram Moolenaar 	    copy_yank_reg(&(y_regs[PLUS_REGISTER]));
14264aea03ebSBram Moolenaar 
14274aea03ebSBram Moolenaar 	clip_own_selection(&clip_plus);
14284aea03ebSBram Moolenaar 	clip_gen_set_selection(&clip_plus);
142937096afdSBram Moolenaar 	if (!clip_isautosel_star()
143037096afdSBram Moolenaar 		&& !clip_isautosel_plus()
143137096afdSBram Moolenaar 		&& !((clip_unnamed | clip_unnamed_saved) == CLIP_UNNAMED_PLUS)
143237096afdSBram Moolenaar 		&& !did_star
143337096afdSBram Moolenaar 		&& curr == &(y_regs[PLUS_REGISTER]))
14344aea03ebSBram Moolenaar 	{
14354aea03ebSBram Moolenaar 	    copy_yank_reg(&(y_regs[STAR_REGISTER]));
14364aea03ebSBram Moolenaar 	    clip_own_selection(&clip_star);
14374aea03ebSBram Moolenaar 	    clip_gen_set_selection(&clip_star);
14384aea03ebSBram Moolenaar 	}
14394aea03ebSBram Moolenaar     }
14404aea03ebSBram Moolenaar # endif
14414aea03ebSBram Moolenaar #endif
14424aea03ebSBram Moolenaar 
14434aea03ebSBram Moolenaar #if defined(FEAT_EVAL)
14444aea03ebSBram Moolenaar     if (!deleting && has_textyankpost())
14454aea03ebSBram Moolenaar 	yank_do_autocmd(oap, y_current);
14464aea03ebSBram Moolenaar #endif
14474aea03ebSBram Moolenaar 
14484aea03ebSBram Moolenaar     return OK;
14494aea03ebSBram Moolenaar 
14504aea03ebSBram Moolenaar fail:		// free the allocated lines
14514aea03ebSBram Moolenaar     free_yank(y_idx + 1);
14524aea03ebSBram Moolenaar     y_current = curr;
14534aea03ebSBram Moolenaar     return FAIL;
14544aea03ebSBram Moolenaar }
14554aea03ebSBram Moolenaar 
1456544a38e4SChristian Brabandt /*
1457544a38e4SChristian Brabandt  * Copy a block range into a register.
1458544a38e4SChristian Brabandt  * If "exclude_trailing_space" is set, do not copy trailing whitespaces.
1459544a38e4SChristian Brabandt  */
14604aea03ebSBram Moolenaar     static int
yank_copy_line(struct block_def * bd,long y_idx,int exclude_trailing_space)1461544a38e4SChristian Brabandt yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space)
14624aea03ebSBram Moolenaar {
14634aea03ebSBram Moolenaar     char_u	*pnew;
14644aea03ebSBram Moolenaar 
14657d7bcc6bSBram Moolenaar     if (exclude_trailing_space)
14667d7bcc6bSBram Moolenaar 	bd->endspaces = 0;
14674aea03ebSBram Moolenaar     if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1))
14684aea03ebSBram Moolenaar 								      == NULL)
14694aea03ebSBram Moolenaar 	return FAIL;
14704aea03ebSBram Moolenaar     y_current->y_array[y_idx] = pnew;
14714aea03ebSBram Moolenaar     vim_memset(pnew, ' ', (size_t)bd->startspaces);
14724aea03ebSBram Moolenaar     pnew += bd->startspaces;
14734aea03ebSBram Moolenaar     mch_memmove(pnew, bd->textstart, (size_t)bd->textlen);
14744aea03ebSBram Moolenaar     pnew += bd->textlen;
14754aea03ebSBram Moolenaar     vim_memset(pnew, ' ', (size_t)bd->endspaces);
14764aea03ebSBram Moolenaar     pnew += bd->endspaces;
1477544a38e4SChristian Brabandt     if (exclude_trailing_space)
1478544a38e4SChristian Brabandt     {
1479544a38e4SChristian Brabandt 	int s = bd->textlen + bd->endspaces;
1480544a38e4SChristian Brabandt 
1481544a38e4SChristian Brabandt 	while (VIM_ISWHITE(*(bd->textstart + s - 1)) && s > 0)
1482544a38e4SChristian Brabandt 	{
1483544a38e4SChristian Brabandt 	    s = s - (*mb_head_off)(bd->textstart, bd->textstart + s - 1) - 1;
1484544a38e4SChristian Brabandt 	    pnew--;
1485544a38e4SChristian Brabandt 	}
1486544a38e4SChristian Brabandt     }
14874aea03ebSBram Moolenaar     *pnew = NUL;
14884aea03ebSBram Moolenaar     return OK;
14894aea03ebSBram Moolenaar }
14904aea03ebSBram Moolenaar 
14914aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
14924aea03ebSBram Moolenaar /*
14934aea03ebSBram Moolenaar  * Make a copy of the y_current register to register "reg".
14944aea03ebSBram Moolenaar  */
14954aea03ebSBram Moolenaar     static void
copy_yank_reg(yankreg_T * reg)14964aea03ebSBram Moolenaar copy_yank_reg(yankreg_T *reg)
14974aea03ebSBram Moolenaar {
14984aea03ebSBram Moolenaar     yankreg_T	*curr = y_current;
14994aea03ebSBram Moolenaar     long	j;
15004aea03ebSBram Moolenaar 
15014aea03ebSBram Moolenaar     y_current = reg;
15024aea03ebSBram Moolenaar     free_yank_all();
15034aea03ebSBram Moolenaar     *y_current = *curr;
15044aea03ebSBram Moolenaar     y_current->y_array = lalloc_clear(
15054aea03ebSBram Moolenaar 				    sizeof(char_u *) * y_current->y_size, TRUE);
15064aea03ebSBram Moolenaar     if (y_current->y_array == NULL)
15074aea03ebSBram Moolenaar 	y_current->y_size = 0;
15084aea03ebSBram Moolenaar     else
15094aea03ebSBram Moolenaar 	for (j = 0; j < y_current->y_size; ++j)
15104aea03ebSBram Moolenaar 	    if ((y_current->y_array[j] = vim_strsave(curr->y_array[j])) == NULL)
15114aea03ebSBram Moolenaar 	    {
15124aea03ebSBram Moolenaar 		free_yank(j);
15134aea03ebSBram Moolenaar 		y_current->y_size = 0;
15144aea03ebSBram Moolenaar 		break;
15154aea03ebSBram Moolenaar 	    }
15164aea03ebSBram Moolenaar     y_current = curr;
15174aea03ebSBram Moolenaar }
15184aea03ebSBram Moolenaar #endif
15194aea03ebSBram Moolenaar 
15204aea03ebSBram Moolenaar /*
15214aea03ebSBram Moolenaar  * Put contents of register "regname" into the text.
15224aea03ebSBram Moolenaar  * Caller must check "regname" to be valid!
15234aea03ebSBram Moolenaar  * "flags": PUT_FIXINDENT	make indent look nice
15244aea03ebSBram Moolenaar  *	    PUT_CURSEND		leave cursor after end of new text
15254aea03ebSBram Moolenaar  *	    PUT_LINE		force linewise put (":put")
15262fa9384cSChristian Brabandt  *	    PUT_BLOCK_INNER     in block mode, do not add trailing spaces
15274aea03ebSBram Moolenaar  */
15284aea03ebSBram Moolenaar     void
do_put(int regname,char_u * expr_result,int dir,long count,int flags)15294aea03ebSBram Moolenaar do_put(
15304aea03ebSBram Moolenaar     int		regname,
1531c3516f7eSBram Moolenaar     char_u	*expr_result,	// result for regname "=" when compiled
15324aea03ebSBram Moolenaar     int		dir,		// BACKWARD for 'P', FORWARD for 'p'
15334aea03ebSBram Moolenaar     long	count,
15344aea03ebSBram Moolenaar     int		flags)
15354aea03ebSBram Moolenaar {
15364aea03ebSBram Moolenaar     char_u	*ptr;
15374aea03ebSBram Moolenaar     char_u	*newp, *oldp;
15384aea03ebSBram Moolenaar     int		yanklen;
15394aea03ebSBram Moolenaar     int		totlen = 0;		// init for gcc
15404aea03ebSBram Moolenaar     linenr_T	lnum;
15414aea03ebSBram Moolenaar     colnr_T	col;
15424aea03ebSBram Moolenaar     long	i;			// index in y_array[]
15434aea03ebSBram Moolenaar     int		y_type;
15444aea03ebSBram Moolenaar     long	y_size;
15454aea03ebSBram Moolenaar     int		oldlen;
15464aea03ebSBram Moolenaar     long	y_width = 0;
15474aea03ebSBram Moolenaar     colnr_T	vcol;
15484aea03ebSBram Moolenaar     int		delcount;
15494aea03ebSBram Moolenaar     int		incr = 0;
15504aea03ebSBram Moolenaar     long	j;
15514aea03ebSBram Moolenaar     struct block_def bd;
15524aea03ebSBram Moolenaar     char_u	**y_array = NULL;
15534aea03ebSBram Moolenaar     long	nr_lines = 0;
15544aea03ebSBram Moolenaar     pos_T	new_cursor;
15554aea03ebSBram Moolenaar     int		indent;
15564aea03ebSBram Moolenaar     int		orig_indent = 0;	// init for gcc
15574aea03ebSBram Moolenaar     int		indent_diff = 0;	// init for gcc
15584aea03ebSBram Moolenaar     int		first_indent = TRUE;
15594aea03ebSBram Moolenaar     int		lendiff = 0;
15604aea03ebSBram Moolenaar     pos_T	old_pos;
15614aea03ebSBram Moolenaar     char_u	*insert_string = NULL;
15624aea03ebSBram Moolenaar     int		allocated = FALSE;
15634aea03ebSBram Moolenaar     long	cnt;
1564f4a1d1c0SBram Moolenaar     pos_T	orig_start = curbuf->b_op_start;
1565f4a1d1c0SBram Moolenaar     pos_T	orig_end = curbuf->b_op_end;
156653ba05b0SGary Johnson     unsigned int cur_ve_flags = get_ve_flags();
15674aea03ebSBram Moolenaar 
15684aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
15694aea03ebSBram Moolenaar     // Adjust register name for "unnamed" in 'clipboard'.
15704aea03ebSBram Moolenaar     adjust_clip_reg(&regname);
15714aea03ebSBram Moolenaar     (void)may_get_selection(regname);
15724aea03ebSBram Moolenaar #endif
15734aea03ebSBram Moolenaar 
15744aea03ebSBram Moolenaar     if (flags & PUT_FIXINDENT)
15754aea03ebSBram Moolenaar 	orig_indent = get_indent();
15764aea03ebSBram Moolenaar 
15774aea03ebSBram Moolenaar     curbuf->b_op_start = curwin->w_cursor;	// default for '[ mark
15784aea03ebSBram Moolenaar     curbuf->b_op_end = curwin->w_cursor;	// default for '] mark
15794aea03ebSBram Moolenaar 
15804aea03ebSBram Moolenaar     // Using inserted text works differently, because the register includes
15814aea03ebSBram Moolenaar     // special characters (newlines, etc.).
15824aea03ebSBram Moolenaar     if (regname == '.')
15834aea03ebSBram Moolenaar     {
15844aea03ebSBram Moolenaar 	if (VIsual_active)
15854aea03ebSBram Moolenaar 	    stuffcharReadbuff(VIsual_mode);
15864aea03ebSBram Moolenaar 	(void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
15874aea03ebSBram Moolenaar 				    (count == -1 ? 'O' : 'i')), count, FALSE);
15884aea03ebSBram Moolenaar 	// Putting the text is done later, so can't really move the cursor to
15894aea03ebSBram Moolenaar 	// the next character.  Use "l" to simulate it.
15904aea03ebSBram Moolenaar 	if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
15914aea03ebSBram Moolenaar 	    stuffcharReadbuff('l');
15924aea03ebSBram Moolenaar 	return;
15934aea03ebSBram Moolenaar     }
15944aea03ebSBram Moolenaar 
15954aea03ebSBram Moolenaar     // For special registers '%' (file name), '#' (alternate file name) and
15964aea03ebSBram Moolenaar     // ':' (last command line), etc. we have to create a fake yank register.
1597c3516f7eSBram Moolenaar     // For compiled code "expr_result" holds the expression result.
1598c3516f7eSBram Moolenaar     if (regname == '=' && expr_result != NULL)
1599c3516f7eSBram Moolenaar 	insert_string = expr_result;
1600c3516f7eSBram Moolenaar     else if (get_spec_reg(regname, &insert_string, &allocated, TRUE)
1601c3516f7eSBram Moolenaar 		&& insert_string == NULL)
16024aea03ebSBram Moolenaar 	return;
16034aea03ebSBram Moolenaar 
16044aea03ebSBram Moolenaar     // Autocommands may be executed when saving lines for undo.  This might
16054aea03ebSBram Moolenaar     // make "y_array" invalid, so we start undo now to avoid that.
16064aea03ebSBram Moolenaar     if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL)
16074aea03ebSBram Moolenaar 	goto end;
16084aea03ebSBram Moolenaar 
16094aea03ebSBram Moolenaar     if (insert_string != NULL)
16104aea03ebSBram Moolenaar     {
16114aea03ebSBram Moolenaar 	y_type = MCHAR;
16124aea03ebSBram Moolenaar #ifdef FEAT_EVAL
16134aea03ebSBram Moolenaar 	if (regname == '=')
16144aea03ebSBram Moolenaar 	{
16154aea03ebSBram Moolenaar 	    // For the = register we need to split the string at NL
16164aea03ebSBram Moolenaar 	    // characters.
16174aea03ebSBram Moolenaar 	    // Loop twice: count the number of lines and save them.
16184aea03ebSBram Moolenaar 	    for (;;)
16194aea03ebSBram Moolenaar 	    {
16204aea03ebSBram Moolenaar 		y_size = 0;
16214aea03ebSBram Moolenaar 		ptr = insert_string;
16224aea03ebSBram Moolenaar 		while (ptr != NULL)
16234aea03ebSBram Moolenaar 		{
16244aea03ebSBram Moolenaar 		    if (y_array != NULL)
16254aea03ebSBram Moolenaar 			y_array[y_size] = ptr;
16264aea03ebSBram Moolenaar 		    ++y_size;
16274aea03ebSBram Moolenaar 		    ptr = vim_strchr(ptr, '\n');
16284aea03ebSBram Moolenaar 		    if (ptr != NULL)
16294aea03ebSBram Moolenaar 		    {
16304aea03ebSBram Moolenaar 			if (y_array != NULL)
16314aea03ebSBram Moolenaar 			    *ptr = NUL;
16324aea03ebSBram Moolenaar 			++ptr;
16334aea03ebSBram Moolenaar 			// A trailing '\n' makes the register linewise.
16344aea03ebSBram Moolenaar 			if (*ptr == NUL)
16354aea03ebSBram Moolenaar 			{
16364aea03ebSBram Moolenaar 			    y_type = MLINE;
16374aea03ebSBram Moolenaar 			    break;
16384aea03ebSBram Moolenaar 			}
16394aea03ebSBram Moolenaar 		    }
16404aea03ebSBram Moolenaar 		}
16414aea03ebSBram Moolenaar 		if (y_array != NULL)
16424aea03ebSBram Moolenaar 		    break;
16434aea03ebSBram Moolenaar 		y_array = ALLOC_MULT(char_u *, y_size);
16444aea03ebSBram Moolenaar 		if (y_array == NULL)
16454aea03ebSBram Moolenaar 		    goto end;
16464aea03ebSBram Moolenaar 	    }
16474aea03ebSBram Moolenaar 	}
16484aea03ebSBram Moolenaar 	else
16494aea03ebSBram Moolenaar #endif
16504aea03ebSBram Moolenaar 	{
16514aea03ebSBram Moolenaar 	    y_size = 1;		// use fake one-line yank register
16524aea03ebSBram Moolenaar 	    y_array = &insert_string;
16534aea03ebSBram Moolenaar 	}
16544aea03ebSBram Moolenaar     }
16554aea03ebSBram Moolenaar     else
16564aea03ebSBram Moolenaar     {
16574aea03ebSBram Moolenaar 	get_yank_register(regname, FALSE);
16584aea03ebSBram Moolenaar 
16594aea03ebSBram Moolenaar 	y_type = y_current->y_type;
16604aea03ebSBram Moolenaar 	y_width = y_current->y_width;
16614aea03ebSBram Moolenaar 	y_size = y_current->y_size;
16624aea03ebSBram Moolenaar 	y_array = y_current->y_array;
16634aea03ebSBram Moolenaar     }
16644aea03ebSBram Moolenaar 
16654aea03ebSBram Moolenaar     if (y_type == MLINE)
16664aea03ebSBram Moolenaar     {
16674aea03ebSBram Moolenaar 	if (flags & PUT_LINE_SPLIT)
16684aea03ebSBram Moolenaar 	{
16694aea03ebSBram Moolenaar 	    char_u *p;
16704aea03ebSBram Moolenaar 
16714aea03ebSBram Moolenaar 	    // "p" or "P" in Visual mode: split the lines to put the text in
16724aea03ebSBram Moolenaar 	    // between.
16734aea03ebSBram Moolenaar 	    if (u_save_cursor() == FAIL)
16744aea03ebSBram Moolenaar 		goto end;
16754aea03ebSBram Moolenaar 	    p = ml_get_cursor();
16764aea03ebSBram Moolenaar 	    if (dir == FORWARD && *p != NUL)
16774aea03ebSBram Moolenaar 		MB_PTR_ADV(p);
16784aea03ebSBram Moolenaar 	    ptr = vim_strsave(p);
16794aea03ebSBram Moolenaar 	    if (ptr == NULL)
16804aea03ebSBram Moolenaar 		goto end;
16814aea03ebSBram Moolenaar 	    ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE);
16824aea03ebSBram Moolenaar 	    vim_free(ptr);
16834aea03ebSBram Moolenaar 
16844aea03ebSBram Moolenaar 	    oldp = ml_get_curline();
16854aea03ebSBram Moolenaar 	    p = oldp + curwin->w_cursor.col;
16864aea03ebSBram Moolenaar 	    if (dir == FORWARD && *p != NUL)
16874aea03ebSBram Moolenaar 		MB_PTR_ADV(p);
16884aea03ebSBram Moolenaar 	    ptr = vim_strnsave(oldp, p - oldp);
16894aea03ebSBram Moolenaar 	    if (ptr == NULL)
16904aea03ebSBram Moolenaar 		goto end;
16914aea03ebSBram Moolenaar 	    ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
16924aea03ebSBram Moolenaar 	    ++nr_lines;
16934aea03ebSBram Moolenaar 	    dir = FORWARD;
16944aea03ebSBram Moolenaar 	}
16954aea03ebSBram Moolenaar 	if (flags & PUT_LINE_FORWARD)
16964aea03ebSBram Moolenaar 	{
16974aea03ebSBram Moolenaar 	    // Must be "p" for a Visual block, put lines below the block.
16984aea03ebSBram Moolenaar 	    curwin->w_cursor = curbuf->b_visual.vi_end;
16994aea03ebSBram Moolenaar 	    dir = FORWARD;
17004aea03ebSBram Moolenaar 	}
17014aea03ebSBram Moolenaar 	curbuf->b_op_start = curwin->w_cursor;	// default for '[ mark
17024aea03ebSBram Moolenaar 	curbuf->b_op_end = curwin->w_cursor;	// default for '] mark
17034aea03ebSBram Moolenaar     }
17044aea03ebSBram Moolenaar 
17054aea03ebSBram Moolenaar     if (flags & PUT_LINE)	// :put command or "p" in Visual line mode.
17064aea03ebSBram Moolenaar 	y_type = MLINE;
17074aea03ebSBram Moolenaar 
17084aea03ebSBram Moolenaar     if (y_size == 0 || y_array == NULL)
17094aea03ebSBram Moolenaar     {
17104aea03ebSBram Moolenaar 	semsg(_("E353: Nothing in register %s"),
17114aea03ebSBram Moolenaar 		  regname == 0 ? (char_u *)"\"" : transchar(regname));
17124aea03ebSBram Moolenaar 	goto end;
17134aea03ebSBram Moolenaar     }
17144aea03ebSBram Moolenaar 
17154aea03ebSBram Moolenaar     if (y_type == MBLOCK)
17164aea03ebSBram Moolenaar     {
17174aea03ebSBram Moolenaar 	lnum = curwin->w_cursor.lnum + y_size + 1;
17184aea03ebSBram Moolenaar 	if (lnum > curbuf->b_ml.ml_line_count)
17194aea03ebSBram Moolenaar 	    lnum = curbuf->b_ml.ml_line_count + 1;
17204aea03ebSBram Moolenaar 	if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
17214aea03ebSBram Moolenaar 	    goto end;
17224aea03ebSBram Moolenaar     }
17234aea03ebSBram Moolenaar     else if (y_type == MLINE)
17244aea03ebSBram Moolenaar     {
17254aea03ebSBram Moolenaar 	lnum = curwin->w_cursor.lnum;
17264aea03ebSBram Moolenaar #ifdef FEAT_FOLDING
17274aea03ebSBram Moolenaar 	// Correct line number for closed fold.  Don't move the cursor yet,
17284aea03ebSBram Moolenaar 	// u_save() uses it.
17294aea03ebSBram Moolenaar 	if (dir == BACKWARD)
17304aea03ebSBram Moolenaar 	    (void)hasFolding(lnum, &lnum, NULL);
17314aea03ebSBram Moolenaar 	else
17324aea03ebSBram Moolenaar 	    (void)hasFolding(lnum, NULL, &lnum);
17334aea03ebSBram Moolenaar #endif
17344aea03ebSBram Moolenaar 	if (dir == FORWARD)
17354aea03ebSBram Moolenaar 	    ++lnum;
17364aea03ebSBram Moolenaar 	// In an empty buffer the empty line is going to be replaced, include
17374aea03ebSBram Moolenaar 	// it in the saved lines.
17384aea03ebSBram Moolenaar 	if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL)
17394aea03ebSBram Moolenaar 	    goto end;
17404aea03ebSBram Moolenaar #ifdef FEAT_FOLDING
17414aea03ebSBram Moolenaar 	if (dir == FORWARD)
17424aea03ebSBram Moolenaar 	    curwin->w_cursor.lnum = lnum - 1;
17434aea03ebSBram Moolenaar 	else
17444aea03ebSBram Moolenaar 	    curwin->w_cursor.lnum = lnum;
17454aea03ebSBram Moolenaar 	curbuf->b_op_start = curwin->w_cursor;	// for mark_adjust()
17464aea03ebSBram Moolenaar #endif
17474aea03ebSBram Moolenaar     }
17484aea03ebSBram Moolenaar     else if (u_save_cursor() == FAIL)
17494aea03ebSBram Moolenaar 	goto end;
17504aea03ebSBram Moolenaar 
17514aea03ebSBram Moolenaar     yanklen = (int)STRLEN(y_array[0]);
17524aea03ebSBram Moolenaar 
175353ba05b0SGary Johnson     if (cur_ve_flags == VE_ALL && y_type == MCHAR)
17544aea03ebSBram Moolenaar     {
17554aea03ebSBram Moolenaar 	if (gchar_cursor() == TAB)
17564aea03ebSBram Moolenaar 	{
17576f1f0ca3SBram Moolenaar 	    int viscol = getviscol();
17586f1f0ca3SBram Moolenaar 	    int ts = curbuf->b_p_ts;
17596f1f0ca3SBram Moolenaar 
17604aea03ebSBram Moolenaar 	    // Don't need to insert spaces when "p" on the last position of a
17614aea03ebSBram Moolenaar 	    // tab or "P" on the first position.
17626f1f0ca3SBram Moolenaar 	    if (dir == FORWARD ?
17634aea03ebSBram Moolenaar #ifdef FEAT_VARTABS
17646f1f0ca3SBram Moolenaar 		    tabstop_padding(viscol, ts, curbuf->b_p_vts_array) != 1
17656f1f0ca3SBram Moolenaar #else
17666f1f0ca3SBram Moolenaar 		    ts - (viscol % ts) != 1
17676f1f0ca3SBram Moolenaar #endif
17684aea03ebSBram Moolenaar 		    : curwin->w_cursor.coladd > 0)
17694aea03ebSBram Moolenaar 		coladvance_force(viscol);
17704aea03ebSBram Moolenaar 	    else
17714aea03ebSBram Moolenaar 		curwin->w_cursor.coladd = 0;
17724aea03ebSBram Moolenaar 	}
17734aea03ebSBram Moolenaar 	else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
17744aea03ebSBram Moolenaar 	    coladvance_force(getviscol() + (dir == FORWARD));
17754aea03ebSBram Moolenaar     }
17764aea03ebSBram Moolenaar 
17774aea03ebSBram Moolenaar     lnum = curwin->w_cursor.lnum;
17784aea03ebSBram Moolenaar     col = curwin->w_cursor.col;
17794aea03ebSBram Moolenaar 
17804aea03ebSBram Moolenaar     // Block mode
17814aea03ebSBram Moolenaar     if (y_type == MBLOCK)
17824aea03ebSBram Moolenaar     {
17834aea03ebSBram Moolenaar 	int	c = gchar_cursor();
17844aea03ebSBram Moolenaar 	colnr_T	endcol2 = 0;
17854aea03ebSBram Moolenaar 
17864aea03ebSBram Moolenaar 	if (dir == FORWARD && c != NUL)
17874aea03ebSBram Moolenaar 	{
178853ba05b0SGary Johnson 	    if (cur_ve_flags == VE_ALL)
17894aea03ebSBram Moolenaar 		getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
17904aea03ebSBram Moolenaar 	    else
17914aea03ebSBram Moolenaar 		getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
17924aea03ebSBram Moolenaar 
17934aea03ebSBram Moolenaar 	    if (has_mbyte)
17944aea03ebSBram Moolenaar 		// move to start of next multi-byte character
17954aea03ebSBram Moolenaar 		curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
17964aea03ebSBram Moolenaar 	    else
179753ba05b0SGary Johnson 	    if (c != TAB || cur_ve_flags != VE_ALL)
17984aea03ebSBram Moolenaar 		++curwin->w_cursor.col;
17994aea03ebSBram Moolenaar 	    ++col;
18004aea03ebSBram Moolenaar 	}
18014aea03ebSBram Moolenaar 	else
18024aea03ebSBram Moolenaar 	    getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
18034aea03ebSBram Moolenaar 
18044aea03ebSBram Moolenaar 	col += curwin->w_cursor.coladd;
180553ba05b0SGary Johnson 	if (cur_ve_flags == VE_ALL
18064aea03ebSBram Moolenaar 		&& (curwin->w_cursor.coladd > 0
18074aea03ebSBram Moolenaar 		    || endcol2 == curwin->w_cursor.col))
18084aea03ebSBram Moolenaar 	{
18094aea03ebSBram Moolenaar 	    if (dir == FORWARD && c == NUL)
18104aea03ebSBram Moolenaar 		++col;
1811ef85a9b2SBram Moolenaar 	    if (dir != FORWARD && c != NUL && curwin->w_cursor.coladd > 0)
18124aea03ebSBram Moolenaar 		++curwin->w_cursor.col;
18134aea03ebSBram Moolenaar 	    if (c == TAB)
18144aea03ebSBram Moolenaar 	    {
18154aea03ebSBram Moolenaar 		if (dir == BACKWARD && curwin->w_cursor.col)
18164aea03ebSBram Moolenaar 		    curwin->w_cursor.col--;
18174aea03ebSBram Moolenaar 		if (dir == FORWARD && col - 1 == endcol2)
18184aea03ebSBram Moolenaar 		    curwin->w_cursor.col++;
18194aea03ebSBram Moolenaar 	    }
18204aea03ebSBram Moolenaar 	}
18214aea03ebSBram Moolenaar 	curwin->w_cursor.coladd = 0;
18224aea03ebSBram Moolenaar 	bd.textcol = 0;
18234aea03ebSBram Moolenaar 	for (i = 0; i < y_size; ++i)
18244aea03ebSBram Moolenaar 	{
18252fa9384cSChristian Brabandt 	    int spaces = 0;
18264aea03ebSBram Moolenaar 	    char shortline;
18274aea03ebSBram Moolenaar 
18284aea03ebSBram Moolenaar 	    bd.startspaces = 0;
18294aea03ebSBram Moolenaar 	    bd.endspaces = 0;
18304aea03ebSBram Moolenaar 	    vcol = 0;
18314aea03ebSBram Moolenaar 	    delcount = 0;
18324aea03ebSBram Moolenaar 
18334aea03ebSBram Moolenaar 	    // add a new line
18344aea03ebSBram Moolenaar 	    if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
18354aea03ebSBram Moolenaar 	    {
18364aea03ebSBram Moolenaar 		if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
18374aea03ebSBram Moolenaar 						   (colnr_T)1, FALSE) == FAIL)
18384aea03ebSBram Moolenaar 		    break;
18394aea03ebSBram Moolenaar 		++nr_lines;
18404aea03ebSBram Moolenaar 	    }
18414aea03ebSBram Moolenaar 	    // get the old line and advance to the position to insert at
18424aea03ebSBram Moolenaar 	    oldp = ml_get_curline();
18434aea03ebSBram Moolenaar 	    oldlen = (int)STRLEN(oldp);
18444aea03ebSBram Moolenaar 	    for (ptr = oldp; vcol < col && *ptr; )
18454aea03ebSBram Moolenaar 	    {
18464aea03ebSBram Moolenaar 		// Count a tab for what it's worth (if list mode not on)
18474aea03ebSBram Moolenaar 		incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol);
18484aea03ebSBram Moolenaar 		vcol += incr;
18494aea03ebSBram Moolenaar 	    }
18504aea03ebSBram Moolenaar 	    bd.textcol = (colnr_T)(ptr - oldp);
18514aea03ebSBram Moolenaar 
18524aea03ebSBram Moolenaar 	    shortline = (vcol < col) || (vcol == col && !*ptr) ;
18534aea03ebSBram Moolenaar 
18544aea03ebSBram Moolenaar 	    if (vcol < col) // line too short, padd with spaces
18554aea03ebSBram Moolenaar 		bd.startspaces = col - vcol;
18564aea03ebSBram Moolenaar 	    else if (vcol > col)
18574aea03ebSBram Moolenaar 	    {
18584aea03ebSBram Moolenaar 		bd.endspaces = vcol - col;
18594aea03ebSBram Moolenaar 		bd.startspaces = incr - bd.endspaces;
18604aea03ebSBram Moolenaar 		--bd.textcol;
18614aea03ebSBram Moolenaar 		delcount = 1;
18624aea03ebSBram Moolenaar 		if (has_mbyte)
18634aea03ebSBram Moolenaar 		    bd.textcol -= (*mb_head_off)(oldp, oldp + bd.textcol);
18644aea03ebSBram Moolenaar 		if (oldp[bd.textcol] != TAB)
18654aea03ebSBram Moolenaar 		{
18664aea03ebSBram Moolenaar 		    // Only a Tab can be split into spaces.  Other
18674aea03ebSBram Moolenaar 		    // characters will have to be moved to after the
18684aea03ebSBram Moolenaar 		    // block, causing misalignment.
18694aea03ebSBram Moolenaar 		    delcount = 0;
18704aea03ebSBram Moolenaar 		    bd.endspaces = 0;
18714aea03ebSBram Moolenaar 		}
18724aea03ebSBram Moolenaar 	    }
18734aea03ebSBram Moolenaar 
18744aea03ebSBram Moolenaar 	    yanklen = (int)STRLEN(y_array[i]);
18754aea03ebSBram Moolenaar 
18762fa9384cSChristian Brabandt 	    if ((flags & PUT_BLOCK_INNER) == 0)
18772fa9384cSChristian Brabandt 	    {
18782fa9384cSChristian Brabandt 		// calculate number of spaces required to fill right side of
18792fa9384cSChristian Brabandt 		// block
18804aea03ebSBram Moolenaar 		spaces = y_width + 1;
18814aea03ebSBram Moolenaar 		for (j = 0; j < yanklen; j++)
18824aea03ebSBram Moolenaar 		    spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
18834aea03ebSBram Moolenaar 		if (spaces < 0)
18844aea03ebSBram Moolenaar 		    spaces = 0;
18852fa9384cSChristian Brabandt 	    }
18864aea03ebSBram Moolenaar 
1887fa537223Sichizok 	    // Insert the new text.
1888fa537223Sichizok 	    // First check for multiplication overflow.
1889fa537223Sichizok 	    if (yanklen + spaces != 0
1890fa537223Sichizok 		     && count > ((INT_MAX - (bd.startspaces + bd.endspaces))
1891fa537223Sichizok 							/ (yanklen + spaces)))
1892fa537223Sichizok 	    {
1893fa537223Sichizok 		emsg(_(e_resulting_text_too_long));
1894fa537223Sichizok 		break;
1895fa537223Sichizok 	    }
1896fa537223Sichizok 
18974aea03ebSBram Moolenaar 	    totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
18984aea03ebSBram Moolenaar 	    newp = alloc(totlen + oldlen + 1);
18994aea03ebSBram Moolenaar 	    if (newp == NULL)
19004aea03ebSBram Moolenaar 		break;
1901fa537223Sichizok 
19024aea03ebSBram Moolenaar 	    // copy part up to cursor to new line
19034aea03ebSBram Moolenaar 	    ptr = newp;
19044aea03ebSBram Moolenaar 	    mch_memmove(ptr, oldp, (size_t)bd.textcol);
19054aea03ebSBram Moolenaar 	    ptr += bd.textcol;
1906fa537223Sichizok 
19074aea03ebSBram Moolenaar 	    // may insert some spaces before the new text
19084aea03ebSBram Moolenaar 	    vim_memset(ptr, ' ', (size_t)bd.startspaces);
19094aea03ebSBram Moolenaar 	    ptr += bd.startspaces;
1910fa537223Sichizok 
19114aea03ebSBram Moolenaar 	    // insert the new text
19124aea03ebSBram Moolenaar 	    for (j = 0; j < count; ++j)
19134aea03ebSBram Moolenaar 	    {
19144aea03ebSBram Moolenaar 		mch_memmove(ptr, y_array[i], (size_t)yanklen);
19154aea03ebSBram Moolenaar 		ptr += yanklen;
19164aea03ebSBram Moolenaar 
19174aea03ebSBram Moolenaar 		// insert block's trailing spaces only if there's text behind
19184aea03ebSBram Moolenaar 		if ((j < count - 1 || !shortline) && spaces)
19194aea03ebSBram Moolenaar 		{
19204aea03ebSBram Moolenaar 		    vim_memset(ptr, ' ', (size_t)spaces);
19214aea03ebSBram Moolenaar 		    ptr += spaces;
19224aea03ebSBram Moolenaar 		}
19234aea03ebSBram Moolenaar 	    }
1924fa537223Sichizok 
19254aea03ebSBram Moolenaar 	    // may insert some spaces after the new text
19264aea03ebSBram Moolenaar 	    vim_memset(ptr, ' ', (size_t)bd.endspaces);
19274aea03ebSBram Moolenaar 	    ptr += bd.endspaces;
1928fa537223Sichizok 
19294aea03ebSBram Moolenaar 	    // move the text after the cursor to the end of the line.
19304aea03ebSBram Moolenaar 	    mch_memmove(ptr, oldp + bd.textcol + delcount,
19314aea03ebSBram Moolenaar 				(size_t)(oldlen - bd.textcol - delcount + 1));
19324aea03ebSBram Moolenaar 	    ml_replace(curwin->w_cursor.lnum, newp, FALSE);
19334aea03ebSBram Moolenaar 
19344aea03ebSBram Moolenaar 	    ++curwin->w_cursor.lnum;
19354aea03ebSBram Moolenaar 	    if (i == 0)
19364aea03ebSBram Moolenaar 		curwin->w_cursor.col += bd.startspaces;
19374aea03ebSBram Moolenaar 	}
19384aea03ebSBram Moolenaar 
19394aea03ebSBram Moolenaar 	changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines);
19404aea03ebSBram Moolenaar 
19414aea03ebSBram Moolenaar 	// Set '[ mark.
19424aea03ebSBram Moolenaar 	curbuf->b_op_start = curwin->w_cursor;
19434aea03ebSBram Moolenaar 	curbuf->b_op_start.lnum = lnum;
19444aea03ebSBram Moolenaar 
19454aea03ebSBram Moolenaar 	// adjust '] mark
19464aea03ebSBram Moolenaar 	curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
19474aea03ebSBram Moolenaar 	curbuf->b_op_end.col = bd.textcol + totlen - 1;
19484aea03ebSBram Moolenaar 	curbuf->b_op_end.coladd = 0;
19494aea03ebSBram Moolenaar 	if (flags & PUT_CURSEND)
19504aea03ebSBram Moolenaar 	{
19514aea03ebSBram Moolenaar 	    colnr_T len;
19524aea03ebSBram Moolenaar 
19534aea03ebSBram Moolenaar 	    curwin->w_cursor = curbuf->b_op_end;
19544aea03ebSBram Moolenaar 	    curwin->w_cursor.col++;
19554aea03ebSBram Moolenaar 
19564aea03ebSBram Moolenaar 	    // in Insert mode we might be after the NUL, correct for that
19574aea03ebSBram Moolenaar 	    len = (colnr_T)STRLEN(ml_get_curline());
19584aea03ebSBram Moolenaar 	    if (curwin->w_cursor.col > len)
19594aea03ebSBram Moolenaar 		curwin->w_cursor.col = len;
19604aea03ebSBram Moolenaar 	}
19614aea03ebSBram Moolenaar 	else
19624aea03ebSBram Moolenaar 	    curwin->w_cursor.lnum = lnum;
19634aea03ebSBram Moolenaar     }
19644aea03ebSBram Moolenaar     else
19654aea03ebSBram Moolenaar     {
19664aea03ebSBram Moolenaar 	// Character or Line mode
19674aea03ebSBram Moolenaar 	if (y_type == MCHAR)
19684aea03ebSBram Moolenaar 	{
19694aea03ebSBram Moolenaar 	    // if type is MCHAR, FORWARD is the same as BACKWARD on the next
19704aea03ebSBram Moolenaar 	    // char
19714aea03ebSBram Moolenaar 	    if (dir == FORWARD && gchar_cursor() != NUL)
19724aea03ebSBram Moolenaar 	    {
19734aea03ebSBram Moolenaar 		if (has_mbyte)
19744aea03ebSBram Moolenaar 		{
19754aea03ebSBram Moolenaar 		    int bytelen = (*mb_ptr2len)(ml_get_cursor());
19764aea03ebSBram Moolenaar 
19774aea03ebSBram Moolenaar 		    // put it on the next of the multi-byte character.
19784aea03ebSBram Moolenaar 		    col += bytelen;
19794aea03ebSBram Moolenaar 		    if (yanklen)
19804aea03ebSBram Moolenaar 		    {
19814aea03ebSBram Moolenaar 			curwin->w_cursor.col += bytelen;
19824aea03ebSBram Moolenaar 			curbuf->b_op_end.col += bytelen;
19834aea03ebSBram Moolenaar 		    }
19844aea03ebSBram Moolenaar 		}
19854aea03ebSBram Moolenaar 		else
19864aea03ebSBram Moolenaar 		{
19874aea03ebSBram Moolenaar 		    ++col;
19884aea03ebSBram Moolenaar 		    if (yanklen)
19894aea03ebSBram Moolenaar 		    {
19904aea03ebSBram Moolenaar 			++curwin->w_cursor.col;
19914aea03ebSBram Moolenaar 			++curbuf->b_op_end.col;
19924aea03ebSBram Moolenaar 		    }
19934aea03ebSBram Moolenaar 		}
19944aea03ebSBram Moolenaar 	    }
19954aea03ebSBram Moolenaar 	    curbuf->b_op_start = curwin->w_cursor;
19964aea03ebSBram Moolenaar 	}
19974aea03ebSBram Moolenaar 	// Line mode: BACKWARD is the same as FORWARD on the previous line
19984aea03ebSBram Moolenaar 	else if (dir == BACKWARD)
19994aea03ebSBram Moolenaar 	    --lnum;
20004aea03ebSBram Moolenaar 	new_cursor = curwin->w_cursor;
20014aea03ebSBram Moolenaar 
2002cd94277fSBram Moolenaar 	// simple case: insert into one line at a time
20034aea03ebSBram Moolenaar 	if (y_type == MCHAR && y_size == 1)
20044aea03ebSBram Moolenaar 	{
20054aea03ebSBram Moolenaar 	    linenr_T	end_lnum = 0; // init for gcc
2006cd94277fSBram Moolenaar 	    linenr_T	start_lnum = lnum;
20074aea03ebSBram Moolenaar 
20084aea03ebSBram Moolenaar 	    if (VIsual_active)
20094aea03ebSBram Moolenaar 	    {
20104aea03ebSBram Moolenaar 		end_lnum = curbuf->b_visual.vi_end.lnum;
20114aea03ebSBram Moolenaar 		if (end_lnum < curbuf->b_visual.vi_start.lnum)
20124aea03ebSBram Moolenaar 		    end_lnum = curbuf->b_visual.vi_start.lnum;
2013cd94277fSBram Moolenaar 		if (end_lnum > start_lnum)
2014cd94277fSBram Moolenaar 		{
2015cd94277fSBram Moolenaar 		    pos_T   pos;
2016cd94277fSBram Moolenaar 
2017cd94277fSBram Moolenaar 		    // "col" is valid for the first line, in following lines
2018cd94277fSBram Moolenaar 		    // the virtual column needs to be used.  Matters for
2019cd94277fSBram Moolenaar 		    // multi-byte characters.
2020cd94277fSBram Moolenaar 		    pos.lnum = lnum;
2021cd94277fSBram Moolenaar 		    pos.col = col;
2022cd94277fSBram Moolenaar 		    pos.coladd = 0;
2023cd94277fSBram Moolenaar 		    getvcol(curwin, &pos, NULL, &vcol, NULL);
2024cd94277fSBram Moolenaar 		}
20254aea03ebSBram Moolenaar 	    }
20264aea03ebSBram Moolenaar 
2027fa537223Sichizok 	    if (count == 0 || yanklen == 0)
2028eeed1c7aSBram Moolenaar 	    {
2029fa537223Sichizok 		if (VIsual_active)
2030fa537223Sichizok 		    lnum = end_lnum;
2031eeed1c7aSBram Moolenaar 	    }
2032fa537223Sichizok 	    else if (count > INT_MAX / yanklen)
2033fa537223Sichizok 		// multiplication overflow
2034fa537223Sichizok 		emsg(_(e_resulting_text_too_long));
2035fa537223Sichizok 	    else
20364aea03ebSBram Moolenaar 	    {
2037fa537223Sichizok 		totlen = count * yanklen;
2038fa537223Sichizok 		do {
20394aea03ebSBram Moolenaar 		    oldp = ml_get(lnum);
2040fa537223Sichizok 		    oldlen = (int)STRLEN(oldp);
2041cd94277fSBram Moolenaar 		    if (lnum > start_lnum)
2042cd94277fSBram Moolenaar 		    {
2043cd94277fSBram Moolenaar 			pos_T   pos;
2044cd94277fSBram Moolenaar 
2045cd94277fSBram Moolenaar 			pos.lnum = lnum;
2046cd94277fSBram Moolenaar 			if (getvpos(&pos, vcol) == OK)
2047cd94277fSBram Moolenaar 			    col = pos.col;
2048cd94277fSBram Moolenaar 			else
2049cd94277fSBram Moolenaar 			    col = MAXCOL;
2050cd94277fSBram Moolenaar 		    }
2051fa537223Sichizok 		    if (VIsual_active && col > oldlen)
20524aea03ebSBram Moolenaar 		    {
20534aea03ebSBram Moolenaar 			lnum++;
20544aea03ebSBram Moolenaar 			continue;
20554aea03ebSBram Moolenaar 		    }
2056fa537223Sichizok 		    newp = alloc(totlen + oldlen + 1);
20574aea03ebSBram Moolenaar 		    if (newp == NULL)
20584aea03ebSBram Moolenaar 			goto end;	// alloc() gave an error message
20594aea03ebSBram Moolenaar 		    mch_memmove(newp, oldp, (size_t)col);
20604aea03ebSBram Moolenaar 		    ptr = newp + col;
20614aea03ebSBram Moolenaar 		    for (i = 0; i < count; ++i)
20624aea03ebSBram Moolenaar 		    {
20634aea03ebSBram Moolenaar 			mch_memmove(ptr, y_array[0], (size_t)yanklen);
20644aea03ebSBram Moolenaar 			ptr += yanklen;
20654aea03ebSBram Moolenaar 		    }
20664aea03ebSBram Moolenaar 		    STRMOVE(ptr, oldp + col);
20674aea03ebSBram Moolenaar 		    ml_replace(lnum, newp, FALSE);
20684aea03ebSBram Moolenaar 		    // Place cursor on last putted char.
20694aea03ebSBram Moolenaar 		    if (lnum == curwin->w_cursor.lnum)
20704aea03ebSBram Moolenaar 		    {
20714aea03ebSBram Moolenaar 			// make sure curwin->w_virtcol is updated
20724aea03ebSBram Moolenaar 			changed_cline_bef_curs();
20734aea03ebSBram Moolenaar 			curwin->w_cursor.col += (colnr_T)(totlen - 1);
20744aea03ebSBram Moolenaar 		    }
20754aea03ebSBram Moolenaar 		    if (VIsual_active)
20764aea03ebSBram Moolenaar 			lnum++;
20774aea03ebSBram Moolenaar 		} while (VIsual_active && lnum <= end_lnum);
20784aea03ebSBram Moolenaar 
20794aea03ebSBram Moolenaar 		if (VIsual_active) // reset lnum to the last visual line
20804aea03ebSBram Moolenaar 		    lnum--;
2081fa537223Sichizok 	    }
20824aea03ebSBram Moolenaar 
20834aea03ebSBram Moolenaar 	    curbuf->b_op_end = curwin->w_cursor;
20844aea03ebSBram Moolenaar 	    // For "CTRL-O p" in Insert mode, put cursor after last char
20854aea03ebSBram Moolenaar 	    if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
20864aea03ebSBram Moolenaar 		++curwin->w_cursor.col;
20874aea03ebSBram Moolenaar 	    changed_bytes(lnum, col);
20884aea03ebSBram Moolenaar 	}
20894aea03ebSBram Moolenaar 	else
20904aea03ebSBram Moolenaar 	{
209123003e51SBram Moolenaar 	    linenr_T	new_lnum = new_cursor.lnum;
209223003e51SBram Moolenaar 
20934aea03ebSBram Moolenaar 	    // Insert at least one line.  When y_type is MCHAR, break the first
20944aea03ebSBram Moolenaar 	    // line in two.
20954aea03ebSBram Moolenaar 	    for (cnt = 1; cnt <= count; ++cnt)
20964aea03ebSBram Moolenaar 	    {
20974aea03ebSBram Moolenaar 		i = 0;
20984aea03ebSBram Moolenaar 		if (y_type == MCHAR)
20994aea03ebSBram Moolenaar 		{
21004aea03ebSBram Moolenaar 		    // Split the current line in two at the insert position.
21014aea03ebSBram Moolenaar 		    // First insert y_array[size - 1] in front of second line.
21024aea03ebSBram Moolenaar 		    // Then append y_array[0] to first line.
21034aea03ebSBram Moolenaar 		    lnum = new_cursor.lnum;
21044aea03ebSBram Moolenaar 		    ptr = ml_get(lnum) + col;
21054aea03ebSBram Moolenaar 		    totlen = (int)STRLEN(y_array[y_size - 1]);
21064aea03ebSBram Moolenaar 		    newp = alloc(STRLEN(ptr) + totlen + 1);
21074aea03ebSBram Moolenaar 		    if (newp == NULL)
21084aea03ebSBram Moolenaar 			goto error;
21094aea03ebSBram Moolenaar 		    STRCPY(newp, y_array[y_size - 1]);
21104aea03ebSBram Moolenaar 		    STRCAT(newp, ptr);
21114aea03ebSBram Moolenaar 		    // insert second line
21124aea03ebSBram Moolenaar 		    ml_append(lnum, newp, (colnr_T)0, FALSE);
211323003e51SBram Moolenaar 		    ++new_lnum;
21144aea03ebSBram Moolenaar 		    vim_free(newp);
21154aea03ebSBram Moolenaar 
21164aea03ebSBram Moolenaar 		    oldp = ml_get(lnum);
21174aea03ebSBram Moolenaar 		    newp = alloc(col + yanklen + 1);
21184aea03ebSBram Moolenaar 		    if (newp == NULL)
21194aea03ebSBram Moolenaar 			goto error;
21204aea03ebSBram Moolenaar 					    // copy first part of line
21214aea03ebSBram Moolenaar 		    mch_memmove(newp, oldp, (size_t)col);
21224aea03ebSBram Moolenaar 					    // append to first line
21234aea03ebSBram Moolenaar 		    mch_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
21244aea03ebSBram Moolenaar 		    ml_replace(lnum, newp, FALSE);
21254aea03ebSBram Moolenaar 
21264aea03ebSBram Moolenaar 		    curwin->w_cursor.lnum = lnum;
21274aea03ebSBram Moolenaar 		    i = 1;
21284aea03ebSBram Moolenaar 		}
21294aea03ebSBram Moolenaar 
21304aea03ebSBram Moolenaar 		for (; i < y_size; ++i)
21314aea03ebSBram Moolenaar 		{
213223003e51SBram Moolenaar 		    if (y_type != MCHAR || i < y_size - 1)
213323003e51SBram Moolenaar 		    {
213423003e51SBram Moolenaar 			if (ml_append(lnum, y_array[i], (colnr_T)0, FALSE)
21354aea03ebSBram Moolenaar 								      == FAIL)
21364aea03ebSBram Moolenaar 			    goto error;
213723003e51SBram Moolenaar 			new_lnum++;
213823003e51SBram Moolenaar 		    }
21394aea03ebSBram Moolenaar 		    lnum++;
21404aea03ebSBram Moolenaar 		    ++nr_lines;
21414aea03ebSBram Moolenaar 		    if (flags & PUT_FIXINDENT)
21424aea03ebSBram Moolenaar 		    {
21434aea03ebSBram Moolenaar 			old_pos = curwin->w_cursor;
21444aea03ebSBram Moolenaar 			curwin->w_cursor.lnum = lnum;
21454aea03ebSBram Moolenaar 			ptr = ml_get(lnum);
21464aea03ebSBram Moolenaar 			if (cnt == count && i == y_size - 1)
21474aea03ebSBram Moolenaar 			    lendiff = (int)STRLEN(ptr);
21484aea03ebSBram Moolenaar #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
21494aea03ebSBram Moolenaar 			if (*ptr == '#' && preprocs_left())
21504aea03ebSBram Moolenaar 			    indent = 0;     // Leave # lines at start
21514aea03ebSBram Moolenaar 			else
21524aea03ebSBram Moolenaar #endif
21534aea03ebSBram Moolenaar 			     if (*ptr == NUL)
21544aea03ebSBram Moolenaar 			    indent = 0;     // Ignore empty lines
21554aea03ebSBram Moolenaar 			else if (first_indent)
21564aea03ebSBram Moolenaar 			{
21574aea03ebSBram Moolenaar 			    indent_diff = orig_indent - get_indent();
21584aea03ebSBram Moolenaar 			    indent = orig_indent;
21594aea03ebSBram Moolenaar 			    first_indent = FALSE;
21604aea03ebSBram Moolenaar 			}
21614aea03ebSBram Moolenaar 			else if ((indent = get_indent() + indent_diff) < 0)
21624aea03ebSBram Moolenaar 			    indent = 0;
21634aea03ebSBram Moolenaar 			(void)set_indent(indent, 0);
21644aea03ebSBram Moolenaar 			curwin->w_cursor = old_pos;
21654aea03ebSBram Moolenaar 			// remember how many chars were removed
21664aea03ebSBram Moolenaar 			if (cnt == count && i == y_size - 1)
21674aea03ebSBram Moolenaar 			    lendiff -= (int)STRLEN(ml_get(lnum));
21684aea03ebSBram Moolenaar 		    }
21694aea03ebSBram Moolenaar 		}
217023003e51SBram Moolenaar 		if (cnt == 1)
217123003e51SBram Moolenaar 		    new_lnum = lnum;
21724aea03ebSBram Moolenaar 	    }
21734aea03ebSBram Moolenaar 
21744aea03ebSBram Moolenaar error:
21754aea03ebSBram Moolenaar 	    // Adjust marks.
21764aea03ebSBram Moolenaar 	    if (y_type == MLINE)
21774aea03ebSBram Moolenaar 	    {
21784aea03ebSBram Moolenaar 		curbuf->b_op_start.col = 0;
21794aea03ebSBram Moolenaar 		if (dir == FORWARD)
21804aea03ebSBram Moolenaar 		    curbuf->b_op_start.lnum++;
21814aea03ebSBram Moolenaar 	    }
21824aea03ebSBram Moolenaar 	    // Skip mark_adjust when adding lines after the last one, there
21834aea03ebSBram Moolenaar 	    // can't be marks there. But still needed in diff mode.
21844aea03ebSBram Moolenaar 	    if (curbuf->b_op_start.lnum + (y_type == MCHAR) - 1 + nr_lines
21854aea03ebSBram Moolenaar 						 < curbuf->b_ml.ml_line_count
21864aea03ebSBram Moolenaar #ifdef FEAT_DIFF
21874aea03ebSBram Moolenaar 						 || curwin->w_p_diff
21884aea03ebSBram Moolenaar #endif
21894aea03ebSBram Moolenaar 						 )
21904aea03ebSBram Moolenaar 		mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
21914aea03ebSBram Moolenaar 					     (linenr_T)MAXLNUM, nr_lines, 0L);
21924aea03ebSBram Moolenaar 
21934aea03ebSBram Moolenaar 	    // note changed text for displaying and folding
21944aea03ebSBram Moolenaar 	    if (y_type == MCHAR)
21954aea03ebSBram Moolenaar 		changed_lines(curwin->w_cursor.lnum, col,
21964aea03ebSBram Moolenaar 					 curwin->w_cursor.lnum + 1, nr_lines);
21974aea03ebSBram Moolenaar 	    else
21984aea03ebSBram Moolenaar 		changed_lines(curbuf->b_op_start.lnum, 0,
21994aea03ebSBram Moolenaar 					   curbuf->b_op_start.lnum, nr_lines);
22004aea03ebSBram Moolenaar 
22014aea03ebSBram Moolenaar 	    // put '] mark at last inserted character
2202f47ebf1eSBram Moolenaar 	    curbuf->b_op_end.lnum = new_lnum;
22034aea03ebSBram Moolenaar 	    // correct length for change in indent
22044aea03ebSBram Moolenaar 	    col = (colnr_T)STRLEN(y_array[y_size - 1]) - lendiff;
22054aea03ebSBram Moolenaar 	    if (col > 1)
22064aea03ebSBram Moolenaar 		curbuf->b_op_end.col = col - 1;
22074aea03ebSBram Moolenaar 	    else
22084aea03ebSBram Moolenaar 		curbuf->b_op_end.col = 0;
22094aea03ebSBram Moolenaar 
22104aea03ebSBram Moolenaar 	    if (flags & PUT_CURSLINE)
22114aea03ebSBram Moolenaar 	    {
22124aea03ebSBram Moolenaar 		// ":put": put cursor on last inserted line
22134aea03ebSBram Moolenaar 		curwin->w_cursor.lnum = lnum;
22144aea03ebSBram Moolenaar 		beginline(BL_WHITE | BL_FIX);
22154aea03ebSBram Moolenaar 	    }
22164aea03ebSBram Moolenaar 	    else if (flags & PUT_CURSEND)
22174aea03ebSBram Moolenaar 	    {
22184aea03ebSBram Moolenaar 		// put cursor after inserted text
22194aea03ebSBram Moolenaar 		if (y_type == MLINE)
22204aea03ebSBram Moolenaar 		{
22214aea03ebSBram Moolenaar 		    if (lnum >= curbuf->b_ml.ml_line_count)
22224aea03ebSBram Moolenaar 			curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
22234aea03ebSBram Moolenaar 		    else
22244aea03ebSBram Moolenaar 			curwin->w_cursor.lnum = lnum + 1;
22254aea03ebSBram Moolenaar 		    curwin->w_cursor.col = 0;
22264aea03ebSBram Moolenaar 		}
22274aea03ebSBram Moolenaar 		else
22284aea03ebSBram Moolenaar 		{
222923003e51SBram Moolenaar 		    curwin->w_cursor.lnum = new_lnum;
22304aea03ebSBram Moolenaar 		    curwin->w_cursor.col = col;
223156858e4eSBram Moolenaar 		    curbuf->b_op_end = curwin->w_cursor;
223256858e4eSBram Moolenaar 		    if (col > 1)
223356858e4eSBram Moolenaar 			curbuf->b_op_end.col = col - 1;
22344aea03ebSBram Moolenaar 		}
22354aea03ebSBram Moolenaar 	    }
22364aea03ebSBram Moolenaar 	    else if (y_type == MLINE)
22374aea03ebSBram Moolenaar 	    {
22384aea03ebSBram Moolenaar 		// put cursor on first non-blank in first inserted line
22394aea03ebSBram Moolenaar 		curwin->w_cursor.col = 0;
22404aea03ebSBram Moolenaar 		if (dir == FORWARD)
22414aea03ebSBram Moolenaar 		    ++curwin->w_cursor.lnum;
22424aea03ebSBram Moolenaar 		beginline(BL_WHITE | BL_FIX);
22434aea03ebSBram Moolenaar 	    }
22444aea03ebSBram Moolenaar 	    else	// put cursor on first inserted character
22454aea03ebSBram Moolenaar 		curwin->w_cursor = new_cursor;
22464aea03ebSBram Moolenaar 	}
22474aea03ebSBram Moolenaar     }
22484aea03ebSBram Moolenaar 
22494aea03ebSBram Moolenaar     msgmore(nr_lines);
22504aea03ebSBram Moolenaar     curwin->w_set_curswant = TRUE;
22514aea03ebSBram Moolenaar 
22524aea03ebSBram Moolenaar end:
2253e1004401SBram Moolenaar     if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
2254f4a1d1c0SBram Moolenaar     {
2255f4a1d1c0SBram Moolenaar 	curbuf->b_op_start = orig_start;
2256f4a1d1c0SBram Moolenaar 	curbuf->b_op_end = orig_end;
2257f4a1d1c0SBram Moolenaar     }
22584aea03ebSBram Moolenaar     if (allocated)
22594aea03ebSBram Moolenaar 	vim_free(insert_string);
22604aea03ebSBram Moolenaar     if (regname == '=')
22614aea03ebSBram Moolenaar 	vim_free(y_array);
22624aea03ebSBram Moolenaar 
22634aea03ebSBram Moolenaar     VIsual_active = FALSE;
22644aea03ebSBram Moolenaar 
22654aea03ebSBram Moolenaar     // If the cursor is past the end of the line put it at the end.
22664aea03ebSBram Moolenaar     adjust_cursor_eol();
22674aea03ebSBram Moolenaar }
22684aea03ebSBram Moolenaar 
22694aea03ebSBram Moolenaar /*
22704aea03ebSBram Moolenaar  * Return the character name of the register with the given number.
22714aea03ebSBram Moolenaar  */
22724aea03ebSBram Moolenaar     int
get_register_name(int num)22734aea03ebSBram Moolenaar get_register_name(int num)
22744aea03ebSBram Moolenaar {
22754aea03ebSBram Moolenaar     if (num == -1)
22764aea03ebSBram Moolenaar 	return '"';
22774aea03ebSBram Moolenaar     else if (num < 10)
22784aea03ebSBram Moolenaar 	return num + '0';
22794aea03ebSBram Moolenaar     else if (num == DELETION_REGISTER)
22804aea03ebSBram Moolenaar 	return '-';
22814aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
22824aea03ebSBram Moolenaar     else if (num == STAR_REGISTER)
22834aea03ebSBram Moolenaar 	return '*';
22844aea03ebSBram Moolenaar     else if (num == PLUS_REGISTER)
22854aea03ebSBram Moolenaar 	return '+';
22864aea03ebSBram Moolenaar #endif
22874aea03ebSBram Moolenaar     else
22884aea03ebSBram Moolenaar     {
22894aea03ebSBram Moolenaar #ifdef EBCDIC
22904aea03ebSBram Moolenaar 	int i;
22914aea03ebSBram Moolenaar 
22924aea03ebSBram Moolenaar 	// EBCDIC is really braindead ...
22934aea03ebSBram Moolenaar 	i = 'a' + (num - 10);
22944aea03ebSBram Moolenaar 	if (i > 'i')
22954aea03ebSBram Moolenaar 	    i += 7;
22964aea03ebSBram Moolenaar 	if (i > 'r')
22974aea03ebSBram Moolenaar 	    i += 8;
22984aea03ebSBram Moolenaar 	return i;
22994aea03ebSBram Moolenaar #else
23004aea03ebSBram Moolenaar 	return num + 'a' - 10;
23014aea03ebSBram Moolenaar #endif
23024aea03ebSBram Moolenaar     }
23034aea03ebSBram Moolenaar }
23044aea03ebSBram Moolenaar 
23054aea03ebSBram Moolenaar /*
2306bb861e29SBram Moolenaar  * Return the index of the register "" points to.
2307bb861e29SBram Moolenaar  */
2308bb861e29SBram Moolenaar     int
get_unname_register()2309bb861e29SBram Moolenaar get_unname_register()
2310bb861e29SBram Moolenaar {
2311bb861e29SBram Moolenaar     return y_previous == NULL ? -1 : y_previous - &y_regs[0];
2312bb861e29SBram Moolenaar }
2313bb861e29SBram Moolenaar 
2314bb861e29SBram Moolenaar /*
23154aea03ebSBram Moolenaar  * ":dis" and ":registers": Display the contents of the yank registers.
23164aea03ebSBram Moolenaar  */
23174aea03ebSBram Moolenaar     void
ex_display(exarg_T * eap)23184aea03ebSBram Moolenaar ex_display(exarg_T *eap)
23194aea03ebSBram Moolenaar {
23204aea03ebSBram Moolenaar     int		i, n;
23214aea03ebSBram Moolenaar     long	j;
23224aea03ebSBram Moolenaar     char_u	*p;
23234aea03ebSBram Moolenaar     yankreg_T	*yb;
23244aea03ebSBram Moolenaar     int		name;
23254aea03ebSBram Moolenaar     int		attr;
23264aea03ebSBram Moolenaar     char_u	*arg = eap->arg;
23274aea03ebSBram Moolenaar     int		clen;
23288fc42964SBram Moolenaar     int		type;
23294aea03ebSBram Moolenaar 
23304aea03ebSBram Moolenaar     if (arg != NULL && *arg == NUL)
23314aea03ebSBram Moolenaar 	arg = NULL;
23324aea03ebSBram Moolenaar     attr = HL_ATTR(HLF_8);
23334aea03ebSBram Moolenaar 
23344aea03ebSBram Moolenaar     // Highlight title
23353691f1eeSBram Moolenaar     msg_puts_title(_("\nType Name Content"));
23364aea03ebSBram Moolenaar     for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
23374aea03ebSBram Moolenaar     {
23384aea03ebSBram Moolenaar 	name = get_register_name(i);
23393691f1eeSBram Moolenaar 	switch (get_reg_type(name, NULL))
23403691f1eeSBram Moolenaar 	{
23418fc42964SBram Moolenaar 	    case MLINE: type = 'l'; break;
23428fc42964SBram Moolenaar 	    case MCHAR: type = 'c'; break;
23438fc42964SBram Moolenaar 	    default:	type = 'b'; break;
23443691f1eeSBram Moolenaar 	}
23454aea03ebSBram Moolenaar 	if (arg != NULL && vim_strchr(arg, name) == NULL
23464aea03ebSBram Moolenaar #ifdef ONE_CLIPBOARD
23474aea03ebSBram Moolenaar 	    // Star register and plus register contain the same thing.
23484aea03ebSBram Moolenaar 		&& (name != '*' || vim_strchr(arg, '+') == NULL)
23494aea03ebSBram Moolenaar #endif
23504aea03ebSBram Moolenaar 		)
23514aea03ebSBram Moolenaar 	    continue;	    // did not ask for this register
23524aea03ebSBram Moolenaar 
23534aea03ebSBram Moolenaar #ifdef FEAT_CLIPBOARD
23544aea03ebSBram Moolenaar 	// Adjust register name for "unnamed" in 'clipboard'.
23554aea03ebSBram Moolenaar 	// When it's a clipboard register, fill it with the current contents
23564aea03ebSBram Moolenaar 	// of the clipboard.
23574aea03ebSBram Moolenaar 	adjust_clip_reg(&name);
23584aea03ebSBram Moolenaar 	(void)may_get_selection(name);
23594aea03ebSBram Moolenaar #endif
23604aea03ebSBram Moolenaar 
23614aea03ebSBram Moolenaar 	if (i == -1)
23624aea03ebSBram Moolenaar 	{
23634aea03ebSBram Moolenaar 	    if (y_previous != NULL)
23644aea03ebSBram Moolenaar 		yb = y_previous;
23654aea03ebSBram Moolenaar 	    else
23664aea03ebSBram Moolenaar 		yb = &(y_regs[0]);
23674aea03ebSBram Moolenaar 	}
23684aea03ebSBram Moolenaar 	else
23694aea03ebSBram Moolenaar 	    yb = &(y_regs[i]);
23704aea03ebSBram Moolenaar 
23714aea03ebSBram Moolenaar #ifdef FEAT_EVAL
23724aea03ebSBram Moolenaar 	if (name == MB_TOLOWER(redir_reg)
23734aea03ebSBram Moolenaar 		|| (redir_reg == '"' && yb == y_previous))
23744aea03ebSBram Moolenaar 	    continue;	    // do not list register being written to, the
23754aea03ebSBram Moolenaar 			    // pointer can be freed
23764aea03ebSBram Moolenaar #endif
23774aea03ebSBram Moolenaar 
23784aea03ebSBram Moolenaar 	if (yb->y_array != NULL)
23794aea03ebSBram Moolenaar 	{
23808fc42964SBram Moolenaar 	    int do_show = FALSE;
23818fc42964SBram Moolenaar 
23828fc42964SBram Moolenaar 	    for (j = 0; !do_show && j < yb->y_size; ++j)
23838fc42964SBram Moolenaar 		do_show = !message_filtered(yb->y_array[j]);
23848fc42964SBram Moolenaar 
23858fc42964SBram Moolenaar 	    if (do_show || yb->y_size == 0)
23868fc42964SBram Moolenaar 	    {
23874aea03ebSBram Moolenaar 		msg_putchar('\n');
23883691f1eeSBram Moolenaar 		msg_puts("  ");
23898fc42964SBram Moolenaar 		msg_putchar(type);
23903691f1eeSBram Moolenaar 		msg_puts("  ");
23914aea03ebSBram Moolenaar 		msg_putchar('"');
23924aea03ebSBram Moolenaar 		msg_putchar(name);
23934aea03ebSBram Moolenaar 		msg_puts("   ");
23944aea03ebSBram Moolenaar 
23953691f1eeSBram Moolenaar 		n = (int)Columns - 11;
23964aea03ebSBram Moolenaar 		for (j = 0; j < yb->y_size && n > 1; ++j)
23974aea03ebSBram Moolenaar 		{
23984aea03ebSBram Moolenaar 		    if (j)
23994aea03ebSBram Moolenaar 		    {
24004aea03ebSBram Moolenaar 			msg_puts_attr("^J", attr);
24014aea03ebSBram Moolenaar 			n -= 2;
24024aea03ebSBram Moolenaar 		    }
24038fc42964SBram Moolenaar 		    for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0;
24048fc42964SBram Moolenaar 									   ++p)
24054aea03ebSBram Moolenaar 		    {
24064aea03ebSBram Moolenaar 			clen = (*mb_ptr2len)(p);
24074aea03ebSBram Moolenaar 			msg_outtrans_len(p, clen);
24084aea03ebSBram Moolenaar 			p += clen - 1;
24094aea03ebSBram Moolenaar 		    }
24104aea03ebSBram Moolenaar 		}
24114aea03ebSBram Moolenaar 		if (n > 1 && yb->y_type == MLINE)
24124aea03ebSBram Moolenaar 		    msg_puts_attr("^J", attr);
24134aea03ebSBram Moolenaar 		out_flush();		    // show one line at a time
24144aea03ebSBram Moolenaar 	    }
24154aea03ebSBram Moolenaar 	    ui_breakcheck();
24164aea03ebSBram Moolenaar 	}
24178fc42964SBram Moolenaar     }
24184aea03ebSBram Moolenaar 
24194aea03ebSBram Moolenaar     // display last inserted text
24204aea03ebSBram Moolenaar     if ((p = get_last_insert()) != NULL
24218fc42964SBram Moolenaar 		  && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
24228fc42964SBram Moolenaar 						      && !message_filtered(p))
24234aea03ebSBram Moolenaar     {
24243691f1eeSBram Moolenaar 	msg_puts("\n  c  \".   ");
24254aea03ebSBram Moolenaar 	dis_msg(p, TRUE);
24264aea03ebSBram Moolenaar     }
24274aea03ebSBram Moolenaar 
24284aea03ebSBram Moolenaar     // display last command line
24294aea03ebSBram Moolenaar     if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
24308fc42964SBram Moolenaar 			       && !got_int && !message_filtered(last_cmdline))
24314aea03ebSBram Moolenaar     {
24323691f1eeSBram Moolenaar 	msg_puts("\n  c  \":   ");
24334aea03ebSBram Moolenaar 	dis_msg(last_cmdline, FALSE);
24344aea03ebSBram Moolenaar     }
24354aea03ebSBram Moolenaar 
24364aea03ebSBram Moolenaar     // display current file name
24374aea03ebSBram Moolenaar     if (curbuf->b_fname != NULL
24388fc42964SBram Moolenaar 	    && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int
24398fc42964SBram Moolenaar 					&& !message_filtered(curbuf->b_fname))
24404aea03ebSBram Moolenaar     {
24413691f1eeSBram Moolenaar 	msg_puts("\n  c  \"%   ");
24424aea03ebSBram Moolenaar 	dis_msg(curbuf->b_fname, FALSE);
24434aea03ebSBram Moolenaar     }
24444aea03ebSBram Moolenaar 
24454aea03ebSBram Moolenaar     // display alternate file name
24464aea03ebSBram Moolenaar     if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
24474aea03ebSBram Moolenaar     {
24484aea03ebSBram Moolenaar 	char_u	    *fname;
24494aea03ebSBram Moolenaar 	linenr_T    dummy;
24504aea03ebSBram Moolenaar 
24518fc42964SBram Moolenaar 	if (buflist_name_nr(0, &fname, &dummy) != FAIL
24528fc42964SBram Moolenaar 						  && !message_filtered(fname))
24534aea03ebSBram Moolenaar 	{
24543691f1eeSBram Moolenaar 	    msg_puts("\n  c  \"#   ");
24554aea03ebSBram Moolenaar 	    dis_msg(fname, FALSE);
24564aea03ebSBram Moolenaar 	}
24574aea03ebSBram Moolenaar     }
24584aea03ebSBram Moolenaar 
24594aea03ebSBram Moolenaar     // display last search pattern
24604aea03ebSBram Moolenaar     if (last_search_pat() != NULL
24618fc42964SBram Moolenaar 		 && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int
24628fc42964SBram Moolenaar 				      && !message_filtered(last_search_pat()))
24634aea03ebSBram Moolenaar     {
24643691f1eeSBram Moolenaar 	msg_puts("\n  c  \"/   ");
24654aea03ebSBram Moolenaar 	dis_msg(last_search_pat(), FALSE);
24664aea03ebSBram Moolenaar     }
24674aea03ebSBram Moolenaar 
24684aea03ebSBram Moolenaar #ifdef FEAT_EVAL
24694aea03ebSBram Moolenaar     // display last used expression
24704aea03ebSBram Moolenaar     if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
24718fc42964SBram Moolenaar 				  && !got_int && !message_filtered(expr_line))
24724aea03ebSBram Moolenaar     {
24733691f1eeSBram Moolenaar 	msg_puts("\n  c  \"=   ");
24744aea03ebSBram Moolenaar 	dis_msg(expr_line, FALSE);
24754aea03ebSBram Moolenaar     }
24764aea03ebSBram Moolenaar #endif
24774aea03ebSBram Moolenaar }
24784aea03ebSBram Moolenaar 
24794aea03ebSBram Moolenaar /*
24804aea03ebSBram Moolenaar  * display a string for do_dis()
24814aea03ebSBram Moolenaar  * truncate at end of screen line
24824aea03ebSBram Moolenaar  */
24834aea03ebSBram Moolenaar     static void
dis_msg(char_u * p,int skip_esc)24844aea03ebSBram Moolenaar dis_msg(
24854aea03ebSBram Moolenaar     char_u	*p,
24864aea03ebSBram Moolenaar     int		skip_esc)	    // if TRUE, ignore trailing ESC
24874aea03ebSBram Moolenaar {
24884aea03ebSBram Moolenaar     int		n;
24894aea03ebSBram Moolenaar     int		l;
24904aea03ebSBram Moolenaar 
24914aea03ebSBram Moolenaar     n = (int)Columns - 6;
24924aea03ebSBram Moolenaar     while (*p != NUL
24934aea03ebSBram Moolenaar 	    && !(*p == ESC && skip_esc && *(p + 1) == NUL)
24944aea03ebSBram Moolenaar 	    && (n -= ptr2cells(p)) >= 0)
24954aea03ebSBram Moolenaar     {
24964aea03ebSBram Moolenaar 	if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
24974aea03ebSBram Moolenaar 	{
24984aea03ebSBram Moolenaar 	    msg_outtrans_len(p, l);
24994aea03ebSBram Moolenaar 	    p += l;
25004aea03ebSBram Moolenaar 	}
25014aea03ebSBram Moolenaar 	else
25024aea03ebSBram Moolenaar 	    msg_outtrans_len(p++, 1);
25034aea03ebSBram Moolenaar     }
25044aea03ebSBram Moolenaar     ui_breakcheck();
25054aea03ebSBram Moolenaar }
25064aea03ebSBram Moolenaar 
25074aea03ebSBram Moolenaar #if defined(FEAT_DND) || defined(PROTO)
25084aea03ebSBram Moolenaar /*
25094aea03ebSBram Moolenaar  * Replace the contents of the '~' register with str.
25104aea03ebSBram Moolenaar  */
25114aea03ebSBram Moolenaar     void
dnd_yank_drag_data(char_u * str,long len)25124aea03ebSBram Moolenaar dnd_yank_drag_data(char_u *str, long len)
25134aea03ebSBram Moolenaar {
25144aea03ebSBram Moolenaar     yankreg_T *curr;
25154aea03ebSBram Moolenaar 
25164aea03ebSBram Moolenaar     curr = y_current;
25174aea03ebSBram Moolenaar     y_current = &y_regs[TILDE_REGISTER];
25184aea03ebSBram Moolenaar     free_yank_all();
25194aea03ebSBram Moolenaar     str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
25204aea03ebSBram Moolenaar     y_current = curr;
25214aea03ebSBram Moolenaar }
25224aea03ebSBram Moolenaar #endif
25234aea03ebSBram Moolenaar 
25244aea03ebSBram Moolenaar 
25254aea03ebSBram Moolenaar /*
25264aea03ebSBram Moolenaar  * Return the type of a register.
25274aea03ebSBram Moolenaar  * Used for getregtype()
25284aea03ebSBram Moolenaar  * Returns MAUTO for error.
25294aea03ebSBram Moolenaar  */
25304aea03ebSBram Moolenaar     char_u
get_reg_type(int regname,long * reglen)25314aea03ebSBram Moolenaar get_reg_type(int regname, long *reglen)
25324aea03ebSBram Moolenaar {
25334aea03ebSBram Moolenaar     switch (regname)
25344aea03ebSBram Moolenaar     {
25354aea03ebSBram Moolenaar 	case '%':		// file name
25364aea03ebSBram Moolenaar 	case '#':		// alternate file name
25374aea03ebSBram Moolenaar 	case '=':		// expression
25384aea03ebSBram Moolenaar 	case ':':		// last command line
25394aea03ebSBram Moolenaar 	case '/':		// last search-pattern
25404aea03ebSBram Moolenaar 	case '.':		// last inserted text
25414aea03ebSBram Moolenaar # ifdef FEAT_SEARCHPATH
25424aea03ebSBram Moolenaar 	case Ctrl_F:		// Filename under cursor
25434aea03ebSBram Moolenaar 	case Ctrl_P:		// Path under cursor, expand via "path"
25444aea03ebSBram Moolenaar # endif
25454aea03ebSBram Moolenaar 	case Ctrl_W:		// word under cursor
25464aea03ebSBram Moolenaar 	case Ctrl_A:		// WORD (mnemonic All) under cursor
25474aea03ebSBram Moolenaar 	case '_':		// black hole: always empty
25484aea03ebSBram Moolenaar 	    return MCHAR;
25494aea03ebSBram Moolenaar     }
25504aea03ebSBram Moolenaar 
25514aea03ebSBram Moolenaar # ifdef FEAT_CLIPBOARD
25524aea03ebSBram Moolenaar     regname = may_get_selection(regname);
25534aea03ebSBram Moolenaar # endif
25544aea03ebSBram Moolenaar 
25554aea03ebSBram Moolenaar     if (regname != NUL && !valid_yank_reg(regname, FALSE))
25564aea03ebSBram Moolenaar 	return MAUTO;
25574aea03ebSBram Moolenaar 
25584aea03ebSBram Moolenaar     get_yank_register(regname, FALSE);
25594aea03ebSBram Moolenaar 
25604aea03ebSBram Moolenaar     if (y_current->y_array != NULL)
25614aea03ebSBram Moolenaar     {
25624aea03ebSBram Moolenaar 	if (reglen != NULL && y_current->y_type == MBLOCK)
25634aea03ebSBram Moolenaar 	    *reglen = y_current->y_width;
25644aea03ebSBram Moolenaar 	return y_current->y_type;
25654aea03ebSBram Moolenaar     }
25664aea03ebSBram Moolenaar     return MAUTO;
25674aea03ebSBram Moolenaar }
25684aea03ebSBram Moolenaar 
25693691f1eeSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
25704aea03ebSBram Moolenaar /*
25714aea03ebSBram Moolenaar  * When "flags" has GREG_LIST return a list with text "s".
25724aea03ebSBram Moolenaar  * Otherwise just return "s".
25734aea03ebSBram Moolenaar  */
25744aea03ebSBram Moolenaar     static char_u *
getreg_wrap_one_line(char_u * s,int flags)25754aea03ebSBram Moolenaar getreg_wrap_one_line(char_u *s, int flags)
25764aea03ebSBram Moolenaar {
25774aea03ebSBram Moolenaar     if (flags & GREG_LIST)
25784aea03ebSBram Moolenaar     {
25794aea03ebSBram Moolenaar 	list_T *list = list_alloc();
25804aea03ebSBram Moolenaar 
25814aea03ebSBram Moolenaar 	if (list != NULL)
25824aea03ebSBram Moolenaar 	{
25834aea03ebSBram Moolenaar 	    if (list_append_string(list, NULL, -1) == FAIL)
25844aea03ebSBram Moolenaar 	    {
25854aea03ebSBram Moolenaar 		list_free(list);
25864aea03ebSBram Moolenaar 		return NULL;
25874aea03ebSBram Moolenaar 	    }
25884aea03ebSBram Moolenaar 	    list->lv_first->li_tv.vval.v_string = s;
25894aea03ebSBram Moolenaar 	}
25904aea03ebSBram Moolenaar 	return (char_u *)list;
25914aea03ebSBram Moolenaar     }
25924aea03ebSBram Moolenaar     return s;
25934aea03ebSBram Moolenaar }
25944aea03ebSBram Moolenaar 
25954aea03ebSBram Moolenaar /*
2596d672dde5SBram Moolenaar  * Return the contents of a register as a single allocated string or as a list.
25974aea03ebSBram Moolenaar  * Used for "@r" in expressions and for getreg().
25984aea03ebSBram Moolenaar  * Returns NULL for error.
25994aea03ebSBram Moolenaar  * Flags:
26004aea03ebSBram Moolenaar  *	GREG_NO_EXPR	Do not allow expression register
26014aea03ebSBram Moolenaar  *	GREG_EXPR_SRC	For the expression register: return expression itself,
26024aea03ebSBram Moolenaar  *			not the result of its evaluation.
2603d672dde5SBram Moolenaar  *	GREG_LIST	Return a list of lines instead of a single string.
26044aea03ebSBram Moolenaar  */
26054aea03ebSBram Moolenaar     char_u *
get_reg_contents(int regname,int flags)26064aea03ebSBram Moolenaar get_reg_contents(int regname, int flags)
26074aea03ebSBram Moolenaar {
26084aea03ebSBram Moolenaar     long	i;
26094aea03ebSBram Moolenaar     char_u	*retval;
26104aea03ebSBram Moolenaar     int		allocated;
26114aea03ebSBram Moolenaar     long	len;
26124aea03ebSBram Moolenaar 
26134aea03ebSBram Moolenaar     // Don't allow using an expression register inside an expression
26144aea03ebSBram Moolenaar     if (regname == '=')
26154aea03ebSBram Moolenaar     {
26164aea03ebSBram Moolenaar 	if (flags & GREG_NO_EXPR)
26174aea03ebSBram Moolenaar 	    return NULL;
26184aea03ebSBram Moolenaar 	if (flags & GREG_EXPR_SRC)
26194aea03ebSBram Moolenaar 	    return getreg_wrap_one_line(get_expr_line_src(), flags);
26204aea03ebSBram Moolenaar 	return getreg_wrap_one_line(get_expr_line(), flags);
26214aea03ebSBram Moolenaar     }
26224aea03ebSBram Moolenaar 
26234aea03ebSBram Moolenaar     if (regname == '@')	    // "@@" is used for unnamed register
26244aea03ebSBram Moolenaar 	regname = '"';
26254aea03ebSBram Moolenaar 
26264aea03ebSBram Moolenaar     // check for valid regname
26274aea03ebSBram Moolenaar     if (regname != NUL && !valid_yank_reg(regname, FALSE))
26284aea03ebSBram Moolenaar 	return NULL;
26294aea03ebSBram Moolenaar 
26304aea03ebSBram Moolenaar # ifdef FEAT_CLIPBOARD
26314aea03ebSBram Moolenaar     regname = may_get_selection(regname);
26324aea03ebSBram Moolenaar # endif
26334aea03ebSBram Moolenaar 
26344aea03ebSBram Moolenaar     if (get_spec_reg(regname, &retval, &allocated, FALSE))
26354aea03ebSBram Moolenaar     {
26364aea03ebSBram Moolenaar 	if (retval == NULL)
26374aea03ebSBram Moolenaar 	    return NULL;
26384aea03ebSBram Moolenaar 	if (allocated)
26394aea03ebSBram Moolenaar 	    return getreg_wrap_one_line(retval, flags);
26404aea03ebSBram Moolenaar 	return getreg_wrap_one_line(vim_strsave(retval), flags);
26414aea03ebSBram Moolenaar     }
26424aea03ebSBram Moolenaar 
26434aea03ebSBram Moolenaar     get_yank_register(regname, FALSE);
26444aea03ebSBram Moolenaar     if (y_current->y_array == NULL)
26454aea03ebSBram Moolenaar 	return NULL;
26464aea03ebSBram Moolenaar 
26474aea03ebSBram Moolenaar     if (flags & GREG_LIST)
26484aea03ebSBram Moolenaar     {
26494aea03ebSBram Moolenaar 	list_T	*list = list_alloc();
26504aea03ebSBram Moolenaar 	int	error = FALSE;
26514aea03ebSBram Moolenaar 
26524aea03ebSBram Moolenaar 	if (list == NULL)
26534aea03ebSBram Moolenaar 	    return NULL;
26544aea03ebSBram Moolenaar 	for (i = 0; i < y_current->y_size; ++i)
26554aea03ebSBram Moolenaar 	    if (list_append_string(list, y_current->y_array[i], -1) == FAIL)
26564aea03ebSBram Moolenaar 		error = TRUE;
26574aea03ebSBram Moolenaar 	if (error)
26584aea03ebSBram Moolenaar 	{
26594aea03ebSBram Moolenaar 	    list_free(list);
26604aea03ebSBram Moolenaar 	    return NULL;
26614aea03ebSBram Moolenaar 	}
26624aea03ebSBram Moolenaar 	return (char_u *)list;
26634aea03ebSBram Moolenaar     }
26644aea03ebSBram Moolenaar 
26654aea03ebSBram Moolenaar     // Compute length of resulting string.
26664aea03ebSBram Moolenaar     len = 0;
26674aea03ebSBram Moolenaar     for (i = 0; i < y_current->y_size; ++i)
26684aea03ebSBram Moolenaar     {
26694aea03ebSBram Moolenaar 	len += (long)STRLEN(y_current->y_array[i]);
26704aea03ebSBram Moolenaar 	// Insert a newline between lines and after last line if
26714aea03ebSBram Moolenaar 	// y_type is MLINE.
26724aea03ebSBram Moolenaar 	if (y_current->y_type == MLINE || i < y_current->y_size - 1)
26734aea03ebSBram Moolenaar 	    ++len;
26744aea03ebSBram Moolenaar     }
26754aea03ebSBram Moolenaar 
26764aea03ebSBram Moolenaar     retval = alloc(len + 1);
26774aea03ebSBram Moolenaar 
26784aea03ebSBram Moolenaar     // Copy the lines of the yank register into the string.
26794aea03ebSBram Moolenaar     if (retval != NULL)
26804aea03ebSBram Moolenaar     {
26814aea03ebSBram Moolenaar 	len = 0;
26824aea03ebSBram Moolenaar 	for (i = 0; i < y_current->y_size; ++i)
26834aea03ebSBram Moolenaar 	{
26844aea03ebSBram Moolenaar 	    STRCPY(retval + len, y_current->y_array[i]);
26854aea03ebSBram Moolenaar 	    len += (long)STRLEN(retval + len);
26864aea03ebSBram Moolenaar 
26874aea03ebSBram Moolenaar 	    // Insert a NL between lines and after the last line if y_type is
26884aea03ebSBram Moolenaar 	    // MLINE.
26894aea03ebSBram Moolenaar 	    if (y_current->y_type == MLINE || i < y_current->y_size - 1)
26904aea03ebSBram Moolenaar 		retval[len++] = '\n';
26914aea03ebSBram Moolenaar 	}
26924aea03ebSBram Moolenaar 	retval[len] = NUL;
26934aea03ebSBram Moolenaar     }
26944aea03ebSBram Moolenaar 
26954aea03ebSBram Moolenaar     return retval;
26964aea03ebSBram Moolenaar }
26974aea03ebSBram Moolenaar 
26984aea03ebSBram Moolenaar     static int
init_write_reg(int name,yankreg_T ** old_y_previous,yankreg_T ** old_y_current,int must_append,int * yank_type UNUSED)26994aea03ebSBram Moolenaar init_write_reg(
27004aea03ebSBram Moolenaar     int		name,
27014aea03ebSBram Moolenaar     yankreg_T	**old_y_previous,
27024aea03ebSBram Moolenaar     yankreg_T	**old_y_current,
27034aea03ebSBram Moolenaar     int		must_append,
27044aea03ebSBram Moolenaar     int		*yank_type UNUSED)
27054aea03ebSBram Moolenaar {
27064aea03ebSBram Moolenaar     if (!valid_yank_reg(name, TRUE))	    // check for valid reg name
27074aea03ebSBram Moolenaar     {
27084aea03ebSBram Moolenaar 	emsg_invreg(name);
27094aea03ebSBram Moolenaar 	return FAIL;
27104aea03ebSBram Moolenaar     }
27114aea03ebSBram Moolenaar 
27124aea03ebSBram Moolenaar     // Don't want to change the current (unnamed) register
27134aea03ebSBram Moolenaar     *old_y_previous = y_previous;
27144aea03ebSBram Moolenaar     *old_y_current = y_current;
27154aea03ebSBram Moolenaar 
27164aea03ebSBram Moolenaar     get_yank_register(name, TRUE);
27174aea03ebSBram Moolenaar     if (!y_append && !must_append)
27184aea03ebSBram Moolenaar 	free_yank_all();
27194aea03ebSBram Moolenaar     return OK;
27204aea03ebSBram Moolenaar }
27214aea03ebSBram Moolenaar 
27224aea03ebSBram Moolenaar     static void
finish_write_reg(int name,yankreg_T * old_y_previous,yankreg_T * old_y_current)27234aea03ebSBram Moolenaar finish_write_reg(
27244aea03ebSBram Moolenaar     int		name,
27254aea03ebSBram Moolenaar     yankreg_T	*old_y_previous,
27264aea03ebSBram Moolenaar     yankreg_T	*old_y_current)
27274aea03ebSBram Moolenaar {
27284aea03ebSBram Moolenaar # ifdef FEAT_CLIPBOARD
27294aea03ebSBram Moolenaar     // Send text of clipboard register to the clipboard.
27304aea03ebSBram Moolenaar     may_set_selection();
27314aea03ebSBram Moolenaar # endif
27324aea03ebSBram Moolenaar 
27334aea03ebSBram Moolenaar     // ':let @" = "val"' should change the meaning of the "" register
27344aea03ebSBram Moolenaar     if (name != '"')
27354aea03ebSBram Moolenaar 	y_previous = old_y_previous;
27364aea03ebSBram Moolenaar     y_current = old_y_current;
27374aea03ebSBram Moolenaar }
27384aea03ebSBram Moolenaar 
27394aea03ebSBram Moolenaar /*
27404aea03ebSBram Moolenaar  * Store string "str" in register "name".
27414aea03ebSBram Moolenaar  * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
27424aea03ebSBram Moolenaar  * If "must_append" is TRUE, always append to the register.  Otherwise append
27434aea03ebSBram Moolenaar  * if "name" is an uppercase letter.
27444aea03ebSBram Moolenaar  * Note: "maxlen" and "must_append" don't work for the "/" register.
27454aea03ebSBram Moolenaar  * Careful: 'str' is modified, you may have to use a copy!
27464aea03ebSBram Moolenaar  * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise.
27474aea03ebSBram Moolenaar  */
27484aea03ebSBram Moolenaar     void
write_reg_contents(int name,char_u * str,int maxlen,int must_append)27494aea03ebSBram Moolenaar write_reg_contents(
27504aea03ebSBram Moolenaar     int		name,
27514aea03ebSBram Moolenaar     char_u	*str,
27524aea03ebSBram Moolenaar     int		maxlen,
27534aea03ebSBram Moolenaar     int		must_append)
27544aea03ebSBram Moolenaar {
27554aea03ebSBram Moolenaar     write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
27564aea03ebSBram Moolenaar }
27574aea03ebSBram Moolenaar 
27584aea03ebSBram Moolenaar     void
write_reg_contents_lst(int name,char_u ** strings,int maxlen UNUSED,int must_append,int yank_type,long block_len)27594aea03ebSBram Moolenaar write_reg_contents_lst(
27604aea03ebSBram Moolenaar     int		name,
27614aea03ebSBram Moolenaar     char_u	**strings,
27624aea03ebSBram Moolenaar     int		maxlen UNUSED,
27634aea03ebSBram Moolenaar     int		must_append,
27644aea03ebSBram Moolenaar     int		yank_type,
27654aea03ebSBram Moolenaar     long	block_len)
27664aea03ebSBram Moolenaar {
27674aea03ebSBram Moolenaar     yankreg_T  *old_y_previous, *old_y_current;
27684aea03ebSBram Moolenaar 
27694aea03ebSBram Moolenaar     if (name == '/' || name == '=')
27704aea03ebSBram Moolenaar     {
27714aea03ebSBram Moolenaar 	char_u	*s;
27724aea03ebSBram Moolenaar 
27734aea03ebSBram Moolenaar 	if (strings[0] == NULL)
27744aea03ebSBram Moolenaar 	    s = (char_u *)"";
27754aea03ebSBram Moolenaar 	else if (strings[1] != NULL)
27764aea03ebSBram Moolenaar 	{
27774aea03ebSBram Moolenaar 	    emsg(_("E883: search pattern and expression register may not "
27784aea03ebSBram Moolenaar 			"contain two or more lines"));
27794aea03ebSBram Moolenaar 	    return;
27804aea03ebSBram Moolenaar 	}
27814aea03ebSBram Moolenaar 	else
27824aea03ebSBram Moolenaar 	    s = strings[0];
27834aea03ebSBram Moolenaar 	write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
27844aea03ebSBram Moolenaar 	return;
27854aea03ebSBram Moolenaar     }
27864aea03ebSBram Moolenaar 
27874aea03ebSBram Moolenaar     if (name == '_')	    // black hole: nothing to do
27884aea03ebSBram Moolenaar 	return;
27894aea03ebSBram Moolenaar 
27904aea03ebSBram Moolenaar     if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
27914aea03ebSBram Moolenaar 		&yank_type) == FAIL)
27924aea03ebSBram Moolenaar 	return;
27934aea03ebSBram Moolenaar 
27944aea03ebSBram Moolenaar     str_to_reg(y_current, yank_type, (char_u *)strings, -1, block_len, TRUE);
27954aea03ebSBram Moolenaar 
27964aea03ebSBram Moolenaar     finish_write_reg(name, old_y_previous, old_y_current);
27974aea03ebSBram Moolenaar }
27984aea03ebSBram Moolenaar 
27994aea03ebSBram Moolenaar     void
write_reg_contents_ex(int name,char_u * str,int maxlen,int must_append,int yank_type,long block_len)28004aea03ebSBram Moolenaar write_reg_contents_ex(
28014aea03ebSBram Moolenaar     int		name,
28024aea03ebSBram Moolenaar     char_u	*str,
28034aea03ebSBram Moolenaar     int		maxlen,
28044aea03ebSBram Moolenaar     int		must_append,
28054aea03ebSBram Moolenaar     int		yank_type,
28064aea03ebSBram Moolenaar     long	block_len)
28074aea03ebSBram Moolenaar {
28084aea03ebSBram Moolenaar     yankreg_T	*old_y_previous, *old_y_current;
28094aea03ebSBram Moolenaar     long	len;
28104aea03ebSBram Moolenaar 
28114aea03ebSBram Moolenaar     if (maxlen >= 0)
28124aea03ebSBram Moolenaar 	len = maxlen;
28134aea03ebSBram Moolenaar     else
28144aea03ebSBram Moolenaar 	len = (long)STRLEN(str);
28154aea03ebSBram Moolenaar 
28164aea03ebSBram Moolenaar     // Special case: '/' search pattern
28174aea03ebSBram Moolenaar     if (name == '/')
28184aea03ebSBram Moolenaar     {
28194aea03ebSBram Moolenaar 	set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
28204aea03ebSBram Moolenaar 	return;
28214aea03ebSBram Moolenaar     }
28224aea03ebSBram Moolenaar 
28234aea03ebSBram Moolenaar     if (name == '#')
28244aea03ebSBram Moolenaar     {
28254aea03ebSBram Moolenaar 	buf_T	*buf;
28264aea03ebSBram Moolenaar 
28274aea03ebSBram Moolenaar 	if (VIM_ISDIGIT(*str))
28284aea03ebSBram Moolenaar 	{
28294aea03ebSBram Moolenaar 	    int	num = atoi((char *)str);
28304aea03ebSBram Moolenaar 
28314aea03ebSBram Moolenaar 	    buf = buflist_findnr(num);
28324aea03ebSBram Moolenaar 	    if (buf == NULL)
28334aea03ebSBram Moolenaar 		semsg(_(e_nobufnr), (long)num);
28344aea03ebSBram Moolenaar 	}
28354aea03ebSBram Moolenaar 	else
28364aea03ebSBram Moolenaar 	    buf = buflist_findnr(buflist_findpat(str, str + STRLEN(str),
28374aea03ebSBram Moolenaar 							 TRUE, FALSE, FALSE));
28384aea03ebSBram Moolenaar 	if (buf == NULL)
28394aea03ebSBram Moolenaar 	    return;
28404aea03ebSBram Moolenaar 	curwin->w_alt_fnum = buf->b_fnum;
28414aea03ebSBram Moolenaar 	return;
28424aea03ebSBram Moolenaar     }
28434aea03ebSBram Moolenaar 
28444aea03ebSBram Moolenaar     if (name == '=')
28454aea03ebSBram Moolenaar     {
28464aea03ebSBram Moolenaar 	char_u	    *p, *s;
28474aea03ebSBram Moolenaar 
284871ccd03eSBram Moolenaar 	p = vim_strnsave(str, len);
28494aea03ebSBram Moolenaar 	if (p == NULL)
28504aea03ebSBram Moolenaar 	    return;
28516b649ac4SBram Moolenaar 	if (must_append && expr_line != NULL)
28524aea03ebSBram Moolenaar 	{
28536b649ac4SBram Moolenaar 	    s = concat_str(expr_line, p);
28544aea03ebSBram Moolenaar 	    vim_free(p);
28554aea03ebSBram Moolenaar 	    p = s;
28564aea03ebSBram Moolenaar 	}
2857b4bcea47SBram Moolenaar 	set_expr_line(p, NULL);
28584aea03ebSBram Moolenaar 	return;
28594aea03ebSBram Moolenaar     }
28604aea03ebSBram Moolenaar 
28614aea03ebSBram Moolenaar     if (name == '_')	    // black hole: nothing to do
28624aea03ebSBram Moolenaar 	return;
28634aea03ebSBram Moolenaar 
28644aea03ebSBram Moolenaar     if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
28654aea03ebSBram Moolenaar 		&yank_type) == FAIL)
28664aea03ebSBram Moolenaar 	return;
28674aea03ebSBram Moolenaar 
28684aea03ebSBram Moolenaar     str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
28694aea03ebSBram Moolenaar 
28704aea03ebSBram Moolenaar     finish_write_reg(name, old_y_previous, old_y_current);
28714aea03ebSBram Moolenaar }
28724aea03ebSBram Moolenaar #endif	// FEAT_EVAL
28734aea03ebSBram Moolenaar 
28744aea03ebSBram Moolenaar #if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
28754aea03ebSBram Moolenaar /*
28764aea03ebSBram Moolenaar  * Put a string into a register.  When the register is not empty, the string
28774aea03ebSBram Moolenaar  * is appended.
28784aea03ebSBram Moolenaar  */
287945fffdf1SBram Moolenaar     void
str_to_reg(yankreg_T * y_ptr,int yank_type,char_u * str,long len,long blocklen,int str_list)28804aea03ebSBram Moolenaar str_to_reg(
28814aea03ebSBram Moolenaar     yankreg_T	*y_ptr,		// pointer to yank register
28824aea03ebSBram Moolenaar     int		yank_type,	// MCHAR, MLINE, MBLOCK, MAUTO
28834aea03ebSBram Moolenaar     char_u	*str,		// string to put in register
28844aea03ebSBram Moolenaar     long	len,		// length of string
28854aea03ebSBram Moolenaar     long	blocklen,	// width of Visual block
28864aea03ebSBram Moolenaar     int		str_list)	// TRUE if str is char_u **
28874aea03ebSBram Moolenaar {
28884aea03ebSBram Moolenaar     int		type;			// MCHAR, MLINE or MBLOCK
28894aea03ebSBram Moolenaar     int		lnum;
28904aea03ebSBram Moolenaar     long	start;
28914aea03ebSBram Moolenaar     long	i;
28924aea03ebSBram Moolenaar     int		extra;
28934aea03ebSBram Moolenaar     int		newlines;		// number of lines added
28944aea03ebSBram Moolenaar     int		extraline = 0;		// extra line at the end
28954aea03ebSBram Moolenaar     int		append = FALSE;		// append to last line in register
28964aea03ebSBram Moolenaar     char_u	*s;
28974aea03ebSBram Moolenaar     char_u	**ss;
28984aea03ebSBram Moolenaar     char_u	**pp;
28994aea03ebSBram Moolenaar     long	maxlen;
29004aea03ebSBram Moolenaar 
29014aea03ebSBram Moolenaar     if (y_ptr->y_array == NULL)		// NULL means empty register
29024aea03ebSBram Moolenaar 	y_ptr->y_size = 0;
29034aea03ebSBram Moolenaar 
29044aea03ebSBram Moolenaar     if (yank_type == MAUTO)
29054aea03ebSBram Moolenaar 	type = ((str_list || (len > 0 && (str[len - 1] == NL
29064aea03ebSBram Moolenaar 					    || str[len - 1] == CAR)))
29074aea03ebSBram Moolenaar 							     ? MLINE : MCHAR);
29084aea03ebSBram Moolenaar     else
29094aea03ebSBram Moolenaar 	type = yank_type;
29104aea03ebSBram Moolenaar 
29114aea03ebSBram Moolenaar     // Count the number of lines within the string
29124aea03ebSBram Moolenaar     newlines = 0;
29134aea03ebSBram Moolenaar     if (str_list)
29144aea03ebSBram Moolenaar     {
29154aea03ebSBram Moolenaar 	for (ss = (char_u **) str; *ss != NULL; ++ss)
29164aea03ebSBram Moolenaar 	    ++newlines;
29174aea03ebSBram Moolenaar     }
29184aea03ebSBram Moolenaar     else
29194aea03ebSBram Moolenaar     {
29204aea03ebSBram Moolenaar 	for (i = 0; i < len; i++)
29214aea03ebSBram Moolenaar 	    if (str[i] == '\n')
29224aea03ebSBram Moolenaar 		++newlines;
29234aea03ebSBram Moolenaar 	if (type == MCHAR || len == 0 || str[len - 1] != '\n')
29244aea03ebSBram Moolenaar 	{
29254aea03ebSBram Moolenaar 	    extraline = 1;
29264aea03ebSBram Moolenaar 	    ++newlines;	// count extra newline at the end
29274aea03ebSBram Moolenaar 	}
29284aea03ebSBram Moolenaar 	if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR)
29294aea03ebSBram Moolenaar 	{
29304aea03ebSBram Moolenaar 	    append = TRUE;
29314aea03ebSBram Moolenaar 	    --newlines;	// uncount newline when appending first line
29324aea03ebSBram Moolenaar 	}
29334aea03ebSBram Moolenaar     }
29344aea03ebSBram Moolenaar 
29354aea03ebSBram Moolenaar     // Without any lines make the register empty.
29364aea03ebSBram Moolenaar     if (y_ptr->y_size + newlines == 0)
29374aea03ebSBram Moolenaar     {
29384aea03ebSBram Moolenaar 	VIM_CLEAR(y_ptr->y_array);
29394aea03ebSBram Moolenaar 	return;
29404aea03ebSBram Moolenaar     }
29414aea03ebSBram Moolenaar 
29424aea03ebSBram Moolenaar     // Allocate an array to hold the pointers to the new register lines.
29434aea03ebSBram Moolenaar     // If the register was not empty, move the existing lines to the new array.
29444aea03ebSBram Moolenaar     pp = lalloc_clear((y_ptr->y_size + newlines) * sizeof(char_u *), TRUE);
29454aea03ebSBram Moolenaar     if (pp == NULL)	// out of memory
29464aea03ebSBram Moolenaar 	return;
29474aea03ebSBram Moolenaar     for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
29484aea03ebSBram Moolenaar 	pp[lnum] = y_ptr->y_array[lnum];
29494aea03ebSBram Moolenaar     vim_free(y_ptr->y_array);
29504aea03ebSBram Moolenaar     y_ptr->y_array = pp;
29514aea03ebSBram Moolenaar     maxlen = 0;
29524aea03ebSBram Moolenaar 
29534aea03ebSBram Moolenaar     // Find the end of each line and save it into the array.
29544aea03ebSBram Moolenaar     if (str_list)
29554aea03ebSBram Moolenaar     {
29564aea03ebSBram Moolenaar 	for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
29574aea03ebSBram Moolenaar 	{
29586c4c404cSBram Moolenaar 	    pp[lnum] = vim_strsave(*ss);
29596c4c404cSBram Moolenaar 	    if (type == MBLOCK)
29606c4c404cSBram Moolenaar 	    {
29616c4c404cSBram Moolenaar 		int charlen = mb_string2cells(*ss, -1);
29626c4c404cSBram Moolenaar 
29636e0b553fSBram Moolenaar 		if (charlen > maxlen)
29646e0b553fSBram Moolenaar 		    maxlen = charlen;
29654aea03ebSBram Moolenaar 	    }
29664aea03ebSBram Moolenaar 	}
29676c4c404cSBram Moolenaar     }
29684aea03ebSBram Moolenaar     else
29694aea03ebSBram Moolenaar     {
29704aea03ebSBram Moolenaar 	for (start = 0; start < len + extraline; start += i + 1)
29714aea03ebSBram Moolenaar 	{
29726c4c404cSBram Moolenaar 	    int charlen = 0;
29736c4c404cSBram Moolenaar 
29744aea03ebSBram Moolenaar 	    for (i = start; i < len; ++i)	// find the end of the line
297524951a67SBram Moolenaar 	    {
29764aea03ebSBram Moolenaar 		if (str[i] == '\n')
29774aea03ebSBram Moolenaar 		    break;
29786c4c404cSBram Moolenaar 		if (type == MBLOCK)
297924951a67SBram Moolenaar 		    charlen += mb_ptr2cells_len(str + i, len - i);
298024951a67SBram Moolenaar 	    }
29814aea03ebSBram Moolenaar 	    i -= start;			// i is now length of line
29826e0b553fSBram Moolenaar 	    if (charlen > maxlen)
29836e0b553fSBram Moolenaar 		maxlen = charlen;
29844aea03ebSBram Moolenaar 	    if (append)
29854aea03ebSBram Moolenaar 	    {
29864aea03ebSBram Moolenaar 		--lnum;
29874aea03ebSBram Moolenaar 		extra = (int)STRLEN(y_ptr->y_array[lnum]);
29884aea03ebSBram Moolenaar 	    }
29894aea03ebSBram Moolenaar 	    else
29904aea03ebSBram Moolenaar 		extra = 0;
29914aea03ebSBram Moolenaar 	    s = alloc(i + extra + 1);
29924aea03ebSBram Moolenaar 	    if (s == NULL)
29934aea03ebSBram Moolenaar 		break;
29944aea03ebSBram Moolenaar 	    if (extra)
29954aea03ebSBram Moolenaar 		mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
29964aea03ebSBram Moolenaar 	    if (append)
29974aea03ebSBram Moolenaar 		vim_free(y_ptr->y_array[lnum]);
299824951a67SBram Moolenaar 	    if (i > 0)
29994aea03ebSBram Moolenaar 		mch_memmove(s + extra, str + start, (size_t)i);
30004aea03ebSBram Moolenaar 	    extra += i;
30014aea03ebSBram Moolenaar 	    s[extra] = NUL;
30024aea03ebSBram Moolenaar 	    y_ptr->y_array[lnum++] = s;
30034aea03ebSBram Moolenaar 	    while (--extra >= 0)
30044aea03ebSBram Moolenaar 	    {
30054aea03ebSBram Moolenaar 		if (*s == NUL)
30064aea03ebSBram Moolenaar 		    *s = '\n';	    // replace NUL with newline
30074aea03ebSBram Moolenaar 		++s;
30084aea03ebSBram Moolenaar 	    }
30094aea03ebSBram Moolenaar 	    append = FALSE;		    // only first line is appended
30104aea03ebSBram Moolenaar 	}
30114aea03ebSBram Moolenaar     }
30124aea03ebSBram Moolenaar     y_ptr->y_type = type;
30134aea03ebSBram Moolenaar     y_ptr->y_size = lnum;
30144aea03ebSBram Moolenaar     if (type == MBLOCK)
30154aea03ebSBram Moolenaar 	y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
30164aea03ebSBram Moolenaar     else
30174aea03ebSBram Moolenaar 	y_ptr->y_width = 0;
30184aea03ebSBram Moolenaar # ifdef FEAT_VIMINFO
30194aea03ebSBram Moolenaar     y_ptr->y_time_set = vim_time();
30204aea03ebSBram Moolenaar # endif
30214aea03ebSBram Moolenaar }
30224aea03ebSBram Moolenaar #endif // FEAT_CLIPBOARD || FEAT_EVAL || PROTO
3023