blob: 9a5e11b9ceb1be2bd816a6eed3736c7ee05c9a11 [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
900#ifdef FEAT_SEARCHPATH
901 case Ctrl_F: // Filename under cursor
902 case Ctrl_P: // Path under cursor, expand via "path"
903 if (!errmsg)
904 return FALSE;
905 *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP
906 | (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL);
907 *allocated = TRUE;
908 return TRUE;
909#endif
910
911 case Ctrl_W: // word under cursor
912 case Ctrl_A: // WORD (mnemonic All) under cursor
913 if (!errmsg)
914 return FALSE;
915 cnt = find_ident_under_cursor(argp, regname == Ctrl_W
916 ? (FIND_IDENT|FIND_STRING) : FIND_STRING);
917 *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
918 *allocated = TRUE;
919 return TRUE;
920
921 case Ctrl_L: // Line under cursor
922 if (!errmsg)
923 return FALSE;
924
925 *argp = ml_get_buf(curwin->w_buffer,
926 curwin->w_cursor.lnum, FALSE);
927 return TRUE;
928
929 case '_': // black hole: always empty
930 *argp = (char_u *)"";
931 return TRUE;
932 }
933
934 return FALSE;
935}
936
937/*
938 * Paste a yank register into the command line.
939 * Only for non-special registers.
940 * Used by CTRL-R command in command-line mode
941 * insert_reg() can't be used here, because special characters from the
942 * register contents will be interpreted as commands.
943 *
944 * return FAIL for failure, OK otherwise
945 */
946 int
947cmdline_paste_reg(
948 int regname,
949 int literally_arg, // Insert text literally instead of "as typed"
950 int remcr) // don't add CR characters
951{
952 long i;
953 int literally = literally_arg;
954
955 if (get_yank_register(regname, FALSE))
956 literally = TRUE;
957 if (y_current->y_array == NULL)
958 return FAIL;
959
960 for (i = 0; i < y_current->y_size; ++i)
961 {
962 cmdline_paste_str(y_current->y_array[i], literally);
963
964 // Insert ^M between lines and after last line if type is MLINE.
965 // Don't do this when "remcr" is TRUE.
966 if ((y_current->y_type == MLINE || i < y_current->y_size - 1) && !remcr)
967 cmdline_paste_str((char_u *)"\r", literally);
968
969 // Check for CTRL-C, in case someone tries to paste a few thousand
970 // lines and gets bored.
971 ui_breakcheck();
972 if (got_int)
973 return FAIL;
974 }
975 return OK;
976}
977
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200978/*
979 * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
980 */
981 void
982shift_delete_registers()
983{
984 int n;
985
986 y_current = &y_regs[9];
987 free_yank_all(); // free register nine
988 for (n = 9; n > 1; --n)
989 y_regs[n] = y_regs[n - 1];
990 y_current = &y_regs[1];
991 if (!y_append)
992 y_previous = y_current;
993 y_regs[1].y_array = NULL; // set register one to empty
994}
995
996#if defined(FEAT_EVAL)
997 void
998yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
999{
Bram Moolenaar3075a452021-11-17 15:51:52 +00001000 static int recursive = FALSE;
1001 dict_T *v_event;
1002 list_T *list;
1003 int n;
1004 char_u buf[NUMBUFLEN + 2];
1005 long reglen = 0;
1006 save_v_event_T save_v_event;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001007
1008 if (recursive)
1009 return;
1010
Bram Moolenaar3075a452021-11-17 15:51:52 +00001011 v_event = get_v_event(&save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001012
1013 list = list_alloc();
1014 if (list == NULL)
1015 return;
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001016
1017 // yanked text contents
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001018 for (n = 0; n < reg->y_size; n++)
1019 list_append_string(list, reg->y_array[n], -1);
1020 list->lv_lock = VAR_FIXED;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001021 (void)dict_add_list(v_event, "regcontents", list);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001022
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001023 // register name or empty string for unnamed operation
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001024 buf[0] = (char_u)oap->regname;
1025 buf[1] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001026 (void)dict_add_string(v_event, "regname", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001027
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001028 // motion type: inclusive or exclusive
1029 (void)dict_add_bool(v_event, "inclusive", oap->inclusive);
1030
1031 // kind of operation (yank, delete, change)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001032 buf[0] = get_op_char(oap->op_type);
1033 buf[1] = get_extra_op_char(oap->op_type);
1034 buf[2] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001035 (void)dict_add_string(v_event, "operator", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001036
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001037 // register type
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001038 buf[0] = NUL;
1039 buf[1] = NUL;
1040 switch (get_reg_type(oap->regname, &reglen))
1041 {
1042 case MLINE: buf[0] = 'V'; break;
1043 case MCHAR: buf[0] = 'v'; break;
1044 case MBLOCK:
1045 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
1046 reglen + 1);
1047 break;
1048 }
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001049 (void)dict_add_string(v_event, "regtype", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001050
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001051 // selection type - visual or not
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001052 (void)dict_add_bool(v_event, "visual", oap->is_VIsual);
Bram Moolenaar37d16732020-06-12 22:09:01 +02001053
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001054 // Lock the dictionary and its keys
1055 dict_set_items_ro(v_event);
1056
1057 recursive = TRUE;
zeertzjqcfe45652022-05-27 17:26:55 +01001058 textlock++;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001059 apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
zeertzjqcfe45652022-05-27 17:26:55 +01001060 textlock--;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001061 recursive = FALSE;
1062
1063 // Empty the dictionary, v:event is still valid
Bram Moolenaar3075a452021-11-17 15:51:52 +00001064 restore_v_event(v_event, &save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001065}
1066#endif
1067
1068/*
1069 * set all the yank registers to empty (called from main())
1070 */
1071 void
1072init_yank(void)
1073{
1074 int i;
1075
1076 for (i = 0; i < NUM_REGISTERS; ++i)
1077 y_regs[i].y_array = NULL;
1078}
1079
1080#if defined(EXITFREE) || defined(PROTO)
1081 void
1082clear_registers(void)
1083{
1084 int i;
1085
1086 for (i = 0; i < NUM_REGISTERS; ++i)
1087 {
1088 y_current = &y_regs[i];
1089 if (y_current->y_array != NULL)
1090 free_yank_all();
1091 }
1092}
1093#endif
1094
1095/*
1096 * Free "n" lines from the current yank register.
1097 * Called for normal freeing and in case of error.
1098 */
1099 static void
1100free_yank(long n)
1101{
1102 if (y_current->y_array != NULL)
1103 {
1104 long i;
1105
1106 for (i = n; --i >= 0; )
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001107 vim_free(y_current->y_array[i]);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001108 VIM_CLEAR(y_current->y_array);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001109 }
1110}
1111
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01001112 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001113free_yank_all(void)
1114{
1115 free_yank(y_current->y_size);
1116}
1117
1118/*
1119 * Yank the text between "oap->start" and "oap->end" into a yank register.
1120 * If we are to append (uppercase register), we first yank into a new yank
1121 * register and then concatenate the old and the new one (so we keep the old
1122 * one in case of out-of-memory).
1123 *
1124 * Return FAIL for failure, OK otherwise.
1125 */
1126 int
1127op_yank(oparg_T *oap, int deleting, int mess)
1128{
1129 long y_idx; // index in y_array[]
1130 yankreg_T *curr; // copy of y_current
1131 yankreg_T newreg; // new yank register when appending
1132 char_u **new_ptr;
1133 linenr_T lnum; // current line number
1134 long j;
1135 int yanktype = oap->motion_type;
1136 long yanklines = oap->line_count;
1137 linenr_T yankendlnum = oap->end.lnum;
1138 char_u *p;
1139 char_u *pnew;
1140 struct block_def bd;
1141#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1142 int did_star = FALSE;
1143#endif
1144
1145 // check for read-only register
1146 if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
1147 {
1148 beep_flush();
1149 return FAIL;
1150 }
1151 if (oap->regname == '_') // black hole: nothing to do
1152 return OK;
1153
1154#ifdef FEAT_CLIPBOARD
1155 if (!clip_star.available && oap->regname == '*')
1156 oap->regname = 0;
1157 else if (!clip_plus.available && oap->regname == '+')
1158 oap->regname = 0;
1159#endif
1160
1161 if (!deleting) // op_delete() already set y_current
1162 get_yank_register(oap->regname, TRUE);
1163
1164 curr = y_current;
1165 // append to existing contents
1166 if (y_append && y_current->y_array != NULL)
1167 y_current = &newreg;
1168 else
1169 free_yank_all(); // free previously yanked lines
1170
1171 // If the cursor was in column 1 before and after the movement, and the
1172 // operator is not inclusive, the yank is always linewise.
1173 if ( oap->motion_type == MCHAR
1174 && oap->start.col == 0
1175 && !oap->inclusive
1176 && (!oap->is_VIsual || *p_sel == 'o')
1177 && !oap->block_mode
1178 && oap->end.col == 0
1179 && yanklines > 1)
1180 {
1181 yanktype = MLINE;
1182 --yankendlnum;
1183 --yanklines;
1184 }
1185
1186 y_current->y_size = yanklines;
1187 y_current->y_type = yanktype; // set the yank register type
1188 y_current->y_width = 0;
1189 y_current->y_array = lalloc_clear(sizeof(char_u *) * yanklines, TRUE);
1190 if (y_current->y_array == NULL)
1191 {
1192 y_current = curr;
1193 return FAIL;
1194 }
1195#ifdef FEAT_VIMINFO
1196 y_current->y_time_set = vim_time();
1197#endif
1198
1199 y_idx = 0;
1200 lnum = oap->start.lnum;
1201
1202 if (oap->block_mode)
1203 {
1204 // Visual block mode
1205 y_current->y_type = MBLOCK; // set the yank register type
1206 y_current->y_width = oap->end_vcol - oap->start_vcol;
1207
1208 if (curwin->w_curswant == MAXCOL && y_current->y_width > 0)
1209 y_current->y_width--;
1210 }
1211
1212 for ( ; lnum <= yankendlnum; lnum++, y_idx++)
1213 {
1214 switch (y_current->y_type)
1215 {
1216 case MBLOCK:
1217 block_prep(oap, &bd, lnum, FALSE);
Christian Brabandt544a38e2021-06-10 19:39:11 +02001218 if (yank_copy_line(&bd, y_idx, oap->excl_tr_ws) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001219 goto fail;
1220 break;
1221
1222 case MLINE:
1223 if ((y_current->y_array[y_idx] =
Christian Brabandt544a38e2021-06-10 19:39:11 +02001224 vim_strsave(ml_get(lnum))) == NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001225 goto fail;
1226 break;
1227
1228 case MCHAR:
1229 {
1230 colnr_T startcol = 0, endcol = MAXCOL;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001231 int is_oneChar = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001232 colnr_T cs, ce;
1233
1234 p = ml_get(lnum);
1235 bd.startspaces = 0;
1236 bd.endspaces = 0;
1237
1238 if (lnum == oap->start.lnum)
1239 {
1240 startcol = oap->start.col;
1241 if (virtual_op)
1242 {
1243 getvcol(curwin, &oap->start, &cs, NULL, &ce);
1244 if (ce != cs && oap->start.coladd > 0)
1245 {
1246 // Part of a tab selected -- but don't
1247 // double-count it.
1248 bd.startspaces = (ce - cs + 1)
1249 - oap->start.coladd;
1250 startcol++;
1251 }
1252 }
1253 }
1254
1255 if (lnum == oap->end.lnum)
1256 {
1257 endcol = oap->end.col;
1258 if (virtual_op)
1259 {
1260 getvcol(curwin, &oap->end, &cs, NULL, &ce);
1261 if (p[endcol] == NUL || (cs + oap->end.coladd < ce
1262 // Don't add space for double-wide
1263 // char; endcol will be on last byte
1264 // of multi-byte char.
1265 && (*mb_head_off)(p, p + endcol) == 0))
1266 {
1267 if (oap->start.lnum == oap->end.lnum
1268 && oap->start.col == oap->end.col)
1269 {
1270 // Special case: inside a single char
1271 is_oneChar = TRUE;
1272 bd.startspaces = oap->end.coladd
1273 - oap->start.coladd + oap->inclusive;
1274 endcol = startcol;
1275 }
1276 else
1277 {
1278 bd.endspaces = oap->end.coladd
1279 + oap->inclusive;
1280 endcol -= oap->inclusive;
1281 }
1282 }
1283 }
1284 }
1285 if (endcol == MAXCOL)
1286 endcol = (colnr_T)STRLEN(p);
1287 if (startcol > endcol || is_oneChar)
1288 bd.textlen = 0;
1289 else
1290 bd.textlen = endcol - startcol + oap->inclusive;
1291 bd.textstart = p + startcol;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001292 if (yank_copy_line(&bd, y_idx, FALSE) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001293 goto fail;
1294 break;
1295 }
1296 // NOTREACHED
1297 }
1298 }
1299
1300 if (curr != y_current) // append the new block to the old block
1301 {
1302 new_ptr = ALLOC_MULT(char_u *, curr->y_size + y_current->y_size);
1303 if (new_ptr == NULL)
1304 goto fail;
1305 for (j = 0; j < curr->y_size; ++j)
1306 new_ptr[j] = curr->y_array[j];
1307 vim_free(curr->y_array);
1308 curr->y_array = new_ptr;
1309#ifdef FEAT_VIMINFO
1310 curr->y_time_set = vim_time();
1311#endif
1312
1313 if (yanktype == MLINE) // MLINE overrides MCHAR and MBLOCK
1314 curr->y_type = MLINE;
1315
1316 // Concatenate the last line of the old block with the first line of
1317 // the new block, unless being Vi compatible.
1318 if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL)
1319 {
1320 pnew = alloc(STRLEN(curr->y_array[curr->y_size - 1])
1321 + STRLEN(y_current->y_array[0]) + 1);
1322 if (pnew == NULL)
1323 {
1324 y_idx = y_current->y_size - 1;
1325 goto fail;
1326 }
1327 STRCPY(pnew, curr->y_array[--j]);
1328 STRCAT(pnew, y_current->y_array[0]);
1329 vim_free(curr->y_array[j]);
1330 vim_free(y_current->y_array[0]);
1331 curr->y_array[j++] = pnew;
1332 y_idx = 1;
1333 }
1334 else
1335 y_idx = 0;
1336 while (y_idx < y_current->y_size)
1337 curr->y_array[j++] = y_current->y_array[y_idx++];
1338 curr->y_size = j;
1339 vim_free(y_current->y_array);
1340 y_current = curr;
1341 }
zeertzjq95d2e762022-03-19 11:42:16 +00001342
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001343 if (mess) // Display message about yank?
1344 {
1345 if (yanktype == MCHAR
1346 && !oap->block_mode
1347 && yanklines == 1)
1348 yanklines = 0;
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001349 // Some versions of Vi use ">=" here, some don't...
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001350 if (yanklines > p_report)
1351 {
1352 char namebuf[100];
1353
1354 if (oap->regname == NUL)
1355 *namebuf = NUL;
1356 else
1357 vim_snprintf(namebuf, sizeof(namebuf),
1358 _(" into \"%c"), oap->regname);
1359
1360 // redisplay now, so message is not deleted
1361 update_topline_redraw();
1362 if (oap->block_mode)
1363 {
1364 smsg(NGETTEXT("block of %ld line yanked%s",
1365 "block of %ld lines yanked%s", yanklines),
1366 yanklines, namebuf);
1367 }
1368 else
1369 {
1370 smsg(NGETTEXT("%ld line yanked%s",
1371 "%ld lines yanked%s", yanklines),
1372 yanklines, namebuf);
1373 }
1374 }
1375 }
1376
Bram Moolenaare1004402020-10-24 20:49:43 +02001377 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001378 {
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001379 // Set "'[" and "']" marks.
1380 curbuf->b_op_start = oap->start;
1381 curbuf->b_op_end = oap->end;
1382 if (yanktype == MLINE && !oap->block_mode)
1383 {
1384 curbuf->b_op_start.col = 0;
1385 curbuf->b_op_end.col = MAXCOL;
1386 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001387 }
1388
1389#ifdef FEAT_CLIPBOARD
1390 // If we were yanking to the '*' register, send result to clipboard.
1391 // If no register was specified, and "unnamed" in 'clipboard', make a copy
1392 // to the '*' register.
1393 if (clip_star.available
1394 && (curr == &(y_regs[STAR_REGISTER])
1395 || (!deleting && oap->regname == 0
1396 && ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
1397 {
1398 if (curr != &(y_regs[STAR_REGISTER]))
1399 // Copy the text from register 0 to the clipboard register.
1400 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1401
1402 clip_own_selection(&clip_star);
1403 clip_gen_set_selection(&clip_star);
1404# ifdef FEAT_X11
1405 did_star = TRUE;
1406# endif
1407 }
1408
1409# ifdef FEAT_X11
1410 // If we were yanking to the '+' register, send result to selection.
Bram Moolenaar37096af2021-03-02 19:04:11 +01001411 // Also copy to the '*' register, in case auto-select is off. But not when
1412 // 'clipboard' has "unnamedplus" and not "unnamed".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001413 if (clip_plus.available
1414 && (curr == &(y_regs[PLUS_REGISTER])
1415 || (!deleting && oap->regname == 0
1416 && ((clip_unnamed | clip_unnamed_saved) &
Bram Moolenaar37096af2021-03-02 19:04:11 +01001417 CLIP_UNNAMED_PLUS))))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001418 {
1419 if (curr != &(y_regs[PLUS_REGISTER]))
1420 // Copy the text from register 0 to the clipboard register.
1421 copy_yank_reg(&(y_regs[PLUS_REGISTER]));
1422
1423 clip_own_selection(&clip_plus);
1424 clip_gen_set_selection(&clip_plus);
Bram Moolenaar37096af2021-03-02 19:04:11 +01001425 if (!clip_isautosel_star()
1426 && !clip_isautosel_plus()
1427 && !((clip_unnamed | clip_unnamed_saved) == CLIP_UNNAMED_PLUS)
1428 && !did_star
1429 && curr == &(y_regs[PLUS_REGISTER]))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001430 {
1431 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1432 clip_own_selection(&clip_star);
1433 clip_gen_set_selection(&clip_star);
1434 }
1435 }
1436# endif
1437#endif
1438
1439#if defined(FEAT_EVAL)
1440 if (!deleting && has_textyankpost())
1441 yank_do_autocmd(oap, y_current);
1442#endif
1443
1444 return OK;
1445
1446fail: // free the allocated lines
1447 free_yank(y_idx + 1);
1448 y_current = curr;
1449 return FAIL;
1450}
1451
Christian Brabandt544a38e2021-06-10 19:39:11 +02001452/*
1453 * Copy a block range into a register.
1454 * If "exclude_trailing_space" is set, do not copy trailing whitespaces.
1455 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001456 static int
Christian Brabandt544a38e2021-06-10 19:39:11 +02001457yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001458{
1459 char_u *pnew;
1460
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02001461 if (exclude_trailing_space)
1462 bd->endspaces = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001463 if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1))
1464 == NULL)
1465 return FAIL;
1466 y_current->y_array[y_idx] = pnew;
1467 vim_memset(pnew, ' ', (size_t)bd->startspaces);
1468 pnew += bd->startspaces;
1469 mch_memmove(pnew, bd->textstart, (size_t)bd->textlen);
1470 pnew += bd->textlen;
1471 vim_memset(pnew, ' ', (size_t)bd->endspaces);
1472 pnew += bd->endspaces;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001473 if (exclude_trailing_space)
1474 {
1475 int s = bd->textlen + bd->endspaces;
1476
Bram Moolenaar44db8212022-01-25 21:26:17 +00001477 while (s > 0 && VIM_ISWHITE(*(bd->textstart + s - 1)))
Christian Brabandt544a38e2021-06-10 19:39:11 +02001478 {
1479 s = s - (*mb_head_off)(bd->textstart, bd->textstart + s - 1) - 1;
1480 pnew--;
1481 }
1482 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001483 *pnew = NUL;
1484 return OK;
1485}
1486
1487#ifdef FEAT_CLIPBOARD
1488/*
1489 * Make a copy of the y_current register to register "reg".
1490 */
1491 static void
1492copy_yank_reg(yankreg_T *reg)
1493{
1494 yankreg_T *curr = y_current;
1495 long j;
1496
1497 y_current = reg;
1498 free_yank_all();
1499 *y_current = *curr;
1500 y_current->y_array = lalloc_clear(
1501 sizeof(char_u *) * y_current->y_size, TRUE);
1502 if (y_current->y_array == NULL)
1503 y_current->y_size = 0;
1504 else
1505 for (j = 0; j < y_current->y_size; ++j)
1506 if ((y_current->y_array[j] = vim_strsave(curr->y_array[j])) == NULL)
1507 {
1508 free_yank(j);
1509 y_current->y_size = 0;
1510 break;
1511 }
1512 y_current = curr;
1513}
1514#endif
1515
1516/*
1517 * Put contents of register "regname" into the text.
1518 * Caller must check "regname" to be valid!
1519 * "flags": PUT_FIXINDENT make indent look nice
1520 * PUT_CURSEND leave cursor after end of new text
1521 * PUT_LINE force linewise put (":put")
Christian Brabandt2fa93842021-05-30 22:17:25 +02001522 * PUT_BLOCK_INNER in block mode, do not add trailing spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001523 */
1524 void
1525do_put(
1526 int regname,
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001527 char_u *expr_result, // result for regname "=" when compiled
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001528 int dir, // BACKWARD for 'P', FORWARD for 'p'
1529 long count,
1530 int flags)
1531{
1532 char_u *ptr;
1533 char_u *newp, *oldp;
1534 int yanklen;
1535 int totlen = 0; // init for gcc
1536 linenr_T lnum;
1537 colnr_T col;
1538 long i; // index in y_array[]
1539 int y_type;
1540 long y_size;
1541 int oldlen;
1542 long y_width = 0;
1543 colnr_T vcol;
1544 int delcount;
1545 int incr = 0;
1546 long j;
1547 struct block_def bd;
1548 char_u **y_array = NULL;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001549 yankreg_T *y_current_used = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001550 long nr_lines = 0;
1551 pos_T new_cursor;
1552 int indent;
1553 int orig_indent = 0; // init for gcc
1554 int indent_diff = 0; // init for gcc
1555 int first_indent = TRUE;
1556 int lendiff = 0;
1557 pos_T old_pos;
1558 char_u *insert_string = NULL;
1559 int allocated = FALSE;
1560 long cnt;
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001561 pos_T orig_start = curbuf->b_op_start;
1562 pos_T orig_end = curbuf->b_op_end;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001563 unsigned int cur_ve_flags = get_ve_flags();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001564
1565#ifdef FEAT_CLIPBOARD
1566 // Adjust register name for "unnamed" in 'clipboard'.
1567 adjust_clip_reg(&regname);
1568 (void)may_get_selection(regname);
1569#endif
1570
1571 if (flags & PUT_FIXINDENT)
1572 orig_indent = get_indent();
1573
1574 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1575 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1576
1577 // Using inserted text works differently, because the register includes
1578 // special characters (newlines, etc.).
1579 if (regname == '.')
1580 {
1581 if (VIsual_active)
1582 stuffcharReadbuff(VIsual_mode);
1583 (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
1584 (count == -1 ? 'O' : 'i')), count, FALSE);
1585 // Putting the text is done later, so can't really move the cursor to
1586 // the next character. Use "l" to simulate it.
1587 if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
1588 stuffcharReadbuff('l');
1589 return;
1590 }
1591
1592 // For special registers '%' (file name), '#' (alternate file name) and
1593 // ':' (last command line), etc. we have to create a fake yank register.
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001594 // For compiled code "expr_result" holds the expression result.
1595 if (regname == '=' && expr_result != NULL)
1596 insert_string = expr_result;
1597 else if (get_spec_reg(regname, &insert_string, &allocated, TRUE)
1598 && insert_string == NULL)
1599 return;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001600
1601 // Autocommands may be executed when saving lines for undo. This might
1602 // make "y_array" invalid, so we start undo now to avoid that.
1603 if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL)
1604 goto end;
1605
1606 if (insert_string != NULL)
1607 {
1608 y_type = MCHAR;
1609#ifdef FEAT_EVAL
1610 if (regname == '=')
1611 {
1612 // For the = register we need to split the string at NL
1613 // characters.
1614 // Loop twice: count the number of lines and save them.
1615 for (;;)
1616 {
1617 y_size = 0;
1618 ptr = insert_string;
1619 while (ptr != NULL)
1620 {
1621 if (y_array != NULL)
1622 y_array[y_size] = ptr;
1623 ++y_size;
1624 ptr = vim_strchr(ptr, '\n');
1625 if (ptr != NULL)
1626 {
1627 if (y_array != NULL)
1628 *ptr = NUL;
1629 ++ptr;
1630 // A trailing '\n' makes the register linewise.
1631 if (*ptr == NUL)
1632 {
1633 y_type = MLINE;
1634 break;
1635 }
1636 }
1637 }
1638 if (y_array != NULL)
1639 break;
1640 y_array = ALLOC_MULT(char_u *, y_size);
1641 if (y_array == NULL)
1642 goto end;
1643 }
1644 }
1645 else
1646#endif
1647 {
1648 y_size = 1; // use fake one-line yank register
1649 y_array = &insert_string;
1650 }
1651 }
1652 else
1653 {
1654 get_yank_register(regname, FALSE);
1655
1656 y_type = y_current->y_type;
1657 y_width = y_current->y_width;
1658 y_size = y_current->y_size;
1659 y_array = y_current->y_array;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001660 y_current_used = y_current;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001661 }
1662
1663 if (y_type == MLINE)
1664 {
1665 if (flags & PUT_LINE_SPLIT)
1666 {
1667 char_u *p;
1668
1669 // "p" or "P" in Visual mode: split the lines to put the text in
1670 // between.
1671 if (u_save_cursor() == FAIL)
1672 goto end;
1673 p = ml_get_cursor();
1674 if (dir == FORWARD && *p != NUL)
1675 MB_PTR_ADV(p);
1676 ptr = vim_strsave(p);
1677 if (ptr == NULL)
1678 goto end;
1679 ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE);
1680 vim_free(ptr);
1681
1682 oldp = ml_get_curline();
1683 p = oldp + curwin->w_cursor.col;
1684 if (dir == FORWARD && *p != NUL)
1685 MB_PTR_ADV(p);
1686 ptr = vim_strnsave(oldp, p - oldp);
1687 if (ptr == NULL)
1688 goto end;
1689 ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
1690 ++nr_lines;
1691 dir = FORWARD;
1692 }
1693 if (flags & PUT_LINE_FORWARD)
1694 {
1695 // Must be "p" for a Visual block, put lines below the block.
1696 curwin->w_cursor = curbuf->b_visual.vi_end;
1697 dir = FORWARD;
1698 }
1699 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1700 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1701 }
1702
1703 if (flags & PUT_LINE) // :put command or "p" in Visual line mode.
1704 y_type = MLINE;
1705
1706 if (y_size == 0 || y_array == NULL)
1707 {
Bram Moolenaarac78dd42022-01-02 19:25:26 +00001708 semsg(_(e_nothing_in_register_str),
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001709 regname == 0 ? (char_u *)"\"" : transchar(regname));
1710 goto end;
1711 }
1712
1713 if (y_type == MBLOCK)
1714 {
1715 lnum = curwin->w_cursor.lnum + y_size + 1;
1716 if (lnum > curbuf->b_ml.ml_line_count)
1717 lnum = curbuf->b_ml.ml_line_count + 1;
1718 if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
1719 goto end;
1720 }
1721 else if (y_type == MLINE)
1722 {
1723 lnum = curwin->w_cursor.lnum;
1724#ifdef FEAT_FOLDING
1725 // Correct line number for closed fold. Don't move the cursor yet,
1726 // u_save() uses it.
1727 if (dir == BACKWARD)
1728 (void)hasFolding(lnum, &lnum, NULL);
1729 else
1730 (void)hasFolding(lnum, NULL, &lnum);
1731#endif
1732 if (dir == FORWARD)
1733 ++lnum;
1734 // In an empty buffer the empty line is going to be replaced, include
1735 // it in the saved lines.
1736 if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL)
1737 goto end;
1738#ifdef FEAT_FOLDING
1739 if (dir == FORWARD)
1740 curwin->w_cursor.lnum = lnum - 1;
1741 else
1742 curwin->w_cursor.lnum = lnum;
1743 curbuf->b_op_start = curwin->w_cursor; // for mark_adjust()
1744#endif
1745 }
1746 else if (u_save_cursor() == FAIL)
1747 goto end;
1748
1749 yanklen = (int)STRLEN(y_array[0]);
1750
Gary Johnson53ba05b2021-07-26 22:19:10 +02001751 if (cur_ve_flags == VE_ALL && y_type == MCHAR)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001752 {
1753 if (gchar_cursor() == TAB)
1754 {
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001755 int viscol = getviscol();
1756 int ts = curbuf->b_p_ts;
1757
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001758 // Don't need to insert spaces when "p" on the last position of a
1759 // tab or "P" on the first position.
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001760 if (dir == FORWARD ?
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001761#ifdef FEAT_VARTABS
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001762 tabstop_padding(viscol, ts, curbuf->b_p_vts_array) != 1
1763#else
1764 ts - (viscol % ts) != 1
1765#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001766 : curwin->w_cursor.coladd > 0)
1767 coladvance_force(viscol);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001768 else
1769 curwin->w_cursor.coladd = 0;
1770 }
1771 else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
1772 coladvance_force(getviscol() + (dir == FORWARD));
1773 }
1774
1775 lnum = curwin->w_cursor.lnum;
1776 col = curwin->w_cursor.col;
1777
1778 // Block mode
1779 if (y_type == MBLOCK)
1780 {
1781 int c = gchar_cursor();
1782 colnr_T endcol2 = 0;
1783
1784 if (dir == FORWARD && c != NUL)
1785 {
Gary Johnson53ba05b2021-07-26 22:19:10 +02001786 if (cur_ve_flags == VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001787 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1788 else
1789 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
1790
1791 if (has_mbyte)
1792 // move to start of next multi-byte character
1793 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
1794 else
Gary Johnson53ba05b2021-07-26 22:19:10 +02001795 if (c != TAB || cur_ve_flags != VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001796 ++curwin->w_cursor.col;
1797 ++col;
1798 }
1799 else
1800 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1801
1802 col += curwin->w_cursor.coladd;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001803 if (cur_ve_flags == VE_ALL
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001804 && (curwin->w_cursor.coladd > 0
1805 || endcol2 == curwin->w_cursor.col))
1806 {
1807 if (dir == FORWARD && c == NUL)
1808 ++col;
Bram Moolenaaref85a9b2020-07-10 20:24:07 +02001809 if (dir != FORWARD && c != NUL && curwin->w_cursor.coladd > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001810 ++curwin->w_cursor.col;
1811 if (c == TAB)
1812 {
1813 if (dir == BACKWARD && curwin->w_cursor.col)
1814 curwin->w_cursor.col--;
1815 if (dir == FORWARD && col - 1 == endcol2)
1816 curwin->w_cursor.col++;
1817 }
1818 }
1819 curwin->w_cursor.coladd = 0;
1820 bd.textcol = 0;
1821 for (i = 0; i < y_size; ++i)
1822 {
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001823 int spaces = 0;
1824 char shortline;
1825 chartabsize_T cts;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001826
1827 bd.startspaces = 0;
1828 bd.endspaces = 0;
1829 vcol = 0;
1830 delcount = 0;
1831
1832 // add a new line
1833 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
1834 {
1835 if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
1836 (colnr_T)1, FALSE) == FAIL)
1837 break;
1838 ++nr_lines;
1839 }
1840 // get the old line and advance to the position to insert at
1841 oldp = ml_get_curline();
1842 oldlen = (int)STRLEN(oldp);
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001843 init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0,
1844 oldp, oldp);
1845
1846 while (cts.cts_vcol < col && *cts.cts_ptr != NUL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001847 {
1848 // Count a tab for what it's worth (if list mode not on)
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001849 incr = lbr_chartabsize_adv(&cts);
1850 cts.cts_vcol += incr;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001851 }
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001852 vcol = cts.cts_vcol;
1853 ptr = cts.cts_ptr;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001854 bd.textcol = (colnr_T)(ptr - oldp);
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001855 clear_chartabsize_arg(&cts);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001856
1857 shortline = (vcol < col) || (vcol == col && !*ptr) ;
1858
1859 if (vcol < col) // line too short, padd with spaces
1860 bd.startspaces = col - vcol;
1861 else if (vcol > col)
1862 {
1863 bd.endspaces = vcol - col;
1864 bd.startspaces = incr - bd.endspaces;
1865 --bd.textcol;
1866 delcount = 1;
1867 if (has_mbyte)
1868 bd.textcol -= (*mb_head_off)(oldp, oldp + bd.textcol);
1869 if (oldp[bd.textcol] != TAB)
1870 {
1871 // Only a Tab can be split into spaces. Other
1872 // characters will have to be moved to after the
1873 // block, causing misalignment.
1874 delcount = 0;
1875 bd.endspaces = 0;
1876 }
1877 }
1878
1879 yanklen = (int)STRLEN(y_array[i]);
1880
Christian Brabandt2fa93842021-05-30 22:17:25 +02001881 if ((flags & PUT_BLOCK_INNER) == 0)
1882 {
1883 // calculate number of spaces required to fill right side of
1884 // block
1885 spaces = y_width + 1;
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001886 init_chartabsize_arg(&cts, curwin, 0, 0,
1887 y_array[i], y_array[i]);
Christian Brabandt2fa93842021-05-30 22:17:25 +02001888 for (j = 0; j < yanklen; j++)
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001889 {
1890 spaces -= lbr_chartabsize(&cts);
1891 ++cts.cts_ptr;
1892 cts.cts_vcol = 0;
1893 }
1894 clear_chartabsize_arg(&cts);
Christian Brabandt2fa93842021-05-30 22:17:25 +02001895 if (spaces < 0)
1896 spaces = 0;
1897 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001898
ichizokfa537222021-11-16 12:50:46 +00001899 // Insert the new text.
1900 // First check for multiplication overflow.
1901 if (yanklen + spaces != 0
1902 && count > ((INT_MAX - (bd.startspaces + bd.endspaces))
1903 / (yanklen + spaces)))
1904 {
1905 emsg(_(e_resulting_text_too_long));
1906 break;
1907 }
1908
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001909 totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
1910 newp = alloc(totlen + oldlen + 1);
1911 if (newp == NULL)
1912 break;
ichizokfa537222021-11-16 12:50:46 +00001913
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001914 // copy part up to cursor to new line
1915 ptr = newp;
1916 mch_memmove(ptr, oldp, (size_t)bd.textcol);
1917 ptr += bd.textcol;
ichizokfa537222021-11-16 12:50:46 +00001918
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001919 // may insert some spaces before the new text
1920 vim_memset(ptr, ' ', (size_t)bd.startspaces);
1921 ptr += bd.startspaces;
ichizokfa537222021-11-16 12:50:46 +00001922
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001923 // insert the new text
1924 for (j = 0; j < count; ++j)
1925 {
1926 mch_memmove(ptr, y_array[i], (size_t)yanklen);
1927 ptr += yanklen;
1928
1929 // insert block's trailing spaces only if there's text behind
1930 if ((j < count - 1 || !shortline) && spaces)
1931 {
1932 vim_memset(ptr, ' ', (size_t)spaces);
1933 ptr += spaces;
1934 }
Bram Moolenaard25f0032022-06-30 12:30:19 +01001935 else
1936 totlen -= spaces; // didn't use these spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001937 }
ichizokfa537222021-11-16 12:50:46 +00001938
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001939 // may insert some spaces after the new text
1940 vim_memset(ptr, ' ', (size_t)bd.endspaces);
1941 ptr += bd.endspaces;
ichizokfa537222021-11-16 12:50:46 +00001942
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001943 // move the text after the cursor to the end of the line.
1944 mch_memmove(ptr, oldp + bd.textcol + delcount,
1945 (size_t)(oldlen - bd.textcol - delcount + 1));
1946 ml_replace(curwin->w_cursor.lnum, newp, FALSE);
1947
1948 ++curwin->w_cursor.lnum;
1949 if (i == 0)
1950 curwin->w_cursor.col += bd.startspaces;
1951 }
1952
1953 changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines);
1954
1955 // Set '[ mark.
1956 curbuf->b_op_start = curwin->w_cursor;
1957 curbuf->b_op_start.lnum = lnum;
1958
1959 // adjust '] mark
1960 curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
1961 curbuf->b_op_end.col = bd.textcol + totlen - 1;
1962 curbuf->b_op_end.coladd = 0;
1963 if (flags & PUT_CURSEND)
1964 {
1965 colnr_T len;
1966
1967 curwin->w_cursor = curbuf->b_op_end;
1968 curwin->w_cursor.col++;
1969
1970 // in Insert mode we might be after the NUL, correct for that
1971 len = (colnr_T)STRLEN(ml_get_curline());
1972 if (curwin->w_cursor.col > len)
1973 curwin->w_cursor.col = len;
1974 }
1975 else
1976 curwin->w_cursor.lnum = lnum;
1977 }
1978 else
1979 {
1980 // Character or Line mode
1981 if (y_type == MCHAR)
1982 {
1983 // if type is MCHAR, FORWARD is the same as BACKWARD on the next
1984 // char
1985 if (dir == FORWARD && gchar_cursor() != NUL)
1986 {
1987 if (has_mbyte)
1988 {
1989 int bytelen = (*mb_ptr2len)(ml_get_cursor());
1990
1991 // put it on the next of the multi-byte character.
1992 col += bytelen;
1993 if (yanklen)
1994 {
1995 curwin->w_cursor.col += bytelen;
1996 curbuf->b_op_end.col += bytelen;
1997 }
1998 }
1999 else
2000 {
2001 ++col;
2002 if (yanklen)
2003 {
2004 ++curwin->w_cursor.col;
2005 ++curbuf->b_op_end.col;
2006 }
2007 }
2008 }
2009 curbuf->b_op_start = curwin->w_cursor;
2010 }
2011 // Line mode: BACKWARD is the same as FORWARD on the previous line
2012 else if (dir == BACKWARD)
2013 --lnum;
2014 new_cursor = curwin->w_cursor;
2015
Bram Moolenaarcd942772020-08-22 21:08:44 +02002016 // simple case: insert into one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002017 if (y_type == MCHAR && y_size == 1)
2018 {
Bram Moolenaarcd942772020-08-22 21:08:44 +02002019 linenr_T end_lnum = 0; // init for gcc
2020 linenr_T start_lnum = lnum;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002021 int first_byte_off = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002022
2023 if (VIsual_active)
2024 {
2025 end_lnum = curbuf->b_visual.vi_end.lnum;
2026 if (end_lnum < curbuf->b_visual.vi_start.lnum)
2027 end_lnum = curbuf->b_visual.vi_start.lnum;
Bram Moolenaarcd942772020-08-22 21:08:44 +02002028 if (end_lnum > start_lnum)
2029 {
2030 pos_T pos;
2031
2032 // "col" is valid for the first line, in following lines
2033 // the virtual column needs to be used. Matters for
2034 // multi-byte characters.
2035 pos.lnum = lnum;
2036 pos.col = col;
2037 pos.coladd = 0;
2038 getvcol(curwin, &pos, NULL, &vcol, NULL);
2039 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002040 }
2041
ichizokfa537222021-11-16 12:50:46 +00002042 if (count == 0 || yanklen == 0)
2043 {
2044 if (VIsual_active)
2045 lnum = end_lnum;
2046 }
2047 else if (count > INT_MAX / yanklen)
2048 // multiplication overflow
2049 emsg(_(e_resulting_text_too_long));
2050 else
2051 {
Bram Moolenaare551ccf2021-11-02 23:11:00 +00002052 totlen = count * yanklen;
ichizokfa537222021-11-16 12:50:46 +00002053 do {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002054 oldp = ml_get(lnum);
ichizokfa537222021-11-16 12:50:46 +00002055 oldlen = (int)STRLEN(oldp);
Bram Moolenaarcd942772020-08-22 21:08:44 +02002056 if (lnum > start_lnum)
2057 {
2058 pos_T pos;
2059
2060 pos.lnum = lnum;
2061 if (getvpos(&pos, vcol) == OK)
2062 col = pos.col;
2063 else
2064 col = MAXCOL;
2065 }
ichizokfa537222021-11-16 12:50:46 +00002066 if (VIsual_active && col > oldlen)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002067 {
2068 lnum++;
2069 continue;
2070 }
ichizokfa537222021-11-16 12:50:46 +00002071 newp = alloc(totlen + oldlen + 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002072 if (newp == NULL)
2073 goto end; // alloc() gave an error message
2074 mch_memmove(newp, oldp, (size_t)col);
2075 ptr = newp + col;
2076 for (i = 0; i < count; ++i)
2077 {
2078 mch_memmove(ptr, y_array[0], (size_t)yanklen);
2079 ptr += yanklen;
2080 }
2081 STRMOVE(ptr, oldp + col);
2082 ml_replace(lnum, newp, FALSE);
Bram Moolenaar4d072532021-11-25 19:31:15 +00002083
2084 // compute the byte offset for the last character
2085 first_byte_off = mb_head_off(newp, ptr - 1);
2086
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002087 // Place cursor on last putted char.
2088 if (lnum == curwin->w_cursor.lnum)
2089 {
2090 // make sure curwin->w_virtcol is updated
2091 changed_cline_bef_curs();
2092 curwin->w_cursor.col += (colnr_T)(totlen - 1);
2093 }
ichizokfa537222021-11-16 12:50:46 +00002094 if (VIsual_active)
2095 lnum++;
2096 } while (VIsual_active && lnum <= end_lnum);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002097
ichizokfa537222021-11-16 12:50:46 +00002098 if (VIsual_active) // reset lnum to the last visual line
2099 lnum--;
2100 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002101
Bram Moolenaar4d072532021-11-25 19:31:15 +00002102 // put '] at the first byte of the last character
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002103 curbuf->b_op_end = curwin->w_cursor;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002104 curbuf->b_op_end.col -= first_byte_off;
2105
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002106 // For "CTRL-O p" in Insert mode, put cursor after last char
2107 if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
2108 ++curwin->w_cursor.col;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002109 else
2110 curwin->w_cursor.col -= first_byte_off;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002111 changed_bytes(lnum, col);
2112 }
2113 else
2114 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002115 linenr_T new_lnum = new_cursor.lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002116 size_t len;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002117
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002118 // Insert at least one line. When y_type is MCHAR, break the first
2119 // line in two.
2120 for (cnt = 1; cnt <= count; ++cnt)
2121 {
2122 i = 0;
2123 if (y_type == MCHAR)
2124 {
2125 // Split the current line in two at the insert position.
2126 // First insert y_array[size - 1] in front of second line.
2127 // Then append y_array[0] to first line.
2128 lnum = new_cursor.lnum;
2129 ptr = ml_get(lnum) + col;
2130 totlen = (int)STRLEN(y_array[y_size - 1]);
2131 newp = alloc(STRLEN(ptr) + totlen + 1);
2132 if (newp == NULL)
2133 goto error;
2134 STRCPY(newp, y_array[y_size - 1]);
2135 STRCAT(newp, ptr);
2136 // insert second line
2137 ml_append(lnum, newp, (colnr_T)0, FALSE);
Bram Moolenaar23003e52021-09-22 16:37:07 +02002138 ++new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002139 vim_free(newp);
2140
2141 oldp = ml_get(lnum);
2142 newp = alloc(col + yanklen + 1);
2143 if (newp == NULL)
2144 goto error;
2145 // copy first part of line
2146 mch_memmove(newp, oldp, (size_t)col);
2147 // append to first line
2148 mch_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
2149 ml_replace(lnum, newp, FALSE);
2150
2151 curwin->w_cursor.lnum = lnum;
2152 i = 1;
2153 }
2154
2155 for (; i < y_size; ++i)
2156 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002157 if (y_type != MCHAR || i < y_size - 1)
2158 {
2159 if (ml_append(lnum, y_array[i], (colnr_T)0, FALSE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002160 == FAIL)
2161 goto error;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002162 new_lnum++;
2163 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002164 lnum++;
2165 ++nr_lines;
2166 if (flags & PUT_FIXINDENT)
2167 {
2168 old_pos = curwin->w_cursor;
2169 curwin->w_cursor.lnum = lnum;
2170 ptr = ml_get(lnum);
2171 if (cnt == count && i == y_size - 1)
2172 lendiff = (int)STRLEN(ptr);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002173 if (*ptr == '#' && preprocs_left())
2174 indent = 0; // Leave # lines at start
2175 else
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002176 if (*ptr == NUL)
2177 indent = 0; // Ignore empty lines
2178 else if (first_indent)
2179 {
2180 indent_diff = orig_indent - get_indent();
2181 indent = orig_indent;
2182 first_indent = FALSE;
2183 }
2184 else if ((indent = get_indent() + indent_diff) < 0)
2185 indent = 0;
2186 (void)set_indent(indent, 0);
2187 curwin->w_cursor = old_pos;
2188 // remember how many chars were removed
2189 if (cnt == count && i == y_size - 1)
2190 lendiff -= (int)STRLEN(ml_get(lnum));
2191 }
2192 }
Bram Moolenaar23003e52021-09-22 16:37:07 +02002193 if (cnt == 1)
2194 new_lnum = lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002195 }
2196
2197error:
2198 // Adjust marks.
2199 if (y_type == MLINE)
2200 {
2201 curbuf->b_op_start.col = 0;
2202 if (dir == FORWARD)
2203 curbuf->b_op_start.lnum++;
2204 }
2205 // Skip mark_adjust when adding lines after the last one, there
2206 // can't be marks there. But still needed in diff mode.
2207 if (curbuf->b_op_start.lnum + (y_type == MCHAR) - 1 + nr_lines
2208 < curbuf->b_ml.ml_line_count
2209#ifdef FEAT_DIFF
2210 || curwin->w_p_diff
2211#endif
2212 )
2213 mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
2214 (linenr_T)MAXLNUM, nr_lines, 0L);
2215
2216 // note changed text for displaying and folding
2217 if (y_type == MCHAR)
2218 changed_lines(curwin->w_cursor.lnum, col,
2219 curwin->w_cursor.lnum + 1, nr_lines);
2220 else
2221 changed_lines(curbuf->b_op_start.lnum, 0,
2222 curbuf->b_op_start.lnum, nr_lines);
Bram Moolenaar9ac38122021-12-02 18:42:33 +00002223 if (y_current_used != NULL && (y_current_used != y_current
2224 || y_current->y_array != y_array))
2225 {
2226 // Something invoked through changed_lines() has changed the
2227 // yank buffer, e.g. a GUI clipboard callback.
2228 emsg(_(e_yank_register_changed_while_using_it));
2229 goto end;
2230 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002231
Bram Moolenaar4d072532021-11-25 19:31:15 +00002232 // Put the '] mark on the first byte of the last inserted character.
2233 // Correct the length for change in indent.
Bram Moolenaarf47ebf12021-10-19 20:08:45 +01002234 curbuf->b_op_end.lnum = new_lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002235 len = STRLEN(y_array[y_size - 1]);
2236 col = (colnr_T)len - lendiff;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002237 if (col > 1)
Bram Moolenaar2a585c82022-05-25 15:15:38 +01002238 {
2239 curbuf->b_op_end.col = col - 1;
2240 if (len > 0)
2241 curbuf->b_op_end.col -= mb_head_off(y_array[y_size - 1],
Bram Moolenaar85be8562021-11-25 20:40:11 +00002242 y_array[y_size - 1] + len - 1);
Bram Moolenaar2a585c82022-05-25 15:15:38 +01002243 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002244 else
2245 curbuf->b_op_end.col = 0;
2246
2247 if (flags & PUT_CURSLINE)
2248 {
2249 // ":put": put cursor on last inserted line
2250 curwin->w_cursor.lnum = lnum;
2251 beginline(BL_WHITE | BL_FIX);
2252 }
2253 else if (flags & PUT_CURSEND)
2254 {
2255 // put cursor after inserted text
2256 if (y_type == MLINE)
2257 {
2258 if (lnum >= curbuf->b_ml.ml_line_count)
2259 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
2260 else
2261 curwin->w_cursor.lnum = lnum + 1;
2262 curwin->w_cursor.col = 0;
2263 }
2264 else
2265 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002266 curwin->w_cursor.lnum = new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002267 curwin->w_cursor.col = col;
Bram Moolenaar56858e42021-09-22 16:43:59 +02002268 curbuf->b_op_end = curwin->w_cursor;
2269 if (col > 1)
2270 curbuf->b_op_end.col = col - 1;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002271 }
2272 }
2273 else if (y_type == MLINE)
2274 {
2275 // put cursor on first non-blank in first inserted line
2276 curwin->w_cursor.col = 0;
2277 if (dir == FORWARD)
2278 ++curwin->w_cursor.lnum;
2279 beginline(BL_WHITE | BL_FIX);
2280 }
2281 else // put cursor on first inserted character
2282 curwin->w_cursor = new_cursor;
2283 }
2284 }
2285
2286 msgmore(nr_lines);
2287 curwin->w_set_curswant = TRUE;
2288
2289end:
Bram Moolenaare1004402020-10-24 20:49:43 +02002290 if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01002291 {
2292 curbuf->b_op_start = orig_start;
2293 curbuf->b_op_end = orig_end;
2294 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002295 if (allocated)
2296 vim_free(insert_string);
2297 if (regname == '=')
2298 vim_free(y_array);
2299
2300 VIsual_active = FALSE;
2301
2302 // If the cursor is past the end of the line put it at the end.
2303 adjust_cursor_eol();
2304}
2305
2306/*
2307 * Return the character name of the register with the given number.
2308 */
2309 int
2310get_register_name(int num)
2311{
2312 if (num == -1)
2313 return '"';
2314 else if (num < 10)
2315 return num + '0';
2316 else if (num == DELETION_REGISTER)
2317 return '-';
2318#ifdef FEAT_CLIPBOARD
2319 else if (num == STAR_REGISTER)
2320 return '*';
2321 else if (num == PLUS_REGISTER)
2322 return '+';
2323#endif
2324 else
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002325 return num + 'a' - 10;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002326}
2327
Dominique Pelle748b3082022-01-08 12:41:16 +00002328#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002329/*
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002330 * Return the index of the register "" points to.
2331 */
2332 int
2333get_unname_register()
2334{
2335 return y_previous == NULL ? -1 : y_previous - &y_regs[0];
2336}
Dominique Pelle748b3082022-01-08 12:41:16 +00002337#endif
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002338
2339/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002340 * ":dis" and ":registers": Display the contents of the yank registers.
2341 */
2342 void
2343ex_display(exarg_T *eap)
2344{
2345 int i, n;
2346 long j;
2347 char_u *p;
2348 yankreg_T *yb;
2349 int name;
2350 int attr;
2351 char_u *arg = eap->arg;
2352 int clen;
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002353 int type;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002354
2355 if (arg != NULL && *arg == NUL)
2356 arg = NULL;
2357 attr = HL_ATTR(HLF_8);
2358
2359 // Highlight title
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002360 msg_puts_title(_("\nType Name Content"));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002361 for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
2362 {
2363 name = get_register_name(i);
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002364 switch (get_reg_type(name, NULL))
2365 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002366 case MLINE: type = 'l'; break;
2367 case MCHAR: type = 'c'; break;
2368 default: type = 'b'; break;
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002369 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002370 if (arg != NULL && vim_strchr(arg, name) == NULL
2371#ifdef ONE_CLIPBOARD
2372 // Star register and plus register contain the same thing.
2373 && (name != '*' || vim_strchr(arg, '+') == NULL)
2374#endif
2375 )
2376 continue; // did not ask for this register
2377
2378#ifdef FEAT_CLIPBOARD
2379 // Adjust register name for "unnamed" in 'clipboard'.
2380 // When it's a clipboard register, fill it with the current contents
2381 // of the clipboard.
2382 adjust_clip_reg(&name);
2383 (void)may_get_selection(name);
2384#endif
2385
2386 if (i == -1)
2387 {
2388 if (y_previous != NULL)
2389 yb = y_previous;
2390 else
2391 yb = &(y_regs[0]);
2392 }
2393 else
2394 yb = &(y_regs[i]);
2395
2396#ifdef FEAT_EVAL
2397 if (name == MB_TOLOWER(redir_reg)
2398 || (redir_reg == '"' && yb == y_previous))
2399 continue; // do not list register being written to, the
2400 // pointer can be freed
2401#endif
2402
2403 if (yb->y_array != NULL)
2404 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002405 int do_show = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002406
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002407 for (j = 0; !do_show && j < yb->y_size; ++j)
2408 do_show = !message_filtered(yb->y_array[j]);
2409
2410 if (do_show || yb->y_size == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002411 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002412 msg_putchar('\n');
2413 msg_puts(" ");
2414 msg_putchar(type);
2415 msg_puts(" ");
2416 msg_putchar('"');
2417 msg_putchar(name);
2418 msg_puts(" ");
2419
2420 n = (int)Columns - 11;
2421 for (j = 0; j < yb->y_size && n > 1; ++j)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002422 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002423 if (j)
2424 {
2425 msg_puts_attr("^J", attr);
2426 n -= 2;
2427 }
Bram Moolenaarb4ad3b02022-03-30 10:57:45 +01002428 for (p = yb->y_array[j];
2429 *p != NUL && (n -= ptr2cells(p)) >= 0; ++p)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002430 {
2431 clen = (*mb_ptr2len)(p);
2432 msg_outtrans_len(p, clen);
2433 p += clen - 1;
2434 }
2435 }
2436 if (n > 1 && yb->y_type == MLINE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002437 msg_puts_attr("^J", attr);
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002438 out_flush(); // show one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002439 }
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002440 ui_breakcheck();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002441 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002442 }
2443
2444 // display last inserted text
2445 if ((p = get_last_insert()) != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002446 && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
2447 && !message_filtered(p))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002448 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002449 msg_puts("\n c \". ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002450 dis_msg(p, TRUE);
2451 }
2452
2453 // display last command line
2454 if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002455 && !got_int && !message_filtered(last_cmdline))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002456 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002457 msg_puts("\n c \": ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002458 dis_msg(last_cmdline, FALSE);
2459 }
2460
2461 // display current file name
2462 if (curbuf->b_fname != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002463 && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int
2464 && !message_filtered(curbuf->b_fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002465 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002466 msg_puts("\n c \"% ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002467 dis_msg(curbuf->b_fname, FALSE);
2468 }
2469
2470 // display alternate file name
2471 if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
2472 {
2473 char_u *fname;
2474 linenr_T dummy;
2475
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002476 if (buflist_name_nr(0, &fname, &dummy) != FAIL
2477 && !message_filtered(fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002478 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002479 msg_puts("\n c \"# ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002480 dis_msg(fname, FALSE);
2481 }
2482 }
2483
2484 // display last search pattern
2485 if (last_search_pat() != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002486 && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int
2487 && !message_filtered(last_search_pat()))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002488 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002489 msg_puts("\n c \"/ ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002490 dis_msg(last_search_pat(), FALSE);
2491 }
2492
2493#ifdef FEAT_EVAL
2494 // display last used expression
2495 if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002496 && !got_int && !message_filtered(expr_line))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002497 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002498 msg_puts("\n c \"= ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002499 dis_msg(expr_line, FALSE);
2500 }
2501#endif
2502}
2503
2504/*
2505 * display a string for do_dis()
2506 * truncate at end of screen line
2507 */
2508 static void
2509dis_msg(
2510 char_u *p,
2511 int skip_esc) // if TRUE, ignore trailing ESC
2512{
2513 int n;
2514 int l;
2515
2516 n = (int)Columns - 6;
2517 while (*p != NUL
2518 && !(*p == ESC && skip_esc && *(p + 1) == NUL)
2519 && (n -= ptr2cells(p)) >= 0)
2520 {
2521 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
2522 {
2523 msg_outtrans_len(p, l);
2524 p += l;
2525 }
2526 else
2527 msg_outtrans_len(p++, 1);
2528 }
2529 ui_breakcheck();
2530}
2531
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002532#if defined(FEAT_DND) || defined(PROTO)
2533/*
2534 * Replace the contents of the '~' register with str.
2535 */
2536 void
2537dnd_yank_drag_data(char_u *str, long len)
2538{
2539 yankreg_T *curr;
2540
2541 curr = y_current;
2542 y_current = &y_regs[TILDE_REGISTER];
2543 free_yank_all();
2544 str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
2545 y_current = curr;
2546}
2547#endif
2548
2549
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002550/*
2551 * Return the type of a register.
2552 * Used for getregtype()
2553 * Returns MAUTO for error.
2554 */
2555 char_u
2556get_reg_type(int regname, long *reglen)
2557{
2558 switch (regname)
2559 {
2560 case '%': // file name
2561 case '#': // alternate file name
2562 case '=': // expression
2563 case ':': // last command line
2564 case '/': // last search-pattern
2565 case '.': // last inserted text
2566# ifdef FEAT_SEARCHPATH
2567 case Ctrl_F: // Filename under cursor
2568 case Ctrl_P: // Path under cursor, expand via "path"
2569# endif
2570 case Ctrl_W: // word under cursor
2571 case Ctrl_A: // WORD (mnemonic All) under cursor
2572 case '_': // black hole: always empty
2573 return MCHAR;
2574 }
2575
2576# ifdef FEAT_CLIPBOARD
2577 regname = may_get_selection(regname);
2578# endif
2579
2580 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2581 return MAUTO;
2582
2583 get_yank_register(regname, FALSE);
2584
2585 if (y_current->y_array != NULL)
2586 {
2587 if (reglen != NULL && y_current->y_type == MBLOCK)
2588 *reglen = y_current->y_width;
2589 return y_current->y_type;
2590 }
2591 return MAUTO;
2592}
2593
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002594#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002595/*
2596 * When "flags" has GREG_LIST return a list with text "s".
2597 * Otherwise just return "s".
2598 */
2599 static char_u *
2600getreg_wrap_one_line(char_u *s, int flags)
2601{
2602 if (flags & GREG_LIST)
2603 {
2604 list_T *list = list_alloc();
2605
2606 if (list != NULL)
2607 {
2608 if (list_append_string(list, NULL, -1) == FAIL)
2609 {
2610 list_free(list);
2611 return NULL;
2612 }
2613 list->lv_first->li_tv.vval.v_string = s;
2614 }
2615 return (char_u *)list;
2616 }
2617 return s;
2618}
2619
2620/*
Bram Moolenaard672dde2020-02-26 13:43:51 +01002621 * Return the contents of a register as a single allocated string or as a list.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002622 * Used for "@r" in expressions and for getreg().
2623 * Returns NULL for error.
2624 * Flags:
2625 * GREG_NO_EXPR Do not allow expression register
2626 * GREG_EXPR_SRC For the expression register: return expression itself,
2627 * not the result of its evaluation.
Bram Moolenaard672dde2020-02-26 13:43:51 +01002628 * GREG_LIST Return a list of lines instead of a single string.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002629 */
2630 char_u *
2631get_reg_contents(int regname, int flags)
2632{
2633 long i;
2634 char_u *retval;
2635 int allocated;
2636 long len;
2637
2638 // Don't allow using an expression register inside an expression
2639 if (regname == '=')
2640 {
2641 if (flags & GREG_NO_EXPR)
2642 return NULL;
2643 if (flags & GREG_EXPR_SRC)
2644 return getreg_wrap_one_line(get_expr_line_src(), flags);
2645 return getreg_wrap_one_line(get_expr_line(), flags);
2646 }
2647
2648 if (regname == '@') // "@@" is used for unnamed register
2649 regname = '"';
2650
2651 // check for valid regname
2652 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2653 return NULL;
2654
2655# ifdef FEAT_CLIPBOARD
2656 regname = may_get_selection(regname);
2657# endif
2658
2659 if (get_spec_reg(regname, &retval, &allocated, FALSE))
2660 {
2661 if (retval == NULL)
2662 return NULL;
2663 if (allocated)
2664 return getreg_wrap_one_line(retval, flags);
2665 return getreg_wrap_one_line(vim_strsave(retval), flags);
2666 }
2667
2668 get_yank_register(regname, FALSE);
2669 if (y_current->y_array == NULL)
2670 return NULL;
2671
2672 if (flags & GREG_LIST)
2673 {
2674 list_T *list = list_alloc();
2675 int error = FALSE;
2676
2677 if (list == NULL)
2678 return NULL;
2679 for (i = 0; i < y_current->y_size; ++i)
2680 if (list_append_string(list, y_current->y_array[i], -1) == FAIL)
2681 error = TRUE;
2682 if (error)
2683 {
2684 list_free(list);
2685 return NULL;
2686 }
2687 return (char_u *)list;
2688 }
2689
2690 // Compute length of resulting string.
2691 len = 0;
2692 for (i = 0; i < y_current->y_size; ++i)
2693 {
2694 len += (long)STRLEN(y_current->y_array[i]);
2695 // Insert a newline between lines and after last line if
2696 // y_type is MLINE.
2697 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2698 ++len;
2699 }
2700
2701 retval = alloc(len + 1);
2702
2703 // Copy the lines of the yank register into the string.
2704 if (retval != NULL)
2705 {
2706 len = 0;
2707 for (i = 0; i < y_current->y_size; ++i)
2708 {
2709 STRCPY(retval + len, y_current->y_array[i]);
2710 len += (long)STRLEN(retval + len);
2711
2712 // Insert a NL between lines and after the last line if y_type is
2713 // MLINE.
2714 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2715 retval[len++] = '\n';
2716 }
2717 retval[len] = NUL;
2718 }
2719
2720 return retval;
2721}
2722
2723 static int
2724init_write_reg(
2725 int name,
2726 yankreg_T **old_y_previous,
2727 yankreg_T **old_y_current,
2728 int must_append,
2729 int *yank_type UNUSED)
2730{
2731 if (!valid_yank_reg(name, TRUE)) // check for valid reg name
2732 {
2733 emsg_invreg(name);
2734 return FAIL;
2735 }
2736
2737 // Don't want to change the current (unnamed) register
2738 *old_y_previous = y_previous;
2739 *old_y_current = y_current;
2740
2741 get_yank_register(name, TRUE);
2742 if (!y_append && !must_append)
2743 free_yank_all();
2744 return OK;
2745}
2746
2747 static void
2748finish_write_reg(
2749 int name,
2750 yankreg_T *old_y_previous,
2751 yankreg_T *old_y_current)
2752{
2753# ifdef FEAT_CLIPBOARD
2754 // Send text of clipboard register to the clipboard.
2755 may_set_selection();
2756# endif
2757
2758 // ':let @" = "val"' should change the meaning of the "" register
2759 if (name != '"')
2760 y_previous = old_y_previous;
2761 y_current = old_y_current;
2762}
2763
2764/*
2765 * Store string "str" in register "name".
2766 * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
2767 * If "must_append" is TRUE, always append to the register. Otherwise append
2768 * if "name" is an uppercase letter.
2769 * Note: "maxlen" and "must_append" don't work for the "/" register.
2770 * Careful: 'str' is modified, you may have to use a copy!
2771 * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise.
2772 */
2773 void
2774write_reg_contents(
2775 int name,
2776 char_u *str,
2777 int maxlen,
2778 int must_append)
2779{
2780 write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
2781}
2782
2783 void
2784write_reg_contents_lst(
2785 int name,
2786 char_u **strings,
2787 int maxlen UNUSED,
2788 int must_append,
2789 int yank_type,
2790 long block_len)
2791{
2792 yankreg_T *old_y_previous, *old_y_current;
2793
2794 if (name == '/' || name == '=')
2795 {
2796 char_u *s;
2797
2798 if (strings[0] == NULL)
2799 s = (char_u *)"";
2800 else if (strings[1] != NULL)
2801 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00002802 emsg(_(e_search_pattern_and_expression_register_may_not_contain_two_or_more_lines));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002803 return;
2804 }
2805 else
2806 s = strings[0];
2807 write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
2808 return;
2809 }
2810
2811 if (name == '_') // black hole: nothing to do
2812 return;
2813
2814 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2815 &yank_type) == FAIL)
2816 return;
2817
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02002818 str_to_reg(y_current, yank_type, (char_u *)strings, -1, block_len, TRUE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002819
2820 finish_write_reg(name, old_y_previous, old_y_current);
2821}
2822
2823 void
2824write_reg_contents_ex(
2825 int name,
2826 char_u *str,
2827 int maxlen,
2828 int must_append,
2829 int yank_type,
2830 long block_len)
2831{
2832 yankreg_T *old_y_previous, *old_y_current;
2833 long len;
2834
2835 if (maxlen >= 0)
2836 len = maxlen;
2837 else
2838 len = (long)STRLEN(str);
2839
2840 // Special case: '/' search pattern
2841 if (name == '/')
2842 {
2843 set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
2844 return;
2845 }
2846
2847 if (name == '#')
2848 {
2849 buf_T *buf;
2850
2851 if (VIM_ISDIGIT(*str))
2852 {
2853 int num = atoi((char *)str);
2854
2855 buf = buflist_findnr(num);
2856 if (buf == NULL)
Bram Moolenaar40bcec12021-12-05 22:19:27 +00002857 semsg(_(e_buffer_nr_does_not_exist), (long)num);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002858 }
2859 else
2860 buf = buflist_findnr(buflist_findpat(str, str + STRLEN(str),
2861 TRUE, FALSE, FALSE));
2862 if (buf == NULL)
2863 return;
2864 curwin->w_alt_fnum = buf->b_fnum;
2865 return;
2866 }
2867
2868 if (name == '=')
2869 {
2870 char_u *p, *s;
2871
Bram Moolenaar71ccd032020-06-12 22:59:11 +02002872 p = vim_strnsave(str, len);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002873 if (p == NULL)
2874 return;
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002875 if (must_append && expr_line != NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002876 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002877 s = concat_str(expr_line, p);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002878 vim_free(p);
2879 p = s;
2880 }
Bram Moolenaarb4bcea42020-10-28 13:53:50 +01002881 set_expr_line(p, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002882 return;
2883 }
2884
2885 if (name == '_') // black hole: nothing to do
2886 return;
2887
2888 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2889 &yank_type) == FAIL)
2890 return;
2891
2892 str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
2893
2894 finish_write_reg(name, old_y_previous, old_y_current);
2895}
2896#endif // FEAT_EVAL
2897
2898#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
2899/*
2900 * Put a string into a register. When the register is not empty, the string
2901 * is appended.
2902 */
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01002903 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002904str_to_reg(
2905 yankreg_T *y_ptr, // pointer to yank register
2906 int yank_type, // MCHAR, MLINE, MBLOCK, MAUTO
2907 char_u *str, // string to put in register
2908 long len, // length of string
2909 long blocklen, // width of Visual block
2910 int str_list) // TRUE if str is char_u **
2911{
2912 int type; // MCHAR, MLINE or MBLOCK
2913 int lnum;
2914 long start;
2915 long i;
2916 int extra;
2917 int newlines; // number of lines added
2918 int extraline = 0; // extra line at the end
2919 int append = FALSE; // append to last line in register
2920 char_u *s;
2921 char_u **ss;
2922 char_u **pp;
2923 long maxlen;
2924
2925 if (y_ptr->y_array == NULL) // NULL means empty register
2926 y_ptr->y_size = 0;
2927
2928 if (yank_type == MAUTO)
2929 type = ((str_list || (len > 0 && (str[len - 1] == NL
2930 || str[len - 1] == CAR)))
2931 ? MLINE : MCHAR);
2932 else
2933 type = yank_type;
2934
2935 // Count the number of lines within the string
2936 newlines = 0;
2937 if (str_list)
2938 {
2939 for (ss = (char_u **) str; *ss != NULL; ++ss)
2940 ++newlines;
2941 }
2942 else
2943 {
2944 for (i = 0; i < len; i++)
2945 if (str[i] == '\n')
2946 ++newlines;
2947 if (type == MCHAR || len == 0 || str[len - 1] != '\n')
2948 {
2949 extraline = 1;
2950 ++newlines; // count extra newline at the end
2951 }
2952 if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR)
2953 {
2954 append = TRUE;
2955 --newlines; // uncount newline when appending first line
2956 }
2957 }
2958
2959 // Without any lines make the register empty.
2960 if (y_ptr->y_size + newlines == 0)
2961 {
2962 VIM_CLEAR(y_ptr->y_array);
2963 return;
2964 }
2965
2966 // Allocate an array to hold the pointers to the new register lines.
2967 // If the register was not empty, move the existing lines to the new array.
2968 pp = lalloc_clear((y_ptr->y_size + newlines) * sizeof(char_u *), TRUE);
2969 if (pp == NULL) // out of memory
2970 return;
2971 for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
2972 pp[lnum] = y_ptr->y_array[lnum];
2973 vim_free(y_ptr->y_array);
2974 y_ptr->y_array = pp;
2975 maxlen = 0;
2976
2977 // Find the end of each line and save it into the array.
2978 if (str_list)
2979 {
2980 for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
2981 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002982 pp[lnum] = vim_strsave(*ss);
2983 if (type == MBLOCK)
2984 {
2985 int charlen = mb_string2cells(*ss, -1);
2986
2987 if (charlen > maxlen)
2988 maxlen = charlen;
2989 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002990 }
2991 }
2992 else
2993 {
2994 for (start = 0; start < len + extraline; start += i + 1)
2995 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002996 int charlen = 0;
2997
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002998 for (i = start; i < len; ++i) // find the end of the line
Bram Moolenaar24951a62021-06-04 18:33:49 +02002999 {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003000 if (str[i] == '\n')
3001 break;
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02003002 if (type == MBLOCK)
3003 charlen += mb_ptr2cells_len(str + i, len - i);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003004 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003005 i -= start; // i is now length of line
Bram Moolenaar6e0b5532021-06-04 17:11:47 +02003006 if (charlen > maxlen)
3007 maxlen = charlen;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003008 if (append)
3009 {
3010 --lnum;
3011 extra = (int)STRLEN(y_ptr->y_array[lnum]);
3012 }
3013 else
3014 extra = 0;
3015 s = alloc(i + extra + 1);
3016 if (s == NULL)
3017 break;
3018 if (extra)
3019 mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
3020 if (append)
3021 vim_free(y_ptr->y_array[lnum]);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003022 if (i > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003023 mch_memmove(s + extra, str + start, (size_t)i);
3024 extra += i;
3025 s[extra] = NUL;
3026 y_ptr->y_array[lnum++] = s;
3027 while (--extra >= 0)
3028 {
3029 if (*s == NUL)
3030 *s = '\n'; // replace NUL with newline
3031 ++s;
3032 }
3033 append = FALSE; // only first line is appended
3034 }
3035 }
3036 y_ptr->y_type = type;
3037 y_ptr->y_size = lnum;
3038 if (type == MBLOCK)
3039 y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
3040 else
3041 y_ptr->y_width = 0;
3042# ifdef FEAT_VIMINFO
3043 y_ptr->y_time_set = vim_time();
3044# endif
3045}
3046#endif // FEAT_CLIPBOARD || FEAT_EVAL || PROTO