blob: ac1d6a3a52f69f78b1af6f500798925de09a1d35 [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;
374 yankreg_T *old_y_previous, *old_y_current;
375 int retval;
376
377 if (reg_recording == 0) // start recording
378 {
379 // registers 0-9, a-z and " are allowed
380 if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
381 retval = FAIL;
382 else
383 {
384 reg_recording = c;
385 showmode();
386 regname = c;
387 retval = OK;
388 }
389 }
390 else // stop recording
391 {
392 // Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
393 // needs to be removed again to put it in a register. exec_reg then
394 // adds the escaping back later.
395 reg_recording = 0;
396 msg("");
397 p = get_recorded();
398 if (p == NULL)
399 retval = FAIL;
400 else
401 {
402 // Remove escaping for CSI and K_SPECIAL in multi-byte chars.
403 vim_unescape_csi(p);
404
405 // We don't want to change the default register here, so save and
406 // restore the current register name.
407 old_y_previous = y_previous;
408 old_y_current = y_current;
409
410 retval = stuff_yank(regname, p);
411
412 y_previous = old_y_previous;
413 y_current = old_y_current;
414 }
415 }
416 return retval;
417}
418
419/*
420 * Stuff string "p" into yank register "regname" as a single line (append if
421 * uppercase). "p" must have been alloced.
422 *
423 * return FAIL for failure, OK otherwise
424 */
425 static int
426stuff_yank(int regname, char_u *p)
427{
428 char_u *lp;
429 char_u **pp;
430
431 // check for read-only register
432 if (regname != 0 && !valid_yank_reg(regname, TRUE))
433 {
434 vim_free(p);
435 return FAIL;
436 }
437 if (regname == '_') // black hole: don't do anything
438 {
439 vim_free(p);
440 return OK;
441 }
442 get_yank_register(regname, TRUE);
443 if (y_append && y_current->y_array != NULL)
444 {
445 pp = &(y_current->y_array[y_current->y_size - 1]);
446 lp = alloc(STRLEN(*pp) + STRLEN(p) + 1);
447 if (lp == NULL)
448 {
449 vim_free(p);
450 return FAIL;
451 }
452 STRCPY(lp, *pp);
453 STRCAT(lp, p);
454 vim_free(p);
455 vim_free(*pp);
456 *pp = lp;
457 }
458 else
459 {
460 free_yank_all();
461 if ((y_current->y_array = ALLOC_ONE(char_u *)) == NULL)
462 {
463 vim_free(p);
464 return FAIL;
465 }
466 y_current->y_array[0] = p;
467 y_current->y_size = 1;
468 y_current->y_type = MCHAR; // used to be MLINE, why?
469#ifdef FEAT_VIMINFO
470 y_current->y_time_set = vim_time();
471#endif
472 }
473 return OK;
474}
475
Yegappan Lakshmanan41a7f822021-06-16 15:53:17 +0200476/*
477 * Last executed register (@ command)
478 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200479static int execreg_lastc = NUL;
480
Dominique Pelle748b3082022-01-08 12:41:16 +0000481#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200482 int
483get_execreg_lastc(void)
484{
485 return execreg_lastc;
486}
487
488 void
489set_execreg_lastc(int lastc)
490{
491 execreg_lastc = lastc;
492}
Dominique Pelle748b3082022-01-08 12:41:16 +0000493#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200494
495/*
Bram Moolenaar856c1112020-06-17 21:47:23 +0200496 * When executing a register as a series of ex-commands, if the
497 * line-continuation character is used for a line, then join it with one or
498 * more previous lines. Note that lines are processed backwards starting from
499 * the last line in the register.
500 *
501 * Arguments:
502 * lines - list of lines in the register
503 * idx - index of the line starting with \ or "\. Join this line with all the
504 * immediate predecessor lines that start with a \ and the first line
505 * that doesn't start with a \. Lines that start with a comment "\
506 * character are ignored.
507 *
508 * Returns the concatenated line. The index of the line that should be
509 * processed next is returned in idx.
510 */
511 static char_u *
512execreg_line_continuation(char_u **lines, long *idx)
513{
514 garray_T ga;
515 long i = *idx;
516 char_u *p;
517 int cmd_start;
518 int cmd_end = i;
519 int j;
520 char_u *str;
521
Bram Moolenaar04935fb2022-01-08 16:19:22 +0000522 ga_init2(&ga, sizeof(char_u), 400);
Bram Moolenaar856c1112020-06-17 21:47:23 +0200523
524 // search backwards to find the first line of this command.
525 // Any line not starting with \ or "\ is the start of the
526 // command.
527 while (--i > 0)
528 {
529 p = skipwhite(lines[i]);
530 if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' '))
531 break;
532 }
533 cmd_start = i;
534
535 // join all the lines
536 ga_concat(&ga, lines[cmd_start]);
537 for (j = cmd_start + 1; j <= cmd_end; j++)
538 {
539 p = skipwhite(lines[j]);
540 if (*p == '\\')
541 {
542 // Adjust the growsize to the current length to
543 // speed up concatenating many lines.
544 if (ga.ga_len > 400)
545 {
546 if (ga.ga_len > 8000)
547 ga.ga_growsize = 8000;
548 else
549 ga.ga_growsize = ga.ga_len;
550 }
551 ga_concat(&ga, p + 1);
552 }
553 }
554 ga_append(&ga, NUL);
555 str = vim_strsave(ga.ga_data);
556 ga_clear(&ga);
557
558 *idx = i;
559 return str;
560}
561
562/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200563 * Execute a yank register: copy it into the stuff buffer.
564 *
565 * Return FAIL for failure, OK otherwise.
566 */
567 int
568do_execreg(
569 int regname,
570 int colon, // insert ':' before each line
571 int addcr, // always add '\n' to end of line
572 int silent) // set "silent" flag in typeahead buffer
573{
574 long i;
575 char_u *p;
576 int retval = OK;
577 int remap;
578
579 // repeat previous one
580 if (regname == '@')
581 {
582 if (execreg_lastc == NUL)
583 {
Bram Moolenaar677658a2022-01-05 16:09:06 +0000584 emsg(_(e_no_previously_used_register));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200585 return FAIL;
586 }
587 regname = execreg_lastc;
588 }
589 // check for valid regname
590 if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
591 {
592 emsg_invreg(regname);
593 return FAIL;
594 }
595 execreg_lastc = regname;
596
597#ifdef FEAT_CLIPBOARD
598 regname = may_get_selection(regname);
599#endif
600
601 // black hole: don't stuff anything
602 if (regname == '_')
603 return OK;
604
605 // use last command line
606 if (regname == ':')
607 {
608 if (last_cmdline == NULL)
609 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200610 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200611 return FAIL;
612 }
613 // don't keep the cmdline containing @:
614 VIM_CLEAR(new_last_cmdline);
615 // Escape all control characters with a CTRL-V
616 p = vim_strsave_escaped_ext(last_cmdline,
617 (char_u *)"\001\002\003\004\005\006\007"
618 "\010\011\012\013\014\015\016\017"
619 "\020\021\022\023\024\025\026\027"
620 "\030\031\032\033\034\035\036\037",
621 Ctrl_V, FALSE);
622 if (p != NULL)
623 {
624 // When in Visual mode "'<,'>" will be prepended to the command.
625 // Remove it when it's already there.
626 if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0)
627 retval = put_in_typebuf(p + 5, TRUE, TRUE, silent);
628 else
629 retval = put_in_typebuf(p, TRUE, TRUE, silent);
630 }
631 vim_free(p);
632 }
633#ifdef FEAT_EVAL
634 else if (regname == '=')
635 {
636 p = get_expr_line();
637 if (p == NULL)
638 return FAIL;
639 retval = put_in_typebuf(p, TRUE, colon, silent);
640 vim_free(p);
641 }
642#endif
643 else if (regname == '.') // use last inserted text
644 {
645 p = get_last_insert_save();
646 if (p == NULL)
647 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200648 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200649 return FAIL;
650 }
651 retval = put_in_typebuf(p, FALSE, colon, silent);
652 vim_free(p);
653 }
654 else
655 {
656 get_yank_register(regname, FALSE);
657 if (y_current->y_array == NULL)
658 return FAIL;
659
Bram Moolenaar4b96df52020-01-26 22:00:26 +0100660 // Disallow remapping for ":@r".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200661 remap = colon ? REMAP_NONE : REMAP_YES;
662
663 // Insert lines into typeahead buffer, from last one to first one.
664 put_reedit_in_typebuf(silent);
665 for (i = y_current->y_size; --i >= 0; )
666 {
667 char_u *escaped;
Bram Moolenaar856c1112020-06-17 21:47:23 +0200668 char_u *str;
669 int free_str = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200670
671 // insert NL between lines and after last line if type is MLINE
672 if (y_current->y_type == MLINE || i < y_current->y_size - 1
673 || addcr)
674 {
675 if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
676 return FAIL;
677 }
Bram Moolenaar856c1112020-06-17 21:47:23 +0200678
679 // Handle line-continuation for :@<register>
680 str = y_current->y_array[i];
681 if (colon && i > 0)
682 {
683 p = skipwhite(str);
684 if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))
685 {
686 str = execreg_line_continuation(y_current->y_array, &i);
687 if (str == NULL)
688 return FAIL;
689 free_str = TRUE;
690 }
691 }
692 escaped = vim_strsave_escape_csi(str);
693 if (free_str)
694 vim_free(str);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200695 if (escaped == NULL)
696 return FAIL;
697 retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
698 vim_free(escaped);
699 if (retval == FAIL)
700 return FAIL;
701 if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
702 == FAIL)
703 return FAIL;
704 }
705 reg_executing = regname == 0 ? '"' : regname; // disable "q" command
706 }
707 return retval;
708}
709
710/*
711 * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
712 * used only after other typeahead has been processed.
713 */
714 static void
715put_reedit_in_typebuf(int silent)
716{
717 char_u buf[3];
718
719 if (restart_edit != NUL)
720 {
721 if (restart_edit == 'V')
722 {
723 buf[0] = 'g';
724 buf[1] = 'R';
725 buf[2] = NUL;
726 }
727 else
728 {
729 buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
730 buf[1] = NUL;
731 }
732 if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
733 restart_edit = NUL;
734 }
735}
736
737/*
738 * Insert register contents "s" into the typeahead buffer, so that it will be
739 * executed again.
740 * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
741 * no remapping.
742 */
743 static int
744put_in_typebuf(
745 char_u *s,
746 int esc,
747 int colon, // add ':' before the line
748 int silent)
749{
750 int retval = OK;
751
752 put_reedit_in_typebuf(silent);
753 if (colon)
754 retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
755 if (retval == OK)
756 {
757 char_u *p;
758
759 if (esc)
760 p = vim_strsave_escape_csi(s);
761 else
762 p = s;
763 if (p == NULL)
764 retval = FAIL;
765 else
766 retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
767 0, TRUE, silent);
768 if (esc)
769 vim_free(p);
770 }
771 if (colon && retval == OK)
772 retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
773 return retval;
774}
775
776/*
777 * Insert a yank register: copy it into the Read buffer.
778 * Used by CTRL-R command and middle mouse button in insert mode.
779 *
780 * return FAIL for failure, OK otherwise
781 */
782 int
783insert_reg(
784 int regname,
785 int literally_arg) // insert literally, not as if typed
786{
787 long i;
788 int retval = OK;
789 char_u *arg;
790 int allocated;
791 int literally = literally_arg;
792
793 // It is possible to get into an endless loop by having CTRL-R a in
794 // register a and then, in insert mode, doing CTRL-R a.
795 // If you hit CTRL-C, the loop will be broken here.
796 ui_breakcheck();
797 if (got_int)
798 return FAIL;
799
800 // check for valid regname
801 if (regname != NUL && !valid_yank_reg(regname, FALSE))
802 return FAIL;
803
804#ifdef FEAT_CLIPBOARD
805 regname = may_get_selection(regname);
806#endif
807
808 if (regname == '.') // insert last inserted text
809 retval = stuff_inserted(NUL, 1L, TRUE);
810 else if (get_spec_reg(regname, &arg, &allocated, TRUE))
811 {
812 if (arg == NULL)
813 return FAIL;
814 stuffescaped(arg, literally);
815 if (allocated)
816 vim_free(arg);
817 }
818 else // name or number register
819 {
820 if (get_yank_register(regname, FALSE))
821 literally = TRUE;
822 if (y_current->y_array == NULL)
823 retval = FAIL;
824 else
825 {
826 for (i = 0; i < y_current->y_size; ++i)
827 {
Bram Moolenaar032a2d02020-12-22 17:59:35 +0100828 if (regname == '-')
829 {
830 AppendCharToRedobuff(Ctrl_R);
831 AppendCharToRedobuff(regname);
832 do_put(regname, NULL, BACKWARD, 1L, PUT_CURSEND);
833 }
834 else
835 stuffescaped(y_current->y_array[i], literally);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200836 // Insert a newline between lines and after last line if
837 // y_type is MLINE.
838 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
839 stuffcharReadbuff('\n');
840 }
841 }
842 }
843
844 return retval;
845}
846
847/*
848 * If "regname" is a special register, return TRUE and store a pointer to its
849 * value in "argp".
850 */
851 int
852get_spec_reg(
853 int regname,
854 char_u **argp,
855 int *allocated, // return: TRUE when value was allocated
856 int errmsg) // give error message when failing
857{
858 int cnt;
859
860 *argp = NULL;
861 *allocated = FALSE;
862 switch (regname)
863 {
864 case '%': // file name
865 if (errmsg)
866 check_fname(); // will give emsg if not set
867 *argp = curbuf->b_fname;
868 return TRUE;
869
870 case '#': // alternate file name
871 *argp = getaltfname(errmsg); // may give emsg if not set
872 return TRUE;
873
874#ifdef FEAT_EVAL
875 case '=': // result of expression
876 *argp = get_expr_line();
877 *allocated = TRUE;
878 return TRUE;
879#endif
880
881 case ':': // last command line
882 if (last_cmdline == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200883 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200884 *argp = last_cmdline;
885 return TRUE;
886
887 case '/': // last search-pattern
888 if (last_search_pat() == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200889 emsg(_(e_no_previous_regular_expression));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200890 *argp = last_search_pat();
891 return TRUE;
892
893 case '.': // last inserted text
894 *argp = get_last_insert_save();
895 *allocated = TRUE;
896 if (*argp == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200897 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200898 return TRUE;
899
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200900 case Ctrl_F: // Filename under cursor
901 case Ctrl_P: // Path under cursor, expand via "path"
902 if (!errmsg)
903 return FALSE;
904 *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP
905 | (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL);
906 *allocated = TRUE;
907 return TRUE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200908
909 case Ctrl_W: // word under cursor
910 case Ctrl_A: // WORD (mnemonic All) under cursor
911 if (!errmsg)
912 return FALSE;
913 cnt = find_ident_under_cursor(argp, regname == Ctrl_W
914 ? (FIND_IDENT|FIND_STRING) : FIND_STRING);
915 *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
916 *allocated = TRUE;
917 return TRUE;
918
919 case Ctrl_L: // Line under cursor
920 if (!errmsg)
921 return FALSE;
922
923 *argp = ml_get_buf(curwin->w_buffer,
924 curwin->w_cursor.lnum, FALSE);
925 return TRUE;
926
927 case '_': // black hole: always empty
928 *argp = (char_u *)"";
929 return TRUE;
930 }
931
932 return FALSE;
933}
934
935/*
936 * Paste a yank register into the command line.
937 * Only for non-special registers.
938 * Used by CTRL-R command in command-line mode
939 * insert_reg() can't be used here, because special characters from the
940 * register contents will be interpreted as commands.
941 *
942 * return FAIL for failure, OK otherwise
943 */
944 int
945cmdline_paste_reg(
946 int regname,
947 int literally_arg, // Insert text literally instead of "as typed"
948 int remcr) // don't add CR characters
949{
950 long i;
951 int literally = literally_arg;
952
953 if (get_yank_register(regname, FALSE))
954 literally = TRUE;
955 if (y_current->y_array == NULL)
956 return FAIL;
957
958 for (i = 0; i < y_current->y_size; ++i)
959 {
960 cmdline_paste_str(y_current->y_array[i], literally);
961
962 // Insert ^M between lines and after last line if type is MLINE.
963 // Don't do this when "remcr" is TRUE.
964 if ((y_current->y_type == MLINE || i < y_current->y_size - 1) && !remcr)
965 cmdline_paste_str((char_u *)"\r", literally);
966
967 // Check for CTRL-C, in case someone tries to paste a few thousand
968 // lines and gets bored.
969 ui_breakcheck();
970 if (got_int)
971 return FAIL;
972 }
973 return OK;
974}
975
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200976/*
977 * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
978 */
979 void
980shift_delete_registers()
981{
982 int n;
983
984 y_current = &y_regs[9];
985 free_yank_all(); // free register nine
986 for (n = 9; n > 1; --n)
987 y_regs[n] = y_regs[n - 1];
988 y_current = &y_regs[1];
989 if (!y_append)
990 y_previous = y_current;
991 y_regs[1].y_array = NULL; // set register one to empty
992}
993
994#if defined(FEAT_EVAL)
995 void
996yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
997{
Bram Moolenaar3075a452021-11-17 15:51:52 +0000998 static int recursive = FALSE;
999 dict_T *v_event;
1000 list_T *list;
1001 int n;
1002 char_u buf[NUMBUFLEN + 2];
1003 long reglen = 0;
1004 save_v_event_T save_v_event;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001005
1006 if (recursive)
1007 return;
1008
Bram Moolenaar3075a452021-11-17 15:51:52 +00001009 v_event = get_v_event(&save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001010
1011 list = list_alloc();
1012 if (list == NULL)
1013 return;
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001014
1015 // yanked text contents
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001016 for (n = 0; n < reg->y_size; n++)
1017 list_append_string(list, reg->y_array[n], -1);
1018 list->lv_lock = VAR_FIXED;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001019 (void)dict_add_list(v_event, "regcontents", list);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001020
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001021 // register name or empty string for unnamed operation
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001022 buf[0] = (char_u)oap->regname;
1023 buf[1] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001024 (void)dict_add_string(v_event, "regname", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001025
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001026 // motion type: inclusive or exclusive
1027 (void)dict_add_bool(v_event, "inclusive", oap->inclusive);
1028
1029 // kind of operation (yank, delete, change)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001030 buf[0] = get_op_char(oap->op_type);
1031 buf[1] = get_extra_op_char(oap->op_type);
1032 buf[2] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001033 (void)dict_add_string(v_event, "operator", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001034
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001035 // register type
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001036 buf[0] = NUL;
1037 buf[1] = NUL;
1038 switch (get_reg_type(oap->regname, &reglen))
1039 {
1040 case MLINE: buf[0] = 'V'; break;
1041 case MCHAR: buf[0] = 'v'; break;
1042 case MBLOCK:
1043 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
1044 reglen + 1);
1045 break;
1046 }
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001047 (void)dict_add_string(v_event, "regtype", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001048
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001049 // selection type - visual or not
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001050 (void)dict_add_bool(v_event, "visual", oap->is_VIsual);
Bram Moolenaar37d16732020-06-12 22:09:01 +02001051
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001052 // Lock the dictionary and its keys
1053 dict_set_items_ro(v_event);
1054
1055 recursive = TRUE;
zeertzjqcfe45652022-05-27 17:26:55 +01001056 textlock++;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001057 apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
zeertzjqcfe45652022-05-27 17:26:55 +01001058 textlock--;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001059 recursive = FALSE;
1060
1061 // Empty the dictionary, v:event is still valid
Bram Moolenaar3075a452021-11-17 15:51:52 +00001062 restore_v_event(v_event, &save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001063}
1064#endif
1065
1066/*
1067 * set all the yank registers to empty (called from main())
1068 */
1069 void
1070init_yank(void)
1071{
1072 int i;
1073
1074 for (i = 0; i < NUM_REGISTERS; ++i)
1075 y_regs[i].y_array = NULL;
1076}
1077
1078#if defined(EXITFREE) || defined(PROTO)
1079 void
1080clear_registers(void)
1081{
1082 int i;
1083
1084 for (i = 0; i < NUM_REGISTERS; ++i)
1085 {
1086 y_current = &y_regs[i];
1087 if (y_current->y_array != NULL)
1088 free_yank_all();
1089 }
1090}
1091#endif
1092
1093/*
1094 * Free "n" lines from the current yank register.
1095 * Called for normal freeing and in case of error.
1096 */
1097 static void
1098free_yank(long n)
1099{
1100 if (y_current->y_array != NULL)
1101 {
1102 long i;
1103
1104 for (i = n; --i >= 0; )
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001105 vim_free(y_current->y_array[i]);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001106 VIM_CLEAR(y_current->y_array);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001107 }
1108}
1109
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01001110 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001111free_yank_all(void)
1112{
1113 free_yank(y_current->y_size);
1114}
1115
1116/*
1117 * Yank the text between "oap->start" and "oap->end" into a yank register.
1118 * If we are to append (uppercase register), we first yank into a new yank
1119 * register and then concatenate the old and the new one (so we keep the old
1120 * one in case of out-of-memory).
1121 *
1122 * Return FAIL for failure, OK otherwise.
1123 */
1124 int
1125op_yank(oparg_T *oap, int deleting, int mess)
1126{
1127 long y_idx; // index in y_array[]
1128 yankreg_T *curr; // copy of y_current
1129 yankreg_T newreg; // new yank register when appending
1130 char_u **new_ptr;
1131 linenr_T lnum; // current line number
1132 long j;
1133 int yanktype = oap->motion_type;
1134 long yanklines = oap->line_count;
1135 linenr_T yankendlnum = oap->end.lnum;
1136 char_u *p;
1137 char_u *pnew;
1138 struct block_def bd;
1139#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1140 int did_star = FALSE;
1141#endif
1142
1143 // check for read-only register
1144 if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
1145 {
1146 beep_flush();
1147 return FAIL;
1148 }
1149 if (oap->regname == '_') // black hole: nothing to do
1150 return OK;
1151
1152#ifdef FEAT_CLIPBOARD
1153 if (!clip_star.available && oap->regname == '*')
1154 oap->regname = 0;
1155 else if (!clip_plus.available && oap->regname == '+')
1156 oap->regname = 0;
1157#endif
1158
1159 if (!deleting) // op_delete() already set y_current
1160 get_yank_register(oap->regname, TRUE);
1161
1162 curr = y_current;
1163 // append to existing contents
1164 if (y_append && y_current->y_array != NULL)
1165 y_current = &newreg;
1166 else
1167 free_yank_all(); // free previously yanked lines
1168
1169 // If the cursor was in column 1 before and after the movement, and the
1170 // operator is not inclusive, the yank is always linewise.
1171 if ( oap->motion_type == MCHAR
1172 && oap->start.col == 0
1173 && !oap->inclusive
1174 && (!oap->is_VIsual || *p_sel == 'o')
1175 && !oap->block_mode
1176 && oap->end.col == 0
1177 && yanklines > 1)
1178 {
1179 yanktype = MLINE;
1180 --yankendlnum;
1181 --yanklines;
1182 }
1183
1184 y_current->y_size = yanklines;
1185 y_current->y_type = yanktype; // set the yank register type
1186 y_current->y_width = 0;
1187 y_current->y_array = lalloc_clear(sizeof(char_u *) * yanklines, TRUE);
1188 if (y_current->y_array == NULL)
1189 {
1190 y_current = curr;
1191 return FAIL;
1192 }
1193#ifdef FEAT_VIMINFO
1194 y_current->y_time_set = vim_time();
1195#endif
1196
1197 y_idx = 0;
1198 lnum = oap->start.lnum;
1199
1200 if (oap->block_mode)
1201 {
1202 // Visual block mode
1203 y_current->y_type = MBLOCK; // set the yank register type
1204 y_current->y_width = oap->end_vcol - oap->start_vcol;
1205
1206 if (curwin->w_curswant == MAXCOL && y_current->y_width > 0)
1207 y_current->y_width--;
1208 }
1209
1210 for ( ; lnum <= yankendlnum; lnum++, y_idx++)
1211 {
1212 switch (y_current->y_type)
1213 {
1214 case MBLOCK:
1215 block_prep(oap, &bd, lnum, FALSE);
Christian Brabandt544a38e2021-06-10 19:39:11 +02001216 if (yank_copy_line(&bd, y_idx, oap->excl_tr_ws) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001217 goto fail;
1218 break;
1219
1220 case MLINE:
1221 if ((y_current->y_array[y_idx] =
Christian Brabandt544a38e2021-06-10 19:39:11 +02001222 vim_strsave(ml_get(lnum))) == NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001223 goto fail;
1224 break;
1225
1226 case MCHAR:
1227 {
1228 colnr_T startcol = 0, endcol = MAXCOL;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001229 int is_oneChar = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001230 colnr_T cs, ce;
1231
1232 p = ml_get(lnum);
1233 bd.startspaces = 0;
1234 bd.endspaces = 0;
1235
1236 if (lnum == oap->start.lnum)
1237 {
1238 startcol = oap->start.col;
1239 if (virtual_op)
1240 {
1241 getvcol(curwin, &oap->start, &cs, NULL, &ce);
1242 if (ce != cs && oap->start.coladd > 0)
1243 {
1244 // Part of a tab selected -- but don't
1245 // double-count it.
1246 bd.startspaces = (ce - cs + 1)
1247 - oap->start.coladd;
1248 startcol++;
1249 }
1250 }
1251 }
1252
1253 if (lnum == oap->end.lnum)
1254 {
1255 endcol = oap->end.col;
1256 if (virtual_op)
1257 {
1258 getvcol(curwin, &oap->end, &cs, NULL, &ce);
1259 if (p[endcol] == NUL || (cs + oap->end.coladd < ce
1260 // Don't add space for double-wide
1261 // char; endcol will be on last byte
1262 // of multi-byte char.
1263 && (*mb_head_off)(p, p + endcol) == 0))
1264 {
1265 if (oap->start.lnum == oap->end.lnum
1266 && oap->start.col == oap->end.col)
1267 {
1268 // Special case: inside a single char
1269 is_oneChar = TRUE;
1270 bd.startspaces = oap->end.coladd
1271 - oap->start.coladd + oap->inclusive;
1272 endcol = startcol;
1273 }
1274 else
1275 {
1276 bd.endspaces = oap->end.coladd
1277 + oap->inclusive;
1278 endcol -= oap->inclusive;
1279 }
1280 }
1281 }
1282 }
1283 if (endcol == MAXCOL)
1284 endcol = (colnr_T)STRLEN(p);
1285 if (startcol > endcol || is_oneChar)
1286 bd.textlen = 0;
1287 else
1288 bd.textlen = endcol - startcol + oap->inclusive;
1289 bd.textstart = p + startcol;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001290 if (yank_copy_line(&bd, y_idx, FALSE) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001291 goto fail;
1292 break;
1293 }
1294 // NOTREACHED
1295 }
1296 }
1297
1298 if (curr != y_current) // append the new block to the old block
1299 {
1300 new_ptr = ALLOC_MULT(char_u *, curr->y_size + y_current->y_size);
1301 if (new_ptr == NULL)
1302 goto fail;
1303 for (j = 0; j < curr->y_size; ++j)
1304 new_ptr[j] = curr->y_array[j];
1305 vim_free(curr->y_array);
1306 curr->y_array = new_ptr;
1307#ifdef FEAT_VIMINFO
1308 curr->y_time_set = vim_time();
1309#endif
1310
1311 if (yanktype == MLINE) // MLINE overrides MCHAR and MBLOCK
1312 curr->y_type = MLINE;
1313
1314 // Concatenate the last line of the old block with the first line of
1315 // the new block, unless being Vi compatible.
1316 if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL)
1317 {
1318 pnew = alloc(STRLEN(curr->y_array[curr->y_size - 1])
1319 + STRLEN(y_current->y_array[0]) + 1);
1320 if (pnew == NULL)
1321 {
1322 y_idx = y_current->y_size - 1;
1323 goto fail;
1324 }
1325 STRCPY(pnew, curr->y_array[--j]);
1326 STRCAT(pnew, y_current->y_array[0]);
1327 vim_free(curr->y_array[j]);
1328 vim_free(y_current->y_array[0]);
1329 curr->y_array[j++] = pnew;
1330 y_idx = 1;
1331 }
1332 else
1333 y_idx = 0;
1334 while (y_idx < y_current->y_size)
1335 curr->y_array[j++] = y_current->y_array[y_idx++];
1336 curr->y_size = j;
1337 vim_free(y_current->y_array);
1338 y_current = curr;
1339 }
zeertzjq95d2e762022-03-19 11:42:16 +00001340
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001341 if (mess) // Display message about yank?
1342 {
1343 if (yanktype == MCHAR
1344 && !oap->block_mode
1345 && yanklines == 1)
1346 yanklines = 0;
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001347 // Some versions of Vi use ">=" here, some don't...
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001348 if (yanklines > p_report)
1349 {
1350 char namebuf[100];
1351
1352 if (oap->regname == NUL)
1353 *namebuf = NUL;
1354 else
1355 vim_snprintf(namebuf, sizeof(namebuf),
1356 _(" into \"%c"), oap->regname);
1357
1358 // redisplay now, so message is not deleted
1359 update_topline_redraw();
1360 if (oap->block_mode)
1361 {
1362 smsg(NGETTEXT("block of %ld line yanked%s",
1363 "block of %ld lines yanked%s", yanklines),
1364 yanklines, namebuf);
1365 }
1366 else
1367 {
1368 smsg(NGETTEXT("%ld line yanked%s",
1369 "%ld lines yanked%s", yanklines),
1370 yanklines, namebuf);
1371 }
1372 }
1373 }
1374
Bram Moolenaare1004402020-10-24 20:49:43 +02001375 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001376 {
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001377 // Set "'[" and "']" marks.
1378 curbuf->b_op_start = oap->start;
1379 curbuf->b_op_end = oap->end;
1380 if (yanktype == MLINE && !oap->block_mode)
1381 {
1382 curbuf->b_op_start.col = 0;
1383 curbuf->b_op_end.col = MAXCOL;
1384 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001385 }
1386
1387#ifdef FEAT_CLIPBOARD
1388 // If we were yanking to the '*' register, send result to clipboard.
1389 // If no register was specified, and "unnamed" in 'clipboard', make a copy
1390 // to the '*' register.
1391 if (clip_star.available
1392 && (curr == &(y_regs[STAR_REGISTER])
1393 || (!deleting && oap->regname == 0
1394 && ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
1395 {
1396 if (curr != &(y_regs[STAR_REGISTER]))
1397 // Copy the text from register 0 to the clipboard register.
1398 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1399
1400 clip_own_selection(&clip_star);
1401 clip_gen_set_selection(&clip_star);
1402# ifdef FEAT_X11
1403 did_star = TRUE;
1404# endif
1405 }
1406
1407# ifdef FEAT_X11
1408 // If we were yanking to the '+' register, send result to selection.
Bram Moolenaar37096af2021-03-02 19:04:11 +01001409 // Also copy to the '*' register, in case auto-select is off. But not when
Ernie Rael559f2302022-07-26 14:44:36 +01001410 // 'clipboard' has "unnamedplus" and not "unnamed"; and not when
1411 // deleting and both "unnamedplus" and "unnamed".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001412 if (clip_plus.available
1413 && (curr == &(y_regs[PLUS_REGISTER])
1414 || (!deleting && oap->regname == 0
1415 && ((clip_unnamed | clip_unnamed_saved) &
Bram Moolenaar37096af2021-03-02 19:04:11 +01001416 CLIP_UNNAMED_PLUS))))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001417 {
1418 if (curr != &(y_regs[PLUS_REGISTER]))
1419 // Copy the text from register 0 to the clipboard register.
1420 copy_yank_reg(&(y_regs[PLUS_REGISTER]));
1421
1422 clip_own_selection(&clip_plus);
1423 clip_gen_set_selection(&clip_plus);
Bram Moolenaar37096af2021-03-02 19:04:11 +01001424 if (!clip_isautosel_star()
1425 && !clip_isautosel_plus()
1426 && !((clip_unnamed | clip_unnamed_saved) == CLIP_UNNAMED_PLUS)
Ernie Rael559f2302022-07-26 14:44:36 +01001427 && !(deleting && (clip_unnamed | clip_unnamed_saved)
1428 == (CLIP_UNNAMED | CLIP_UNNAMED_PLUS))
Bram Moolenaar37096af2021-03-02 19:04:11 +01001429 && !did_star
1430 && curr == &(y_regs[PLUS_REGISTER]))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001431 {
1432 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1433 clip_own_selection(&clip_star);
1434 clip_gen_set_selection(&clip_star);
1435 }
1436 }
1437# endif
1438#endif
1439
1440#if defined(FEAT_EVAL)
1441 if (!deleting && has_textyankpost())
1442 yank_do_autocmd(oap, y_current);
1443#endif
1444
1445 return OK;
1446
1447fail: // free the allocated lines
1448 free_yank(y_idx + 1);
1449 y_current = curr;
1450 return FAIL;
1451}
1452
Christian Brabandt544a38e2021-06-10 19:39:11 +02001453/*
1454 * Copy a block range into a register.
1455 * If "exclude_trailing_space" is set, do not copy trailing whitespaces.
1456 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001457 static int
Christian Brabandt544a38e2021-06-10 19:39:11 +02001458yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001459{
1460 char_u *pnew;
1461
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02001462 if (exclude_trailing_space)
1463 bd->endspaces = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001464 if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1))
1465 == NULL)
1466 return FAIL;
1467 y_current->y_array[y_idx] = pnew;
1468 vim_memset(pnew, ' ', (size_t)bd->startspaces);
1469 pnew += bd->startspaces;
1470 mch_memmove(pnew, bd->textstart, (size_t)bd->textlen);
1471 pnew += bd->textlen;
1472 vim_memset(pnew, ' ', (size_t)bd->endspaces);
1473 pnew += bd->endspaces;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001474 if (exclude_trailing_space)
1475 {
1476 int s = bd->textlen + bd->endspaces;
1477
Bram Moolenaar44db8212022-01-25 21:26:17 +00001478 while (s > 0 && VIM_ISWHITE(*(bd->textstart + s - 1)))
Christian Brabandt544a38e2021-06-10 19:39:11 +02001479 {
1480 s = s - (*mb_head_off)(bd->textstart, bd->textstart + s - 1) - 1;
1481 pnew--;
1482 }
1483 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001484 *pnew = NUL;
1485 return OK;
1486}
1487
1488#ifdef FEAT_CLIPBOARD
1489/*
1490 * Make a copy of the y_current register to register "reg".
1491 */
1492 static void
1493copy_yank_reg(yankreg_T *reg)
1494{
1495 yankreg_T *curr = y_current;
1496 long j;
1497
1498 y_current = reg;
1499 free_yank_all();
1500 *y_current = *curr;
1501 y_current->y_array = lalloc_clear(
1502 sizeof(char_u *) * y_current->y_size, TRUE);
1503 if (y_current->y_array == NULL)
1504 y_current->y_size = 0;
1505 else
1506 for (j = 0; j < y_current->y_size; ++j)
1507 if ((y_current->y_array[j] = vim_strsave(curr->y_array[j])) == NULL)
1508 {
1509 free_yank(j);
1510 y_current->y_size = 0;
1511 break;
1512 }
1513 y_current = curr;
1514}
1515#endif
1516
1517/*
1518 * Put contents of register "regname" into the text.
1519 * Caller must check "regname" to be valid!
1520 * "flags": PUT_FIXINDENT make indent look nice
1521 * PUT_CURSEND leave cursor after end of new text
1522 * PUT_LINE force linewise put (":put")
Christian Brabandt2fa93842021-05-30 22:17:25 +02001523 * PUT_BLOCK_INNER in block mode, do not add trailing spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001524 */
1525 void
1526do_put(
1527 int regname,
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001528 char_u *expr_result, // result for regname "=" when compiled
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001529 int dir, // BACKWARD for 'P', FORWARD for 'p'
1530 long count,
1531 int flags)
1532{
1533 char_u *ptr;
1534 char_u *newp, *oldp;
1535 int yanklen;
1536 int totlen = 0; // init for gcc
1537 linenr_T lnum;
1538 colnr_T col;
1539 long i; // index in y_array[]
1540 int y_type;
1541 long y_size;
1542 int oldlen;
1543 long y_width = 0;
1544 colnr_T vcol;
1545 int delcount;
1546 int incr = 0;
1547 long j;
1548 struct block_def bd;
1549 char_u **y_array = NULL;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001550 yankreg_T *y_current_used = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001551 long nr_lines = 0;
1552 pos_T new_cursor;
1553 int indent;
1554 int orig_indent = 0; // init for gcc
1555 int indent_diff = 0; // init for gcc
1556 int first_indent = TRUE;
1557 int lendiff = 0;
1558 pos_T old_pos;
1559 char_u *insert_string = NULL;
1560 int allocated = FALSE;
1561 long cnt;
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001562 pos_T orig_start = curbuf->b_op_start;
1563 pos_T orig_end = curbuf->b_op_end;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001564 unsigned int cur_ve_flags = get_ve_flags();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001565
1566#ifdef FEAT_CLIPBOARD
1567 // Adjust register name for "unnamed" in 'clipboard'.
1568 adjust_clip_reg(&regname);
1569 (void)may_get_selection(regname);
1570#endif
1571
1572 if (flags & PUT_FIXINDENT)
1573 orig_indent = get_indent();
1574
1575 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1576 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1577
1578 // Using inserted text works differently, because the register includes
1579 // special characters (newlines, etc.).
1580 if (regname == '.')
1581 {
1582 if (VIsual_active)
1583 stuffcharReadbuff(VIsual_mode);
1584 (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
1585 (count == -1 ? 'O' : 'i')), count, FALSE);
1586 // Putting the text is done later, so can't really move the cursor to
1587 // the next character. Use "l" to simulate it.
1588 if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
1589 stuffcharReadbuff('l');
1590 return;
1591 }
1592
1593 // For special registers '%' (file name), '#' (alternate file name) and
1594 // ':' (last command line), etc. we have to create a fake yank register.
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001595 // For compiled code "expr_result" holds the expression result.
1596 if (regname == '=' && expr_result != NULL)
1597 insert_string = expr_result;
1598 else if (get_spec_reg(regname, &insert_string, &allocated, TRUE)
1599 && insert_string == NULL)
1600 return;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001601
1602 // Autocommands may be executed when saving lines for undo. This might
1603 // make "y_array" invalid, so we start undo now to avoid that.
1604 if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL)
1605 goto end;
1606
1607 if (insert_string != NULL)
1608 {
1609 y_type = MCHAR;
1610#ifdef FEAT_EVAL
1611 if (regname == '=')
1612 {
1613 // For the = register we need to split the string at NL
1614 // characters.
1615 // Loop twice: count the number of lines and save them.
1616 for (;;)
1617 {
1618 y_size = 0;
1619 ptr = insert_string;
1620 while (ptr != NULL)
1621 {
1622 if (y_array != NULL)
1623 y_array[y_size] = ptr;
1624 ++y_size;
1625 ptr = vim_strchr(ptr, '\n');
1626 if (ptr != NULL)
1627 {
1628 if (y_array != NULL)
1629 *ptr = NUL;
1630 ++ptr;
1631 // A trailing '\n' makes the register linewise.
1632 if (*ptr == NUL)
1633 {
1634 y_type = MLINE;
1635 break;
1636 }
1637 }
1638 }
1639 if (y_array != NULL)
1640 break;
1641 y_array = ALLOC_MULT(char_u *, y_size);
1642 if (y_array == NULL)
1643 goto end;
1644 }
1645 }
1646 else
1647#endif
1648 {
1649 y_size = 1; // use fake one-line yank register
1650 y_array = &insert_string;
1651 }
1652 }
1653 else
1654 {
1655 get_yank_register(regname, FALSE);
1656
1657 y_type = y_current->y_type;
1658 y_width = y_current->y_width;
1659 y_size = y_current->y_size;
1660 y_array = y_current->y_array;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001661 y_current_used = y_current;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001662 }
1663
1664 if (y_type == MLINE)
1665 {
1666 if (flags & PUT_LINE_SPLIT)
1667 {
1668 char_u *p;
1669
1670 // "p" or "P" in Visual mode: split the lines to put the text in
1671 // between.
1672 if (u_save_cursor() == FAIL)
1673 goto end;
1674 p = ml_get_cursor();
1675 if (dir == FORWARD && *p != NUL)
1676 MB_PTR_ADV(p);
1677 ptr = vim_strsave(p);
1678 if (ptr == NULL)
1679 goto end;
1680 ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE);
1681 vim_free(ptr);
1682
1683 oldp = ml_get_curline();
1684 p = oldp + curwin->w_cursor.col;
1685 if (dir == FORWARD && *p != NUL)
1686 MB_PTR_ADV(p);
1687 ptr = vim_strnsave(oldp, p - oldp);
1688 if (ptr == NULL)
1689 goto end;
1690 ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
1691 ++nr_lines;
1692 dir = FORWARD;
1693 }
1694 if (flags & PUT_LINE_FORWARD)
1695 {
1696 // Must be "p" for a Visual block, put lines below the block.
1697 curwin->w_cursor = curbuf->b_visual.vi_end;
1698 dir = FORWARD;
1699 }
1700 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1701 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1702 }
1703
1704 if (flags & PUT_LINE) // :put command or "p" in Visual line mode.
1705 y_type = MLINE;
1706
1707 if (y_size == 0 || y_array == NULL)
1708 {
Bram Moolenaarac78dd42022-01-02 19:25:26 +00001709 semsg(_(e_nothing_in_register_str),
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001710 regname == 0 ? (char_u *)"\"" : transchar(regname));
1711 goto end;
1712 }
1713
1714 if (y_type == MBLOCK)
1715 {
1716 lnum = curwin->w_cursor.lnum + y_size + 1;
1717 if (lnum > curbuf->b_ml.ml_line_count)
1718 lnum = curbuf->b_ml.ml_line_count + 1;
1719 if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
1720 goto end;
1721 }
1722 else if (y_type == MLINE)
1723 {
1724 lnum = curwin->w_cursor.lnum;
1725#ifdef FEAT_FOLDING
1726 // Correct line number for closed fold. Don't move the cursor yet,
1727 // u_save() uses it.
1728 if (dir == BACKWARD)
1729 (void)hasFolding(lnum, &lnum, NULL);
1730 else
1731 (void)hasFolding(lnum, NULL, &lnum);
1732#endif
1733 if (dir == FORWARD)
1734 ++lnum;
1735 // In an empty buffer the empty line is going to be replaced, include
1736 // it in the saved lines.
1737 if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL)
1738 goto end;
1739#ifdef FEAT_FOLDING
1740 if (dir == FORWARD)
1741 curwin->w_cursor.lnum = lnum - 1;
1742 else
1743 curwin->w_cursor.lnum = lnum;
1744 curbuf->b_op_start = curwin->w_cursor; // for mark_adjust()
1745#endif
1746 }
1747 else if (u_save_cursor() == FAIL)
1748 goto end;
1749
1750 yanklen = (int)STRLEN(y_array[0]);
1751
Gary Johnson53ba05b2021-07-26 22:19:10 +02001752 if (cur_ve_flags == VE_ALL && y_type == MCHAR)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001753 {
1754 if (gchar_cursor() == TAB)
1755 {
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001756 int viscol = getviscol();
1757 int ts = curbuf->b_p_ts;
1758
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001759 // Don't need to insert spaces when "p" on the last position of a
1760 // tab or "P" on the first position.
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001761 if (dir == FORWARD ?
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001762#ifdef FEAT_VARTABS
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001763 tabstop_padding(viscol, ts, curbuf->b_p_vts_array) != 1
1764#else
1765 ts - (viscol % ts) != 1
1766#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001767 : curwin->w_cursor.coladd > 0)
1768 coladvance_force(viscol);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001769 else
1770 curwin->w_cursor.coladd = 0;
1771 }
1772 else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
1773 coladvance_force(getviscol() + (dir == FORWARD));
1774 }
1775
1776 lnum = curwin->w_cursor.lnum;
1777 col = curwin->w_cursor.col;
1778
1779 // Block mode
1780 if (y_type == MBLOCK)
1781 {
1782 int c = gchar_cursor();
1783 colnr_T endcol2 = 0;
1784
1785 if (dir == FORWARD && c != NUL)
1786 {
Gary Johnson53ba05b2021-07-26 22:19:10 +02001787 if (cur_ve_flags == VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001788 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1789 else
1790 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
1791
1792 if (has_mbyte)
1793 // move to start of next multi-byte character
1794 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
1795 else
Gary Johnson53ba05b2021-07-26 22:19:10 +02001796 if (c != TAB || cur_ve_flags != VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001797 ++curwin->w_cursor.col;
1798 ++col;
1799 }
1800 else
1801 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1802
1803 col += curwin->w_cursor.coladd;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001804 if (cur_ve_flags == VE_ALL
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001805 && (curwin->w_cursor.coladd > 0
1806 || endcol2 == curwin->w_cursor.col))
1807 {
1808 if (dir == FORWARD && c == NUL)
1809 ++col;
Bram Moolenaaref85a9b2020-07-10 20:24:07 +02001810 if (dir != FORWARD && c != NUL && curwin->w_cursor.coladd > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001811 ++curwin->w_cursor.col;
1812 if (c == TAB)
1813 {
1814 if (dir == BACKWARD && curwin->w_cursor.col)
1815 curwin->w_cursor.col--;
1816 if (dir == FORWARD && col - 1 == endcol2)
1817 curwin->w_cursor.col++;
1818 }
1819 }
1820 curwin->w_cursor.coladd = 0;
1821 bd.textcol = 0;
1822 for (i = 0; i < y_size; ++i)
1823 {
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001824 int spaces = 0;
1825 char shortline;
1826 chartabsize_T cts;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001827
1828 bd.startspaces = 0;
1829 bd.endspaces = 0;
1830 vcol = 0;
1831 delcount = 0;
1832
1833 // add a new line
1834 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
1835 {
1836 if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
1837 (colnr_T)1, FALSE) == FAIL)
1838 break;
1839 ++nr_lines;
1840 }
1841 // get the old line and advance to the position to insert at
1842 oldp = ml_get_curline();
1843 oldlen = (int)STRLEN(oldp);
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001844 init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0,
1845 oldp, oldp);
1846
1847 while (cts.cts_vcol < col && *cts.cts_ptr != NUL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001848 {
1849 // Count a tab for what it's worth (if list mode not on)
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001850 incr = lbr_chartabsize_adv(&cts);
1851 cts.cts_vcol += incr;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001852 }
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001853 vcol = cts.cts_vcol;
1854 ptr = cts.cts_ptr;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001855 bd.textcol = (colnr_T)(ptr - oldp);
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001856 clear_chartabsize_arg(&cts);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001857
1858 shortline = (vcol < col) || (vcol == col && !*ptr) ;
1859
1860 if (vcol < col) // line too short, padd with spaces
1861 bd.startspaces = col - vcol;
1862 else if (vcol > col)
1863 {
1864 bd.endspaces = vcol - col;
1865 bd.startspaces = incr - bd.endspaces;
1866 --bd.textcol;
1867 delcount = 1;
1868 if (has_mbyte)
1869 bd.textcol -= (*mb_head_off)(oldp, oldp + bd.textcol);
1870 if (oldp[bd.textcol] != TAB)
1871 {
1872 // Only a Tab can be split into spaces. Other
1873 // characters will have to be moved to after the
1874 // block, causing misalignment.
1875 delcount = 0;
1876 bd.endspaces = 0;
1877 }
1878 }
1879
1880 yanklen = (int)STRLEN(y_array[i]);
1881
Christian Brabandt2fa93842021-05-30 22:17:25 +02001882 if ((flags & PUT_BLOCK_INNER) == 0)
1883 {
1884 // calculate number of spaces required to fill right side of
1885 // block
1886 spaces = y_width + 1;
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001887 init_chartabsize_arg(&cts, curwin, 0, 0,
1888 y_array[i], y_array[i]);
Christian Brabandt2fa93842021-05-30 22:17:25 +02001889 for (j = 0; j < yanklen; j++)
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001890 {
1891 spaces -= lbr_chartabsize(&cts);
1892 ++cts.cts_ptr;
1893 cts.cts_vcol = 0;
1894 }
1895 clear_chartabsize_arg(&cts);
Christian Brabandt2fa93842021-05-30 22:17:25 +02001896 if (spaces < 0)
1897 spaces = 0;
1898 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001899
ichizokfa537222021-11-16 12:50:46 +00001900 // Insert the new text.
1901 // First check for multiplication overflow.
1902 if (yanklen + spaces != 0
1903 && count > ((INT_MAX - (bd.startspaces + bd.endspaces))
1904 / (yanklen + spaces)))
1905 {
1906 emsg(_(e_resulting_text_too_long));
1907 break;
1908 }
1909
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001910 totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
1911 newp = alloc(totlen + oldlen + 1);
1912 if (newp == NULL)
1913 break;
ichizokfa537222021-11-16 12:50:46 +00001914
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001915 // copy part up to cursor to new line
1916 ptr = newp;
1917 mch_memmove(ptr, oldp, (size_t)bd.textcol);
1918 ptr += bd.textcol;
ichizokfa537222021-11-16 12:50:46 +00001919
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001920 // may insert some spaces before the new text
1921 vim_memset(ptr, ' ', (size_t)bd.startspaces);
1922 ptr += bd.startspaces;
ichizokfa537222021-11-16 12:50:46 +00001923
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001924 // insert the new text
1925 for (j = 0; j < count; ++j)
1926 {
1927 mch_memmove(ptr, y_array[i], (size_t)yanklen);
1928 ptr += yanklen;
1929
1930 // insert block's trailing spaces only if there's text behind
1931 if ((j < count - 1 || !shortline) && spaces)
1932 {
1933 vim_memset(ptr, ' ', (size_t)spaces);
1934 ptr += spaces;
1935 }
Bram Moolenaard25f0032022-06-30 12:30:19 +01001936 else
1937 totlen -= spaces; // didn't use these spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001938 }
ichizokfa537222021-11-16 12:50:46 +00001939
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001940 // may insert some spaces after the new text
1941 vim_memset(ptr, ' ', (size_t)bd.endspaces);
1942 ptr += bd.endspaces;
ichizokfa537222021-11-16 12:50:46 +00001943
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001944 // move the text after the cursor to the end of the line.
1945 mch_memmove(ptr, oldp + bd.textcol + delcount,
1946 (size_t)(oldlen - bd.textcol - delcount + 1));
1947 ml_replace(curwin->w_cursor.lnum, newp, FALSE);
1948
1949 ++curwin->w_cursor.lnum;
1950 if (i == 0)
1951 curwin->w_cursor.col += bd.startspaces;
1952 }
1953
1954 changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines);
1955
1956 // Set '[ mark.
1957 curbuf->b_op_start = curwin->w_cursor;
1958 curbuf->b_op_start.lnum = lnum;
1959
1960 // adjust '] mark
1961 curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
1962 curbuf->b_op_end.col = bd.textcol + totlen - 1;
1963 curbuf->b_op_end.coladd = 0;
1964 if (flags & PUT_CURSEND)
1965 {
1966 colnr_T len;
1967
1968 curwin->w_cursor = curbuf->b_op_end;
1969 curwin->w_cursor.col++;
1970
1971 // in Insert mode we might be after the NUL, correct for that
1972 len = (colnr_T)STRLEN(ml_get_curline());
1973 if (curwin->w_cursor.col > len)
1974 curwin->w_cursor.col = len;
1975 }
1976 else
1977 curwin->w_cursor.lnum = lnum;
1978 }
1979 else
1980 {
1981 // Character or Line mode
1982 if (y_type == MCHAR)
1983 {
1984 // if type is MCHAR, FORWARD is the same as BACKWARD on the next
1985 // char
1986 if (dir == FORWARD && gchar_cursor() != NUL)
1987 {
1988 if (has_mbyte)
1989 {
1990 int bytelen = (*mb_ptr2len)(ml_get_cursor());
1991
1992 // put it on the next of the multi-byte character.
1993 col += bytelen;
1994 if (yanklen)
1995 {
1996 curwin->w_cursor.col += bytelen;
1997 curbuf->b_op_end.col += bytelen;
1998 }
1999 }
2000 else
2001 {
2002 ++col;
2003 if (yanklen)
2004 {
2005 ++curwin->w_cursor.col;
2006 ++curbuf->b_op_end.col;
2007 }
2008 }
2009 }
2010 curbuf->b_op_start = curwin->w_cursor;
2011 }
2012 // Line mode: BACKWARD is the same as FORWARD on the previous line
2013 else if (dir == BACKWARD)
2014 --lnum;
2015 new_cursor = curwin->w_cursor;
2016
Bram Moolenaarcd942772020-08-22 21:08:44 +02002017 // simple case: insert into one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002018 if (y_type == MCHAR && y_size == 1)
2019 {
Bram Moolenaarcd942772020-08-22 21:08:44 +02002020 linenr_T end_lnum = 0; // init for gcc
2021 linenr_T start_lnum = lnum;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002022 int first_byte_off = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002023
2024 if (VIsual_active)
2025 {
2026 end_lnum = curbuf->b_visual.vi_end.lnum;
2027 if (end_lnum < curbuf->b_visual.vi_start.lnum)
2028 end_lnum = curbuf->b_visual.vi_start.lnum;
Bram Moolenaarcd942772020-08-22 21:08:44 +02002029 if (end_lnum > start_lnum)
2030 {
2031 pos_T pos;
2032
2033 // "col" is valid for the first line, in following lines
2034 // the virtual column needs to be used. Matters for
2035 // multi-byte characters.
2036 pos.lnum = lnum;
2037 pos.col = col;
2038 pos.coladd = 0;
2039 getvcol(curwin, &pos, NULL, &vcol, NULL);
2040 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002041 }
2042
ichizokfa537222021-11-16 12:50:46 +00002043 if (count == 0 || yanklen == 0)
2044 {
2045 if (VIsual_active)
2046 lnum = end_lnum;
2047 }
2048 else if (count > INT_MAX / yanklen)
2049 // multiplication overflow
2050 emsg(_(e_resulting_text_too_long));
2051 else
2052 {
Bram Moolenaare551ccf2021-11-02 23:11:00 +00002053 totlen = count * yanklen;
ichizokfa537222021-11-16 12:50:46 +00002054 do {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002055 oldp = ml_get(lnum);
ichizokfa537222021-11-16 12:50:46 +00002056 oldlen = (int)STRLEN(oldp);
Bram Moolenaarcd942772020-08-22 21:08:44 +02002057 if (lnum > start_lnum)
2058 {
2059 pos_T pos;
2060
2061 pos.lnum = lnum;
2062 if (getvpos(&pos, vcol) == OK)
2063 col = pos.col;
2064 else
2065 col = MAXCOL;
2066 }
ichizokfa537222021-11-16 12:50:46 +00002067 if (VIsual_active && col > oldlen)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002068 {
2069 lnum++;
2070 continue;
2071 }
ichizokfa537222021-11-16 12:50:46 +00002072 newp = alloc(totlen + oldlen + 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002073 if (newp == NULL)
2074 goto end; // alloc() gave an error message
2075 mch_memmove(newp, oldp, (size_t)col);
2076 ptr = newp + col;
2077 for (i = 0; i < count; ++i)
2078 {
2079 mch_memmove(ptr, y_array[0], (size_t)yanklen);
2080 ptr += yanklen;
2081 }
2082 STRMOVE(ptr, oldp + col);
Bram Moolenaarecb00c72022-08-07 14:55:14 +01002083
Bram Moolenaar4d072532021-11-25 19:31:15 +00002084 // compute the byte offset for the last character
2085 first_byte_off = mb_head_off(newp, ptr - 1);
2086
Bram Moolenaarc390cc12022-08-07 18:09:10 +01002087 // Note: this may free "newp"
2088 ml_replace(lnum, newp, FALSE);
2089
2090 inserted_bytes(lnum, col, totlen);
2091
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002092 // Place cursor on last putted char.
2093 if (lnum == curwin->w_cursor.lnum)
2094 {
2095 // make sure curwin->w_virtcol is updated
2096 changed_cline_bef_curs();
2097 curwin->w_cursor.col += (colnr_T)(totlen - 1);
2098 }
ichizokfa537222021-11-16 12:50:46 +00002099 if (VIsual_active)
2100 lnum++;
2101 } while (VIsual_active && lnum <= end_lnum);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002102
ichizokfa537222021-11-16 12:50:46 +00002103 if (VIsual_active) // reset lnum to the last visual line
2104 lnum--;
2105 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002106
Bram Moolenaar4d072532021-11-25 19:31:15 +00002107 // put '] at the first byte of the last character
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002108 curbuf->b_op_end = curwin->w_cursor;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002109 curbuf->b_op_end.col -= first_byte_off;
2110
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002111 // For "CTRL-O p" in Insert mode, put cursor after last char
2112 if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
2113 ++curwin->w_cursor.col;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002114 else
2115 curwin->w_cursor.col -= first_byte_off;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002116 }
2117 else
2118 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002119 linenr_T new_lnum = new_cursor.lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002120 size_t len;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002121
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002122 // Insert at least one line. When y_type is MCHAR, break the first
2123 // line in two.
2124 for (cnt = 1; cnt <= count; ++cnt)
2125 {
2126 i = 0;
2127 if (y_type == MCHAR)
2128 {
2129 // Split the current line in two at the insert position.
2130 // First insert y_array[size - 1] in front of second line.
2131 // Then append y_array[0] to first line.
2132 lnum = new_cursor.lnum;
2133 ptr = ml_get(lnum) + col;
2134 totlen = (int)STRLEN(y_array[y_size - 1]);
2135 newp = alloc(STRLEN(ptr) + totlen + 1);
2136 if (newp == NULL)
2137 goto error;
2138 STRCPY(newp, y_array[y_size - 1]);
2139 STRCAT(newp, ptr);
2140 // insert second line
2141 ml_append(lnum, newp, (colnr_T)0, FALSE);
Bram Moolenaar23003e52021-09-22 16:37:07 +02002142 ++new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002143 vim_free(newp);
2144
2145 oldp = ml_get(lnum);
2146 newp = alloc(col + yanklen + 1);
2147 if (newp == NULL)
2148 goto error;
2149 // copy first part of line
2150 mch_memmove(newp, oldp, (size_t)col);
2151 // append to first line
2152 mch_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
2153 ml_replace(lnum, newp, FALSE);
2154
2155 curwin->w_cursor.lnum = lnum;
2156 i = 1;
2157 }
2158
2159 for (; i < y_size; ++i)
2160 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002161 if (y_type != MCHAR || i < y_size - 1)
2162 {
2163 if (ml_append(lnum, y_array[i], (colnr_T)0, FALSE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002164 == FAIL)
2165 goto error;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002166 new_lnum++;
2167 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002168 lnum++;
2169 ++nr_lines;
2170 if (flags & PUT_FIXINDENT)
2171 {
2172 old_pos = curwin->w_cursor;
2173 curwin->w_cursor.lnum = lnum;
2174 ptr = ml_get(lnum);
2175 if (cnt == count && i == y_size - 1)
2176 lendiff = (int)STRLEN(ptr);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002177 if (*ptr == '#' && preprocs_left())
2178 indent = 0; // Leave # lines at start
2179 else
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002180 if (*ptr == NUL)
2181 indent = 0; // Ignore empty lines
2182 else if (first_indent)
2183 {
2184 indent_diff = orig_indent - get_indent();
2185 indent = orig_indent;
2186 first_indent = FALSE;
2187 }
2188 else if ((indent = get_indent() + indent_diff) < 0)
2189 indent = 0;
2190 (void)set_indent(indent, 0);
2191 curwin->w_cursor = old_pos;
2192 // remember how many chars were removed
2193 if (cnt == count && i == y_size - 1)
2194 lendiff -= (int)STRLEN(ml_get(lnum));
2195 }
2196 }
Bram Moolenaar23003e52021-09-22 16:37:07 +02002197 if (cnt == 1)
2198 new_lnum = lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002199 }
2200
2201error:
2202 // Adjust marks.
2203 if (y_type == MLINE)
2204 {
2205 curbuf->b_op_start.col = 0;
2206 if (dir == FORWARD)
2207 curbuf->b_op_start.lnum++;
2208 }
2209 // Skip mark_adjust when adding lines after the last one, there
2210 // can't be marks there. But still needed in diff mode.
2211 if (curbuf->b_op_start.lnum + (y_type == MCHAR) - 1 + nr_lines
2212 < curbuf->b_ml.ml_line_count
2213#ifdef FEAT_DIFF
2214 || curwin->w_p_diff
2215#endif
2216 )
2217 mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
2218 (linenr_T)MAXLNUM, nr_lines, 0L);
2219
2220 // note changed text for displaying and folding
2221 if (y_type == MCHAR)
2222 changed_lines(curwin->w_cursor.lnum, col,
2223 curwin->w_cursor.lnum + 1, nr_lines);
2224 else
2225 changed_lines(curbuf->b_op_start.lnum, 0,
2226 curbuf->b_op_start.lnum, nr_lines);
Bram Moolenaar9ac38122021-12-02 18:42:33 +00002227 if (y_current_used != NULL && (y_current_used != y_current
2228 || y_current->y_array != y_array))
2229 {
2230 // Something invoked through changed_lines() has changed the
2231 // yank buffer, e.g. a GUI clipboard callback.
2232 emsg(_(e_yank_register_changed_while_using_it));
2233 goto end;
2234 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002235
Bram Moolenaar4d072532021-11-25 19:31:15 +00002236 // Put the '] mark on the first byte of the last inserted character.
2237 // Correct the length for change in indent.
Bram Moolenaarf47ebf12021-10-19 20:08:45 +01002238 curbuf->b_op_end.lnum = new_lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002239 len = STRLEN(y_array[y_size - 1]);
2240 col = (colnr_T)len - lendiff;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002241 if (col > 1)
Bram Moolenaar2a585c82022-05-25 15:15:38 +01002242 {
2243 curbuf->b_op_end.col = col - 1;
2244 if (len > 0)
2245 curbuf->b_op_end.col -= mb_head_off(y_array[y_size - 1],
Bram Moolenaar85be8562021-11-25 20:40:11 +00002246 y_array[y_size - 1] + len - 1);
Bram Moolenaar2a585c82022-05-25 15:15:38 +01002247 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002248 else
2249 curbuf->b_op_end.col = 0;
2250
2251 if (flags & PUT_CURSLINE)
2252 {
2253 // ":put": put cursor on last inserted line
2254 curwin->w_cursor.lnum = lnum;
2255 beginline(BL_WHITE | BL_FIX);
2256 }
2257 else if (flags & PUT_CURSEND)
2258 {
2259 // put cursor after inserted text
2260 if (y_type == MLINE)
2261 {
2262 if (lnum >= curbuf->b_ml.ml_line_count)
2263 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
2264 else
2265 curwin->w_cursor.lnum = lnum + 1;
2266 curwin->w_cursor.col = 0;
2267 }
2268 else
2269 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002270 curwin->w_cursor.lnum = new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002271 curwin->w_cursor.col = col;
Bram Moolenaar56858e42021-09-22 16:43:59 +02002272 curbuf->b_op_end = curwin->w_cursor;
2273 if (col > 1)
2274 curbuf->b_op_end.col = col - 1;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002275 }
2276 }
2277 else if (y_type == MLINE)
2278 {
2279 // put cursor on first non-blank in first inserted line
2280 curwin->w_cursor.col = 0;
2281 if (dir == FORWARD)
2282 ++curwin->w_cursor.lnum;
2283 beginline(BL_WHITE | BL_FIX);
2284 }
2285 else // put cursor on first inserted character
2286 curwin->w_cursor = new_cursor;
2287 }
2288 }
2289
2290 msgmore(nr_lines);
2291 curwin->w_set_curswant = TRUE;
2292
2293end:
Bram Moolenaare1004402020-10-24 20:49:43 +02002294 if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01002295 {
2296 curbuf->b_op_start = orig_start;
2297 curbuf->b_op_end = orig_end;
2298 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002299 if (allocated)
2300 vim_free(insert_string);
2301 if (regname == '=')
2302 vim_free(y_array);
2303
2304 VIsual_active = FALSE;
2305
2306 // If the cursor is past the end of the line put it at the end.
2307 adjust_cursor_eol();
2308}
2309
2310/*
2311 * Return the character name of the register with the given number.
2312 */
2313 int
2314get_register_name(int num)
2315{
2316 if (num == -1)
2317 return '"';
2318 else if (num < 10)
2319 return num + '0';
2320 else if (num == DELETION_REGISTER)
2321 return '-';
2322#ifdef FEAT_CLIPBOARD
2323 else if (num == STAR_REGISTER)
2324 return '*';
2325 else if (num == PLUS_REGISTER)
2326 return '+';
2327#endif
2328 else
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002329 return num + 'a' - 10;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002330}
2331
Dominique Pelle748b3082022-01-08 12:41:16 +00002332#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002333/*
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002334 * Return the index of the register "" points to.
2335 */
2336 int
2337get_unname_register()
2338{
2339 return y_previous == NULL ? -1 : y_previous - &y_regs[0];
2340}
Dominique Pelle748b3082022-01-08 12:41:16 +00002341#endif
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002342
2343/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002344 * ":dis" and ":registers": Display the contents of the yank registers.
2345 */
2346 void
2347ex_display(exarg_T *eap)
2348{
2349 int i, n;
2350 long j;
2351 char_u *p;
2352 yankreg_T *yb;
2353 int name;
2354 int attr;
2355 char_u *arg = eap->arg;
2356 int clen;
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002357 int type;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002358
2359 if (arg != NULL && *arg == NUL)
2360 arg = NULL;
2361 attr = HL_ATTR(HLF_8);
2362
2363 // Highlight title
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002364 msg_puts_title(_("\nType Name Content"));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002365 for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
2366 {
2367 name = get_register_name(i);
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002368 switch (get_reg_type(name, NULL))
2369 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002370 case MLINE: type = 'l'; break;
2371 case MCHAR: type = 'c'; break;
2372 default: type = 'b'; break;
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002373 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002374 if (arg != NULL && vim_strchr(arg, name) == NULL
2375#ifdef ONE_CLIPBOARD
2376 // Star register and plus register contain the same thing.
2377 && (name != '*' || vim_strchr(arg, '+') == NULL)
2378#endif
2379 )
2380 continue; // did not ask for this register
2381
2382#ifdef FEAT_CLIPBOARD
2383 // Adjust register name for "unnamed" in 'clipboard'.
2384 // When it's a clipboard register, fill it with the current contents
2385 // of the clipboard.
2386 adjust_clip_reg(&name);
2387 (void)may_get_selection(name);
2388#endif
2389
2390 if (i == -1)
2391 {
2392 if (y_previous != NULL)
2393 yb = y_previous;
2394 else
2395 yb = &(y_regs[0]);
2396 }
2397 else
2398 yb = &(y_regs[i]);
2399
2400#ifdef FEAT_EVAL
2401 if (name == MB_TOLOWER(redir_reg)
2402 || (redir_reg == '"' && yb == y_previous))
2403 continue; // do not list register being written to, the
2404 // pointer can be freed
2405#endif
2406
2407 if (yb->y_array != NULL)
2408 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002409 int do_show = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002410
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002411 for (j = 0; !do_show && j < yb->y_size; ++j)
2412 do_show = !message_filtered(yb->y_array[j]);
2413
2414 if (do_show || yb->y_size == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002415 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002416 msg_putchar('\n');
2417 msg_puts(" ");
2418 msg_putchar(type);
2419 msg_puts(" ");
2420 msg_putchar('"');
2421 msg_putchar(name);
2422 msg_puts(" ");
2423
2424 n = (int)Columns - 11;
2425 for (j = 0; j < yb->y_size && n > 1; ++j)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002426 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002427 if (j)
2428 {
2429 msg_puts_attr("^J", attr);
2430 n -= 2;
2431 }
Bram Moolenaarb4ad3b02022-03-30 10:57:45 +01002432 for (p = yb->y_array[j];
2433 *p != NUL && (n -= ptr2cells(p)) >= 0; ++p)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002434 {
2435 clen = (*mb_ptr2len)(p);
2436 msg_outtrans_len(p, clen);
2437 p += clen - 1;
2438 }
2439 }
2440 if (n > 1 && yb->y_type == MLINE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002441 msg_puts_attr("^J", attr);
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002442 out_flush(); // show one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002443 }
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002444 ui_breakcheck();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002445 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002446 }
2447
2448 // display last inserted text
2449 if ((p = get_last_insert()) != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002450 && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
2451 && !message_filtered(p))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002452 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002453 msg_puts("\n c \". ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002454 dis_msg(p, TRUE);
2455 }
2456
2457 // display last command line
2458 if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002459 && !got_int && !message_filtered(last_cmdline))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002460 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002461 msg_puts("\n c \": ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002462 dis_msg(last_cmdline, FALSE);
2463 }
2464
2465 // display current file name
2466 if (curbuf->b_fname != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002467 && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int
2468 && !message_filtered(curbuf->b_fname))
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(curbuf->b_fname, FALSE);
2472 }
2473
2474 // display alternate file name
2475 if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
2476 {
2477 char_u *fname;
2478 linenr_T dummy;
2479
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002480 if (buflist_name_nr(0, &fname, &dummy) != FAIL
2481 && !message_filtered(fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002482 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002483 msg_puts("\n c \"# ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002484 dis_msg(fname, FALSE);
2485 }
2486 }
2487
2488 // display last search pattern
2489 if (last_search_pat() != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002490 && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int
2491 && !message_filtered(last_search_pat()))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002492 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002493 msg_puts("\n c \"/ ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002494 dis_msg(last_search_pat(), FALSE);
2495 }
2496
2497#ifdef FEAT_EVAL
2498 // display last used expression
2499 if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002500 && !got_int && !message_filtered(expr_line))
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(expr_line, FALSE);
2504 }
2505#endif
2506}
2507
2508/*
2509 * display a string for do_dis()
2510 * truncate at end of screen line
2511 */
2512 static void
2513dis_msg(
2514 char_u *p,
2515 int skip_esc) // if TRUE, ignore trailing ESC
2516{
2517 int n;
2518 int l;
2519
2520 n = (int)Columns - 6;
2521 while (*p != NUL
2522 && !(*p == ESC && skip_esc && *(p + 1) == NUL)
2523 && (n -= ptr2cells(p)) >= 0)
2524 {
2525 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
2526 {
2527 msg_outtrans_len(p, l);
2528 p += l;
2529 }
2530 else
2531 msg_outtrans_len(p++, 1);
2532 }
2533 ui_breakcheck();
2534}
2535
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002536#if defined(FEAT_DND) || defined(PROTO)
2537/*
2538 * Replace the contents of the '~' register with str.
2539 */
2540 void
2541dnd_yank_drag_data(char_u *str, long len)
2542{
2543 yankreg_T *curr;
2544
2545 curr = y_current;
2546 y_current = &y_regs[TILDE_REGISTER];
2547 free_yank_all();
2548 str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
2549 y_current = curr;
2550}
2551#endif
2552
2553
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002554/*
2555 * Return the type of a register.
2556 * Used for getregtype()
2557 * Returns MAUTO for error.
2558 */
2559 char_u
2560get_reg_type(int regname, long *reglen)
2561{
2562 switch (regname)
2563 {
2564 case '%': // file name
2565 case '#': // alternate file name
2566 case '=': // expression
2567 case ':': // last command line
2568 case '/': // last search-pattern
2569 case '.': // last inserted text
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002570 case Ctrl_F: // Filename under cursor
2571 case Ctrl_P: // Path under cursor, expand via "path"
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002572 case Ctrl_W: // word under cursor
2573 case Ctrl_A: // WORD (mnemonic All) under cursor
2574 case '_': // black hole: always empty
2575 return MCHAR;
2576 }
2577
2578# ifdef FEAT_CLIPBOARD
2579 regname = may_get_selection(regname);
2580# endif
2581
2582 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2583 return MAUTO;
2584
2585 get_yank_register(regname, FALSE);
2586
2587 if (y_current->y_array != NULL)
2588 {
2589 if (reglen != NULL && y_current->y_type == MBLOCK)
2590 *reglen = y_current->y_width;
2591 return y_current->y_type;
2592 }
2593 return MAUTO;
2594}
2595
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002596#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002597/*
2598 * When "flags" has GREG_LIST return a list with text "s".
2599 * Otherwise just return "s".
2600 */
2601 static char_u *
2602getreg_wrap_one_line(char_u *s, int flags)
2603{
2604 if (flags & GREG_LIST)
2605 {
2606 list_T *list = list_alloc();
2607
2608 if (list != NULL)
2609 {
2610 if (list_append_string(list, NULL, -1) == FAIL)
2611 {
2612 list_free(list);
2613 return NULL;
2614 }
2615 list->lv_first->li_tv.vval.v_string = s;
2616 }
2617 return (char_u *)list;
2618 }
2619 return s;
2620}
2621
2622/*
Bram Moolenaard672dde2020-02-26 13:43:51 +01002623 * Return the contents of a register as a single allocated string or as a list.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002624 * Used for "@r" in expressions and for getreg().
2625 * Returns NULL for error.
2626 * Flags:
2627 * GREG_NO_EXPR Do not allow expression register
2628 * GREG_EXPR_SRC For the expression register: return expression itself,
2629 * not the result of its evaluation.
Bram Moolenaard672dde2020-02-26 13:43:51 +01002630 * GREG_LIST Return a list of lines instead of a single string.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002631 */
2632 char_u *
2633get_reg_contents(int regname, int flags)
2634{
2635 long i;
2636 char_u *retval;
2637 int allocated;
2638 long len;
2639
2640 // Don't allow using an expression register inside an expression
2641 if (regname == '=')
2642 {
2643 if (flags & GREG_NO_EXPR)
2644 return NULL;
2645 if (flags & GREG_EXPR_SRC)
2646 return getreg_wrap_one_line(get_expr_line_src(), flags);
2647 return getreg_wrap_one_line(get_expr_line(), flags);
2648 }
2649
2650 if (regname == '@') // "@@" is used for unnamed register
2651 regname = '"';
2652
2653 // check for valid regname
2654 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2655 return NULL;
2656
2657# ifdef FEAT_CLIPBOARD
2658 regname = may_get_selection(regname);
2659# endif
2660
2661 if (get_spec_reg(regname, &retval, &allocated, FALSE))
2662 {
2663 if (retval == NULL)
2664 return NULL;
2665 if (allocated)
2666 return getreg_wrap_one_line(retval, flags);
2667 return getreg_wrap_one_line(vim_strsave(retval), flags);
2668 }
2669
2670 get_yank_register(regname, FALSE);
2671 if (y_current->y_array == NULL)
2672 return NULL;
2673
2674 if (flags & GREG_LIST)
2675 {
2676 list_T *list = list_alloc();
2677 int error = FALSE;
2678
2679 if (list == NULL)
2680 return NULL;
2681 for (i = 0; i < y_current->y_size; ++i)
2682 if (list_append_string(list, y_current->y_array[i], -1) == FAIL)
2683 error = TRUE;
2684 if (error)
2685 {
2686 list_free(list);
2687 return NULL;
2688 }
2689 return (char_u *)list;
2690 }
2691
2692 // Compute length of resulting string.
2693 len = 0;
2694 for (i = 0; i < y_current->y_size; ++i)
2695 {
2696 len += (long)STRLEN(y_current->y_array[i]);
2697 // Insert a newline between lines and after last line if
2698 // y_type is MLINE.
2699 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2700 ++len;
2701 }
2702
2703 retval = alloc(len + 1);
2704
2705 // Copy the lines of the yank register into the string.
2706 if (retval != NULL)
2707 {
2708 len = 0;
2709 for (i = 0; i < y_current->y_size; ++i)
2710 {
2711 STRCPY(retval + len, y_current->y_array[i]);
2712 len += (long)STRLEN(retval + len);
2713
2714 // Insert a NL between lines and after the last line if y_type is
2715 // MLINE.
2716 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2717 retval[len++] = '\n';
2718 }
2719 retval[len] = NUL;
2720 }
2721
2722 return retval;
2723}
2724
2725 static int
2726init_write_reg(
2727 int name,
2728 yankreg_T **old_y_previous,
2729 yankreg_T **old_y_current,
2730 int must_append,
2731 int *yank_type UNUSED)
2732{
2733 if (!valid_yank_reg(name, TRUE)) // check for valid reg name
2734 {
2735 emsg_invreg(name);
2736 return FAIL;
2737 }
2738
2739 // Don't want to change the current (unnamed) register
2740 *old_y_previous = y_previous;
2741 *old_y_current = y_current;
2742
2743 get_yank_register(name, TRUE);
2744 if (!y_append && !must_append)
2745 free_yank_all();
2746 return OK;
2747}
2748
2749 static void
2750finish_write_reg(
2751 int name,
2752 yankreg_T *old_y_previous,
2753 yankreg_T *old_y_current)
2754{
2755# ifdef FEAT_CLIPBOARD
2756 // Send text of clipboard register to the clipboard.
2757 may_set_selection();
2758# endif
2759
2760 // ':let @" = "val"' should change the meaning of the "" register
2761 if (name != '"')
2762 y_previous = old_y_previous;
2763 y_current = old_y_current;
2764}
2765
2766/*
2767 * Store string "str" in register "name".
2768 * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
2769 * If "must_append" is TRUE, always append to the register. Otherwise append
2770 * if "name" is an uppercase letter.
2771 * Note: "maxlen" and "must_append" don't work for the "/" register.
2772 * Careful: 'str' is modified, you may have to use a copy!
2773 * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise.
2774 */
2775 void
2776write_reg_contents(
2777 int name,
2778 char_u *str,
2779 int maxlen,
2780 int must_append)
2781{
2782 write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
2783}
2784
2785 void
2786write_reg_contents_lst(
2787 int name,
2788 char_u **strings,
2789 int maxlen UNUSED,
2790 int must_append,
2791 int yank_type,
2792 long block_len)
2793{
2794 yankreg_T *old_y_previous, *old_y_current;
2795
2796 if (name == '/' || name == '=')
2797 {
2798 char_u *s;
2799
2800 if (strings[0] == NULL)
2801 s = (char_u *)"";
2802 else if (strings[1] != NULL)
2803 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00002804 emsg(_(e_search_pattern_and_expression_register_may_not_contain_two_or_more_lines));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002805 return;
2806 }
2807 else
2808 s = strings[0];
2809 write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
2810 return;
2811 }
2812
2813 if (name == '_') // black hole: nothing to do
2814 return;
2815
2816 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2817 &yank_type) == FAIL)
2818 return;
2819
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02002820 str_to_reg(y_current, yank_type, (char_u *)strings, -1, block_len, TRUE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002821
2822 finish_write_reg(name, old_y_previous, old_y_current);
2823}
2824
2825 void
2826write_reg_contents_ex(
2827 int name,
2828 char_u *str,
2829 int maxlen,
2830 int must_append,
2831 int yank_type,
2832 long block_len)
2833{
2834 yankreg_T *old_y_previous, *old_y_current;
2835 long len;
2836
2837 if (maxlen >= 0)
2838 len = maxlen;
2839 else
2840 len = (long)STRLEN(str);
2841
2842 // Special case: '/' search pattern
2843 if (name == '/')
2844 {
2845 set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
2846 return;
2847 }
2848
2849 if (name == '#')
2850 {
2851 buf_T *buf;
2852
2853 if (VIM_ISDIGIT(*str))
2854 {
2855 int num = atoi((char *)str);
2856
2857 buf = buflist_findnr(num);
2858 if (buf == NULL)
Bram Moolenaar40bcec12021-12-05 22:19:27 +00002859 semsg(_(e_buffer_nr_does_not_exist), (long)num);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002860 }
2861 else
2862 buf = buflist_findnr(buflist_findpat(str, str + STRLEN(str),
2863 TRUE, FALSE, FALSE));
2864 if (buf == NULL)
2865 return;
2866 curwin->w_alt_fnum = buf->b_fnum;
2867 return;
2868 }
2869
2870 if (name == '=')
2871 {
2872 char_u *p, *s;
2873
Bram Moolenaar71ccd032020-06-12 22:59:11 +02002874 p = vim_strnsave(str, len);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002875 if (p == NULL)
2876 return;
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002877 if (must_append && expr_line != NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002878 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002879 s = concat_str(expr_line, p);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002880 vim_free(p);
2881 p = s;
2882 }
Bram Moolenaarb4bcea42020-10-28 13:53:50 +01002883 set_expr_line(p, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002884 return;
2885 }
2886
2887 if (name == '_') // black hole: nothing to do
2888 return;
2889
2890 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2891 &yank_type) == FAIL)
2892 return;
2893
2894 str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
2895
2896 finish_write_reg(name, old_y_previous, old_y_current);
2897}
2898#endif // FEAT_EVAL
2899
2900#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
2901/*
2902 * Put a string into a register. When the register is not empty, the string
2903 * is appended.
2904 */
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01002905 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002906str_to_reg(
2907 yankreg_T *y_ptr, // pointer to yank register
2908 int yank_type, // MCHAR, MLINE, MBLOCK, MAUTO
2909 char_u *str, // string to put in register
2910 long len, // length of string
2911 long blocklen, // width of Visual block
2912 int str_list) // TRUE if str is char_u **
2913{
2914 int type; // MCHAR, MLINE or MBLOCK
2915 int lnum;
2916 long start;
2917 long i;
2918 int extra;
2919 int newlines; // number of lines added
2920 int extraline = 0; // extra line at the end
2921 int append = FALSE; // append to last line in register
2922 char_u *s;
2923 char_u **ss;
2924 char_u **pp;
2925 long maxlen;
2926
2927 if (y_ptr->y_array == NULL) // NULL means empty register
2928 y_ptr->y_size = 0;
2929
2930 if (yank_type == MAUTO)
2931 type = ((str_list || (len > 0 && (str[len - 1] == NL
2932 || str[len - 1] == CAR)))
2933 ? MLINE : MCHAR);
2934 else
2935 type = yank_type;
2936
2937 // Count the number of lines within the string
2938 newlines = 0;
2939 if (str_list)
2940 {
2941 for (ss = (char_u **) str; *ss != NULL; ++ss)
2942 ++newlines;
2943 }
2944 else
2945 {
2946 for (i = 0; i < len; i++)
2947 if (str[i] == '\n')
2948 ++newlines;
2949 if (type == MCHAR || len == 0 || str[len - 1] != '\n')
2950 {
2951 extraline = 1;
2952 ++newlines; // count extra newline at the end
2953 }
2954 if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR)
2955 {
2956 append = TRUE;
2957 --newlines; // uncount newline when appending first line
2958 }
2959 }
2960
2961 // Without any lines make the register empty.
2962 if (y_ptr->y_size + newlines == 0)
2963 {
2964 VIM_CLEAR(y_ptr->y_array);
2965 return;
2966 }
2967
2968 // Allocate an array to hold the pointers to the new register lines.
2969 // If the register was not empty, move the existing lines to the new array.
2970 pp = lalloc_clear((y_ptr->y_size + newlines) * sizeof(char_u *), TRUE);
2971 if (pp == NULL) // out of memory
2972 return;
2973 for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
2974 pp[lnum] = y_ptr->y_array[lnum];
2975 vim_free(y_ptr->y_array);
2976 y_ptr->y_array = pp;
2977 maxlen = 0;
2978
2979 // Find the end of each line and save it into the array.
2980 if (str_list)
2981 {
2982 for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
2983 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002984 pp[lnum] = vim_strsave(*ss);
2985 if (type == MBLOCK)
2986 {
2987 int charlen = mb_string2cells(*ss, -1);
2988
2989 if (charlen > maxlen)
2990 maxlen = charlen;
2991 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002992 }
2993 }
2994 else
2995 {
2996 for (start = 0; start < len + extraline; start += i + 1)
2997 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002998 int charlen = 0;
2999
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003000 for (i = start; i < len; ++i) // find the end of the line
Bram Moolenaar24951a62021-06-04 18:33:49 +02003001 {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003002 if (str[i] == '\n')
3003 break;
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02003004 if (type == MBLOCK)
3005 charlen += mb_ptr2cells_len(str + i, len - i);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003006 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003007 i -= start; // i is now length of line
Bram Moolenaar6e0b5532021-06-04 17:11:47 +02003008 if (charlen > maxlen)
3009 maxlen = charlen;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003010 if (append)
3011 {
3012 --lnum;
3013 extra = (int)STRLEN(y_ptr->y_array[lnum]);
3014 }
3015 else
3016 extra = 0;
3017 s = alloc(i + extra + 1);
3018 if (s == NULL)
3019 break;
3020 if (extra)
3021 mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
3022 if (append)
3023 vim_free(y_ptr->y_array[lnum]);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003024 if (i > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003025 mch_memmove(s + extra, str + start, (size_t)i);
3026 extra += i;
3027 s[extra] = NUL;
3028 y_ptr->y_array[lnum++] = s;
3029 while (--extra >= 0)
3030 {
3031 if (*s == NUL)
3032 *s = '\n'; // replace NUL with newline
3033 ++s;
3034 }
3035 append = FALSE; // only first line is appended
3036 }
3037 }
3038 y_ptr->y_type = type;
3039 y_ptr->y_size = lnum;
3040 if (type == MBLOCK)
3041 y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
3042 else
3043 y_ptr->y_width = 0;
3044# ifdef FEAT_VIMINFO
3045 y_ptr->y_time_set = vim_time();
3046# endif
3047}
3048#endif // FEAT_CLIPBOARD || FEAT_EVAL || PROTO