blob: 36fe954c1015a3c239a7925cd813631282a343da [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
41 yankreg_T *
42get_y_regs(void)
43{
44 return y_regs;
45}
46
47 yankreg_T *
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010048get_y_register(int reg)
49{
50 return &y_regs[reg];
51}
52
53 yankreg_T *
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020054get_y_current(void)
55{
56 return y_current;
57}
58
59 yankreg_T *
60get_y_previous(void)
61{
62 return y_previous;
63}
64
65 void
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010066set_y_current(yankreg_T *yreg)
67{
68 y_current = yreg;
69}
70
71 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020072set_y_previous(yankreg_T *yreg)
73{
74 y_previous = yreg;
75}
76
Christian Brabandt78eb9cc2021-09-14 18:55:51 +020077 void
78reset_y_append(void)
79{
80 y_append = FALSE;
81}
82
83
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020084#if defined(FEAT_EVAL) || defined(PROTO)
85/*
86 * Keep the last expression line here, for repeating.
87 */
88static char_u *expr_line = NULL;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +010089static exarg_T *expr_eap = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020090
91/*
92 * Get an expression for the "\"=expr1" or "CTRL-R =expr1"
93 * Returns '=' when OK, NUL otherwise.
94 */
95 int
96get_expr_register(void)
97{
98 char_u *new_line;
99
Bram Moolenaarc97f9a52021-12-28 20:59:56 +0000100 new_line = getcmdline('=', 0L, 0, 0);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200101 if (new_line == NULL)
102 return NUL;
103 if (*new_line == NUL) // use previous line
104 vim_free(new_line);
105 else
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100106 set_expr_line(new_line, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200107 return '=';
108}
109
110/*
111 * Set the expression for the '=' register.
112 * Argument must be an allocated string.
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100113 * "eap" may be used if the next line needs to be checked when evaluating the
114 * expression.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200115 */
116 void
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100117set_expr_line(char_u *new_line, exarg_T *eap)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200118{
119 vim_free(expr_line);
120 expr_line = new_line;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100121 expr_eap = eap;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200122}
123
124/*
125 * Get the result of the '=' register expression.
126 * Returns a pointer to allocated memory, or NULL for failure.
127 */
128 char_u *
129get_expr_line(void)
130{
131 char_u *expr_copy;
132 char_u *rv;
133 static int nested = 0;
134
135 if (expr_line == NULL)
136 return NULL;
137
138 // Make a copy of the expression, because evaluating it may cause it to be
139 // changed.
140 expr_copy = vim_strsave(expr_line);
141 if (expr_copy == NULL)
142 return NULL;
143
144 // When we are invoked recursively limit the evaluation to 10 levels.
145 // Then return the string as-is.
146 if (nested >= 10)
147 return expr_copy;
148
149 ++nested;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100150 rv = eval_to_string_eap(expr_copy, TRUE, expr_eap);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200151 --nested;
152 vim_free(expr_copy);
153 return rv;
154}
155
156/*
157 * Get the '=' register expression itself, without evaluating it.
158 */
159 static char_u *
160get_expr_line_src(void)
161{
162 if (expr_line == NULL)
163 return NULL;
164 return vim_strsave(expr_line);
165}
166#endif // FEAT_EVAL
167
168/*
169 * Check if 'regname' is a valid name of a yank register.
170 * Note: There is no check for 0 (default register), caller should do this
171 */
172 int
173valid_yank_reg(
174 int regname,
175 int writing) // if TRUE check for writable registers
176{
177 if ( (regname > 0 && ASCII_ISALNUM(regname))
178 || (!writing && vim_strchr((char_u *)
179#ifdef FEAT_EVAL
180 "/.%:="
181#else
182 "/.%:"
183#endif
184 , regname) != NULL)
185 || regname == '#'
186 || regname == '"'
187 || regname == '-'
188 || regname == '_'
189#ifdef FEAT_CLIPBOARD
190 || regname == '*'
191 || regname == '+'
192#endif
193#ifdef FEAT_DND
194 || (!writing && regname == '~')
195#endif
196 )
197 return TRUE;
198 return FALSE;
199}
200
201/*
202 * Set y_current and y_append, according to the value of "regname".
203 * Cannot handle the '_' register.
204 * Must only be called with a valid register name!
205 *
206 * If regname is 0 and writing, use register 0
207 * If regname is 0 and reading, use previous register
208 *
209 * Return TRUE when the register should be inserted literally (selection or
210 * clipboard).
211 */
212 int
213get_yank_register(int regname, int writing)
214{
215 int i;
216 int ret = FALSE;
217
218 y_append = FALSE;
219 if ((regname == 0 || regname == '"') && !writing && y_previous != NULL)
220 {
221 y_current = y_previous;
222 return ret;
223 }
224 i = regname;
225 if (VIM_ISDIGIT(i))
226 i -= '0';
227 else if (ASCII_ISLOWER(i))
228 i = CharOrdLow(i) + 10;
229 else if (ASCII_ISUPPER(i))
230 {
231 i = CharOrdUp(i) + 10;
232 y_append = TRUE;
233 }
234 else if (regname == '-')
235 i = DELETION_REGISTER;
236#ifdef FEAT_CLIPBOARD
237 // When selection is not available, use register 0 instead of '*'
238 else if (clip_star.available && regname == '*')
239 {
240 i = STAR_REGISTER;
241 ret = TRUE;
242 }
243 // When clipboard is not available, use register 0 instead of '+'
244 else if (clip_plus.available && regname == '+')
245 {
246 i = PLUS_REGISTER;
247 ret = TRUE;
248 }
249#endif
250#ifdef FEAT_DND
251 else if (!writing && regname == '~')
252 i = TILDE_REGISTER;
253#endif
254 else // not 0-9, a-z, A-Z or '-': use register 0
255 i = 0;
256 y_current = &(y_regs[i]);
257 if (writing) // remember the register we write into for do_put()
258 y_previous = y_current;
259 return ret;
260}
261
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200262/*
263 * Obtain the contents of a "normal" register. The register is made empty.
264 * The returned pointer has allocated memory, use put_register() later.
265 */
266 void *
267get_register(
268 int name,
269 int copy) // make a copy, if FALSE make register empty.
270{
271 yankreg_T *reg;
272 int i;
273
274#ifdef FEAT_CLIPBOARD
275 // When Visual area changed, may have to update selection. Obtain the
276 // selection too.
277 if (name == '*' && clip_star.available)
278 {
279 if (clip_isautosel_star())
280 clip_update_selection(&clip_star);
281 may_get_selection(name);
282 }
283 if (name == '+' && clip_plus.available)
284 {
285 if (clip_isautosel_plus())
286 clip_update_selection(&clip_plus);
287 may_get_selection(name);
288 }
289#endif
290
291 get_yank_register(name, 0);
292 reg = ALLOC_ONE(yankreg_T);
293 if (reg != NULL)
294 {
295 *reg = *y_current;
296 if (copy)
297 {
298 // If we run out of memory some or all of the lines are empty.
299 if (reg->y_size == 0)
300 reg->y_array = NULL;
301 else
302 reg->y_array = ALLOC_MULT(char_u *, reg->y_size);
303 if (reg->y_array != NULL)
304 {
305 for (i = 0; i < reg->y_size; ++i)
306 reg->y_array[i] = vim_strsave(y_current->y_array[i]);
307 }
308 }
309 else
310 y_current->y_array = NULL;
311 }
312 return (void *)reg;
313}
314
315/*
316 * Put "reg" into register "name". Free any previous contents and "reg".
317 */
318 void
319put_register(int name, void *reg)
320{
321 get_yank_register(name, 0);
322 free_yank_all();
323 *y_current = *(yankreg_T *)reg;
324 vim_free(reg);
325
326#ifdef FEAT_CLIPBOARD
327 // Send text written to clipboard register to the clipboard.
328 may_set_selection();
329#endif
330}
331
Bram Moolenaarfccbf062020-11-26 20:34:00 +0100332#if defined(FEAT_CLIPBOARD) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200333 void
334free_register(void *reg)
335{
336 yankreg_T tmp;
337
338 tmp = *y_current;
339 *y_current = *(yankreg_T *)reg;
340 free_yank_all();
341 vim_free(reg);
342 *y_current = tmp;
343}
344#endif
345
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200346/*
347 * return TRUE if the current yank register has type MLINE
348 */
349 int
350yank_register_mline(int regname)
351{
352 if (regname != 0 && !valid_yank_reg(regname, FALSE))
353 return FALSE;
354 if (regname == '_') // black hole is always empty
355 return FALSE;
356 get_yank_register(regname, FALSE);
357 return (y_current->y_type == MLINE);
358}
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200359
360/*
361 * Start or stop recording into a yank register.
362 *
363 * Return FAIL for failure, OK otherwise.
364 */
365 int
366do_record(int c)
367{
368 char_u *p;
369 static int regname;
370 yankreg_T *old_y_previous, *old_y_current;
371 int retval;
372
373 if (reg_recording == 0) // start recording
374 {
375 // registers 0-9, a-z and " are allowed
376 if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
377 retval = FAIL;
378 else
379 {
380 reg_recording = c;
381 showmode();
382 regname = c;
383 retval = OK;
384 }
385 }
386 else // stop recording
387 {
388 // Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
389 // needs to be removed again to put it in a register. exec_reg then
390 // adds the escaping back later.
391 reg_recording = 0;
392 msg("");
393 p = get_recorded();
394 if (p == NULL)
395 retval = FAIL;
396 else
397 {
398 // Remove escaping for CSI and K_SPECIAL in multi-byte chars.
399 vim_unescape_csi(p);
400
401 // We don't want to change the default register here, so save and
402 // restore the current register name.
403 old_y_previous = y_previous;
404 old_y_current = y_current;
405
406 retval = stuff_yank(regname, p);
407
408 y_previous = old_y_previous;
409 y_current = old_y_current;
410 }
411 }
412 return retval;
413}
414
415/*
416 * Stuff string "p" into yank register "regname" as a single line (append if
417 * uppercase). "p" must have been alloced.
418 *
419 * return FAIL for failure, OK otherwise
420 */
421 static int
422stuff_yank(int regname, char_u *p)
423{
424 char_u *lp;
425 char_u **pp;
426
427 // check for read-only register
428 if (regname != 0 && !valid_yank_reg(regname, TRUE))
429 {
430 vim_free(p);
431 return FAIL;
432 }
433 if (regname == '_') // black hole: don't do anything
434 {
435 vim_free(p);
436 return OK;
437 }
438 get_yank_register(regname, TRUE);
439 if (y_append && y_current->y_array != NULL)
440 {
441 pp = &(y_current->y_array[y_current->y_size - 1]);
442 lp = alloc(STRLEN(*pp) + STRLEN(p) + 1);
443 if (lp == NULL)
444 {
445 vim_free(p);
446 return FAIL;
447 }
448 STRCPY(lp, *pp);
449 STRCAT(lp, p);
450 vim_free(p);
451 vim_free(*pp);
452 *pp = lp;
453 }
454 else
455 {
456 free_yank_all();
457 if ((y_current->y_array = ALLOC_ONE(char_u *)) == NULL)
458 {
459 vim_free(p);
460 return FAIL;
461 }
462 y_current->y_array[0] = p;
463 y_current->y_size = 1;
464 y_current->y_type = MCHAR; // used to be MLINE, why?
465#ifdef FEAT_VIMINFO
466 y_current->y_time_set = vim_time();
467#endif
468 }
469 return OK;
470}
471
Yegappan Lakshmanan41a7f822021-06-16 15:53:17 +0200472/*
473 * Last executed register (@ command)
474 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200475static int execreg_lastc = NUL;
476
477 int
478get_execreg_lastc(void)
479{
480 return execreg_lastc;
481}
482
483 void
484set_execreg_lastc(int lastc)
485{
486 execreg_lastc = lastc;
487}
488
489/*
Bram Moolenaar856c1112020-06-17 21:47:23 +0200490 * When executing a register as a series of ex-commands, if the
491 * line-continuation character is used for a line, then join it with one or
492 * more previous lines. Note that lines are processed backwards starting from
493 * the last line in the register.
494 *
495 * Arguments:
496 * lines - list of lines in the register
497 * idx - index of the line starting with \ or "\. Join this line with all the
498 * immediate predecessor lines that start with a \ and the first line
499 * that doesn't start with a \. Lines that start with a comment "\
500 * character are ignored.
501 *
502 * Returns the concatenated line. The index of the line that should be
503 * processed next is returned in idx.
504 */
505 static char_u *
506execreg_line_continuation(char_u **lines, long *idx)
507{
508 garray_T ga;
509 long i = *idx;
510 char_u *p;
511 int cmd_start;
512 int cmd_end = i;
513 int j;
514 char_u *str;
515
516 ga_init2(&ga, (int)sizeof(char_u), 400);
517
518 // search backwards to find the first line of this command.
519 // Any line not starting with \ or "\ is the start of the
520 // command.
521 while (--i > 0)
522 {
523 p = skipwhite(lines[i]);
524 if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' '))
525 break;
526 }
527 cmd_start = i;
528
529 // join all the lines
530 ga_concat(&ga, lines[cmd_start]);
531 for (j = cmd_start + 1; j <= cmd_end; j++)
532 {
533 p = skipwhite(lines[j]);
534 if (*p == '\\')
535 {
536 // Adjust the growsize to the current length to
537 // speed up concatenating many lines.
538 if (ga.ga_len > 400)
539 {
540 if (ga.ga_len > 8000)
541 ga.ga_growsize = 8000;
542 else
543 ga.ga_growsize = ga.ga_len;
544 }
545 ga_concat(&ga, p + 1);
546 }
547 }
548 ga_append(&ga, NUL);
549 str = vim_strsave(ga.ga_data);
550 ga_clear(&ga);
551
552 *idx = i;
553 return str;
554}
555
556/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200557 * Execute a yank register: copy it into the stuff buffer.
558 *
559 * Return FAIL for failure, OK otherwise.
560 */
561 int
562do_execreg(
563 int regname,
564 int colon, // insert ':' before each line
565 int addcr, // always add '\n' to end of line
566 int silent) // set "silent" flag in typeahead buffer
567{
568 long i;
569 char_u *p;
570 int retval = OK;
571 int remap;
572
573 // repeat previous one
574 if (regname == '@')
575 {
576 if (execreg_lastc == NUL)
577 {
578 emsg(_("E748: No previously used register"));
579 return FAIL;
580 }
581 regname = execreg_lastc;
582 }
583 // check for valid regname
584 if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
585 {
586 emsg_invreg(regname);
587 return FAIL;
588 }
589 execreg_lastc = regname;
590
591#ifdef FEAT_CLIPBOARD
592 regname = may_get_selection(regname);
593#endif
594
595 // black hole: don't stuff anything
596 if (regname == '_')
597 return OK;
598
599 // use last command line
600 if (regname == ':')
601 {
602 if (last_cmdline == NULL)
603 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200604 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200605 return FAIL;
606 }
607 // don't keep the cmdline containing @:
608 VIM_CLEAR(new_last_cmdline);
609 // Escape all control characters with a CTRL-V
610 p = vim_strsave_escaped_ext(last_cmdline,
611 (char_u *)"\001\002\003\004\005\006\007"
612 "\010\011\012\013\014\015\016\017"
613 "\020\021\022\023\024\025\026\027"
614 "\030\031\032\033\034\035\036\037",
615 Ctrl_V, FALSE);
616 if (p != NULL)
617 {
618 // When in Visual mode "'<,'>" will be prepended to the command.
619 // Remove it when it's already there.
620 if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0)
621 retval = put_in_typebuf(p + 5, TRUE, TRUE, silent);
622 else
623 retval = put_in_typebuf(p, TRUE, TRUE, silent);
624 }
625 vim_free(p);
626 }
627#ifdef FEAT_EVAL
628 else if (regname == '=')
629 {
630 p = get_expr_line();
631 if (p == NULL)
632 return FAIL;
633 retval = put_in_typebuf(p, TRUE, colon, silent);
634 vim_free(p);
635 }
636#endif
637 else if (regname == '.') // use last inserted text
638 {
639 p = get_last_insert_save();
640 if (p == NULL)
641 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200642 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200643 return FAIL;
644 }
645 retval = put_in_typebuf(p, FALSE, colon, silent);
646 vim_free(p);
647 }
648 else
649 {
650 get_yank_register(regname, FALSE);
651 if (y_current->y_array == NULL)
652 return FAIL;
653
Bram Moolenaar4b96df52020-01-26 22:00:26 +0100654 // Disallow remapping for ":@r".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200655 remap = colon ? REMAP_NONE : REMAP_YES;
656
657 // Insert lines into typeahead buffer, from last one to first one.
658 put_reedit_in_typebuf(silent);
659 for (i = y_current->y_size; --i >= 0; )
660 {
661 char_u *escaped;
Bram Moolenaar856c1112020-06-17 21:47:23 +0200662 char_u *str;
663 int free_str = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200664
665 // insert NL between lines and after last line if type is MLINE
666 if (y_current->y_type == MLINE || i < y_current->y_size - 1
667 || addcr)
668 {
669 if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
670 return FAIL;
671 }
Bram Moolenaar856c1112020-06-17 21:47:23 +0200672
673 // Handle line-continuation for :@<register>
674 str = y_current->y_array[i];
675 if (colon && i > 0)
676 {
677 p = skipwhite(str);
678 if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))
679 {
680 str = execreg_line_continuation(y_current->y_array, &i);
681 if (str == NULL)
682 return FAIL;
683 free_str = TRUE;
684 }
685 }
686 escaped = vim_strsave_escape_csi(str);
687 if (free_str)
688 vim_free(str);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200689 if (escaped == NULL)
690 return FAIL;
691 retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
692 vim_free(escaped);
693 if (retval == FAIL)
694 return FAIL;
695 if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
696 == FAIL)
697 return FAIL;
698 }
699 reg_executing = regname == 0 ? '"' : regname; // disable "q" command
700 }
701 return retval;
702}
703
704/*
705 * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
706 * used only after other typeahead has been processed.
707 */
708 static void
709put_reedit_in_typebuf(int silent)
710{
711 char_u buf[3];
712
713 if (restart_edit != NUL)
714 {
715 if (restart_edit == 'V')
716 {
717 buf[0] = 'g';
718 buf[1] = 'R';
719 buf[2] = NUL;
720 }
721 else
722 {
723 buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
724 buf[1] = NUL;
725 }
726 if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
727 restart_edit = NUL;
728 }
729}
730
731/*
732 * Insert register contents "s" into the typeahead buffer, so that it will be
733 * executed again.
734 * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
735 * no remapping.
736 */
737 static int
738put_in_typebuf(
739 char_u *s,
740 int esc,
741 int colon, // add ':' before the line
742 int silent)
743{
744 int retval = OK;
745
746 put_reedit_in_typebuf(silent);
747 if (colon)
748 retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
749 if (retval == OK)
750 {
751 char_u *p;
752
753 if (esc)
754 p = vim_strsave_escape_csi(s);
755 else
756 p = s;
757 if (p == NULL)
758 retval = FAIL;
759 else
760 retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
761 0, TRUE, silent);
762 if (esc)
763 vim_free(p);
764 }
765 if (colon && retval == OK)
766 retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
767 return retval;
768}
769
770/*
771 * Insert a yank register: copy it into the Read buffer.
772 * Used by CTRL-R command and middle mouse button in insert mode.
773 *
774 * return FAIL for failure, OK otherwise
775 */
776 int
777insert_reg(
778 int regname,
779 int literally_arg) // insert literally, not as if typed
780{
781 long i;
782 int retval = OK;
783 char_u *arg;
784 int allocated;
785 int literally = literally_arg;
786
787 // It is possible to get into an endless loop by having CTRL-R a in
788 // register a and then, in insert mode, doing CTRL-R a.
789 // If you hit CTRL-C, the loop will be broken here.
790 ui_breakcheck();
791 if (got_int)
792 return FAIL;
793
794 // check for valid regname
795 if (regname != NUL && !valid_yank_reg(regname, FALSE))
796 return FAIL;
797
798#ifdef FEAT_CLIPBOARD
799 regname = may_get_selection(regname);
800#endif
801
802 if (regname == '.') // insert last inserted text
803 retval = stuff_inserted(NUL, 1L, TRUE);
804 else if (get_spec_reg(regname, &arg, &allocated, TRUE))
805 {
806 if (arg == NULL)
807 return FAIL;
808 stuffescaped(arg, literally);
809 if (allocated)
810 vim_free(arg);
811 }
812 else // name or number register
813 {
814 if (get_yank_register(regname, FALSE))
815 literally = TRUE;
816 if (y_current->y_array == NULL)
817 retval = FAIL;
818 else
819 {
820 for (i = 0; i < y_current->y_size; ++i)
821 {
Bram Moolenaar032a2d02020-12-22 17:59:35 +0100822 if (regname == '-')
823 {
824 AppendCharToRedobuff(Ctrl_R);
825 AppendCharToRedobuff(regname);
826 do_put(regname, NULL, BACKWARD, 1L, PUT_CURSEND);
827 }
828 else
829 stuffescaped(y_current->y_array[i], literally);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200830 // Insert a newline between lines and after last line if
831 // y_type is MLINE.
832 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
833 stuffcharReadbuff('\n');
834 }
835 }
836 }
837
838 return retval;
839}
840
841/*
842 * If "regname" is a special register, return TRUE and store a pointer to its
843 * value in "argp".
844 */
845 int
846get_spec_reg(
847 int regname,
848 char_u **argp,
849 int *allocated, // return: TRUE when value was allocated
850 int errmsg) // give error message when failing
851{
852 int cnt;
853
854 *argp = NULL;
855 *allocated = FALSE;
856 switch (regname)
857 {
858 case '%': // file name
859 if (errmsg)
860 check_fname(); // will give emsg if not set
861 *argp = curbuf->b_fname;
862 return TRUE;
863
864 case '#': // alternate file name
865 *argp = getaltfname(errmsg); // may give emsg if not set
866 return TRUE;
867
868#ifdef FEAT_EVAL
869 case '=': // result of expression
870 *argp = get_expr_line();
871 *allocated = TRUE;
872 return TRUE;
873#endif
874
875 case ':': // last command line
876 if (last_cmdline == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200877 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200878 *argp = last_cmdline;
879 return TRUE;
880
881 case '/': // last search-pattern
882 if (last_search_pat() == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200883 emsg(_(e_no_previous_regular_expression));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200884 *argp = last_search_pat();
885 return TRUE;
886
887 case '.': // last inserted text
888 *argp = get_last_insert_save();
889 *allocated = TRUE;
890 if (*argp == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200891 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200892 return TRUE;
893
894#ifdef FEAT_SEARCHPATH
895 case Ctrl_F: // Filename under cursor
896 case Ctrl_P: // Path under cursor, expand via "path"
897 if (!errmsg)
898 return FALSE;
899 *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP
900 | (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL);
901 *allocated = TRUE;
902 return TRUE;
903#endif
904
905 case Ctrl_W: // word under cursor
906 case Ctrl_A: // WORD (mnemonic All) under cursor
907 if (!errmsg)
908 return FALSE;
909 cnt = find_ident_under_cursor(argp, regname == Ctrl_W
910 ? (FIND_IDENT|FIND_STRING) : FIND_STRING);
911 *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
912 *allocated = TRUE;
913 return TRUE;
914
915 case Ctrl_L: // Line under cursor
916 if (!errmsg)
917 return FALSE;
918
919 *argp = ml_get_buf(curwin->w_buffer,
920 curwin->w_cursor.lnum, FALSE);
921 return TRUE;
922
923 case '_': // black hole: always empty
924 *argp = (char_u *)"";
925 return TRUE;
926 }
927
928 return FALSE;
929}
930
931/*
932 * Paste a yank register into the command line.
933 * Only for non-special registers.
934 * Used by CTRL-R command in command-line mode
935 * insert_reg() can't be used here, because special characters from the
936 * register contents will be interpreted as commands.
937 *
938 * return FAIL for failure, OK otherwise
939 */
940 int
941cmdline_paste_reg(
942 int regname,
943 int literally_arg, // Insert text literally instead of "as typed"
944 int remcr) // don't add CR characters
945{
946 long i;
947 int literally = literally_arg;
948
949 if (get_yank_register(regname, FALSE))
950 literally = TRUE;
951 if (y_current->y_array == NULL)
952 return FAIL;
953
954 for (i = 0; i < y_current->y_size; ++i)
955 {
956 cmdline_paste_str(y_current->y_array[i], literally);
957
958 // Insert ^M between lines and after last line if type is MLINE.
959 // Don't do this when "remcr" is TRUE.
960 if ((y_current->y_type == MLINE || i < y_current->y_size - 1) && !remcr)
961 cmdline_paste_str((char_u *)"\r", literally);
962
963 // Check for CTRL-C, in case someone tries to paste a few thousand
964 // lines and gets bored.
965 ui_breakcheck();
966 if (got_int)
967 return FAIL;
968 }
969 return OK;
970}
971
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200972/*
973 * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
974 */
975 void
976shift_delete_registers()
977{
978 int n;
979
980 y_current = &y_regs[9];
981 free_yank_all(); // free register nine
982 for (n = 9; n > 1; --n)
983 y_regs[n] = y_regs[n - 1];
984 y_current = &y_regs[1];
985 if (!y_append)
986 y_previous = y_current;
987 y_regs[1].y_array = NULL; // set register one to empty
988}
989
990#if defined(FEAT_EVAL)
991 void
992yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
993{
Bram Moolenaar3075a452021-11-17 15:51:52 +0000994 static int recursive = FALSE;
995 dict_T *v_event;
996 list_T *list;
997 int n;
998 char_u buf[NUMBUFLEN + 2];
999 long reglen = 0;
1000 save_v_event_T save_v_event;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001001
1002 if (recursive)
1003 return;
1004
Bram Moolenaar3075a452021-11-17 15:51:52 +00001005 v_event = get_v_event(&save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001006
1007 list = list_alloc();
1008 if (list == NULL)
1009 return;
1010 for (n = 0; n < reg->y_size; n++)
1011 list_append_string(list, reg->y_array[n], -1);
1012 list->lv_lock = VAR_FIXED;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001013 (void)dict_add_list(v_event, "regcontents", list);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001014
1015 buf[0] = (char_u)oap->regname;
1016 buf[1] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001017 (void)dict_add_string(v_event, "regname", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001018
1019 buf[0] = get_op_char(oap->op_type);
1020 buf[1] = get_extra_op_char(oap->op_type);
1021 buf[2] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001022 (void)dict_add_string(v_event, "operator", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001023
1024 buf[0] = NUL;
1025 buf[1] = NUL;
1026 switch (get_reg_type(oap->regname, &reglen))
1027 {
1028 case MLINE: buf[0] = 'V'; break;
1029 case MCHAR: buf[0] = 'v'; break;
1030 case MBLOCK:
1031 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
1032 reglen + 1);
1033 break;
1034 }
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001035 (void)dict_add_string(v_event, "regtype", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001036
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001037 (void)dict_add_bool(v_event, "visual", oap->is_VIsual);
Bram Moolenaar37d16732020-06-12 22:09:01 +02001038
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001039 // Lock the dictionary and its keys
1040 dict_set_items_ro(v_event);
1041
1042 recursive = TRUE;
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02001043 textwinlock++;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001044 apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02001045 textwinlock--;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001046 recursive = FALSE;
1047
1048 // Empty the dictionary, v:event is still valid
Bram Moolenaar3075a452021-11-17 15:51:52 +00001049 restore_v_event(v_event, &save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001050}
1051#endif
1052
1053/*
1054 * set all the yank registers to empty (called from main())
1055 */
1056 void
1057init_yank(void)
1058{
1059 int i;
1060
1061 for (i = 0; i < NUM_REGISTERS; ++i)
1062 y_regs[i].y_array = NULL;
1063}
1064
1065#if defined(EXITFREE) || defined(PROTO)
1066 void
1067clear_registers(void)
1068{
1069 int i;
1070
1071 for (i = 0; i < NUM_REGISTERS; ++i)
1072 {
1073 y_current = &y_regs[i];
1074 if (y_current->y_array != NULL)
1075 free_yank_all();
1076 }
1077}
1078#endif
1079
1080/*
1081 * Free "n" lines from the current yank register.
1082 * Called for normal freeing and in case of error.
1083 */
1084 static void
1085free_yank(long n)
1086{
1087 if (y_current->y_array != NULL)
1088 {
1089 long i;
1090
1091 for (i = n; --i >= 0; )
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001092 vim_free(y_current->y_array[i]);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001093 VIM_CLEAR(y_current->y_array);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001094 }
1095}
1096
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01001097 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001098free_yank_all(void)
1099{
1100 free_yank(y_current->y_size);
1101}
1102
1103/*
1104 * Yank the text between "oap->start" and "oap->end" into a yank register.
1105 * If we are to append (uppercase register), we first yank into a new yank
1106 * register and then concatenate the old and the new one (so we keep the old
1107 * one in case of out-of-memory).
1108 *
1109 * Return FAIL for failure, OK otherwise.
1110 */
1111 int
1112op_yank(oparg_T *oap, int deleting, int mess)
1113{
1114 long y_idx; // index in y_array[]
1115 yankreg_T *curr; // copy of y_current
1116 yankreg_T newreg; // new yank register when appending
1117 char_u **new_ptr;
1118 linenr_T lnum; // current line number
1119 long j;
1120 int yanktype = oap->motion_type;
1121 long yanklines = oap->line_count;
1122 linenr_T yankendlnum = oap->end.lnum;
1123 char_u *p;
1124 char_u *pnew;
1125 struct block_def bd;
1126#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1127 int did_star = FALSE;
1128#endif
1129
1130 // check for read-only register
1131 if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
1132 {
1133 beep_flush();
1134 return FAIL;
1135 }
1136 if (oap->regname == '_') // black hole: nothing to do
1137 return OK;
1138
1139#ifdef FEAT_CLIPBOARD
1140 if (!clip_star.available && oap->regname == '*')
1141 oap->regname = 0;
1142 else if (!clip_plus.available && oap->regname == '+')
1143 oap->regname = 0;
1144#endif
1145
1146 if (!deleting) // op_delete() already set y_current
1147 get_yank_register(oap->regname, TRUE);
1148
1149 curr = y_current;
1150 // append to existing contents
1151 if (y_append && y_current->y_array != NULL)
1152 y_current = &newreg;
1153 else
1154 free_yank_all(); // free previously yanked lines
1155
1156 // If the cursor was in column 1 before and after the movement, and the
1157 // operator is not inclusive, the yank is always linewise.
1158 if ( oap->motion_type == MCHAR
1159 && oap->start.col == 0
1160 && !oap->inclusive
1161 && (!oap->is_VIsual || *p_sel == 'o')
1162 && !oap->block_mode
1163 && oap->end.col == 0
1164 && yanklines > 1)
1165 {
1166 yanktype = MLINE;
1167 --yankendlnum;
1168 --yanklines;
1169 }
1170
1171 y_current->y_size = yanklines;
1172 y_current->y_type = yanktype; // set the yank register type
1173 y_current->y_width = 0;
1174 y_current->y_array = lalloc_clear(sizeof(char_u *) * yanklines, TRUE);
1175 if (y_current->y_array == NULL)
1176 {
1177 y_current = curr;
1178 return FAIL;
1179 }
1180#ifdef FEAT_VIMINFO
1181 y_current->y_time_set = vim_time();
1182#endif
1183
1184 y_idx = 0;
1185 lnum = oap->start.lnum;
1186
1187 if (oap->block_mode)
1188 {
1189 // Visual block mode
1190 y_current->y_type = MBLOCK; // set the yank register type
1191 y_current->y_width = oap->end_vcol - oap->start_vcol;
1192
1193 if (curwin->w_curswant == MAXCOL && y_current->y_width > 0)
1194 y_current->y_width--;
1195 }
1196
1197 for ( ; lnum <= yankendlnum; lnum++, y_idx++)
1198 {
1199 switch (y_current->y_type)
1200 {
1201 case MBLOCK:
1202 block_prep(oap, &bd, lnum, FALSE);
Christian Brabandt544a38e2021-06-10 19:39:11 +02001203 if (yank_copy_line(&bd, y_idx, oap->excl_tr_ws) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001204 goto fail;
1205 break;
1206
1207 case MLINE:
1208 if ((y_current->y_array[y_idx] =
Christian Brabandt544a38e2021-06-10 19:39:11 +02001209 vim_strsave(ml_get(lnum))) == NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001210 goto fail;
1211 break;
1212
1213 case MCHAR:
1214 {
1215 colnr_T startcol = 0, endcol = MAXCOL;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001216 int is_oneChar = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001217 colnr_T cs, ce;
1218
1219 p = ml_get(lnum);
1220 bd.startspaces = 0;
1221 bd.endspaces = 0;
1222
1223 if (lnum == oap->start.lnum)
1224 {
1225 startcol = oap->start.col;
1226 if (virtual_op)
1227 {
1228 getvcol(curwin, &oap->start, &cs, NULL, &ce);
1229 if (ce != cs && oap->start.coladd > 0)
1230 {
1231 // Part of a tab selected -- but don't
1232 // double-count it.
1233 bd.startspaces = (ce - cs + 1)
1234 - oap->start.coladd;
1235 startcol++;
1236 }
1237 }
1238 }
1239
1240 if (lnum == oap->end.lnum)
1241 {
1242 endcol = oap->end.col;
1243 if (virtual_op)
1244 {
1245 getvcol(curwin, &oap->end, &cs, NULL, &ce);
1246 if (p[endcol] == NUL || (cs + oap->end.coladd < ce
1247 // Don't add space for double-wide
1248 // char; endcol will be on last byte
1249 // of multi-byte char.
1250 && (*mb_head_off)(p, p + endcol) == 0))
1251 {
1252 if (oap->start.lnum == oap->end.lnum
1253 && oap->start.col == oap->end.col)
1254 {
1255 // Special case: inside a single char
1256 is_oneChar = TRUE;
1257 bd.startspaces = oap->end.coladd
1258 - oap->start.coladd + oap->inclusive;
1259 endcol = startcol;
1260 }
1261 else
1262 {
1263 bd.endspaces = oap->end.coladd
1264 + oap->inclusive;
1265 endcol -= oap->inclusive;
1266 }
1267 }
1268 }
1269 }
1270 if (endcol == MAXCOL)
1271 endcol = (colnr_T)STRLEN(p);
1272 if (startcol > endcol || is_oneChar)
1273 bd.textlen = 0;
1274 else
1275 bd.textlen = endcol - startcol + oap->inclusive;
1276 bd.textstart = p + startcol;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001277 if (yank_copy_line(&bd, y_idx, FALSE) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001278 goto fail;
1279 break;
1280 }
1281 // NOTREACHED
1282 }
1283 }
1284
1285 if (curr != y_current) // append the new block to the old block
1286 {
1287 new_ptr = ALLOC_MULT(char_u *, curr->y_size + y_current->y_size);
1288 if (new_ptr == NULL)
1289 goto fail;
1290 for (j = 0; j < curr->y_size; ++j)
1291 new_ptr[j] = curr->y_array[j];
1292 vim_free(curr->y_array);
1293 curr->y_array = new_ptr;
1294#ifdef FEAT_VIMINFO
1295 curr->y_time_set = vim_time();
1296#endif
1297
1298 if (yanktype == MLINE) // MLINE overrides MCHAR and MBLOCK
1299 curr->y_type = MLINE;
1300
1301 // Concatenate the last line of the old block with the first line of
1302 // the new block, unless being Vi compatible.
1303 if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL)
1304 {
1305 pnew = alloc(STRLEN(curr->y_array[curr->y_size - 1])
1306 + STRLEN(y_current->y_array[0]) + 1);
1307 if (pnew == NULL)
1308 {
1309 y_idx = y_current->y_size - 1;
1310 goto fail;
1311 }
1312 STRCPY(pnew, curr->y_array[--j]);
1313 STRCAT(pnew, y_current->y_array[0]);
1314 vim_free(curr->y_array[j]);
1315 vim_free(y_current->y_array[0]);
1316 curr->y_array[j++] = pnew;
1317 y_idx = 1;
1318 }
1319 else
1320 y_idx = 0;
1321 while (y_idx < y_current->y_size)
1322 curr->y_array[j++] = y_current->y_array[y_idx++];
1323 curr->y_size = j;
1324 vim_free(y_current->y_array);
1325 y_current = curr;
1326 }
1327 if (curwin->w_p_rnu)
1328 redraw_later(SOME_VALID); // cursor moved to start
1329 if (mess) // Display message about yank?
1330 {
1331 if (yanktype == MCHAR
1332 && !oap->block_mode
1333 && yanklines == 1)
1334 yanklines = 0;
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001335 // Some versions of Vi use ">=" here, some don't...
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001336 if (yanklines > p_report)
1337 {
1338 char namebuf[100];
1339
1340 if (oap->regname == NUL)
1341 *namebuf = NUL;
1342 else
1343 vim_snprintf(namebuf, sizeof(namebuf),
1344 _(" into \"%c"), oap->regname);
1345
1346 // redisplay now, so message is not deleted
1347 update_topline_redraw();
1348 if (oap->block_mode)
1349 {
1350 smsg(NGETTEXT("block of %ld line yanked%s",
1351 "block of %ld lines yanked%s", yanklines),
1352 yanklines, namebuf);
1353 }
1354 else
1355 {
1356 smsg(NGETTEXT("%ld line yanked%s",
1357 "%ld lines yanked%s", yanklines),
1358 yanklines, namebuf);
1359 }
1360 }
1361 }
1362
Bram Moolenaare1004402020-10-24 20:49:43 +02001363 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001364 {
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001365 // Set "'[" and "']" marks.
1366 curbuf->b_op_start = oap->start;
1367 curbuf->b_op_end = oap->end;
1368 if (yanktype == MLINE && !oap->block_mode)
1369 {
1370 curbuf->b_op_start.col = 0;
1371 curbuf->b_op_end.col = MAXCOL;
1372 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001373 }
1374
1375#ifdef FEAT_CLIPBOARD
1376 // If we were yanking to the '*' register, send result to clipboard.
1377 // If no register was specified, and "unnamed" in 'clipboard', make a copy
1378 // to the '*' register.
1379 if (clip_star.available
1380 && (curr == &(y_regs[STAR_REGISTER])
1381 || (!deleting && oap->regname == 0
1382 && ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
1383 {
1384 if (curr != &(y_regs[STAR_REGISTER]))
1385 // Copy the text from register 0 to the clipboard register.
1386 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1387
1388 clip_own_selection(&clip_star);
1389 clip_gen_set_selection(&clip_star);
1390# ifdef FEAT_X11
1391 did_star = TRUE;
1392# endif
1393 }
1394
1395# ifdef FEAT_X11
1396 // If we were yanking to the '+' register, send result to selection.
Bram Moolenaar37096af2021-03-02 19:04:11 +01001397 // Also copy to the '*' register, in case auto-select is off. But not when
1398 // 'clipboard' has "unnamedplus" and not "unnamed".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001399 if (clip_plus.available
1400 && (curr == &(y_regs[PLUS_REGISTER])
1401 || (!deleting && oap->regname == 0
1402 && ((clip_unnamed | clip_unnamed_saved) &
Bram Moolenaar37096af2021-03-02 19:04:11 +01001403 CLIP_UNNAMED_PLUS))))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001404 {
1405 if (curr != &(y_regs[PLUS_REGISTER]))
1406 // Copy the text from register 0 to the clipboard register.
1407 copy_yank_reg(&(y_regs[PLUS_REGISTER]));
1408
1409 clip_own_selection(&clip_plus);
1410 clip_gen_set_selection(&clip_plus);
Bram Moolenaar37096af2021-03-02 19:04:11 +01001411 if (!clip_isautosel_star()
1412 && !clip_isautosel_plus()
1413 && !((clip_unnamed | clip_unnamed_saved) == CLIP_UNNAMED_PLUS)
1414 && !did_star
1415 && curr == &(y_regs[PLUS_REGISTER]))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001416 {
1417 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1418 clip_own_selection(&clip_star);
1419 clip_gen_set_selection(&clip_star);
1420 }
1421 }
1422# endif
1423#endif
1424
1425#if defined(FEAT_EVAL)
1426 if (!deleting && has_textyankpost())
1427 yank_do_autocmd(oap, y_current);
1428#endif
1429
1430 return OK;
1431
1432fail: // free the allocated lines
1433 free_yank(y_idx + 1);
1434 y_current = curr;
1435 return FAIL;
1436}
1437
Christian Brabandt544a38e2021-06-10 19:39:11 +02001438/*
1439 * Copy a block range into a register.
1440 * If "exclude_trailing_space" is set, do not copy trailing whitespaces.
1441 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001442 static int
Christian Brabandt544a38e2021-06-10 19:39:11 +02001443yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001444{
1445 char_u *pnew;
1446
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02001447 if (exclude_trailing_space)
1448 bd->endspaces = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001449 if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1))
1450 == NULL)
1451 return FAIL;
1452 y_current->y_array[y_idx] = pnew;
1453 vim_memset(pnew, ' ', (size_t)bd->startspaces);
1454 pnew += bd->startspaces;
1455 mch_memmove(pnew, bd->textstart, (size_t)bd->textlen);
1456 pnew += bd->textlen;
1457 vim_memset(pnew, ' ', (size_t)bd->endspaces);
1458 pnew += bd->endspaces;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001459 if (exclude_trailing_space)
1460 {
1461 int s = bd->textlen + bd->endspaces;
1462
1463 while (VIM_ISWHITE(*(bd->textstart + s - 1)) && s > 0)
1464 {
1465 s = s - (*mb_head_off)(bd->textstart, bd->textstart + s - 1) - 1;
1466 pnew--;
1467 }
1468 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001469 *pnew = NUL;
1470 return OK;
1471}
1472
1473#ifdef FEAT_CLIPBOARD
1474/*
1475 * Make a copy of the y_current register to register "reg".
1476 */
1477 static void
1478copy_yank_reg(yankreg_T *reg)
1479{
1480 yankreg_T *curr = y_current;
1481 long j;
1482
1483 y_current = reg;
1484 free_yank_all();
1485 *y_current = *curr;
1486 y_current->y_array = lalloc_clear(
1487 sizeof(char_u *) * y_current->y_size, TRUE);
1488 if (y_current->y_array == NULL)
1489 y_current->y_size = 0;
1490 else
1491 for (j = 0; j < y_current->y_size; ++j)
1492 if ((y_current->y_array[j] = vim_strsave(curr->y_array[j])) == NULL)
1493 {
1494 free_yank(j);
1495 y_current->y_size = 0;
1496 break;
1497 }
1498 y_current = curr;
1499}
1500#endif
1501
1502/*
1503 * Put contents of register "regname" into the text.
1504 * Caller must check "regname" to be valid!
1505 * "flags": PUT_FIXINDENT make indent look nice
1506 * PUT_CURSEND leave cursor after end of new text
1507 * PUT_LINE force linewise put (":put")
Christian Brabandt2fa93842021-05-30 22:17:25 +02001508 * PUT_BLOCK_INNER in block mode, do not add trailing spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001509 */
1510 void
1511do_put(
1512 int regname,
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001513 char_u *expr_result, // result for regname "=" when compiled
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001514 int dir, // BACKWARD for 'P', FORWARD for 'p'
1515 long count,
1516 int flags)
1517{
1518 char_u *ptr;
1519 char_u *newp, *oldp;
1520 int yanklen;
1521 int totlen = 0; // init for gcc
1522 linenr_T lnum;
1523 colnr_T col;
1524 long i; // index in y_array[]
1525 int y_type;
1526 long y_size;
1527 int oldlen;
1528 long y_width = 0;
1529 colnr_T vcol;
1530 int delcount;
1531 int incr = 0;
1532 long j;
1533 struct block_def bd;
1534 char_u **y_array = NULL;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001535 yankreg_T *y_current_used = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001536 long nr_lines = 0;
1537 pos_T new_cursor;
1538 int indent;
1539 int orig_indent = 0; // init for gcc
1540 int indent_diff = 0; // init for gcc
1541 int first_indent = TRUE;
1542 int lendiff = 0;
1543 pos_T old_pos;
1544 char_u *insert_string = NULL;
1545 int allocated = FALSE;
1546 long cnt;
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001547 pos_T orig_start = curbuf->b_op_start;
1548 pos_T orig_end = curbuf->b_op_end;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001549 unsigned int cur_ve_flags = get_ve_flags();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001550
1551#ifdef FEAT_CLIPBOARD
1552 // Adjust register name for "unnamed" in 'clipboard'.
1553 adjust_clip_reg(&regname);
1554 (void)may_get_selection(regname);
1555#endif
1556
1557 if (flags & PUT_FIXINDENT)
1558 orig_indent = get_indent();
1559
1560 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1561 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1562
1563 // Using inserted text works differently, because the register includes
1564 // special characters (newlines, etc.).
1565 if (regname == '.')
1566 {
1567 if (VIsual_active)
1568 stuffcharReadbuff(VIsual_mode);
1569 (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
1570 (count == -1 ? 'O' : 'i')), count, FALSE);
1571 // Putting the text is done later, so can't really move the cursor to
1572 // the next character. Use "l" to simulate it.
1573 if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
1574 stuffcharReadbuff('l');
1575 return;
1576 }
1577
1578 // For special registers '%' (file name), '#' (alternate file name) and
1579 // ':' (last command line), etc. we have to create a fake yank register.
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001580 // For compiled code "expr_result" holds the expression result.
1581 if (regname == '=' && expr_result != NULL)
1582 insert_string = expr_result;
1583 else if (get_spec_reg(regname, &insert_string, &allocated, TRUE)
1584 && insert_string == NULL)
1585 return;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001586
1587 // Autocommands may be executed when saving lines for undo. This might
1588 // make "y_array" invalid, so we start undo now to avoid that.
1589 if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL)
1590 goto end;
1591
1592 if (insert_string != NULL)
1593 {
1594 y_type = MCHAR;
1595#ifdef FEAT_EVAL
1596 if (regname == '=')
1597 {
1598 // For the = register we need to split the string at NL
1599 // characters.
1600 // Loop twice: count the number of lines and save them.
1601 for (;;)
1602 {
1603 y_size = 0;
1604 ptr = insert_string;
1605 while (ptr != NULL)
1606 {
1607 if (y_array != NULL)
1608 y_array[y_size] = ptr;
1609 ++y_size;
1610 ptr = vim_strchr(ptr, '\n');
1611 if (ptr != NULL)
1612 {
1613 if (y_array != NULL)
1614 *ptr = NUL;
1615 ++ptr;
1616 // A trailing '\n' makes the register linewise.
1617 if (*ptr == NUL)
1618 {
1619 y_type = MLINE;
1620 break;
1621 }
1622 }
1623 }
1624 if (y_array != NULL)
1625 break;
1626 y_array = ALLOC_MULT(char_u *, y_size);
1627 if (y_array == NULL)
1628 goto end;
1629 }
1630 }
1631 else
1632#endif
1633 {
1634 y_size = 1; // use fake one-line yank register
1635 y_array = &insert_string;
1636 }
1637 }
1638 else
1639 {
1640 get_yank_register(regname, FALSE);
1641
1642 y_type = y_current->y_type;
1643 y_width = y_current->y_width;
1644 y_size = y_current->y_size;
1645 y_array = y_current->y_array;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001646 y_current_used = y_current;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001647 }
1648
1649 if (y_type == MLINE)
1650 {
1651 if (flags & PUT_LINE_SPLIT)
1652 {
1653 char_u *p;
1654
1655 // "p" or "P" in Visual mode: split the lines to put the text in
1656 // between.
1657 if (u_save_cursor() == FAIL)
1658 goto end;
1659 p = ml_get_cursor();
1660 if (dir == FORWARD && *p != NUL)
1661 MB_PTR_ADV(p);
1662 ptr = vim_strsave(p);
1663 if (ptr == NULL)
1664 goto end;
1665 ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE);
1666 vim_free(ptr);
1667
1668 oldp = ml_get_curline();
1669 p = oldp + curwin->w_cursor.col;
1670 if (dir == FORWARD && *p != NUL)
1671 MB_PTR_ADV(p);
1672 ptr = vim_strnsave(oldp, p - oldp);
1673 if (ptr == NULL)
1674 goto end;
1675 ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
1676 ++nr_lines;
1677 dir = FORWARD;
1678 }
1679 if (flags & PUT_LINE_FORWARD)
1680 {
1681 // Must be "p" for a Visual block, put lines below the block.
1682 curwin->w_cursor = curbuf->b_visual.vi_end;
1683 dir = FORWARD;
1684 }
1685 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1686 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1687 }
1688
1689 if (flags & PUT_LINE) // :put command or "p" in Visual line mode.
1690 y_type = MLINE;
1691
1692 if (y_size == 0 || y_array == NULL)
1693 {
Bram Moolenaarac78dd42022-01-02 19:25:26 +00001694 semsg(_(e_nothing_in_register_str),
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001695 regname == 0 ? (char_u *)"\"" : transchar(regname));
1696 goto end;
1697 }
1698
1699 if (y_type == MBLOCK)
1700 {
1701 lnum = curwin->w_cursor.lnum + y_size + 1;
1702 if (lnum > curbuf->b_ml.ml_line_count)
1703 lnum = curbuf->b_ml.ml_line_count + 1;
1704 if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
1705 goto end;
1706 }
1707 else if (y_type == MLINE)
1708 {
1709 lnum = curwin->w_cursor.lnum;
1710#ifdef FEAT_FOLDING
1711 // Correct line number for closed fold. Don't move the cursor yet,
1712 // u_save() uses it.
1713 if (dir == BACKWARD)
1714 (void)hasFolding(lnum, &lnum, NULL);
1715 else
1716 (void)hasFolding(lnum, NULL, &lnum);
1717#endif
1718 if (dir == FORWARD)
1719 ++lnum;
1720 // In an empty buffer the empty line is going to be replaced, include
1721 // it in the saved lines.
1722 if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL)
1723 goto end;
1724#ifdef FEAT_FOLDING
1725 if (dir == FORWARD)
1726 curwin->w_cursor.lnum = lnum - 1;
1727 else
1728 curwin->w_cursor.lnum = lnum;
1729 curbuf->b_op_start = curwin->w_cursor; // for mark_adjust()
1730#endif
1731 }
1732 else if (u_save_cursor() == FAIL)
1733 goto end;
1734
1735 yanklen = (int)STRLEN(y_array[0]);
1736
Gary Johnson53ba05b2021-07-26 22:19:10 +02001737 if (cur_ve_flags == VE_ALL && y_type == MCHAR)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001738 {
1739 if (gchar_cursor() == TAB)
1740 {
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001741 int viscol = getviscol();
1742 int ts = curbuf->b_p_ts;
1743
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001744 // Don't need to insert spaces when "p" on the last position of a
1745 // tab or "P" on the first position.
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001746 if (dir == FORWARD ?
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001747#ifdef FEAT_VARTABS
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001748 tabstop_padding(viscol, ts, curbuf->b_p_vts_array) != 1
1749#else
1750 ts - (viscol % ts) != 1
1751#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001752 : curwin->w_cursor.coladd > 0)
1753 coladvance_force(viscol);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001754 else
1755 curwin->w_cursor.coladd = 0;
1756 }
1757 else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
1758 coladvance_force(getviscol() + (dir == FORWARD));
1759 }
1760
1761 lnum = curwin->w_cursor.lnum;
1762 col = curwin->w_cursor.col;
1763
1764 // Block mode
1765 if (y_type == MBLOCK)
1766 {
1767 int c = gchar_cursor();
1768 colnr_T endcol2 = 0;
1769
1770 if (dir == FORWARD && c != NUL)
1771 {
Gary Johnson53ba05b2021-07-26 22:19:10 +02001772 if (cur_ve_flags == VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001773 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1774 else
1775 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
1776
1777 if (has_mbyte)
1778 // move to start of next multi-byte character
1779 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
1780 else
Gary Johnson53ba05b2021-07-26 22:19:10 +02001781 if (c != TAB || cur_ve_flags != VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001782 ++curwin->w_cursor.col;
1783 ++col;
1784 }
1785 else
1786 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1787
1788 col += curwin->w_cursor.coladd;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001789 if (cur_ve_flags == VE_ALL
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001790 && (curwin->w_cursor.coladd > 0
1791 || endcol2 == curwin->w_cursor.col))
1792 {
1793 if (dir == FORWARD && c == NUL)
1794 ++col;
Bram Moolenaaref85a9b2020-07-10 20:24:07 +02001795 if (dir != FORWARD && c != NUL && curwin->w_cursor.coladd > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001796 ++curwin->w_cursor.col;
1797 if (c == TAB)
1798 {
1799 if (dir == BACKWARD && curwin->w_cursor.col)
1800 curwin->w_cursor.col--;
1801 if (dir == FORWARD && col - 1 == endcol2)
1802 curwin->w_cursor.col++;
1803 }
1804 }
1805 curwin->w_cursor.coladd = 0;
1806 bd.textcol = 0;
1807 for (i = 0; i < y_size; ++i)
1808 {
Christian Brabandt2fa93842021-05-30 22:17:25 +02001809 int spaces = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001810 char shortline;
1811
1812 bd.startspaces = 0;
1813 bd.endspaces = 0;
1814 vcol = 0;
1815 delcount = 0;
1816
1817 // add a new line
1818 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
1819 {
1820 if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
1821 (colnr_T)1, FALSE) == FAIL)
1822 break;
1823 ++nr_lines;
1824 }
1825 // get the old line and advance to the position to insert at
1826 oldp = ml_get_curline();
1827 oldlen = (int)STRLEN(oldp);
1828 for (ptr = oldp; vcol < col && *ptr; )
1829 {
1830 // Count a tab for what it's worth (if list mode not on)
1831 incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol);
1832 vcol += incr;
1833 }
1834 bd.textcol = (colnr_T)(ptr - oldp);
1835
1836 shortline = (vcol < col) || (vcol == col && !*ptr) ;
1837
1838 if (vcol < col) // line too short, padd with spaces
1839 bd.startspaces = col - vcol;
1840 else if (vcol > col)
1841 {
1842 bd.endspaces = vcol - col;
1843 bd.startspaces = incr - bd.endspaces;
1844 --bd.textcol;
1845 delcount = 1;
1846 if (has_mbyte)
1847 bd.textcol -= (*mb_head_off)(oldp, oldp + bd.textcol);
1848 if (oldp[bd.textcol] != TAB)
1849 {
1850 // Only a Tab can be split into spaces. Other
1851 // characters will have to be moved to after the
1852 // block, causing misalignment.
1853 delcount = 0;
1854 bd.endspaces = 0;
1855 }
1856 }
1857
1858 yanklen = (int)STRLEN(y_array[i]);
1859
Christian Brabandt2fa93842021-05-30 22:17:25 +02001860 if ((flags & PUT_BLOCK_INNER) == 0)
1861 {
1862 // calculate number of spaces required to fill right side of
1863 // block
1864 spaces = y_width + 1;
1865 for (j = 0; j < yanklen; j++)
1866 spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
1867 if (spaces < 0)
1868 spaces = 0;
1869 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001870
ichizokfa537222021-11-16 12:50:46 +00001871 // Insert the new text.
1872 // First check for multiplication overflow.
1873 if (yanklen + spaces != 0
1874 && count > ((INT_MAX - (bd.startspaces + bd.endspaces))
1875 / (yanklen + spaces)))
1876 {
1877 emsg(_(e_resulting_text_too_long));
1878 break;
1879 }
1880
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001881 totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
1882 newp = alloc(totlen + oldlen + 1);
1883 if (newp == NULL)
1884 break;
ichizokfa537222021-11-16 12:50:46 +00001885
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001886 // copy part up to cursor to new line
1887 ptr = newp;
1888 mch_memmove(ptr, oldp, (size_t)bd.textcol);
1889 ptr += bd.textcol;
ichizokfa537222021-11-16 12:50:46 +00001890
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001891 // may insert some spaces before the new text
1892 vim_memset(ptr, ' ', (size_t)bd.startspaces);
1893 ptr += bd.startspaces;
ichizokfa537222021-11-16 12:50:46 +00001894
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001895 // insert the new text
1896 for (j = 0; j < count; ++j)
1897 {
1898 mch_memmove(ptr, y_array[i], (size_t)yanklen);
1899 ptr += yanklen;
1900
1901 // insert block's trailing spaces only if there's text behind
1902 if ((j < count - 1 || !shortline) && spaces)
1903 {
1904 vim_memset(ptr, ' ', (size_t)spaces);
1905 ptr += spaces;
1906 }
1907 }
ichizokfa537222021-11-16 12:50:46 +00001908
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001909 // may insert some spaces after the new text
1910 vim_memset(ptr, ' ', (size_t)bd.endspaces);
1911 ptr += bd.endspaces;
ichizokfa537222021-11-16 12:50:46 +00001912
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001913 // move the text after the cursor to the end of the line.
1914 mch_memmove(ptr, oldp + bd.textcol + delcount,
1915 (size_t)(oldlen - bd.textcol - delcount + 1));
1916 ml_replace(curwin->w_cursor.lnum, newp, FALSE);
1917
1918 ++curwin->w_cursor.lnum;
1919 if (i == 0)
1920 curwin->w_cursor.col += bd.startspaces;
1921 }
1922
1923 changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines);
1924
1925 // Set '[ mark.
1926 curbuf->b_op_start = curwin->w_cursor;
1927 curbuf->b_op_start.lnum = lnum;
1928
1929 // adjust '] mark
1930 curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
1931 curbuf->b_op_end.col = bd.textcol + totlen - 1;
1932 curbuf->b_op_end.coladd = 0;
1933 if (flags & PUT_CURSEND)
1934 {
1935 colnr_T len;
1936
1937 curwin->w_cursor = curbuf->b_op_end;
1938 curwin->w_cursor.col++;
1939
1940 // in Insert mode we might be after the NUL, correct for that
1941 len = (colnr_T)STRLEN(ml_get_curline());
1942 if (curwin->w_cursor.col > len)
1943 curwin->w_cursor.col = len;
1944 }
1945 else
1946 curwin->w_cursor.lnum = lnum;
1947 }
1948 else
1949 {
1950 // Character or Line mode
1951 if (y_type == MCHAR)
1952 {
1953 // if type is MCHAR, FORWARD is the same as BACKWARD on the next
1954 // char
1955 if (dir == FORWARD && gchar_cursor() != NUL)
1956 {
1957 if (has_mbyte)
1958 {
1959 int bytelen = (*mb_ptr2len)(ml_get_cursor());
1960
1961 // put it on the next of the multi-byte character.
1962 col += bytelen;
1963 if (yanklen)
1964 {
1965 curwin->w_cursor.col += bytelen;
1966 curbuf->b_op_end.col += bytelen;
1967 }
1968 }
1969 else
1970 {
1971 ++col;
1972 if (yanklen)
1973 {
1974 ++curwin->w_cursor.col;
1975 ++curbuf->b_op_end.col;
1976 }
1977 }
1978 }
1979 curbuf->b_op_start = curwin->w_cursor;
1980 }
1981 // Line mode: BACKWARD is the same as FORWARD on the previous line
1982 else if (dir == BACKWARD)
1983 --lnum;
1984 new_cursor = curwin->w_cursor;
1985
Bram Moolenaarcd942772020-08-22 21:08:44 +02001986 // simple case: insert into one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001987 if (y_type == MCHAR && y_size == 1)
1988 {
Bram Moolenaarcd942772020-08-22 21:08:44 +02001989 linenr_T end_lnum = 0; // init for gcc
1990 linenr_T start_lnum = lnum;
Bram Moolenaar4d072532021-11-25 19:31:15 +00001991 int first_byte_off = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001992
1993 if (VIsual_active)
1994 {
1995 end_lnum = curbuf->b_visual.vi_end.lnum;
1996 if (end_lnum < curbuf->b_visual.vi_start.lnum)
1997 end_lnum = curbuf->b_visual.vi_start.lnum;
Bram Moolenaarcd942772020-08-22 21:08:44 +02001998 if (end_lnum > start_lnum)
1999 {
2000 pos_T pos;
2001
2002 // "col" is valid for the first line, in following lines
2003 // the virtual column needs to be used. Matters for
2004 // multi-byte characters.
2005 pos.lnum = lnum;
2006 pos.col = col;
2007 pos.coladd = 0;
2008 getvcol(curwin, &pos, NULL, &vcol, NULL);
2009 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002010 }
2011
ichizokfa537222021-11-16 12:50:46 +00002012 if (count == 0 || yanklen == 0)
2013 {
2014 if (VIsual_active)
2015 lnum = end_lnum;
2016 }
2017 else if (count > INT_MAX / yanklen)
2018 // multiplication overflow
2019 emsg(_(e_resulting_text_too_long));
2020 else
2021 {
Bram Moolenaare551ccf2021-11-02 23:11:00 +00002022 totlen = count * yanklen;
ichizokfa537222021-11-16 12:50:46 +00002023 do {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002024 oldp = ml_get(lnum);
ichizokfa537222021-11-16 12:50:46 +00002025 oldlen = (int)STRLEN(oldp);
Bram Moolenaarcd942772020-08-22 21:08:44 +02002026 if (lnum > start_lnum)
2027 {
2028 pos_T pos;
2029
2030 pos.lnum = lnum;
2031 if (getvpos(&pos, vcol) == OK)
2032 col = pos.col;
2033 else
2034 col = MAXCOL;
2035 }
ichizokfa537222021-11-16 12:50:46 +00002036 if (VIsual_active && col > oldlen)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002037 {
2038 lnum++;
2039 continue;
2040 }
ichizokfa537222021-11-16 12:50:46 +00002041 newp = alloc(totlen + oldlen + 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002042 if (newp == NULL)
2043 goto end; // alloc() gave an error message
2044 mch_memmove(newp, oldp, (size_t)col);
2045 ptr = newp + col;
2046 for (i = 0; i < count; ++i)
2047 {
2048 mch_memmove(ptr, y_array[0], (size_t)yanklen);
2049 ptr += yanklen;
2050 }
2051 STRMOVE(ptr, oldp + col);
2052 ml_replace(lnum, newp, FALSE);
Bram Moolenaar4d072532021-11-25 19:31:15 +00002053
2054 // compute the byte offset for the last character
2055 first_byte_off = mb_head_off(newp, ptr - 1);
2056
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002057 // Place cursor on last putted char.
2058 if (lnum == curwin->w_cursor.lnum)
2059 {
2060 // make sure curwin->w_virtcol is updated
2061 changed_cline_bef_curs();
2062 curwin->w_cursor.col += (colnr_T)(totlen - 1);
2063 }
ichizokfa537222021-11-16 12:50:46 +00002064 if (VIsual_active)
2065 lnum++;
2066 } while (VIsual_active && lnum <= end_lnum);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002067
ichizokfa537222021-11-16 12:50:46 +00002068 if (VIsual_active) // reset lnum to the last visual line
2069 lnum--;
2070 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002071
Bram Moolenaar4d072532021-11-25 19:31:15 +00002072 // put '] at the first byte of the last character
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002073 curbuf->b_op_end = curwin->w_cursor;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002074 curbuf->b_op_end.col -= first_byte_off;
2075
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002076 // For "CTRL-O p" in Insert mode, put cursor after last char
2077 if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
2078 ++curwin->w_cursor.col;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002079 else
2080 curwin->w_cursor.col -= first_byte_off;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002081 changed_bytes(lnum, col);
2082 }
2083 else
2084 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002085 linenr_T new_lnum = new_cursor.lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002086 size_t len;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002087
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002088 // Insert at least one line. When y_type is MCHAR, break the first
2089 // line in two.
2090 for (cnt = 1; cnt <= count; ++cnt)
2091 {
2092 i = 0;
2093 if (y_type == MCHAR)
2094 {
2095 // Split the current line in two at the insert position.
2096 // First insert y_array[size - 1] in front of second line.
2097 // Then append y_array[0] to first line.
2098 lnum = new_cursor.lnum;
2099 ptr = ml_get(lnum) + col;
2100 totlen = (int)STRLEN(y_array[y_size - 1]);
2101 newp = alloc(STRLEN(ptr) + totlen + 1);
2102 if (newp == NULL)
2103 goto error;
2104 STRCPY(newp, y_array[y_size - 1]);
2105 STRCAT(newp, ptr);
2106 // insert second line
2107 ml_append(lnum, newp, (colnr_T)0, FALSE);
Bram Moolenaar23003e52021-09-22 16:37:07 +02002108 ++new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002109 vim_free(newp);
2110
2111 oldp = ml_get(lnum);
2112 newp = alloc(col + yanklen + 1);
2113 if (newp == NULL)
2114 goto error;
2115 // copy first part of line
2116 mch_memmove(newp, oldp, (size_t)col);
2117 // append to first line
2118 mch_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
2119 ml_replace(lnum, newp, FALSE);
2120
2121 curwin->w_cursor.lnum = lnum;
2122 i = 1;
2123 }
2124
2125 for (; i < y_size; ++i)
2126 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002127 if (y_type != MCHAR || i < y_size - 1)
2128 {
2129 if (ml_append(lnum, y_array[i], (colnr_T)0, FALSE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002130 == FAIL)
2131 goto error;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002132 new_lnum++;
2133 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002134 lnum++;
2135 ++nr_lines;
2136 if (flags & PUT_FIXINDENT)
2137 {
2138 old_pos = curwin->w_cursor;
2139 curwin->w_cursor.lnum = lnum;
2140 ptr = ml_get(lnum);
2141 if (cnt == count && i == y_size - 1)
2142 lendiff = (int)STRLEN(ptr);
2143#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
2144 if (*ptr == '#' && preprocs_left())
2145 indent = 0; // Leave # lines at start
2146 else
2147#endif
2148 if (*ptr == NUL)
2149 indent = 0; // Ignore empty lines
2150 else if (first_indent)
2151 {
2152 indent_diff = orig_indent - get_indent();
2153 indent = orig_indent;
2154 first_indent = FALSE;
2155 }
2156 else if ((indent = get_indent() + indent_diff) < 0)
2157 indent = 0;
2158 (void)set_indent(indent, 0);
2159 curwin->w_cursor = old_pos;
2160 // remember how many chars were removed
2161 if (cnt == count && i == y_size - 1)
2162 lendiff -= (int)STRLEN(ml_get(lnum));
2163 }
2164 }
Bram Moolenaar23003e52021-09-22 16:37:07 +02002165 if (cnt == 1)
2166 new_lnum = lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002167 }
2168
2169error:
2170 // Adjust marks.
2171 if (y_type == MLINE)
2172 {
2173 curbuf->b_op_start.col = 0;
2174 if (dir == FORWARD)
2175 curbuf->b_op_start.lnum++;
2176 }
2177 // Skip mark_adjust when adding lines after the last one, there
2178 // can't be marks there. But still needed in diff mode.
2179 if (curbuf->b_op_start.lnum + (y_type == MCHAR) - 1 + nr_lines
2180 < curbuf->b_ml.ml_line_count
2181#ifdef FEAT_DIFF
2182 || curwin->w_p_diff
2183#endif
2184 )
2185 mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
2186 (linenr_T)MAXLNUM, nr_lines, 0L);
2187
2188 // note changed text for displaying and folding
2189 if (y_type == MCHAR)
2190 changed_lines(curwin->w_cursor.lnum, col,
2191 curwin->w_cursor.lnum + 1, nr_lines);
2192 else
2193 changed_lines(curbuf->b_op_start.lnum, 0,
2194 curbuf->b_op_start.lnum, nr_lines);
Bram Moolenaar9ac38122021-12-02 18:42:33 +00002195 if (y_current_used != NULL && (y_current_used != y_current
2196 || y_current->y_array != y_array))
2197 {
2198 // Something invoked through changed_lines() has changed the
2199 // yank buffer, e.g. a GUI clipboard callback.
2200 emsg(_(e_yank_register_changed_while_using_it));
2201 goto end;
2202 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002203
Bram Moolenaar4d072532021-11-25 19:31:15 +00002204 // Put the '] mark on the first byte of the last inserted character.
2205 // Correct the length for change in indent.
Bram Moolenaarf47ebf12021-10-19 20:08:45 +01002206 curbuf->b_op_end.lnum = new_lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002207 len = STRLEN(y_array[y_size - 1]);
2208 col = (colnr_T)len - lendiff;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002209 if (col > 1)
Bram Moolenaar4d072532021-11-25 19:31:15 +00002210 curbuf->b_op_end.col = col - 1
2211 - mb_head_off(y_array[y_size - 1],
Bram Moolenaar85be8562021-11-25 20:40:11 +00002212 y_array[y_size - 1] + len - 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002213 else
2214 curbuf->b_op_end.col = 0;
2215
2216 if (flags & PUT_CURSLINE)
2217 {
2218 // ":put": put cursor on last inserted line
2219 curwin->w_cursor.lnum = lnum;
2220 beginline(BL_WHITE | BL_FIX);
2221 }
2222 else if (flags & PUT_CURSEND)
2223 {
2224 // put cursor after inserted text
2225 if (y_type == MLINE)
2226 {
2227 if (lnum >= curbuf->b_ml.ml_line_count)
2228 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
2229 else
2230 curwin->w_cursor.lnum = lnum + 1;
2231 curwin->w_cursor.col = 0;
2232 }
2233 else
2234 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002235 curwin->w_cursor.lnum = new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002236 curwin->w_cursor.col = col;
Bram Moolenaar56858e42021-09-22 16:43:59 +02002237 curbuf->b_op_end = curwin->w_cursor;
2238 if (col > 1)
2239 curbuf->b_op_end.col = col - 1;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002240 }
2241 }
2242 else if (y_type == MLINE)
2243 {
2244 // put cursor on first non-blank in first inserted line
2245 curwin->w_cursor.col = 0;
2246 if (dir == FORWARD)
2247 ++curwin->w_cursor.lnum;
2248 beginline(BL_WHITE | BL_FIX);
2249 }
2250 else // put cursor on first inserted character
2251 curwin->w_cursor = new_cursor;
2252 }
2253 }
2254
2255 msgmore(nr_lines);
2256 curwin->w_set_curswant = TRUE;
2257
2258end:
Bram Moolenaare1004402020-10-24 20:49:43 +02002259 if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01002260 {
2261 curbuf->b_op_start = orig_start;
2262 curbuf->b_op_end = orig_end;
2263 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002264 if (allocated)
2265 vim_free(insert_string);
2266 if (regname == '=')
2267 vim_free(y_array);
2268
2269 VIsual_active = FALSE;
2270
2271 // If the cursor is past the end of the line put it at the end.
2272 adjust_cursor_eol();
2273}
2274
2275/*
2276 * Return the character name of the register with the given number.
2277 */
2278 int
2279get_register_name(int num)
2280{
2281 if (num == -1)
2282 return '"';
2283 else if (num < 10)
2284 return num + '0';
2285 else if (num == DELETION_REGISTER)
2286 return '-';
2287#ifdef FEAT_CLIPBOARD
2288 else if (num == STAR_REGISTER)
2289 return '*';
2290 else if (num == PLUS_REGISTER)
2291 return '+';
2292#endif
2293 else
2294 {
2295#ifdef EBCDIC
2296 int i;
2297
2298 // EBCDIC is really braindead ...
2299 i = 'a' + (num - 10);
2300 if (i > 'i')
2301 i += 7;
2302 if (i > 'r')
2303 i += 8;
2304 return i;
2305#else
2306 return num + 'a' - 10;
2307#endif
2308 }
2309}
2310
2311/*
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002312 * Return the index of the register "" points to.
2313 */
2314 int
2315get_unname_register()
2316{
2317 return y_previous == NULL ? -1 : y_previous - &y_regs[0];
2318}
2319
2320/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002321 * ":dis" and ":registers": Display the contents of the yank registers.
2322 */
2323 void
2324ex_display(exarg_T *eap)
2325{
2326 int i, n;
2327 long j;
2328 char_u *p;
2329 yankreg_T *yb;
2330 int name;
2331 int attr;
2332 char_u *arg = eap->arg;
2333 int clen;
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002334 int type;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002335
2336 if (arg != NULL && *arg == NUL)
2337 arg = NULL;
2338 attr = HL_ATTR(HLF_8);
2339
2340 // Highlight title
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002341 msg_puts_title(_("\nType Name Content"));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002342 for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
2343 {
2344 name = get_register_name(i);
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002345 switch (get_reg_type(name, NULL))
2346 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002347 case MLINE: type = 'l'; break;
2348 case MCHAR: type = 'c'; break;
2349 default: type = 'b'; break;
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002350 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002351 if (arg != NULL && vim_strchr(arg, name) == NULL
2352#ifdef ONE_CLIPBOARD
2353 // Star register and plus register contain the same thing.
2354 && (name != '*' || vim_strchr(arg, '+') == NULL)
2355#endif
2356 )
2357 continue; // did not ask for this register
2358
2359#ifdef FEAT_CLIPBOARD
2360 // Adjust register name for "unnamed" in 'clipboard'.
2361 // When it's a clipboard register, fill it with the current contents
2362 // of the clipboard.
2363 adjust_clip_reg(&name);
2364 (void)may_get_selection(name);
2365#endif
2366
2367 if (i == -1)
2368 {
2369 if (y_previous != NULL)
2370 yb = y_previous;
2371 else
2372 yb = &(y_regs[0]);
2373 }
2374 else
2375 yb = &(y_regs[i]);
2376
2377#ifdef FEAT_EVAL
2378 if (name == MB_TOLOWER(redir_reg)
2379 || (redir_reg == '"' && yb == y_previous))
2380 continue; // do not list register being written to, the
2381 // pointer can be freed
2382#endif
2383
2384 if (yb->y_array != NULL)
2385 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002386 int do_show = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002387
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002388 for (j = 0; !do_show && j < yb->y_size; ++j)
2389 do_show = !message_filtered(yb->y_array[j]);
2390
2391 if (do_show || yb->y_size == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002392 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002393 msg_putchar('\n');
2394 msg_puts(" ");
2395 msg_putchar(type);
2396 msg_puts(" ");
2397 msg_putchar('"');
2398 msg_putchar(name);
2399 msg_puts(" ");
2400
2401 n = (int)Columns - 11;
2402 for (j = 0; j < yb->y_size && n > 1; ++j)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002403 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002404 if (j)
2405 {
2406 msg_puts_attr("^J", attr);
2407 n -= 2;
2408 }
2409 for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0;
2410 ++p)
2411 {
2412 clen = (*mb_ptr2len)(p);
2413 msg_outtrans_len(p, clen);
2414 p += clen - 1;
2415 }
2416 }
2417 if (n > 1 && yb->y_type == MLINE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002418 msg_puts_attr("^J", attr);
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002419 out_flush(); // show one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002420 }
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002421 ui_breakcheck();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002422 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002423 }
2424
2425 // display last inserted text
2426 if ((p = get_last_insert()) != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002427 && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
2428 && !message_filtered(p))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002429 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002430 msg_puts("\n c \". ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002431 dis_msg(p, TRUE);
2432 }
2433
2434 // display last command line
2435 if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002436 && !got_int && !message_filtered(last_cmdline))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002437 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002438 msg_puts("\n c \": ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002439 dis_msg(last_cmdline, FALSE);
2440 }
2441
2442 // display current file name
2443 if (curbuf->b_fname != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002444 && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int
2445 && !message_filtered(curbuf->b_fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002446 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002447 msg_puts("\n c \"% ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002448 dis_msg(curbuf->b_fname, FALSE);
2449 }
2450
2451 // display alternate file name
2452 if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
2453 {
2454 char_u *fname;
2455 linenr_T dummy;
2456
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002457 if (buflist_name_nr(0, &fname, &dummy) != FAIL
2458 && !message_filtered(fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002459 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002460 msg_puts("\n c \"# ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002461 dis_msg(fname, FALSE);
2462 }
2463 }
2464
2465 // display last search pattern
2466 if (last_search_pat() != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002467 && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int
2468 && !message_filtered(last_search_pat()))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002469 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002470 msg_puts("\n c \"/ ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002471 dis_msg(last_search_pat(), FALSE);
2472 }
2473
2474#ifdef FEAT_EVAL
2475 // display last used expression
2476 if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002477 && !got_int && !message_filtered(expr_line))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002478 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002479 msg_puts("\n c \"= ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002480 dis_msg(expr_line, FALSE);
2481 }
2482#endif
2483}
2484
2485/*
2486 * display a string for do_dis()
2487 * truncate at end of screen line
2488 */
2489 static void
2490dis_msg(
2491 char_u *p,
2492 int skip_esc) // if TRUE, ignore trailing ESC
2493{
2494 int n;
2495 int l;
2496
2497 n = (int)Columns - 6;
2498 while (*p != NUL
2499 && !(*p == ESC && skip_esc && *(p + 1) == NUL)
2500 && (n -= ptr2cells(p)) >= 0)
2501 {
2502 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
2503 {
2504 msg_outtrans_len(p, l);
2505 p += l;
2506 }
2507 else
2508 msg_outtrans_len(p++, 1);
2509 }
2510 ui_breakcheck();
2511}
2512
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002513#if defined(FEAT_DND) || defined(PROTO)
2514/*
2515 * Replace the contents of the '~' register with str.
2516 */
2517 void
2518dnd_yank_drag_data(char_u *str, long len)
2519{
2520 yankreg_T *curr;
2521
2522 curr = y_current;
2523 y_current = &y_regs[TILDE_REGISTER];
2524 free_yank_all();
2525 str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
2526 y_current = curr;
2527}
2528#endif
2529
2530
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002531/*
2532 * Return the type of a register.
2533 * Used for getregtype()
2534 * Returns MAUTO for error.
2535 */
2536 char_u
2537get_reg_type(int regname, long *reglen)
2538{
2539 switch (regname)
2540 {
2541 case '%': // file name
2542 case '#': // alternate file name
2543 case '=': // expression
2544 case ':': // last command line
2545 case '/': // last search-pattern
2546 case '.': // last inserted text
2547# ifdef FEAT_SEARCHPATH
2548 case Ctrl_F: // Filename under cursor
2549 case Ctrl_P: // Path under cursor, expand via "path"
2550# endif
2551 case Ctrl_W: // word under cursor
2552 case Ctrl_A: // WORD (mnemonic All) under cursor
2553 case '_': // black hole: always empty
2554 return MCHAR;
2555 }
2556
2557# ifdef FEAT_CLIPBOARD
2558 regname = may_get_selection(regname);
2559# endif
2560
2561 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2562 return MAUTO;
2563
2564 get_yank_register(regname, FALSE);
2565
2566 if (y_current->y_array != NULL)
2567 {
2568 if (reglen != NULL && y_current->y_type == MBLOCK)
2569 *reglen = y_current->y_width;
2570 return y_current->y_type;
2571 }
2572 return MAUTO;
2573}
2574
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002575#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002576/*
2577 * When "flags" has GREG_LIST return a list with text "s".
2578 * Otherwise just return "s".
2579 */
2580 static char_u *
2581getreg_wrap_one_line(char_u *s, int flags)
2582{
2583 if (flags & GREG_LIST)
2584 {
2585 list_T *list = list_alloc();
2586
2587 if (list != NULL)
2588 {
2589 if (list_append_string(list, NULL, -1) == FAIL)
2590 {
2591 list_free(list);
2592 return NULL;
2593 }
2594 list->lv_first->li_tv.vval.v_string = s;
2595 }
2596 return (char_u *)list;
2597 }
2598 return s;
2599}
2600
2601/*
Bram Moolenaard672dde2020-02-26 13:43:51 +01002602 * Return the contents of a register as a single allocated string or as a list.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002603 * Used for "@r" in expressions and for getreg().
2604 * Returns NULL for error.
2605 * Flags:
2606 * GREG_NO_EXPR Do not allow expression register
2607 * GREG_EXPR_SRC For the expression register: return expression itself,
2608 * not the result of its evaluation.
Bram Moolenaard672dde2020-02-26 13:43:51 +01002609 * GREG_LIST Return a list of lines instead of a single string.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002610 */
2611 char_u *
2612get_reg_contents(int regname, int flags)
2613{
2614 long i;
2615 char_u *retval;
2616 int allocated;
2617 long len;
2618
2619 // Don't allow using an expression register inside an expression
2620 if (regname == '=')
2621 {
2622 if (flags & GREG_NO_EXPR)
2623 return NULL;
2624 if (flags & GREG_EXPR_SRC)
2625 return getreg_wrap_one_line(get_expr_line_src(), flags);
2626 return getreg_wrap_one_line(get_expr_line(), flags);
2627 }
2628
2629 if (regname == '@') // "@@" is used for unnamed register
2630 regname = '"';
2631
2632 // check for valid regname
2633 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2634 return NULL;
2635
2636# ifdef FEAT_CLIPBOARD
2637 regname = may_get_selection(regname);
2638# endif
2639
2640 if (get_spec_reg(regname, &retval, &allocated, FALSE))
2641 {
2642 if (retval == NULL)
2643 return NULL;
2644 if (allocated)
2645 return getreg_wrap_one_line(retval, flags);
2646 return getreg_wrap_one_line(vim_strsave(retval), flags);
2647 }
2648
2649 get_yank_register(regname, FALSE);
2650 if (y_current->y_array == NULL)
2651 return NULL;
2652
2653 if (flags & GREG_LIST)
2654 {
2655 list_T *list = list_alloc();
2656 int error = FALSE;
2657
2658 if (list == NULL)
2659 return NULL;
2660 for (i = 0; i < y_current->y_size; ++i)
2661 if (list_append_string(list, y_current->y_array[i], -1) == FAIL)
2662 error = TRUE;
2663 if (error)
2664 {
2665 list_free(list);
2666 return NULL;
2667 }
2668 return (char_u *)list;
2669 }
2670
2671 // Compute length of resulting string.
2672 len = 0;
2673 for (i = 0; i < y_current->y_size; ++i)
2674 {
2675 len += (long)STRLEN(y_current->y_array[i]);
2676 // Insert a newline between lines and after last line if
2677 // y_type is MLINE.
2678 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2679 ++len;
2680 }
2681
2682 retval = alloc(len + 1);
2683
2684 // Copy the lines of the yank register into the string.
2685 if (retval != NULL)
2686 {
2687 len = 0;
2688 for (i = 0; i < y_current->y_size; ++i)
2689 {
2690 STRCPY(retval + len, y_current->y_array[i]);
2691 len += (long)STRLEN(retval + len);
2692
2693 // Insert a NL between lines and after the last line if y_type is
2694 // MLINE.
2695 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2696 retval[len++] = '\n';
2697 }
2698 retval[len] = NUL;
2699 }
2700
2701 return retval;
2702}
2703
2704 static int
2705init_write_reg(
2706 int name,
2707 yankreg_T **old_y_previous,
2708 yankreg_T **old_y_current,
2709 int must_append,
2710 int *yank_type UNUSED)
2711{
2712 if (!valid_yank_reg(name, TRUE)) // check for valid reg name
2713 {
2714 emsg_invreg(name);
2715 return FAIL;
2716 }
2717
2718 // Don't want to change the current (unnamed) register
2719 *old_y_previous = y_previous;
2720 *old_y_current = y_current;
2721
2722 get_yank_register(name, TRUE);
2723 if (!y_append && !must_append)
2724 free_yank_all();
2725 return OK;
2726}
2727
2728 static void
2729finish_write_reg(
2730 int name,
2731 yankreg_T *old_y_previous,
2732 yankreg_T *old_y_current)
2733{
2734# ifdef FEAT_CLIPBOARD
2735 // Send text of clipboard register to the clipboard.
2736 may_set_selection();
2737# endif
2738
2739 // ':let @" = "val"' should change the meaning of the "" register
2740 if (name != '"')
2741 y_previous = old_y_previous;
2742 y_current = old_y_current;
2743}
2744
2745/*
2746 * Store string "str" in register "name".
2747 * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
2748 * If "must_append" is TRUE, always append to the register. Otherwise append
2749 * if "name" is an uppercase letter.
2750 * Note: "maxlen" and "must_append" don't work for the "/" register.
2751 * Careful: 'str' is modified, you may have to use a copy!
2752 * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise.
2753 */
2754 void
2755write_reg_contents(
2756 int name,
2757 char_u *str,
2758 int maxlen,
2759 int must_append)
2760{
2761 write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
2762}
2763
2764 void
2765write_reg_contents_lst(
2766 int name,
2767 char_u **strings,
2768 int maxlen UNUSED,
2769 int must_append,
2770 int yank_type,
2771 long block_len)
2772{
2773 yankreg_T *old_y_previous, *old_y_current;
2774
2775 if (name == '/' || name == '=')
2776 {
2777 char_u *s;
2778
2779 if (strings[0] == NULL)
2780 s = (char_u *)"";
2781 else if (strings[1] != NULL)
2782 {
2783 emsg(_("E883: search pattern and expression register may not "
2784 "contain two or more lines"));
2785 return;
2786 }
2787 else
2788 s = strings[0];
2789 write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
2790 return;
2791 }
2792
2793 if (name == '_') // black hole: nothing to do
2794 return;
2795
2796 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2797 &yank_type) == FAIL)
2798 return;
2799
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02002800 str_to_reg(y_current, yank_type, (char_u *)strings, -1, block_len, TRUE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002801
2802 finish_write_reg(name, old_y_previous, old_y_current);
2803}
2804
2805 void
2806write_reg_contents_ex(
2807 int name,
2808 char_u *str,
2809 int maxlen,
2810 int must_append,
2811 int yank_type,
2812 long block_len)
2813{
2814 yankreg_T *old_y_previous, *old_y_current;
2815 long len;
2816
2817 if (maxlen >= 0)
2818 len = maxlen;
2819 else
2820 len = (long)STRLEN(str);
2821
2822 // Special case: '/' search pattern
2823 if (name == '/')
2824 {
2825 set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
2826 return;
2827 }
2828
2829 if (name == '#')
2830 {
2831 buf_T *buf;
2832
2833 if (VIM_ISDIGIT(*str))
2834 {
2835 int num = atoi((char *)str);
2836
2837 buf = buflist_findnr(num);
2838 if (buf == NULL)
Bram Moolenaar40bcec12021-12-05 22:19:27 +00002839 semsg(_(e_buffer_nr_does_not_exist), (long)num);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002840 }
2841 else
2842 buf = buflist_findnr(buflist_findpat(str, str + STRLEN(str),
2843 TRUE, FALSE, FALSE));
2844 if (buf == NULL)
2845 return;
2846 curwin->w_alt_fnum = buf->b_fnum;
2847 return;
2848 }
2849
2850 if (name == '=')
2851 {
2852 char_u *p, *s;
2853
Bram Moolenaar71ccd032020-06-12 22:59:11 +02002854 p = vim_strnsave(str, len);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002855 if (p == NULL)
2856 return;
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002857 if (must_append && expr_line != NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002858 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002859 s = concat_str(expr_line, p);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002860 vim_free(p);
2861 p = s;
2862 }
Bram Moolenaarb4bcea42020-10-28 13:53:50 +01002863 set_expr_line(p, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002864 return;
2865 }
2866
2867 if (name == '_') // black hole: nothing to do
2868 return;
2869
2870 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2871 &yank_type) == FAIL)
2872 return;
2873
2874 str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
2875
2876 finish_write_reg(name, old_y_previous, old_y_current);
2877}
2878#endif // FEAT_EVAL
2879
2880#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
2881/*
2882 * Put a string into a register. When the register is not empty, the string
2883 * is appended.
2884 */
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01002885 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002886str_to_reg(
2887 yankreg_T *y_ptr, // pointer to yank register
2888 int yank_type, // MCHAR, MLINE, MBLOCK, MAUTO
2889 char_u *str, // string to put in register
2890 long len, // length of string
2891 long blocklen, // width of Visual block
2892 int str_list) // TRUE if str is char_u **
2893{
2894 int type; // MCHAR, MLINE or MBLOCK
2895 int lnum;
2896 long start;
2897 long i;
2898 int extra;
2899 int newlines; // number of lines added
2900 int extraline = 0; // extra line at the end
2901 int append = FALSE; // append to last line in register
2902 char_u *s;
2903 char_u **ss;
2904 char_u **pp;
2905 long maxlen;
2906
2907 if (y_ptr->y_array == NULL) // NULL means empty register
2908 y_ptr->y_size = 0;
2909
2910 if (yank_type == MAUTO)
2911 type = ((str_list || (len > 0 && (str[len - 1] == NL
2912 || str[len - 1] == CAR)))
2913 ? MLINE : MCHAR);
2914 else
2915 type = yank_type;
2916
2917 // Count the number of lines within the string
2918 newlines = 0;
2919 if (str_list)
2920 {
2921 for (ss = (char_u **) str; *ss != NULL; ++ss)
2922 ++newlines;
2923 }
2924 else
2925 {
2926 for (i = 0; i < len; i++)
2927 if (str[i] == '\n')
2928 ++newlines;
2929 if (type == MCHAR || len == 0 || str[len - 1] != '\n')
2930 {
2931 extraline = 1;
2932 ++newlines; // count extra newline at the end
2933 }
2934 if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR)
2935 {
2936 append = TRUE;
2937 --newlines; // uncount newline when appending first line
2938 }
2939 }
2940
2941 // Without any lines make the register empty.
2942 if (y_ptr->y_size + newlines == 0)
2943 {
2944 VIM_CLEAR(y_ptr->y_array);
2945 return;
2946 }
2947
2948 // Allocate an array to hold the pointers to the new register lines.
2949 // If the register was not empty, move the existing lines to the new array.
2950 pp = lalloc_clear((y_ptr->y_size + newlines) * sizeof(char_u *), TRUE);
2951 if (pp == NULL) // out of memory
2952 return;
2953 for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
2954 pp[lnum] = y_ptr->y_array[lnum];
2955 vim_free(y_ptr->y_array);
2956 y_ptr->y_array = pp;
2957 maxlen = 0;
2958
2959 // Find the end of each line and save it into the array.
2960 if (str_list)
2961 {
2962 for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
2963 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002964 pp[lnum] = vim_strsave(*ss);
2965 if (type == MBLOCK)
2966 {
2967 int charlen = mb_string2cells(*ss, -1);
2968
2969 if (charlen > maxlen)
2970 maxlen = charlen;
2971 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002972 }
2973 }
2974 else
2975 {
2976 for (start = 0; start < len + extraline; start += i + 1)
2977 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002978 int charlen = 0;
2979
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002980 for (i = start; i < len; ++i) // find the end of the line
Bram Moolenaar24951a62021-06-04 18:33:49 +02002981 {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002982 if (str[i] == '\n')
2983 break;
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002984 if (type == MBLOCK)
2985 charlen += mb_ptr2cells_len(str + i, len - i);
Bram Moolenaar24951a62021-06-04 18:33:49 +02002986 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002987 i -= start; // i is now length of line
Bram Moolenaar6e0b5532021-06-04 17:11:47 +02002988 if (charlen > maxlen)
2989 maxlen = charlen;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002990 if (append)
2991 {
2992 --lnum;
2993 extra = (int)STRLEN(y_ptr->y_array[lnum]);
2994 }
2995 else
2996 extra = 0;
2997 s = alloc(i + extra + 1);
2998 if (s == NULL)
2999 break;
3000 if (extra)
3001 mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
3002 if (append)
3003 vim_free(y_ptr->y_array[lnum]);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003004 if (i > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003005 mch_memmove(s + extra, str + start, (size_t)i);
3006 extra += i;
3007 s[extra] = NUL;
3008 y_ptr->y_array[lnum++] = s;
3009 while (--extra >= 0)
3010 {
3011 if (*s == NUL)
3012 *s = '\n'; // replace NUL with newline
3013 ++s;
3014 }
3015 append = FALSE; // only first line is appended
3016 }
3017 }
3018 y_ptr->y_type = type;
3019 y_ptr->y_size = lnum;
3020 if (type == MBLOCK)
3021 y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
3022 else
3023 y_ptr->y_width = 0;
3024# ifdef FEAT_VIMINFO
3025 y_ptr->y_time_set = vim_time();
3026# endif
3027}
3028#endif // FEAT_CLIPBOARD || FEAT_EVAL || PROTO