blob: 2dafeabf5ed3096f73dfb77be4fda1513b6e9f46 [file] [log] [blame]
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * register.c: functions for managing registers
12 */
13
14#include "vim.h"
15
16/*
17 * Registers:
18 * 0 = unnamed register, for normal yanks and puts
19 * 1..9 = registers '1' to '9', for deletes
20 * 10..35 = registers 'a' to 'z' ('A' to 'Z' for appending)
21 * 36 = delete register '-'
22 * 37 = Selection register '*'. Only if FEAT_CLIPBOARD defined
23 * 38 = Clipboard register '+'. Only if FEAT_CLIPBOARD and FEAT_X11 defined
24 */
25static yankreg_T y_regs[NUM_REGISTERS];
26
27static yankreg_T *y_current; // ptr to current yankreg
28static int y_append; // TRUE when appending
29static yankreg_T *y_previous = NULL; // ptr to last written yankreg
30
31static int stuff_yank(int, char_u *);
32static void put_reedit_in_typebuf(int silent);
33static int put_in_typebuf(char_u *s, int esc, int colon,
34 int silent);
Christian Brabandt544a38e2021-06-10 19:39:11 +020035static int yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020036#ifdef FEAT_CLIPBOARD
37static void copy_yank_reg(yankreg_T *reg);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020038#endif
39static void dis_msg(char_u *p, int skip_esc);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020040
Dominique Pelle748b3082022-01-08 12:41:16 +000041#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020042 yankreg_T *
43get_y_regs(void)
44{
45 return y_regs;
46}
Dominique Pelle748b3082022-01-08 12:41:16 +000047#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020048
Dominique Pelle748b3082022-01-08 12:41:16 +000049#if defined(FEAT_CLIPBOARD) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020050 yankreg_T *
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010051get_y_register(int reg)
52{
53 return &y_regs[reg];
54}
Dominique Pelle748b3082022-01-08 12:41:16 +000055#endif
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010056
57 yankreg_T *
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020058get_y_current(void)
59{
60 return y_current;
61}
62
63 yankreg_T *
64get_y_previous(void)
65{
66 return y_previous;
67}
68
69 void
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010070set_y_current(yankreg_T *yreg)
71{
72 y_current = yreg;
73}
74
75 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020076set_y_previous(yankreg_T *yreg)
77{
78 y_previous = yreg;
79}
80
Christian Brabandt78eb9cc2021-09-14 18:55:51 +020081 void
82reset_y_append(void)
83{
84 y_append = FALSE;
85}
86
87
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020088#if defined(FEAT_EVAL) || defined(PROTO)
89/*
90 * Keep the last expression line here, for repeating.
91 */
92static char_u *expr_line = NULL;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +010093static exarg_T *expr_eap = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020094
95/*
96 * Get an expression for the "\"=expr1" or "CTRL-R =expr1"
97 * Returns '=' when OK, NUL otherwise.
98 */
99 int
100get_expr_register(void)
101{
102 char_u *new_line;
103
Bram Moolenaarc97f9a52021-12-28 20:59:56 +0000104 new_line = getcmdline('=', 0L, 0, 0);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200105 if (new_line == NULL)
106 return NUL;
107 if (*new_line == NUL) // use previous line
108 vim_free(new_line);
109 else
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100110 set_expr_line(new_line, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200111 return '=';
112}
113
114/*
115 * Set the expression for the '=' register.
116 * Argument must be an allocated string.
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100117 * "eap" may be used if the next line needs to be checked when evaluating the
118 * expression.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200119 */
120 void
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100121set_expr_line(char_u *new_line, exarg_T *eap)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200122{
123 vim_free(expr_line);
124 expr_line = new_line;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100125 expr_eap = eap;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200126}
127
128/*
129 * Get the result of the '=' register expression.
130 * Returns a pointer to allocated memory, or NULL for failure.
131 */
132 char_u *
133get_expr_line(void)
134{
135 char_u *expr_copy;
136 char_u *rv;
137 static int nested = 0;
138
139 if (expr_line == NULL)
140 return NULL;
141
142 // Make a copy of the expression, because evaluating it may cause it to be
143 // changed.
144 expr_copy = vim_strsave(expr_line);
145 if (expr_copy == NULL)
146 return NULL;
147
148 // When we are invoked recursively limit the evaluation to 10 levels.
149 // Then return the string as-is.
150 if (nested >= 10)
151 return expr_copy;
152
153 ++nested;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100154 rv = eval_to_string_eap(expr_copy, TRUE, expr_eap);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200155 --nested;
156 vim_free(expr_copy);
157 return rv;
158}
159
160/*
161 * Get the '=' register expression itself, without evaluating it.
162 */
163 static char_u *
164get_expr_line_src(void)
165{
166 if (expr_line == NULL)
167 return NULL;
168 return vim_strsave(expr_line);
169}
170#endif // FEAT_EVAL
171
172/*
173 * Check if 'regname' is a valid name of a yank register.
174 * Note: There is no check for 0 (default register), caller should do this
175 */
176 int
177valid_yank_reg(
178 int regname,
179 int writing) // if TRUE check for writable registers
180{
181 if ( (regname > 0 && ASCII_ISALNUM(regname))
182 || (!writing && vim_strchr((char_u *)
183#ifdef FEAT_EVAL
184 "/.%:="
185#else
186 "/.%:"
187#endif
188 , regname) != NULL)
189 || regname == '#'
190 || regname == '"'
191 || regname == '-'
192 || regname == '_'
193#ifdef FEAT_CLIPBOARD
194 || regname == '*'
195 || regname == '+'
196#endif
197#ifdef FEAT_DND
198 || (!writing && regname == '~')
199#endif
200 )
201 return TRUE;
202 return FALSE;
203}
204
205/*
206 * Set y_current and y_append, according to the value of "regname".
207 * Cannot handle the '_' register.
208 * Must only be called with a valid register name!
209 *
210 * If regname is 0 and writing, use register 0
211 * If regname is 0 and reading, use previous register
212 *
213 * Return TRUE when the register should be inserted literally (selection or
214 * clipboard).
215 */
216 int
217get_yank_register(int regname, int writing)
218{
219 int i;
220 int ret = FALSE;
221
222 y_append = FALSE;
223 if ((regname == 0 || regname == '"') && !writing && y_previous != NULL)
224 {
225 y_current = y_previous;
226 return ret;
227 }
228 i = regname;
229 if (VIM_ISDIGIT(i))
230 i -= '0';
231 else if (ASCII_ISLOWER(i))
232 i = CharOrdLow(i) + 10;
233 else if (ASCII_ISUPPER(i))
234 {
235 i = CharOrdUp(i) + 10;
236 y_append = TRUE;
237 }
238 else if (regname == '-')
239 i = DELETION_REGISTER;
240#ifdef FEAT_CLIPBOARD
241 // When selection is not available, use register 0 instead of '*'
242 else if (clip_star.available && regname == '*')
243 {
244 i = STAR_REGISTER;
245 ret = TRUE;
246 }
247 // When clipboard is not available, use register 0 instead of '+'
248 else if (clip_plus.available && regname == '+')
249 {
250 i = PLUS_REGISTER;
251 ret = TRUE;
252 }
253#endif
254#ifdef FEAT_DND
255 else if (!writing && regname == '~')
256 i = TILDE_REGISTER;
257#endif
258 else // not 0-9, a-z, A-Z or '-': use register 0
259 i = 0;
260 y_current = &(y_regs[i]);
261 if (writing) // remember the register we write into for do_put()
262 y_previous = y_current;
263 return ret;
264}
265
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200266/*
267 * Obtain the contents of a "normal" register. The register is made empty.
268 * The returned pointer has allocated memory, use put_register() later.
269 */
270 void *
271get_register(
272 int name,
273 int copy) // make a copy, if FALSE make register empty.
274{
275 yankreg_T *reg;
276 int i;
277
278#ifdef FEAT_CLIPBOARD
279 // When Visual area changed, may have to update selection. Obtain the
280 // selection too.
281 if (name == '*' && clip_star.available)
282 {
283 if (clip_isautosel_star())
284 clip_update_selection(&clip_star);
285 may_get_selection(name);
286 }
287 if (name == '+' && clip_plus.available)
288 {
289 if (clip_isautosel_plus())
290 clip_update_selection(&clip_plus);
291 may_get_selection(name);
292 }
293#endif
294
295 get_yank_register(name, 0);
296 reg = ALLOC_ONE(yankreg_T);
297 if (reg != NULL)
298 {
299 *reg = *y_current;
300 if (copy)
301 {
302 // If we run out of memory some or all of the lines are empty.
303 if (reg->y_size == 0)
304 reg->y_array = NULL;
305 else
306 reg->y_array = ALLOC_MULT(char_u *, reg->y_size);
307 if (reg->y_array != NULL)
308 {
309 for (i = 0; i < reg->y_size; ++i)
310 reg->y_array[i] = vim_strsave(y_current->y_array[i]);
311 }
312 }
313 else
314 y_current->y_array = NULL;
315 }
316 return (void *)reg;
317}
318
319/*
320 * Put "reg" into register "name". Free any previous contents and "reg".
321 */
322 void
323put_register(int name, void *reg)
324{
325 get_yank_register(name, 0);
326 free_yank_all();
327 *y_current = *(yankreg_T *)reg;
328 vim_free(reg);
329
330#ifdef FEAT_CLIPBOARD
331 // Send text written to clipboard register to the clipboard.
332 may_set_selection();
333#endif
334}
335
Bram Moolenaarfccbf062020-11-26 20:34:00 +0100336#if defined(FEAT_CLIPBOARD) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200337 void
338free_register(void *reg)
339{
340 yankreg_T tmp;
341
342 tmp = *y_current;
343 *y_current = *(yankreg_T *)reg;
344 free_yank_all();
345 vim_free(reg);
346 *y_current = tmp;
347}
348#endif
349
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200350/*
351 * return TRUE if the current yank register has type MLINE
352 */
353 int
354yank_register_mline(int regname)
355{
356 if (regname != 0 && !valid_yank_reg(regname, FALSE))
357 return FALSE;
358 if (regname == '_') // black hole is always empty
359 return FALSE;
360 get_yank_register(regname, FALSE);
361 return (y_current->y_type == MLINE);
362}
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200363
364/*
365 * Start or stop recording into a yank register.
366 *
367 * Return FAIL for failure, OK otherwise.
368 */
369 int
370do_record(int c)
371{
372 char_u *p;
373 static int regname;
Shougo Matsushitaf39cfb72022-07-30 16:54:05 +0100374 static int changed_cmdheight = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200375 yankreg_T *old_y_previous, *old_y_current;
376 int retval;
377
378 if (reg_recording == 0) // start recording
379 {
380 // registers 0-9, a-z and " are allowed
381 if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
382 retval = FAIL;
383 else
384 {
385 reg_recording = c;
386 showmode();
387 regname = c;
388 retval = OK;
Shougo Matsushitaf39cfb72022-07-30 16:54:05 +0100389
390 if (p_ch < 1)
391 {
zeertzjq75020942022-07-31 11:37:20 +0100392 // Enable macro indicator temporarily
Shougo Matsushitaf39cfb72022-07-30 16:54:05 +0100393 set_option_value((char_u *)"ch", 1L, NULL, 0);
394 update_screen(VALID);
395
396 changed_cmdheight = TRUE;
397 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200398 }
399 }
400 else // stop recording
401 {
402 // Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
403 // needs to be removed again to put it in a register. exec_reg then
404 // adds the escaping back later.
405 reg_recording = 0;
406 msg("");
407 p = get_recorded();
408 if (p == NULL)
409 retval = FAIL;
410 else
411 {
412 // Remove escaping for CSI and K_SPECIAL in multi-byte chars.
413 vim_unescape_csi(p);
414
415 // We don't want to change the default register here, so save and
416 // restore the current register name.
417 old_y_previous = y_previous;
418 old_y_current = y_current;
419
420 retval = stuff_yank(regname, p);
421
422 y_previous = old_y_previous;
423 y_current = old_y_current;
424 }
Shougo Matsushitaf39cfb72022-07-30 16:54:05 +0100425
426 if (changed_cmdheight)
427 {
428 // Restore cmdheight
429 set_option_value((char_u *)"ch", 0L, NULL, 0);
430 redraw_all_later(CLEAR);
431 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200432 }
433 return retval;
434}
435
436/*
437 * Stuff string "p" into yank register "regname" as a single line (append if
438 * uppercase). "p" must have been alloced.
439 *
440 * return FAIL for failure, OK otherwise
441 */
442 static int
443stuff_yank(int regname, char_u *p)
444{
445 char_u *lp;
446 char_u **pp;
447
448 // check for read-only register
449 if (regname != 0 && !valid_yank_reg(regname, TRUE))
450 {
451 vim_free(p);
452 return FAIL;
453 }
454 if (regname == '_') // black hole: don't do anything
455 {
456 vim_free(p);
457 return OK;
458 }
459 get_yank_register(regname, TRUE);
460 if (y_append && y_current->y_array != NULL)
461 {
462 pp = &(y_current->y_array[y_current->y_size - 1]);
463 lp = alloc(STRLEN(*pp) + STRLEN(p) + 1);
464 if (lp == NULL)
465 {
466 vim_free(p);
467 return FAIL;
468 }
469 STRCPY(lp, *pp);
470 STRCAT(lp, p);
471 vim_free(p);
472 vim_free(*pp);
473 *pp = lp;
474 }
475 else
476 {
477 free_yank_all();
478 if ((y_current->y_array = ALLOC_ONE(char_u *)) == NULL)
479 {
480 vim_free(p);
481 return FAIL;
482 }
483 y_current->y_array[0] = p;
484 y_current->y_size = 1;
485 y_current->y_type = MCHAR; // used to be MLINE, why?
486#ifdef FEAT_VIMINFO
487 y_current->y_time_set = vim_time();
488#endif
489 }
490 return OK;
491}
492
Yegappan Lakshmanan41a7f822021-06-16 15:53:17 +0200493/*
494 * Last executed register (@ command)
495 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200496static int execreg_lastc = NUL;
497
Dominique Pelle748b3082022-01-08 12:41:16 +0000498#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200499 int
500get_execreg_lastc(void)
501{
502 return execreg_lastc;
503}
504
505 void
506set_execreg_lastc(int lastc)
507{
508 execreg_lastc = lastc;
509}
Dominique Pelle748b3082022-01-08 12:41:16 +0000510#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200511
512/*
Bram Moolenaar856c1112020-06-17 21:47:23 +0200513 * When executing a register as a series of ex-commands, if the
514 * line-continuation character is used for a line, then join it with one or
515 * more previous lines. Note that lines are processed backwards starting from
516 * the last line in the register.
517 *
518 * Arguments:
519 * lines - list of lines in the register
520 * idx - index of the line starting with \ or "\. Join this line with all the
521 * immediate predecessor lines that start with a \ and the first line
522 * that doesn't start with a \. Lines that start with a comment "\
523 * character are ignored.
524 *
525 * Returns the concatenated line. The index of the line that should be
526 * processed next is returned in idx.
527 */
528 static char_u *
529execreg_line_continuation(char_u **lines, long *idx)
530{
531 garray_T ga;
532 long i = *idx;
533 char_u *p;
534 int cmd_start;
535 int cmd_end = i;
536 int j;
537 char_u *str;
538
Bram Moolenaar04935fb2022-01-08 16:19:22 +0000539 ga_init2(&ga, sizeof(char_u), 400);
Bram Moolenaar856c1112020-06-17 21:47:23 +0200540
541 // search backwards to find the first line of this command.
542 // Any line not starting with \ or "\ is the start of the
543 // command.
544 while (--i > 0)
545 {
546 p = skipwhite(lines[i]);
547 if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' '))
548 break;
549 }
550 cmd_start = i;
551
552 // join all the lines
553 ga_concat(&ga, lines[cmd_start]);
554 for (j = cmd_start + 1; j <= cmd_end; j++)
555 {
556 p = skipwhite(lines[j]);
557 if (*p == '\\')
558 {
559 // Adjust the growsize to the current length to
560 // speed up concatenating many lines.
561 if (ga.ga_len > 400)
562 {
563 if (ga.ga_len > 8000)
564 ga.ga_growsize = 8000;
565 else
566 ga.ga_growsize = ga.ga_len;
567 }
568 ga_concat(&ga, p + 1);
569 }
570 }
571 ga_append(&ga, NUL);
572 str = vim_strsave(ga.ga_data);
573 ga_clear(&ga);
574
575 *idx = i;
576 return str;
577}
578
579/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200580 * Execute a yank register: copy it into the stuff buffer.
581 *
582 * Return FAIL for failure, OK otherwise.
583 */
584 int
585do_execreg(
586 int regname,
587 int colon, // insert ':' before each line
588 int addcr, // always add '\n' to end of line
589 int silent) // set "silent" flag in typeahead buffer
590{
591 long i;
592 char_u *p;
593 int retval = OK;
594 int remap;
595
596 // repeat previous one
597 if (regname == '@')
598 {
599 if (execreg_lastc == NUL)
600 {
Bram Moolenaar677658a2022-01-05 16:09:06 +0000601 emsg(_(e_no_previously_used_register));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200602 return FAIL;
603 }
604 regname = execreg_lastc;
605 }
606 // check for valid regname
607 if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
608 {
609 emsg_invreg(regname);
610 return FAIL;
611 }
612 execreg_lastc = regname;
613
614#ifdef FEAT_CLIPBOARD
615 regname = may_get_selection(regname);
616#endif
617
618 // black hole: don't stuff anything
619 if (regname == '_')
620 return OK;
621
622 // use last command line
623 if (regname == ':')
624 {
625 if (last_cmdline == NULL)
626 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200627 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200628 return FAIL;
629 }
630 // don't keep the cmdline containing @:
631 VIM_CLEAR(new_last_cmdline);
632 // Escape all control characters with a CTRL-V
633 p = vim_strsave_escaped_ext(last_cmdline,
634 (char_u *)"\001\002\003\004\005\006\007"
635 "\010\011\012\013\014\015\016\017"
636 "\020\021\022\023\024\025\026\027"
637 "\030\031\032\033\034\035\036\037",
638 Ctrl_V, FALSE);
639 if (p != NULL)
640 {
641 // When in Visual mode "'<,'>" will be prepended to the command.
642 // Remove it when it's already there.
643 if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0)
644 retval = put_in_typebuf(p + 5, TRUE, TRUE, silent);
645 else
646 retval = put_in_typebuf(p, TRUE, TRUE, silent);
647 }
648 vim_free(p);
649 }
650#ifdef FEAT_EVAL
651 else if (regname == '=')
652 {
653 p = get_expr_line();
654 if (p == NULL)
655 return FAIL;
656 retval = put_in_typebuf(p, TRUE, colon, silent);
657 vim_free(p);
658 }
659#endif
660 else if (regname == '.') // use last inserted text
661 {
662 p = get_last_insert_save();
663 if (p == NULL)
664 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200665 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200666 return FAIL;
667 }
668 retval = put_in_typebuf(p, FALSE, colon, silent);
669 vim_free(p);
670 }
671 else
672 {
673 get_yank_register(regname, FALSE);
674 if (y_current->y_array == NULL)
675 return FAIL;
676
Bram Moolenaar4b96df52020-01-26 22:00:26 +0100677 // Disallow remapping for ":@r".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200678 remap = colon ? REMAP_NONE : REMAP_YES;
679
680 // Insert lines into typeahead buffer, from last one to first one.
681 put_reedit_in_typebuf(silent);
682 for (i = y_current->y_size; --i >= 0; )
683 {
684 char_u *escaped;
Bram Moolenaar856c1112020-06-17 21:47:23 +0200685 char_u *str;
686 int free_str = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200687
688 // insert NL between lines and after last line if type is MLINE
689 if (y_current->y_type == MLINE || i < y_current->y_size - 1
690 || addcr)
691 {
692 if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
693 return FAIL;
694 }
Bram Moolenaar856c1112020-06-17 21:47:23 +0200695
696 // Handle line-continuation for :@<register>
697 str = y_current->y_array[i];
698 if (colon && i > 0)
699 {
700 p = skipwhite(str);
701 if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))
702 {
703 str = execreg_line_continuation(y_current->y_array, &i);
704 if (str == NULL)
705 return FAIL;
706 free_str = TRUE;
707 }
708 }
709 escaped = vim_strsave_escape_csi(str);
710 if (free_str)
711 vim_free(str);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200712 if (escaped == NULL)
713 return FAIL;
714 retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
715 vim_free(escaped);
716 if (retval == FAIL)
717 return FAIL;
718 if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
719 == FAIL)
720 return FAIL;
721 }
722 reg_executing = regname == 0 ? '"' : regname; // disable "q" command
723 }
724 return retval;
725}
726
727/*
728 * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
729 * used only after other typeahead has been processed.
730 */
731 static void
732put_reedit_in_typebuf(int silent)
733{
734 char_u buf[3];
735
736 if (restart_edit != NUL)
737 {
738 if (restart_edit == 'V')
739 {
740 buf[0] = 'g';
741 buf[1] = 'R';
742 buf[2] = NUL;
743 }
744 else
745 {
746 buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
747 buf[1] = NUL;
748 }
749 if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
750 restart_edit = NUL;
751 }
752}
753
754/*
755 * Insert register contents "s" into the typeahead buffer, so that it will be
756 * executed again.
757 * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
758 * no remapping.
759 */
760 static int
761put_in_typebuf(
762 char_u *s,
763 int esc,
764 int colon, // add ':' before the line
765 int silent)
766{
767 int retval = OK;
768
769 put_reedit_in_typebuf(silent);
770 if (colon)
771 retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
772 if (retval == OK)
773 {
774 char_u *p;
775
776 if (esc)
777 p = vim_strsave_escape_csi(s);
778 else
779 p = s;
780 if (p == NULL)
781 retval = FAIL;
782 else
783 retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
784 0, TRUE, silent);
785 if (esc)
786 vim_free(p);
787 }
788 if (colon && retval == OK)
789 retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
790 return retval;
791}
792
793/*
794 * Insert a yank register: copy it into the Read buffer.
795 * Used by CTRL-R command and middle mouse button in insert mode.
796 *
797 * return FAIL for failure, OK otherwise
798 */
799 int
800insert_reg(
801 int regname,
802 int literally_arg) // insert literally, not as if typed
803{
804 long i;
805 int retval = OK;
806 char_u *arg;
807 int allocated;
808 int literally = literally_arg;
809
810 // It is possible to get into an endless loop by having CTRL-R a in
811 // register a and then, in insert mode, doing CTRL-R a.
812 // If you hit CTRL-C, the loop will be broken here.
813 ui_breakcheck();
814 if (got_int)
815 return FAIL;
816
817 // check for valid regname
818 if (regname != NUL && !valid_yank_reg(regname, FALSE))
819 return FAIL;
820
821#ifdef FEAT_CLIPBOARD
822 regname = may_get_selection(regname);
823#endif
824
825 if (regname == '.') // insert last inserted text
826 retval = stuff_inserted(NUL, 1L, TRUE);
827 else if (get_spec_reg(regname, &arg, &allocated, TRUE))
828 {
829 if (arg == NULL)
830 return FAIL;
831 stuffescaped(arg, literally);
832 if (allocated)
833 vim_free(arg);
834 }
835 else // name or number register
836 {
837 if (get_yank_register(regname, FALSE))
838 literally = TRUE;
839 if (y_current->y_array == NULL)
840 retval = FAIL;
841 else
842 {
843 for (i = 0; i < y_current->y_size; ++i)
844 {
Bram Moolenaar032a2d02020-12-22 17:59:35 +0100845 if (regname == '-')
846 {
847 AppendCharToRedobuff(Ctrl_R);
848 AppendCharToRedobuff(regname);
849 do_put(regname, NULL, BACKWARD, 1L, PUT_CURSEND);
850 }
851 else
852 stuffescaped(y_current->y_array[i], literally);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200853 // Insert a newline between lines and after last line if
854 // y_type is MLINE.
855 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
856 stuffcharReadbuff('\n');
857 }
858 }
859 }
860
861 return retval;
862}
863
864/*
865 * If "regname" is a special register, return TRUE and store a pointer to its
866 * value in "argp".
867 */
868 int
869get_spec_reg(
870 int regname,
871 char_u **argp,
872 int *allocated, // return: TRUE when value was allocated
873 int errmsg) // give error message when failing
874{
875 int cnt;
876
877 *argp = NULL;
878 *allocated = FALSE;
879 switch (regname)
880 {
881 case '%': // file name
882 if (errmsg)
883 check_fname(); // will give emsg if not set
884 *argp = curbuf->b_fname;
885 return TRUE;
886
887 case '#': // alternate file name
888 *argp = getaltfname(errmsg); // may give emsg if not set
889 return TRUE;
890
891#ifdef FEAT_EVAL
892 case '=': // result of expression
893 *argp = get_expr_line();
894 *allocated = TRUE;
895 return TRUE;
896#endif
897
898 case ':': // last command line
899 if (last_cmdline == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200900 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200901 *argp = last_cmdline;
902 return TRUE;
903
904 case '/': // last search-pattern
905 if (last_search_pat() == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200906 emsg(_(e_no_previous_regular_expression));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200907 *argp = last_search_pat();
908 return TRUE;
909
910 case '.': // last inserted text
911 *argp = get_last_insert_save();
912 *allocated = TRUE;
913 if (*argp == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200914 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200915 return TRUE;
916
917#ifdef FEAT_SEARCHPATH
918 case Ctrl_F: // Filename under cursor
919 case Ctrl_P: // Path under cursor, expand via "path"
920 if (!errmsg)
921 return FALSE;
922 *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP
923 | (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL);
924 *allocated = TRUE;
925 return TRUE;
926#endif
927
928 case Ctrl_W: // word under cursor
929 case Ctrl_A: // WORD (mnemonic All) under cursor
930 if (!errmsg)
931 return FALSE;
932 cnt = find_ident_under_cursor(argp, regname == Ctrl_W
933 ? (FIND_IDENT|FIND_STRING) : FIND_STRING);
934 *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
935 *allocated = TRUE;
936 return TRUE;
937
938 case Ctrl_L: // Line under cursor
939 if (!errmsg)
940 return FALSE;
941
942 *argp = ml_get_buf(curwin->w_buffer,
943 curwin->w_cursor.lnum, FALSE);
944 return TRUE;
945
946 case '_': // black hole: always empty
947 *argp = (char_u *)"";
948 return TRUE;
949 }
950
951 return FALSE;
952}
953
954/*
955 * Paste a yank register into the command line.
956 * Only for non-special registers.
957 * Used by CTRL-R command in command-line mode
958 * insert_reg() can't be used here, because special characters from the
959 * register contents will be interpreted as commands.
960 *
961 * return FAIL for failure, OK otherwise
962 */
963 int
964cmdline_paste_reg(
965 int regname,
966 int literally_arg, // Insert text literally instead of "as typed"
967 int remcr) // don't add CR characters
968{
969 long i;
970 int literally = literally_arg;
971
972 if (get_yank_register(regname, FALSE))
973 literally = TRUE;
974 if (y_current->y_array == NULL)
975 return FAIL;
976
977 for (i = 0; i < y_current->y_size; ++i)
978 {
979 cmdline_paste_str(y_current->y_array[i], literally);
980
981 // Insert ^M between lines and after last line if type is MLINE.
982 // Don't do this when "remcr" is TRUE.
983 if ((y_current->y_type == MLINE || i < y_current->y_size - 1) && !remcr)
984 cmdline_paste_str((char_u *)"\r", literally);
985
986 // Check for CTRL-C, in case someone tries to paste a few thousand
987 // lines and gets bored.
988 ui_breakcheck();
989 if (got_int)
990 return FAIL;
991 }
992 return OK;
993}
994
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200995/*
996 * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
997 */
998 void
999shift_delete_registers()
1000{
1001 int n;
1002
1003 y_current = &y_regs[9];
1004 free_yank_all(); // free register nine
1005 for (n = 9; n > 1; --n)
1006 y_regs[n] = y_regs[n - 1];
1007 y_current = &y_regs[1];
1008 if (!y_append)
1009 y_previous = y_current;
1010 y_regs[1].y_array = NULL; // set register one to empty
1011}
1012
1013#if defined(FEAT_EVAL)
1014 void
1015yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
1016{
Bram Moolenaar3075a452021-11-17 15:51:52 +00001017 static int recursive = FALSE;
1018 dict_T *v_event;
1019 list_T *list;
1020 int n;
1021 char_u buf[NUMBUFLEN + 2];
1022 long reglen = 0;
1023 save_v_event_T save_v_event;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001024
1025 if (recursive)
1026 return;
1027
Bram Moolenaar3075a452021-11-17 15:51:52 +00001028 v_event = get_v_event(&save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001029
1030 list = list_alloc();
1031 if (list == NULL)
1032 return;
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001033
1034 // yanked text contents
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001035 for (n = 0; n < reg->y_size; n++)
1036 list_append_string(list, reg->y_array[n], -1);
1037 list->lv_lock = VAR_FIXED;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001038 (void)dict_add_list(v_event, "regcontents", list);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001039
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001040 // register name or empty string for unnamed operation
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001041 buf[0] = (char_u)oap->regname;
1042 buf[1] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001043 (void)dict_add_string(v_event, "regname", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001044
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001045 // motion type: inclusive or exclusive
1046 (void)dict_add_bool(v_event, "inclusive", oap->inclusive);
1047
1048 // kind of operation (yank, delete, change)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001049 buf[0] = get_op_char(oap->op_type);
1050 buf[1] = get_extra_op_char(oap->op_type);
1051 buf[2] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001052 (void)dict_add_string(v_event, "operator", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001053
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001054 // register type
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001055 buf[0] = NUL;
1056 buf[1] = NUL;
1057 switch (get_reg_type(oap->regname, &reglen))
1058 {
1059 case MLINE: buf[0] = 'V'; break;
1060 case MCHAR: buf[0] = 'v'; break;
1061 case MBLOCK:
1062 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
1063 reglen + 1);
1064 break;
1065 }
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001066 (void)dict_add_string(v_event, "regtype", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001067
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001068 // selection type - visual or not
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001069 (void)dict_add_bool(v_event, "visual", oap->is_VIsual);
Bram Moolenaar37d16732020-06-12 22:09:01 +02001070
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001071 // Lock the dictionary and its keys
1072 dict_set_items_ro(v_event);
1073
1074 recursive = TRUE;
zeertzjqcfe45652022-05-27 17:26:55 +01001075 textlock++;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001076 apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
zeertzjqcfe45652022-05-27 17:26:55 +01001077 textlock--;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001078 recursive = FALSE;
1079
1080 // Empty the dictionary, v:event is still valid
Bram Moolenaar3075a452021-11-17 15:51:52 +00001081 restore_v_event(v_event, &save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001082}
1083#endif
1084
1085/*
1086 * set all the yank registers to empty (called from main())
1087 */
1088 void
1089init_yank(void)
1090{
1091 int i;
1092
1093 for (i = 0; i < NUM_REGISTERS; ++i)
1094 y_regs[i].y_array = NULL;
1095}
1096
1097#if defined(EXITFREE) || defined(PROTO)
1098 void
1099clear_registers(void)
1100{
1101 int i;
1102
1103 for (i = 0; i < NUM_REGISTERS; ++i)
1104 {
1105 y_current = &y_regs[i];
1106 if (y_current->y_array != NULL)
1107 free_yank_all();
1108 }
1109}
1110#endif
1111
1112/*
1113 * Free "n" lines from the current yank register.
1114 * Called for normal freeing and in case of error.
1115 */
1116 static void
1117free_yank(long n)
1118{
1119 if (y_current->y_array != NULL)
1120 {
1121 long i;
1122
1123 for (i = n; --i >= 0; )
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001124 vim_free(y_current->y_array[i]);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001125 VIM_CLEAR(y_current->y_array);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001126 }
1127}
1128
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01001129 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001130free_yank_all(void)
1131{
1132 free_yank(y_current->y_size);
1133}
1134
1135/*
1136 * Yank the text between "oap->start" and "oap->end" into a yank register.
1137 * If we are to append (uppercase register), we first yank into a new yank
1138 * register and then concatenate the old and the new one (so we keep the old
1139 * one in case of out-of-memory).
1140 *
1141 * Return FAIL for failure, OK otherwise.
1142 */
1143 int
1144op_yank(oparg_T *oap, int deleting, int mess)
1145{
1146 long y_idx; // index in y_array[]
1147 yankreg_T *curr; // copy of y_current
1148 yankreg_T newreg; // new yank register when appending
1149 char_u **new_ptr;
1150 linenr_T lnum; // current line number
1151 long j;
1152 int yanktype = oap->motion_type;
1153 long yanklines = oap->line_count;
1154 linenr_T yankendlnum = oap->end.lnum;
1155 char_u *p;
1156 char_u *pnew;
1157 struct block_def bd;
1158#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1159 int did_star = FALSE;
1160#endif
1161
1162 // check for read-only register
1163 if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
1164 {
1165 beep_flush();
1166 return FAIL;
1167 }
1168 if (oap->regname == '_') // black hole: nothing to do
1169 return OK;
1170
1171#ifdef FEAT_CLIPBOARD
1172 if (!clip_star.available && oap->regname == '*')
1173 oap->regname = 0;
1174 else if (!clip_plus.available && oap->regname == '+')
1175 oap->regname = 0;
1176#endif
1177
1178 if (!deleting) // op_delete() already set y_current
1179 get_yank_register(oap->regname, TRUE);
1180
1181 curr = y_current;
1182 // append to existing contents
1183 if (y_append && y_current->y_array != NULL)
1184 y_current = &newreg;
1185 else
1186 free_yank_all(); // free previously yanked lines
1187
1188 // If the cursor was in column 1 before and after the movement, and the
1189 // operator is not inclusive, the yank is always linewise.
1190 if ( oap->motion_type == MCHAR
1191 && oap->start.col == 0
1192 && !oap->inclusive
1193 && (!oap->is_VIsual || *p_sel == 'o')
1194 && !oap->block_mode
1195 && oap->end.col == 0
1196 && yanklines > 1)
1197 {
1198 yanktype = MLINE;
1199 --yankendlnum;
1200 --yanklines;
1201 }
1202
1203 y_current->y_size = yanklines;
1204 y_current->y_type = yanktype; // set the yank register type
1205 y_current->y_width = 0;
1206 y_current->y_array = lalloc_clear(sizeof(char_u *) * yanklines, TRUE);
1207 if (y_current->y_array == NULL)
1208 {
1209 y_current = curr;
1210 return FAIL;
1211 }
1212#ifdef FEAT_VIMINFO
1213 y_current->y_time_set = vim_time();
1214#endif
1215
1216 y_idx = 0;
1217 lnum = oap->start.lnum;
1218
1219 if (oap->block_mode)
1220 {
1221 // Visual block mode
1222 y_current->y_type = MBLOCK; // set the yank register type
1223 y_current->y_width = oap->end_vcol - oap->start_vcol;
1224
1225 if (curwin->w_curswant == MAXCOL && y_current->y_width > 0)
1226 y_current->y_width--;
1227 }
1228
1229 for ( ; lnum <= yankendlnum; lnum++, y_idx++)
1230 {
1231 switch (y_current->y_type)
1232 {
1233 case MBLOCK:
1234 block_prep(oap, &bd, lnum, FALSE);
Christian Brabandt544a38e2021-06-10 19:39:11 +02001235 if (yank_copy_line(&bd, y_idx, oap->excl_tr_ws) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001236 goto fail;
1237 break;
1238
1239 case MLINE:
1240 if ((y_current->y_array[y_idx] =
Christian Brabandt544a38e2021-06-10 19:39:11 +02001241 vim_strsave(ml_get(lnum))) == NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001242 goto fail;
1243 break;
1244
1245 case MCHAR:
1246 {
1247 colnr_T startcol = 0, endcol = MAXCOL;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001248 int is_oneChar = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001249 colnr_T cs, ce;
1250
1251 p = ml_get(lnum);
1252 bd.startspaces = 0;
1253 bd.endspaces = 0;
1254
1255 if (lnum == oap->start.lnum)
1256 {
1257 startcol = oap->start.col;
1258 if (virtual_op)
1259 {
1260 getvcol(curwin, &oap->start, &cs, NULL, &ce);
1261 if (ce != cs && oap->start.coladd > 0)
1262 {
1263 // Part of a tab selected -- but don't
1264 // double-count it.
1265 bd.startspaces = (ce - cs + 1)
1266 - oap->start.coladd;
1267 startcol++;
1268 }
1269 }
1270 }
1271
1272 if (lnum == oap->end.lnum)
1273 {
1274 endcol = oap->end.col;
1275 if (virtual_op)
1276 {
1277 getvcol(curwin, &oap->end, &cs, NULL, &ce);
1278 if (p[endcol] == NUL || (cs + oap->end.coladd < ce
1279 // Don't add space for double-wide
1280 // char; endcol will be on last byte
1281 // of multi-byte char.
1282 && (*mb_head_off)(p, p + endcol) == 0))
1283 {
1284 if (oap->start.lnum == oap->end.lnum
1285 && oap->start.col == oap->end.col)
1286 {
1287 // Special case: inside a single char
1288 is_oneChar = TRUE;
1289 bd.startspaces = oap->end.coladd
1290 - oap->start.coladd + oap->inclusive;
1291 endcol = startcol;
1292 }
1293 else
1294 {
1295 bd.endspaces = oap->end.coladd
1296 + oap->inclusive;
1297 endcol -= oap->inclusive;
1298 }
1299 }
1300 }
1301 }
1302 if (endcol == MAXCOL)
1303 endcol = (colnr_T)STRLEN(p);
1304 if (startcol > endcol || is_oneChar)
1305 bd.textlen = 0;
1306 else
1307 bd.textlen = endcol - startcol + oap->inclusive;
1308 bd.textstart = p + startcol;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001309 if (yank_copy_line(&bd, y_idx, FALSE) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001310 goto fail;
1311 break;
1312 }
1313 // NOTREACHED
1314 }
1315 }
1316
1317 if (curr != y_current) // append the new block to the old block
1318 {
1319 new_ptr = ALLOC_MULT(char_u *, curr->y_size + y_current->y_size);
1320 if (new_ptr == NULL)
1321 goto fail;
1322 for (j = 0; j < curr->y_size; ++j)
1323 new_ptr[j] = curr->y_array[j];
1324 vim_free(curr->y_array);
1325 curr->y_array = new_ptr;
1326#ifdef FEAT_VIMINFO
1327 curr->y_time_set = vim_time();
1328#endif
1329
1330 if (yanktype == MLINE) // MLINE overrides MCHAR and MBLOCK
1331 curr->y_type = MLINE;
1332
1333 // Concatenate the last line of the old block with the first line of
1334 // the new block, unless being Vi compatible.
1335 if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL)
1336 {
1337 pnew = alloc(STRLEN(curr->y_array[curr->y_size - 1])
1338 + STRLEN(y_current->y_array[0]) + 1);
1339 if (pnew == NULL)
1340 {
1341 y_idx = y_current->y_size - 1;
1342 goto fail;
1343 }
1344 STRCPY(pnew, curr->y_array[--j]);
1345 STRCAT(pnew, y_current->y_array[0]);
1346 vim_free(curr->y_array[j]);
1347 vim_free(y_current->y_array[0]);
1348 curr->y_array[j++] = pnew;
1349 y_idx = 1;
1350 }
1351 else
1352 y_idx = 0;
1353 while (y_idx < y_current->y_size)
1354 curr->y_array[j++] = y_current->y_array[y_idx++];
1355 curr->y_size = j;
1356 vim_free(y_current->y_array);
1357 y_current = curr;
1358 }
zeertzjq95d2e762022-03-19 11:42:16 +00001359
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001360 if (mess) // Display message about yank?
1361 {
1362 if (yanktype == MCHAR
1363 && !oap->block_mode
1364 && yanklines == 1)
1365 yanklines = 0;
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001366 // Some versions of Vi use ">=" here, some don't...
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001367 if (yanklines > p_report)
1368 {
1369 char namebuf[100];
1370
1371 if (oap->regname == NUL)
1372 *namebuf = NUL;
1373 else
1374 vim_snprintf(namebuf, sizeof(namebuf),
1375 _(" into \"%c"), oap->regname);
1376
1377 // redisplay now, so message is not deleted
1378 update_topline_redraw();
1379 if (oap->block_mode)
1380 {
1381 smsg(NGETTEXT("block of %ld line yanked%s",
1382 "block of %ld lines yanked%s", yanklines),
1383 yanklines, namebuf);
1384 }
1385 else
1386 {
1387 smsg(NGETTEXT("%ld line yanked%s",
1388 "%ld lines yanked%s", yanklines),
1389 yanklines, namebuf);
1390 }
1391 }
1392 }
1393
Bram Moolenaare1004402020-10-24 20:49:43 +02001394 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001395 {
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001396 // Set "'[" and "']" marks.
1397 curbuf->b_op_start = oap->start;
1398 curbuf->b_op_end = oap->end;
1399 if (yanktype == MLINE && !oap->block_mode)
1400 {
1401 curbuf->b_op_start.col = 0;
1402 curbuf->b_op_end.col = MAXCOL;
1403 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001404 }
1405
1406#ifdef FEAT_CLIPBOARD
1407 // If we were yanking to the '*' register, send result to clipboard.
1408 // If no register was specified, and "unnamed" in 'clipboard', make a copy
1409 // to the '*' register.
1410 if (clip_star.available
1411 && (curr == &(y_regs[STAR_REGISTER])
1412 || (!deleting && oap->regname == 0
1413 && ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
1414 {
1415 if (curr != &(y_regs[STAR_REGISTER]))
1416 // Copy the text from register 0 to the clipboard register.
1417 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1418
1419 clip_own_selection(&clip_star);
1420 clip_gen_set_selection(&clip_star);
1421# ifdef FEAT_X11
1422 did_star = TRUE;
1423# endif
1424 }
1425
1426# ifdef FEAT_X11
1427 // If we were yanking to the '+' register, send result to selection.
Bram Moolenaar37096af2021-03-02 19:04:11 +01001428 // Also copy to the '*' register, in case auto-select is off. But not when
Ernie Rael559f2302022-07-26 14:44:36 +01001429 // 'clipboard' has "unnamedplus" and not "unnamed"; and not when
1430 // deleting and both "unnamedplus" and "unnamed".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001431 if (clip_plus.available
1432 && (curr == &(y_regs[PLUS_REGISTER])
1433 || (!deleting && oap->regname == 0
1434 && ((clip_unnamed | clip_unnamed_saved) &
Bram Moolenaar37096af2021-03-02 19:04:11 +01001435 CLIP_UNNAMED_PLUS))))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001436 {
1437 if (curr != &(y_regs[PLUS_REGISTER]))
1438 // Copy the text from register 0 to the clipboard register.
1439 copy_yank_reg(&(y_regs[PLUS_REGISTER]));
1440
1441 clip_own_selection(&clip_plus);
1442 clip_gen_set_selection(&clip_plus);
Bram Moolenaar37096af2021-03-02 19:04:11 +01001443 if (!clip_isautosel_star()
1444 && !clip_isautosel_plus()
1445 && !((clip_unnamed | clip_unnamed_saved) == CLIP_UNNAMED_PLUS)
Ernie Rael559f2302022-07-26 14:44:36 +01001446 && !(deleting && (clip_unnamed | clip_unnamed_saved)
1447 == (CLIP_UNNAMED | CLIP_UNNAMED_PLUS))
Bram Moolenaar37096af2021-03-02 19:04:11 +01001448 && !did_star
1449 && curr == &(y_regs[PLUS_REGISTER]))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001450 {
1451 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1452 clip_own_selection(&clip_star);
1453 clip_gen_set_selection(&clip_star);
1454 }
1455 }
1456# endif
1457#endif
1458
1459#if defined(FEAT_EVAL)
1460 if (!deleting && has_textyankpost())
1461 yank_do_autocmd(oap, y_current);
1462#endif
1463
1464 return OK;
1465
1466fail: // free the allocated lines
1467 free_yank(y_idx + 1);
1468 y_current = curr;
1469 return FAIL;
1470}
1471
Christian Brabandt544a38e2021-06-10 19:39:11 +02001472/*
1473 * Copy a block range into a register.
1474 * If "exclude_trailing_space" is set, do not copy trailing whitespaces.
1475 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001476 static int
Christian Brabandt544a38e2021-06-10 19:39:11 +02001477yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001478{
1479 char_u *pnew;
1480
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02001481 if (exclude_trailing_space)
1482 bd->endspaces = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001483 if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1))
1484 == NULL)
1485 return FAIL;
1486 y_current->y_array[y_idx] = pnew;
1487 vim_memset(pnew, ' ', (size_t)bd->startspaces);
1488 pnew += bd->startspaces;
1489 mch_memmove(pnew, bd->textstart, (size_t)bd->textlen);
1490 pnew += bd->textlen;
1491 vim_memset(pnew, ' ', (size_t)bd->endspaces);
1492 pnew += bd->endspaces;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001493 if (exclude_trailing_space)
1494 {
1495 int s = bd->textlen + bd->endspaces;
1496
Bram Moolenaar44db8212022-01-25 21:26:17 +00001497 while (s > 0 && VIM_ISWHITE(*(bd->textstart + s - 1)))
Christian Brabandt544a38e2021-06-10 19:39:11 +02001498 {
1499 s = s - (*mb_head_off)(bd->textstart, bd->textstart + s - 1) - 1;
1500 pnew--;
1501 }
1502 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001503 *pnew = NUL;
1504 return OK;
1505}
1506
1507#ifdef FEAT_CLIPBOARD
1508/*
1509 * Make a copy of the y_current register to register "reg".
1510 */
1511 static void
1512copy_yank_reg(yankreg_T *reg)
1513{
1514 yankreg_T *curr = y_current;
1515 long j;
1516
1517 y_current = reg;
1518 free_yank_all();
1519 *y_current = *curr;
1520 y_current->y_array = lalloc_clear(
1521 sizeof(char_u *) * y_current->y_size, TRUE);
1522 if (y_current->y_array == NULL)
1523 y_current->y_size = 0;
1524 else
1525 for (j = 0; j < y_current->y_size; ++j)
1526 if ((y_current->y_array[j] = vim_strsave(curr->y_array[j])) == NULL)
1527 {
1528 free_yank(j);
1529 y_current->y_size = 0;
1530 break;
1531 }
1532 y_current = curr;
1533}
1534#endif
1535
1536/*
1537 * Put contents of register "regname" into the text.
1538 * Caller must check "regname" to be valid!
1539 * "flags": PUT_FIXINDENT make indent look nice
1540 * PUT_CURSEND leave cursor after end of new text
1541 * PUT_LINE force linewise put (":put")
Christian Brabandt2fa93842021-05-30 22:17:25 +02001542 * PUT_BLOCK_INNER in block mode, do not add trailing spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001543 */
1544 void
1545do_put(
1546 int regname,
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001547 char_u *expr_result, // result for regname "=" when compiled
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001548 int dir, // BACKWARD for 'P', FORWARD for 'p'
1549 long count,
1550 int flags)
1551{
1552 char_u *ptr;
1553 char_u *newp, *oldp;
1554 int yanklen;
1555 int totlen = 0; // init for gcc
1556 linenr_T lnum;
1557 colnr_T col;
1558 long i; // index in y_array[]
1559 int y_type;
1560 long y_size;
1561 int oldlen;
1562 long y_width = 0;
1563 colnr_T vcol;
1564 int delcount;
1565 int incr = 0;
1566 long j;
1567 struct block_def bd;
1568 char_u **y_array = NULL;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001569 yankreg_T *y_current_used = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001570 long nr_lines = 0;
1571 pos_T new_cursor;
1572 int indent;
1573 int orig_indent = 0; // init for gcc
1574 int indent_diff = 0; // init for gcc
1575 int first_indent = TRUE;
1576 int lendiff = 0;
1577 pos_T old_pos;
1578 char_u *insert_string = NULL;
1579 int allocated = FALSE;
1580 long cnt;
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001581 pos_T orig_start = curbuf->b_op_start;
1582 pos_T orig_end = curbuf->b_op_end;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001583 unsigned int cur_ve_flags = get_ve_flags();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001584
1585#ifdef FEAT_CLIPBOARD
1586 // Adjust register name for "unnamed" in 'clipboard'.
1587 adjust_clip_reg(&regname);
1588 (void)may_get_selection(regname);
1589#endif
1590
1591 if (flags & PUT_FIXINDENT)
1592 orig_indent = get_indent();
1593
1594 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1595 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1596
1597 // Using inserted text works differently, because the register includes
1598 // special characters (newlines, etc.).
1599 if (regname == '.')
1600 {
1601 if (VIsual_active)
1602 stuffcharReadbuff(VIsual_mode);
1603 (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
1604 (count == -1 ? 'O' : 'i')), count, FALSE);
1605 // Putting the text is done later, so can't really move the cursor to
1606 // the next character. Use "l" to simulate it.
1607 if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
1608 stuffcharReadbuff('l');
1609 return;
1610 }
1611
1612 // For special registers '%' (file name), '#' (alternate file name) and
1613 // ':' (last command line), etc. we have to create a fake yank register.
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001614 // For compiled code "expr_result" holds the expression result.
1615 if (regname == '=' && expr_result != NULL)
1616 insert_string = expr_result;
1617 else if (get_spec_reg(regname, &insert_string, &allocated, TRUE)
1618 && insert_string == NULL)
1619 return;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001620
1621 // Autocommands may be executed when saving lines for undo. This might
1622 // make "y_array" invalid, so we start undo now to avoid that.
1623 if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL)
1624 goto end;
1625
1626 if (insert_string != NULL)
1627 {
1628 y_type = MCHAR;
1629#ifdef FEAT_EVAL
1630 if (regname == '=')
1631 {
1632 // For the = register we need to split the string at NL
1633 // characters.
1634 // Loop twice: count the number of lines and save them.
1635 for (;;)
1636 {
1637 y_size = 0;
1638 ptr = insert_string;
1639 while (ptr != NULL)
1640 {
1641 if (y_array != NULL)
1642 y_array[y_size] = ptr;
1643 ++y_size;
1644 ptr = vim_strchr(ptr, '\n');
1645 if (ptr != NULL)
1646 {
1647 if (y_array != NULL)
1648 *ptr = NUL;
1649 ++ptr;
1650 // A trailing '\n' makes the register linewise.
1651 if (*ptr == NUL)
1652 {
1653 y_type = MLINE;
1654 break;
1655 }
1656 }
1657 }
1658 if (y_array != NULL)
1659 break;
1660 y_array = ALLOC_MULT(char_u *, y_size);
1661 if (y_array == NULL)
1662 goto end;
1663 }
1664 }
1665 else
1666#endif
1667 {
1668 y_size = 1; // use fake one-line yank register
1669 y_array = &insert_string;
1670 }
1671 }
1672 else
1673 {
1674 get_yank_register(regname, FALSE);
1675
1676 y_type = y_current->y_type;
1677 y_width = y_current->y_width;
1678 y_size = y_current->y_size;
1679 y_array = y_current->y_array;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001680 y_current_used = y_current;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001681 }
1682
1683 if (y_type == MLINE)
1684 {
1685 if (flags & PUT_LINE_SPLIT)
1686 {
1687 char_u *p;
1688
1689 // "p" or "P" in Visual mode: split the lines to put the text in
1690 // between.
1691 if (u_save_cursor() == FAIL)
1692 goto end;
1693 p = ml_get_cursor();
1694 if (dir == FORWARD && *p != NUL)
1695 MB_PTR_ADV(p);
1696 ptr = vim_strsave(p);
1697 if (ptr == NULL)
1698 goto end;
1699 ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE);
1700 vim_free(ptr);
1701
1702 oldp = ml_get_curline();
1703 p = oldp + curwin->w_cursor.col;
1704 if (dir == FORWARD && *p != NUL)
1705 MB_PTR_ADV(p);
1706 ptr = vim_strnsave(oldp, p - oldp);
1707 if (ptr == NULL)
1708 goto end;
1709 ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
1710 ++nr_lines;
1711 dir = FORWARD;
1712 }
1713 if (flags & PUT_LINE_FORWARD)
1714 {
1715 // Must be "p" for a Visual block, put lines below the block.
1716 curwin->w_cursor = curbuf->b_visual.vi_end;
1717 dir = FORWARD;
1718 }
1719 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1720 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1721 }
1722
1723 if (flags & PUT_LINE) // :put command or "p" in Visual line mode.
1724 y_type = MLINE;
1725
1726 if (y_size == 0 || y_array == NULL)
1727 {
Bram Moolenaarac78dd42022-01-02 19:25:26 +00001728 semsg(_(e_nothing_in_register_str),
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001729 regname == 0 ? (char_u *)"\"" : transchar(regname));
1730 goto end;
1731 }
1732
1733 if (y_type == MBLOCK)
1734 {
1735 lnum = curwin->w_cursor.lnum + y_size + 1;
1736 if (lnum > curbuf->b_ml.ml_line_count)
1737 lnum = curbuf->b_ml.ml_line_count + 1;
1738 if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
1739 goto end;
1740 }
1741 else if (y_type == MLINE)
1742 {
1743 lnum = curwin->w_cursor.lnum;
1744#ifdef FEAT_FOLDING
1745 // Correct line number for closed fold. Don't move the cursor yet,
1746 // u_save() uses it.
1747 if (dir == BACKWARD)
1748 (void)hasFolding(lnum, &lnum, NULL);
1749 else
1750 (void)hasFolding(lnum, NULL, &lnum);
1751#endif
1752 if (dir == FORWARD)
1753 ++lnum;
1754 // In an empty buffer the empty line is going to be replaced, include
1755 // it in the saved lines.
1756 if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL)
1757 goto end;
1758#ifdef FEAT_FOLDING
1759 if (dir == FORWARD)
1760 curwin->w_cursor.lnum = lnum - 1;
1761 else
1762 curwin->w_cursor.lnum = lnum;
1763 curbuf->b_op_start = curwin->w_cursor; // for mark_adjust()
1764#endif
1765 }
1766 else if (u_save_cursor() == FAIL)
1767 goto end;
1768
1769 yanklen = (int)STRLEN(y_array[0]);
1770
Gary Johnson53ba05b2021-07-26 22:19:10 +02001771 if (cur_ve_flags == VE_ALL && y_type == MCHAR)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001772 {
1773 if (gchar_cursor() == TAB)
1774 {
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001775 int viscol = getviscol();
1776 int ts = curbuf->b_p_ts;
1777
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001778 // Don't need to insert spaces when "p" on the last position of a
1779 // tab or "P" on the first position.
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001780 if (dir == FORWARD ?
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001781#ifdef FEAT_VARTABS
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001782 tabstop_padding(viscol, ts, curbuf->b_p_vts_array) != 1
1783#else
1784 ts - (viscol % ts) != 1
1785#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001786 : curwin->w_cursor.coladd > 0)
1787 coladvance_force(viscol);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001788 else
1789 curwin->w_cursor.coladd = 0;
1790 }
1791 else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
1792 coladvance_force(getviscol() + (dir == FORWARD));
1793 }
1794
1795 lnum = curwin->w_cursor.lnum;
1796 col = curwin->w_cursor.col;
1797
1798 // Block mode
1799 if (y_type == MBLOCK)
1800 {
1801 int c = gchar_cursor();
1802 colnr_T endcol2 = 0;
1803
1804 if (dir == FORWARD && c != NUL)
1805 {
Gary Johnson53ba05b2021-07-26 22:19:10 +02001806 if (cur_ve_flags == VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001807 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1808 else
1809 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
1810
1811 if (has_mbyte)
1812 // move to start of next multi-byte character
1813 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
1814 else
Gary Johnson53ba05b2021-07-26 22:19:10 +02001815 if (c != TAB || cur_ve_flags != VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001816 ++curwin->w_cursor.col;
1817 ++col;
1818 }
1819 else
1820 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1821
1822 col += curwin->w_cursor.coladd;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001823 if (cur_ve_flags == VE_ALL
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001824 && (curwin->w_cursor.coladd > 0
1825 || endcol2 == curwin->w_cursor.col))
1826 {
1827 if (dir == FORWARD && c == NUL)
1828 ++col;
Bram Moolenaaref85a9b2020-07-10 20:24:07 +02001829 if (dir != FORWARD && c != NUL && curwin->w_cursor.coladd > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001830 ++curwin->w_cursor.col;
1831 if (c == TAB)
1832 {
1833 if (dir == BACKWARD && curwin->w_cursor.col)
1834 curwin->w_cursor.col--;
1835 if (dir == FORWARD && col - 1 == endcol2)
1836 curwin->w_cursor.col++;
1837 }
1838 }
1839 curwin->w_cursor.coladd = 0;
1840 bd.textcol = 0;
1841 for (i = 0; i < y_size; ++i)
1842 {
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001843 int spaces = 0;
1844 char shortline;
1845 chartabsize_T cts;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001846
1847 bd.startspaces = 0;
1848 bd.endspaces = 0;
1849 vcol = 0;
1850 delcount = 0;
1851
1852 // add a new line
1853 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
1854 {
1855 if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
1856 (colnr_T)1, FALSE) == FAIL)
1857 break;
1858 ++nr_lines;
1859 }
1860 // get the old line and advance to the position to insert at
1861 oldp = ml_get_curline();
1862 oldlen = (int)STRLEN(oldp);
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001863 init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0,
1864 oldp, oldp);
1865
1866 while (cts.cts_vcol < col && *cts.cts_ptr != NUL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001867 {
1868 // Count a tab for what it's worth (if list mode not on)
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001869 incr = lbr_chartabsize_adv(&cts);
1870 cts.cts_vcol += incr;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001871 }
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001872 vcol = cts.cts_vcol;
1873 ptr = cts.cts_ptr;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001874 bd.textcol = (colnr_T)(ptr - oldp);
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001875 clear_chartabsize_arg(&cts);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001876
1877 shortline = (vcol < col) || (vcol == col && !*ptr) ;
1878
1879 if (vcol < col) // line too short, padd with spaces
1880 bd.startspaces = col - vcol;
1881 else if (vcol > col)
1882 {
1883 bd.endspaces = vcol - col;
1884 bd.startspaces = incr - bd.endspaces;
1885 --bd.textcol;
1886 delcount = 1;
1887 if (has_mbyte)
1888 bd.textcol -= (*mb_head_off)(oldp, oldp + bd.textcol);
1889 if (oldp[bd.textcol] != TAB)
1890 {
1891 // Only a Tab can be split into spaces. Other
1892 // characters will have to be moved to after the
1893 // block, causing misalignment.
1894 delcount = 0;
1895 bd.endspaces = 0;
1896 }
1897 }
1898
1899 yanklen = (int)STRLEN(y_array[i]);
1900
Christian Brabandt2fa93842021-05-30 22:17:25 +02001901 if ((flags & PUT_BLOCK_INNER) == 0)
1902 {
1903 // calculate number of spaces required to fill right side of
1904 // block
1905 spaces = y_width + 1;
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001906 init_chartabsize_arg(&cts, curwin, 0, 0,
1907 y_array[i], y_array[i]);
Christian Brabandt2fa93842021-05-30 22:17:25 +02001908 for (j = 0; j < yanklen; j++)
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001909 {
1910 spaces -= lbr_chartabsize(&cts);
1911 ++cts.cts_ptr;
1912 cts.cts_vcol = 0;
1913 }
1914 clear_chartabsize_arg(&cts);
Christian Brabandt2fa93842021-05-30 22:17:25 +02001915 if (spaces < 0)
1916 spaces = 0;
1917 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001918
ichizokfa537222021-11-16 12:50:46 +00001919 // Insert the new text.
1920 // First check for multiplication overflow.
1921 if (yanklen + spaces != 0
1922 && count > ((INT_MAX - (bd.startspaces + bd.endspaces))
1923 / (yanklen + spaces)))
1924 {
1925 emsg(_(e_resulting_text_too_long));
1926 break;
1927 }
1928
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001929 totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
1930 newp = alloc(totlen + oldlen + 1);
1931 if (newp == NULL)
1932 break;
ichizokfa537222021-11-16 12:50:46 +00001933
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001934 // copy part up to cursor to new line
1935 ptr = newp;
1936 mch_memmove(ptr, oldp, (size_t)bd.textcol);
1937 ptr += bd.textcol;
ichizokfa537222021-11-16 12:50:46 +00001938
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001939 // may insert some spaces before the new text
1940 vim_memset(ptr, ' ', (size_t)bd.startspaces);
1941 ptr += bd.startspaces;
ichizokfa537222021-11-16 12:50:46 +00001942
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001943 // insert the new text
1944 for (j = 0; j < count; ++j)
1945 {
1946 mch_memmove(ptr, y_array[i], (size_t)yanklen);
1947 ptr += yanklen;
1948
1949 // insert block's trailing spaces only if there's text behind
1950 if ((j < count - 1 || !shortline) && spaces)
1951 {
1952 vim_memset(ptr, ' ', (size_t)spaces);
1953 ptr += spaces;
1954 }
Bram Moolenaard25f0032022-06-30 12:30:19 +01001955 else
1956 totlen -= spaces; // didn't use these spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001957 }
ichizokfa537222021-11-16 12:50:46 +00001958
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001959 // may insert some spaces after the new text
1960 vim_memset(ptr, ' ', (size_t)bd.endspaces);
1961 ptr += bd.endspaces;
ichizokfa537222021-11-16 12:50:46 +00001962
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001963 // move the text after the cursor to the end of the line.
1964 mch_memmove(ptr, oldp + bd.textcol + delcount,
1965 (size_t)(oldlen - bd.textcol - delcount + 1));
1966 ml_replace(curwin->w_cursor.lnum, newp, FALSE);
1967
1968 ++curwin->w_cursor.lnum;
1969 if (i == 0)
1970 curwin->w_cursor.col += bd.startspaces;
1971 }
1972
1973 changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines);
1974
1975 // Set '[ mark.
1976 curbuf->b_op_start = curwin->w_cursor;
1977 curbuf->b_op_start.lnum = lnum;
1978
1979 // adjust '] mark
1980 curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
1981 curbuf->b_op_end.col = bd.textcol + totlen - 1;
1982 curbuf->b_op_end.coladd = 0;
1983 if (flags & PUT_CURSEND)
1984 {
1985 colnr_T len;
1986
1987 curwin->w_cursor = curbuf->b_op_end;
1988 curwin->w_cursor.col++;
1989
1990 // in Insert mode we might be after the NUL, correct for that
1991 len = (colnr_T)STRLEN(ml_get_curline());
1992 if (curwin->w_cursor.col > len)
1993 curwin->w_cursor.col = len;
1994 }
1995 else
1996 curwin->w_cursor.lnum = lnum;
1997 }
1998 else
1999 {
2000 // Character or Line mode
2001 if (y_type == MCHAR)
2002 {
2003 // if type is MCHAR, FORWARD is the same as BACKWARD on the next
2004 // char
2005 if (dir == FORWARD && gchar_cursor() != NUL)
2006 {
2007 if (has_mbyte)
2008 {
2009 int bytelen = (*mb_ptr2len)(ml_get_cursor());
2010
2011 // put it on the next of the multi-byte character.
2012 col += bytelen;
2013 if (yanklen)
2014 {
2015 curwin->w_cursor.col += bytelen;
2016 curbuf->b_op_end.col += bytelen;
2017 }
2018 }
2019 else
2020 {
2021 ++col;
2022 if (yanklen)
2023 {
2024 ++curwin->w_cursor.col;
2025 ++curbuf->b_op_end.col;
2026 }
2027 }
2028 }
2029 curbuf->b_op_start = curwin->w_cursor;
2030 }
2031 // Line mode: BACKWARD is the same as FORWARD on the previous line
2032 else if (dir == BACKWARD)
2033 --lnum;
2034 new_cursor = curwin->w_cursor;
2035
Bram Moolenaarcd942772020-08-22 21:08:44 +02002036 // simple case: insert into one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002037 if (y_type == MCHAR && y_size == 1)
2038 {
Bram Moolenaarcd942772020-08-22 21:08:44 +02002039 linenr_T end_lnum = 0; // init for gcc
2040 linenr_T start_lnum = lnum;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002041 int first_byte_off = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002042
2043 if (VIsual_active)
2044 {
2045 end_lnum = curbuf->b_visual.vi_end.lnum;
2046 if (end_lnum < curbuf->b_visual.vi_start.lnum)
2047 end_lnum = curbuf->b_visual.vi_start.lnum;
Bram Moolenaarcd942772020-08-22 21:08:44 +02002048 if (end_lnum > start_lnum)
2049 {
2050 pos_T pos;
2051
2052 // "col" is valid for the first line, in following lines
2053 // the virtual column needs to be used. Matters for
2054 // multi-byte characters.
2055 pos.lnum = lnum;
2056 pos.col = col;
2057 pos.coladd = 0;
2058 getvcol(curwin, &pos, NULL, &vcol, NULL);
2059 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002060 }
2061
ichizokfa537222021-11-16 12:50:46 +00002062 if (count == 0 || yanklen == 0)
2063 {
2064 if (VIsual_active)
2065 lnum = end_lnum;
2066 }
2067 else if (count > INT_MAX / yanklen)
2068 // multiplication overflow
2069 emsg(_(e_resulting_text_too_long));
2070 else
2071 {
Bram Moolenaare551ccf2021-11-02 23:11:00 +00002072 totlen = count * yanklen;
ichizokfa537222021-11-16 12:50:46 +00002073 do {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002074 oldp = ml_get(lnum);
ichizokfa537222021-11-16 12:50:46 +00002075 oldlen = (int)STRLEN(oldp);
Bram Moolenaarcd942772020-08-22 21:08:44 +02002076 if (lnum > start_lnum)
2077 {
2078 pos_T pos;
2079
2080 pos.lnum = lnum;
2081 if (getvpos(&pos, vcol) == OK)
2082 col = pos.col;
2083 else
2084 col = MAXCOL;
2085 }
ichizokfa537222021-11-16 12:50:46 +00002086 if (VIsual_active && col > oldlen)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002087 {
2088 lnum++;
2089 continue;
2090 }
ichizokfa537222021-11-16 12:50:46 +00002091 newp = alloc(totlen + oldlen + 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002092 if (newp == NULL)
2093 goto end; // alloc() gave an error message
2094 mch_memmove(newp, oldp, (size_t)col);
2095 ptr = newp + col;
2096 for (i = 0; i < count; ++i)
2097 {
2098 mch_memmove(ptr, y_array[0], (size_t)yanklen);
2099 ptr += yanklen;
2100 }
2101 STRMOVE(ptr, oldp + col);
Bram Moolenaarecb00c72022-08-07 14:55:14 +01002102
Bram Moolenaar4d072532021-11-25 19:31:15 +00002103 // compute the byte offset for the last character
2104 first_byte_off = mb_head_off(newp, ptr - 1);
2105
Bram Moolenaarc390cc12022-08-07 18:09:10 +01002106 // Note: this may free "newp"
2107 ml_replace(lnum, newp, FALSE);
2108
2109 inserted_bytes(lnum, col, totlen);
2110
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002111 // Place cursor on last putted char.
2112 if (lnum == curwin->w_cursor.lnum)
2113 {
2114 // make sure curwin->w_virtcol is updated
2115 changed_cline_bef_curs();
2116 curwin->w_cursor.col += (colnr_T)(totlen - 1);
2117 }
ichizokfa537222021-11-16 12:50:46 +00002118 if (VIsual_active)
2119 lnum++;
2120 } while (VIsual_active && lnum <= end_lnum);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002121
ichizokfa537222021-11-16 12:50:46 +00002122 if (VIsual_active) // reset lnum to the last visual line
2123 lnum--;
2124 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002125
Bram Moolenaar4d072532021-11-25 19:31:15 +00002126 // put '] at the first byte of the last character
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002127 curbuf->b_op_end = curwin->w_cursor;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002128 curbuf->b_op_end.col -= first_byte_off;
2129
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002130 // For "CTRL-O p" in Insert mode, put cursor after last char
2131 if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
2132 ++curwin->w_cursor.col;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002133 else
2134 curwin->w_cursor.col -= first_byte_off;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002135 }
2136 else
2137 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002138 linenr_T new_lnum = new_cursor.lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002139 size_t len;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002140
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002141 // Insert at least one line. When y_type is MCHAR, break the first
2142 // line in two.
2143 for (cnt = 1; cnt <= count; ++cnt)
2144 {
2145 i = 0;
2146 if (y_type == MCHAR)
2147 {
2148 // Split the current line in two at the insert position.
2149 // First insert y_array[size - 1] in front of second line.
2150 // Then append y_array[0] to first line.
2151 lnum = new_cursor.lnum;
2152 ptr = ml_get(lnum) + col;
2153 totlen = (int)STRLEN(y_array[y_size - 1]);
2154 newp = alloc(STRLEN(ptr) + totlen + 1);
2155 if (newp == NULL)
2156 goto error;
2157 STRCPY(newp, y_array[y_size - 1]);
2158 STRCAT(newp, ptr);
2159 // insert second line
2160 ml_append(lnum, newp, (colnr_T)0, FALSE);
Bram Moolenaar23003e52021-09-22 16:37:07 +02002161 ++new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002162 vim_free(newp);
2163
2164 oldp = ml_get(lnum);
2165 newp = alloc(col + yanklen + 1);
2166 if (newp == NULL)
2167 goto error;
2168 // copy first part of line
2169 mch_memmove(newp, oldp, (size_t)col);
2170 // append to first line
2171 mch_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
2172 ml_replace(lnum, newp, FALSE);
2173
2174 curwin->w_cursor.lnum = lnum;
2175 i = 1;
2176 }
2177
2178 for (; i < y_size; ++i)
2179 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002180 if (y_type != MCHAR || i < y_size - 1)
2181 {
2182 if (ml_append(lnum, y_array[i], (colnr_T)0, FALSE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002183 == FAIL)
2184 goto error;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002185 new_lnum++;
2186 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002187 lnum++;
2188 ++nr_lines;
2189 if (flags & PUT_FIXINDENT)
2190 {
2191 old_pos = curwin->w_cursor;
2192 curwin->w_cursor.lnum = lnum;
2193 ptr = ml_get(lnum);
2194 if (cnt == count && i == y_size - 1)
2195 lendiff = (int)STRLEN(ptr);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002196 if (*ptr == '#' && preprocs_left())
2197 indent = 0; // Leave # lines at start
2198 else
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002199 if (*ptr == NUL)
2200 indent = 0; // Ignore empty lines
2201 else if (first_indent)
2202 {
2203 indent_diff = orig_indent - get_indent();
2204 indent = orig_indent;
2205 first_indent = FALSE;
2206 }
2207 else if ((indent = get_indent() + indent_diff) < 0)
2208 indent = 0;
2209 (void)set_indent(indent, 0);
2210 curwin->w_cursor = old_pos;
2211 // remember how many chars were removed
2212 if (cnt == count && i == y_size - 1)
2213 lendiff -= (int)STRLEN(ml_get(lnum));
2214 }
2215 }
Bram Moolenaar23003e52021-09-22 16:37:07 +02002216 if (cnt == 1)
2217 new_lnum = lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002218 }
2219
2220error:
2221 // Adjust marks.
2222 if (y_type == MLINE)
2223 {
2224 curbuf->b_op_start.col = 0;
2225 if (dir == FORWARD)
2226 curbuf->b_op_start.lnum++;
2227 }
2228 // Skip mark_adjust when adding lines after the last one, there
2229 // can't be marks there. But still needed in diff mode.
2230 if (curbuf->b_op_start.lnum + (y_type == MCHAR) - 1 + nr_lines
2231 < curbuf->b_ml.ml_line_count
2232#ifdef FEAT_DIFF
2233 || curwin->w_p_diff
2234#endif
2235 )
2236 mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
2237 (linenr_T)MAXLNUM, nr_lines, 0L);
2238
2239 // note changed text for displaying and folding
2240 if (y_type == MCHAR)
2241 changed_lines(curwin->w_cursor.lnum, col,
2242 curwin->w_cursor.lnum + 1, nr_lines);
2243 else
2244 changed_lines(curbuf->b_op_start.lnum, 0,
2245 curbuf->b_op_start.lnum, nr_lines);
Bram Moolenaar9ac38122021-12-02 18:42:33 +00002246 if (y_current_used != NULL && (y_current_used != y_current
2247 || y_current->y_array != y_array))
2248 {
2249 // Something invoked through changed_lines() has changed the
2250 // yank buffer, e.g. a GUI clipboard callback.
2251 emsg(_(e_yank_register_changed_while_using_it));
2252 goto end;
2253 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002254
Bram Moolenaar4d072532021-11-25 19:31:15 +00002255 // Put the '] mark on the first byte of the last inserted character.
2256 // Correct the length for change in indent.
Bram Moolenaarf47ebf12021-10-19 20:08:45 +01002257 curbuf->b_op_end.lnum = new_lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002258 len = STRLEN(y_array[y_size - 1]);
2259 col = (colnr_T)len - lendiff;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002260 if (col > 1)
Bram Moolenaar2a585c82022-05-25 15:15:38 +01002261 {
2262 curbuf->b_op_end.col = col - 1;
2263 if (len > 0)
2264 curbuf->b_op_end.col -= mb_head_off(y_array[y_size - 1],
Bram Moolenaar85be8562021-11-25 20:40:11 +00002265 y_array[y_size - 1] + len - 1);
Bram Moolenaar2a585c82022-05-25 15:15:38 +01002266 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002267 else
2268 curbuf->b_op_end.col = 0;
2269
2270 if (flags & PUT_CURSLINE)
2271 {
2272 // ":put": put cursor on last inserted line
2273 curwin->w_cursor.lnum = lnum;
2274 beginline(BL_WHITE | BL_FIX);
2275 }
2276 else if (flags & PUT_CURSEND)
2277 {
2278 // put cursor after inserted text
2279 if (y_type == MLINE)
2280 {
2281 if (lnum >= curbuf->b_ml.ml_line_count)
2282 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
2283 else
2284 curwin->w_cursor.lnum = lnum + 1;
2285 curwin->w_cursor.col = 0;
2286 }
2287 else
2288 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002289 curwin->w_cursor.lnum = new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002290 curwin->w_cursor.col = col;
Bram Moolenaar56858e42021-09-22 16:43:59 +02002291 curbuf->b_op_end = curwin->w_cursor;
2292 if (col > 1)
2293 curbuf->b_op_end.col = col - 1;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002294 }
2295 }
2296 else if (y_type == MLINE)
2297 {
2298 // put cursor on first non-blank in first inserted line
2299 curwin->w_cursor.col = 0;
2300 if (dir == FORWARD)
2301 ++curwin->w_cursor.lnum;
2302 beginline(BL_WHITE | BL_FIX);
2303 }
2304 else // put cursor on first inserted character
2305 curwin->w_cursor = new_cursor;
2306 }
2307 }
2308
2309 msgmore(nr_lines);
2310 curwin->w_set_curswant = TRUE;
2311
2312end:
Bram Moolenaare1004402020-10-24 20:49:43 +02002313 if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01002314 {
2315 curbuf->b_op_start = orig_start;
2316 curbuf->b_op_end = orig_end;
2317 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002318 if (allocated)
2319 vim_free(insert_string);
2320 if (regname == '=')
2321 vim_free(y_array);
2322
2323 VIsual_active = FALSE;
2324
2325 // If the cursor is past the end of the line put it at the end.
2326 adjust_cursor_eol();
2327}
2328
2329/*
2330 * Return the character name of the register with the given number.
2331 */
2332 int
2333get_register_name(int num)
2334{
2335 if (num == -1)
2336 return '"';
2337 else if (num < 10)
2338 return num + '0';
2339 else if (num == DELETION_REGISTER)
2340 return '-';
2341#ifdef FEAT_CLIPBOARD
2342 else if (num == STAR_REGISTER)
2343 return '*';
2344 else if (num == PLUS_REGISTER)
2345 return '+';
2346#endif
2347 else
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002348 return num + 'a' - 10;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002349}
2350
Dominique Pelle748b3082022-01-08 12:41:16 +00002351#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002352/*
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002353 * Return the index of the register "" points to.
2354 */
2355 int
2356get_unname_register()
2357{
2358 return y_previous == NULL ? -1 : y_previous - &y_regs[0];
2359}
Dominique Pelle748b3082022-01-08 12:41:16 +00002360#endif
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002361
2362/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002363 * ":dis" and ":registers": Display the contents of the yank registers.
2364 */
2365 void
2366ex_display(exarg_T *eap)
2367{
2368 int i, n;
2369 long j;
2370 char_u *p;
2371 yankreg_T *yb;
2372 int name;
2373 int attr;
2374 char_u *arg = eap->arg;
2375 int clen;
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002376 int type;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002377
2378 if (arg != NULL && *arg == NUL)
2379 arg = NULL;
2380 attr = HL_ATTR(HLF_8);
2381
2382 // Highlight title
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002383 msg_puts_title(_("\nType Name Content"));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002384 for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
2385 {
2386 name = get_register_name(i);
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002387 switch (get_reg_type(name, NULL))
2388 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002389 case MLINE: type = 'l'; break;
2390 case MCHAR: type = 'c'; break;
2391 default: type = 'b'; break;
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002392 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002393 if (arg != NULL && vim_strchr(arg, name) == NULL
2394#ifdef ONE_CLIPBOARD
2395 // Star register and plus register contain the same thing.
2396 && (name != '*' || vim_strchr(arg, '+') == NULL)
2397#endif
2398 )
2399 continue; // did not ask for this register
2400
2401#ifdef FEAT_CLIPBOARD
2402 // Adjust register name for "unnamed" in 'clipboard'.
2403 // When it's a clipboard register, fill it with the current contents
2404 // of the clipboard.
2405 adjust_clip_reg(&name);
2406 (void)may_get_selection(name);
2407#endif
2408
2409 if (i == -1)
2410 {
2411 if (y_previous != NULL)
2412 yb = y_previous;
2413 else
2414 yb = &(y_regs[0]);
2415 }
2416 else
2417 yb = &(y_regs[i]);
2418
2419#ifdef FEAT_EVAL
2420 if (name == MB_TOLOWER(redir_reg)
2421 || (redir_reg == '"' && yb == y_previous))
2422 continue; // do not list register being written to, the
2423 // pointer can be freed
2424#endif
2425
2426 if (yb->y_array != NULL)
2427 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002428 int do_show = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002429
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002430 for (j = 0; !do_show && j < yb->y_size; ++j)
2431 do_show = !message_filtered(yb->y_array[j]);
2432
2433 if (do_show || yb->y_size == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002434 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002435 msg_putchar('\n');
2436 msg_puts(" ");
2437 msg_putchar(type);
2438 msg_puts(" ");
2439 msg_putchar('"');
2440 msg_putchar(name);
2441 msg_puts(" ");
2442
2443 n = (int)Columns - 11;
2444 for (j = 0; j < yb->y_size && n > 1; ++j)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002445 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002446 if (j)
2447 {
2448 msg_puts_attr("^J", attr);
2449 n -= 2;
2450 }
Bram Moolenaarb4ad3b02022-03-30 10:57:45 +01002451 for (p = yb->y_array[j];
2452 *p != NUL && (n -= ptr2cells(p)) >= 0; ++p)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002453 {
2454 clen = (*mb_ptr2len)(p);
2455 msg_outtrans_len(p, clen);
2456 p += clen - 1;
2457 }
2458 }
2459 if (n > 1 && yb->y_type == MLINE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002460 msg_puts_attr("^J", attr);
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002461 out_flush(); // show one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002462 }
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002463 ui_breakcheck();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002464 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002465 }
2466
2467 // display last inserted text
2468 if ((p = get_last_insert()) != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002469 && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
2470 && !message_filtered(p))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002471 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002472 msg_puts("\n c \". ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002473 dis_msg(p, TRUE);
2474 }
2475
2476 // display last command line
2477 if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002478 && !got_int && !message_filtered(last_cmdline))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002479 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002480 msg_puts("\n c \": ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002481 dis_msg(last_cmdline, FALSE);
2482 }
2483
2484 // display current file name
2485 if (curbuf->b_fname != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002486 && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int
2487 && !message_filtered(curbuf->b_fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002488 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002489 msg_puts("\n c \"% ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002490 dis_msg(curbuf->b_fname, FALSE);
2491 }
2492
2493 // display alternate file name
2494 if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
2495 {
2496 char_u *fname;
2497 linenr_T dummy;
2498
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002499 if (buflist_name_nr(0, &fname, &dummy) != FAIL
2500 && !message_filtered(fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002501 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002502 msg_puts("\n c \"# ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002503 dis_msg(fname, FALSE);
2504 }
2505 }
2506
2507 // display last search pattern
2508 if (last_search_pat() != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002509 && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int
2510 && !message_filtered(last_search_pat()))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002511 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002512 msg_puts("\n c \"/ ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002513 dis_msg(last_search_pat(), FALSE);
2514 }
2515
2516#ifdef FEAT_EVAL
2517 // display last used expression
2518 if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002519 && !got_int && !message_filtered(expr_line))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002520 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002521 msg_puts("\n c \"= ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002522 dis_msg(expr_line, FALSE);
2523 }
2524#endif
2525}
2526
2527/*
2528 * display a string for do_dis()
2529 * truncate at end of screen line
2530 */
2531 static void
2532dis_msg(
2533 char_u *p,
2534 int skip_esc) // if TRUE, ignore trailing ESC
2535{
2536 int n;
2537 int l;
2538
2539 n = (int)Columns - 6;
2540 while (*p != NUL
2541 && !(*p == ESC && skip_esc && *(p + 1) == NUL)
2542 && (n -= ptr2cells(p)) >= 0)
2543 {
2544 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
2545 {
2546 msg_outtrans_len(p, l);
2547 p += l;
2548 }
2549 else
2550 msg_outtrans_len(p++, 1);
2551 }
2552 ui_breakcheck();
2553}
2554
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002555#if defined(FEAT_DND) || defined(PROTO)
2556/*
2557 * Replace the contents of the '~' register with str.
2558 */
2559 void
2560dnd_yank_drag_data(char_u *str, long len)
2561{
2562 yankreg_T *curr;
2563
2564 curr = y_current;
2565 y_current = &y_regs[TILDE_REGISTER];
2566 free_yank_all();
2567 str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
2568 y_current = curr;
2569}
2570#endif
2571
2572
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002573/*
2574 * Return the type of a register.
2575 * Used for getregtype()
2576 * Returns MAUTO for error.
2577 */
2578 char_u
2579get_reg_type(int regname, long *reglen)
2580{
2581 switch (regname)
2582 {
2583 case '%': // file name
2584 case '#': // alternate file name
2585 case '=': // expression
2586 case ':': // last command line
2587 case '/': // last search-pattern
2588 case '.': // last inserted text
2589# ifdef FEAT_SEARCHPATH
2590 case Ctrl_F: // Filename under cursor
2591 case Ctrl_P: // Path under cursor, expand via "path"
2592# endif
2593 case Ctrl_W: // word under cursor
2594 case Ctrl_A: // WORD (mnemonic All) under cursor
2595 case '_': // black hole: always empty
2596 return MCHAR;
2597 }
2598
2599# ifdef FEAT_CLIPBOARD
2600 regname = may_get_selection(regname);
2601# endif
2602
2603 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2604 return MAUTO;
2605
2606 get_yank_register(regname, FALSE);
2607
2608 if (y_current->y_array != NULL)
2609 {
2610 if (reglen != NULL && y_current->y_type == MBLOCK)
2611 *reglen = y_current->y_width;
2612 return y_current->y_type;
2613 }
2614 return MAUTO;
2615}
2616
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002617#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002618/*
2619 * When "flags" has GREG_LIST return a list with text "s".
2620 * Otherwise just return "s".
2621 */
2622 static char_u *
2623getreg_wrap_one_line(char_u *s, int flags)
2624{
2625 if (flags & GREG_LIST)
2626 {
2627 list_T *list = list_alloc();
2628
2629 if (list != NULL)
2630 {
2631 if (list_append_string(list, NULL, -1) == FAIL)
2632 {
2633 list_free(list);
2634 return NULL;
2635 }
2636 list->lv_first->li_tv.vval.v_string = s;
2637 }
2638 return (char_u *)list;
2639 }
2640 return s;
2641}
2642
2643/*
Bram Moolenaard672dde2020-02-26 13:43:51 +01002644 * Return the contents of a register as a single allocated string or as a list.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002645 * Used for "@r" in expressions and for getreg().
2646 * Returns NULL for error.
2647 * Flags:
2648 * GREG_NO_EXPR Do not allow expression register
2649 * GREG_EXPR_SRC For the expression register: return expression itself,
2650 * not the result of its evaluation.
Bram Moolenaard672dde2020-02-26 13:43:51 +01002651 * GREG_LIST Return a list of lines instead of a single string.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002652 */
2653 char_u *
2654get_reg_contents(int regname, int flags)
2655{
2656 long i;
2657 char_u *retval;
2658 int allocated;
2659 long len;
2660
2661 // Don't allow using an expression register inside an expression
2662 if (regname == '=')
2663 {
2664 if (flags & GREG_NO_EXPR)
2665 return NULL;
2666 if (flags & GREG_EXPR_SRC)
2667 return getreg_wrap_one_line(get_expr_line_src(), flags);
2668 return getreg_wrap_one_line(get_expr_line(), flags);
2669 }
2670
2671 if (regname == '@') // "@@" is used for unnamed register
2672 regname = '"';
2673
2674 // check for valid regname
2675 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2676 return NULL;
2677
2678# ifdef FEAT_CLIPBOARD
2679 regname = may_get_selection(regname);
2680# endif
2681
2682 if (get_spec_reg(regname, &retval, &allocated, FALSE))
2683 {
2684 if (retval == NULL)
2685 return NULL;
2686 if (allocated)
2687 return getreg_wrap_one_line(retval, flags);
2688 return getreg_wrap_one_line(vim_strsave(retval), flags);
2689 }
2690
2691 get_yank_register(regname, FALSE);
2692 if (y_current->y_array == NULL)
2693 return NULL;
2694
2695 if (flags & GREG_LIST)
2696 {
2697 list_T *list = list_alloc();
2698 int error = FALSE;
2699
2700 if (list == NULL)
2701 return NULL;
2702 for (i = 0; i < y_current->y_size; ++i)
2703 if (list_append_string(list, y_current->y_array[i], -1) == FAIL)
2704 error = TRUE;
2705 if (error)
2706 {
2707 list_free(list);
2708 return NULL;
2709 }
2710 return (char_u *)list;
2711 }
2712
2713 // Compute length of resulting string.
2714 len = 0;
2715 for (i = 0; i < y_current->y_size; ++i)
2716 {
2717 len += (long)STRLEN(y_current->y_array[i]);
2718 // Insert a newline between lines and after last line if
2719 // y_type is MLINE.
2720 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2721 ++len;
2722 }
2723
2724 retval = alloc(len + 1);
2725
2726 // Copy the lines of the yank register into the string.
2727 if (retval != NULL)
2728 {
2729 len = 0;
2730 for (i = 0; i < y_current->y_size; ++i)
2731 {
2732 STRCPY(retval + len, y_current->y_array[i]);
2733 len += (long)STRLEN(retval + len);
2734
2735 // Insert a NL between lines and after the last line if y_type is
2736 // MLINE.
2737 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2738 retval[len++] = '\n';
2739 }
2740 retval[len] = NUL;
2741 }
2742
2743 return retval;
2744}
2745
2746 static int
2747init_write_reg(
2748 int name,
2749 yankreg_T **old_y_previous,
2750 yankreg_T **old_y_current,
2751 int must_append,
2752 int *yank_type UNUSED)
2753{
2754 if (!valid_yank_reg(name, TRUE)) // check for valid reg name
2755 {
2756 emsg_invreg(name);
2757 return FAIL;
2758 }
2759
2760 // Don't want to change the current (unnamed) register
2761 *old_y_previous = y_previous;
2762 *old_y_current = y_current;
2763
2764 get_yank_register(name, TRUE);
2765 if (!y_append && !must_append)
2766 free_yank_all();
2767 return OK;
2768}
2769
2770 static void
2771finish_write_reg(
2772 int name,
2773 yankreg_T *old_y_previous,
2774 yankreg_T *old_y_current)
2775{
2776# ifdef FEAT_CLIPBOARD
2777 // Send text of clipboard register to the clipboard.
2778 may_set_selection();
2779# endif
2780
2781 // ':let @" = "val"' should change the meaning of the "" register
2782 if (name != '"')
2783 y_previous = old_y_previous;
2784 y_current = old_y_current;
2785}
2786
2787/*
2788 * Store string "str" in register "name".
2789 * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
2790 * If "must_append" is TRUE, always append to the register. Otherwise append
2791 * if "name" is an uppercase letter.
2792 * Note: "maxlen" and "must_append" don't work for the "/" register.
2793 * Careful: 'str' is modified, you may have to use a copy!
2794 * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise.
2795 */
2796 void
2797write_reg_contents(
2798 int name,
2799 char_u *str,
2800 int maxlen,
2801 int must_append)
2802{
2803 write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
2804}
2805
2806 void
2807write_reg_contents_lst(
2808 int name,
2809 char_u **strings,
2810 int maxlen UNUSED,
2811 int must_append,
2812 int yank_type,
2813 long block_len)
2814{
2815 yankreg_T *old_y_previous, *old_y_current;
2816
2817 if (name == '/' || name == '=')
2818 {
2819 char_u *s;
2820
2821 if (strings[0] == NULL)
2822 s = (char_u *)"";
2823 else if (strings[1] != NULL)
2824 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00002825 emsg(_(e_search_pattern_and_expression_register_may_not_contain_two_or_more_lines));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002826 return;
2827 }
2828 else
2829 s = strings[0];
2830 write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
2831 return;
2832 }
2833
2834 if (name == '_') // black hole: nothing to do
2835 return;
2836
2837 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2838 &yank_type) == FAIL)
2839 return;
2840
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02002841 str_to_reg(y_current, yank_type, (char_u *)strings, -1, block_len, TRUE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002842
2843 finish_write_reg(name, old_y_previous, old_y_current);
2844}
2845
2846 void
2847write_reg_contents_ex(
2848 int name,
2849 char_u *str,
2850 int maxlen,
2851 int must_append,
2852 int yank_type,
2853 long block_len)
2854{
2855 yankreg_T *old_y_previous, *old_y_current;
2856 long len;
2857
2858 if (maxlen >= 0)
2859 len = maxlen;
2860 else
2861 len = (long)STRLEN(str);
2862
2863 // Special case: '/' search pattern
2864 if (name == '/')
2865 {
2866 set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
2867 return;
2868 }
2869
2870 if (name == '#')
2871 {
2872 buf_T *buf;
2873
2874 if (VIM_ISDIGIT(*str))
2875 {
2876 int num = atoi((char *)str);
2877
2878 buf = buflist_findnr(num);
2879 if (buf == NULL)
Bram Moolenaar40bcec12021-12-05 22:19:27 +00002880 semsg(_(e_buffer_nr_does_not_exist), (long)num);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002881 }
2882 else
2883 buf = buflist_findnr(buflist_findpat(str, str + STRLEN(str),
2884 TRUE, FALSE, FALSE));
2885 if (buf == NULL)
2886 return;
2887 curwin->w_alt_fnum = buf->b_fnum;
2888 return;
2889 }
2890
2891 if (name == '=')
2892 {
2893 char_u *p, *s;
2894
Bram Moolenaar71ccd032020-06-12 22:59:11 +02002895 p = vim_strnsave(str, len);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002896 if (p == NULL)
2897 return;
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002898 if (must_append && expr_line != NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002899 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002900 s = concat_str(expr_line, p);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002901 vim_free(p);
2902 p = s;
2903 }
Bram Moolenaarb4bcea42020-10-28 13:53:50 +01002904 set_expr_line(p, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002905 return;
2906 }
2907
2908 if (name == '_') // black hole: nothing to do
2909 return;
2910
2911 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2912 &yank_type) == FAIL)
2913 return;
2914
2915 str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
2916
2917 finish_write_reg(name, old_y_previous, old_y_current);
2918}
2919#endif // FEAT_EVAL
2920
2921#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
2922/*
2923 * Put a string into a register. When the register is not empty, the string
2924 * is appended.
2925 */
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01002926 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002927str_to_reg(
2928 yankreg_T *y_ptr, // pointer to yank register
2929 int yank_type, // MCHAR, MLINE, MBLOCK, MAUTO
2930 char_u *str, // string to put in register
2931 long len, // length of string
2932 long blocklen, // width of Visual block
2933 int str_list) // TRUE if str is char_u **
2934{
2935 int type; // MCHAR, MLINE or MBLOCK
2936 int lnum;
2937 long start;
2938 long i;
2939 int extra;
2940 int newlines; // number of lines added
2941 int extraline = 0; // extra line at the end
2942 int append = FALSE; // append to last line in register
2943 char_u *s;
2944 char_u **ss;
2945 char_u **pp;
2946 long maxlen;
2947
2948 if (y_ptr->y_array == NULL) // NULL means empty register
2949 y_ptr->y_size = 0;
2950
2951 if (yank_type == MAUTO)
2952 type = ((str_list || (len > 0 && (str[len - 1] == NL
2953 || str[len - 1] == CAR)))
2954 ? MLINE : MCHAR);
2955 else
2956 type = yank_type;
2957
2958 // Count the number of lines within the string
2959 newlines = 0;
2960 if (str_list)
2961 {
2962 for (ss = (char_u **) str; *ss != NULL; ++ss)
2963 ++newlines;
2964 }
2965 else
2966 {
2967 for (i = 0; i < len; i++)
2968 if (str[i] == '\n')
2969 ++newlines;
2970 if (type == MCHAR || len == 0 || str[len - 1] != '\n')
2971 {
2972 extraline = 1;
2973 ++newlines; // count extra newline at the end
2974 }
2975 if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR)
2976 {
2977 append = TRUE;
2978 --newlines; // uncount newline when appending first line
2979 }
2980 }
2981
2982 // Without any lines make the register empty.
2983 if (y_ptr->y_size + newlines == 0)
2984 {
2985 VIM_CLEAR(y_ptr->y_array);
2986 return;
2987 }
2988
2989 // Allocate an array to hold the pointers to the new register lines.
2990 // If the register was not empty, move the existing lines to the new array.
2991 pp = lalloc_clear((y_ptr->y_size + newlines) * sizeof(char_u *), TRUE);
2992 if (pp == NULL) // out of memory
2993 return;
2994 for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
2995 pp[lnum] = y_ptr->y_array[lnum];
2996 vim_free(y_ptr->y_array);
2997 y_ptr->y_array = pp;
2998 maxlen = 0;
2999
3000 // Find the end of each line and save it into the array.
3001 if (str_list)
3002 {
3003 for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
3004 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02003005 pp[lnum] = vim_strsave(*ss);
3006 if (type == MBLOCK)
3007 {
3008 int charlen = mb_string2cells(*ss, -1);
3009
3010 if (charlen > maxlen)
3011 maxlen = charlen;
3012 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003013 }
3014 }
3015 else
3016 {
3017 for (start = 0; start < len + extraline; start += i + 1)
3018 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02003019 int charlen = 0;
3020
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003021 for (i = start; i < len; ++i) // find the end of the line
Bram Moolenaar24951a62021-06-04 18:33:49 +02003022 {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003023 if (str[i] == '\n')
3024 break;
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02003025 if (type == MBLOCK)
3026 charlen += mb_ptr2cells_len(str + i, len - i);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003027 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003028 i -= start; // i is now length of line
Bram Moolenaar6e0b5532021-06-04 17:11:47 +02003029 if (charlen > maxlen)
3030 maxlen = charlen;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003031 if (append)
3032 {
3033 --lnum;
3034 extra = (int)STRLEN(y_ptr->y_array[lnum]);
3035 }
3036 else
3037 extra = 0;
3038 s = alloc(i + extra + 1);
3039 if (s == NULL)
3040 break;
3041 if (extra)
3042 mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
3043 if (append)
3044 vim_free(y_ptr->y_array[lnum]);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003045 if (i > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003046 mch_memmove(s + extra, str + start, (size_t)i);
3047 extra += i;
3048 s[extra] = NUL;
3049 y_ptr->y_array[lnum++] = s;
3050 while (--extra >= 0)
3051 {
3052 if (*s == NUL)
3053 *s = '\n'; // replace NUL with newline
3054 ++s;
3055 }
3056 append = FALSE; // only first line is appended
3057 }
3058 }
3059 y_ptr->y_type = type;
3060 y_ptr->y_size = lnum;
3061 if (type == MBLOCK)
3062 y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
3063 else
3064 y_ptr->y_width = 0;
3065# ifdef FEAT_VIMINFO
3066 y_ptr->y_time_set = vim_time();
3067# endif
3068}
3069#endif // FEAT_CLIPBOARD || FEAT_EVAL || PROTO