blob: 72d3135395e60196587108c50f9d5b83dba6627a [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
John Marriott18bacc82025-02-26 19:14:06 +010031static int stuff_yank(int, char_u *);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020032static void put_reedit_in_typebuf(int silent);
John Marriott79f6ffd2024-10-31 10:06:54 +010033static int put_in_typebuf(char_u *s, int esc, int colon, int silent);
Christian Brabandt544a38e2021-06-10 19:39:11 +020034static int yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020035#ifdef FEAT_CLIPBOARD
36static void copy_yank_reg(yankreg_T *reg);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020037#endif
38static void dis_msg(char_u *p, int skip_esc);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020039
Dominique Pelle748b3082022-01-08 12:41:16 +000040#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020041 yankreg_T *
42get_y_regs(void)
43{
44 return y_regs;
45}
Dominique Pelle748b3082022-01-08 12:41:16 +000046#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020047
Dominique Pelle748b3082022-01-08 12:41:16 +000048#if defined(FEAT_CLIPBOARD) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020049 yankreg_T *
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010050get_y_register(int reg)
51{
52 return &y_regs[reg];
53}
Dominique Pelle748b3082022-01-08 12:41:16 +000054#endif
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010055
56 yankreg_T *
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020057get_y_current(void)
58{
59 return y_current;
60}
61
62 yankreg_T *
63get_y_previous(void)
64{
65 return y_previous;
66}
67
68 void
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010069set_y_current(yankreg_T *yreg)
70{
71 y_current = yreg;
72}
73
74 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020075set_y_previous(yankreg_T *yreg)
76{
77 y_previous = yreg;
78}
79
Christian Brabandt78eb9cc2021-09-14 18:55:51 +020080 void
81reset_y_append(void)
82{
83 y_append = FALSE;
84}
85
86
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020087#if defined(FEAT_EVAL) || defined(PROTO)
88/*
89 * Keep the last expression line here, for repeating.
90 */
91static char_u *expr_line = NULL;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +010092static exarg_T *expr_eap = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020093
94/*
95 * Get an expression for the "\"=expr1" or "CTRL-R =expr1"
96 * Returns '=' when OK, NUL otherwise.
97 */
98 int
99get_expr_register(void)
100{
101 char_u *new_line;
102
Bram Moolenaarc97f9a52021-12-28 20:59:56 +0000103 new_line = getcmdline('=', 0L, 0, 0);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200104 if (new_line == NULL)
105 return NUL;
106 if (*new_line == NUL) // use previous line
107 vim_free(new_line);
108 else
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100109 set_expr_line(new_line, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200110 return '=';
111}
112
113/*
114 * Set the expression for the '=' register.
115 * Argument must be an allocated string.
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100116 * "eap" may be used if the next line needs to be checked when evaluating the
117 * expression.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200118 */
119 void
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100120set_expr_line(char_u *new_line, exarg_T *eap)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200121{
122 vim_free(expr_line);
123 expr_line = new_line;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100124 expr_eap = eap;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200125}
126
127/*
128 * Get the result of the '=' register expression.
129 * Returns a pointer to allocated memory, or NULL for failure.
130 */
131 char_u *
132get_expr_line(void)
133{
134 char_u *expr_copy;
135 char_u *rv;
136 static int nested = 0;
137
138 if (expr_line == NULL)
139 return NULL;
140
141 // Make a copy of the expression, because evaluating it may cause it to be
142 // changed.
143 expr_copy = vim_strsave(expr_line);
144 if (expr_copy == NULL)
145 return NULL;
146
147 // When we are invoked recursively limit the evaluation to 10 levels.
148 // Then return the string as-is.
149 if (nested >= 10)
150 return expr_copy;
151
152 ++nested;
Bram Moolenaara4e0b972022-10-01 19:43:52 +0100153 rv = eval_to_string_eap(expr_copy, TRUE, expr_eap, FALSE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200154 --nested;
155 vim_free(expr_copy);
156 return rv;
157}
158
159/*
160 * Get the '=' register expression itself, without evaluating it.
161 */
162 static char_u *
163get_expr_line_src(void)
164{
165 if (expr_line == NULL)
166 return NULL;
167 return vim_strsave(expr_line);
168}
169#endif // FEAT_EVAL
170
171/*
172 * Check if 'regname' is a valid name of a yank register.
173 * Note: There is no check for 0 (default register), caller should do this
174 */
175 int
176valid_yank_reg(
177 int regname,
178 int writing) // if TRUE check for writable registers
179{
180 if ( (regname > 0 && ASCII_ISALNUM(regname))
181 || (!writing && vim_strchr((char_u *)
182#ifdef FEAT_EVAL
183 "/.%:="
184#else
185 "/.%:"
186#endif
187 , regname) != NULL)
188 || regname == '#'
189 || regname == '"'
190 || regname == '-'
191 || regname == '_'
192#ifdef FEAT_CLIPBOARD
193 || regname == '*'
194 || regname == '+'
195#endif
196#ifdef FEAT_DND
197 || (!writing && regname == '~')
198#endif
199 )
200 return TRUE;
Christian Brabandt002ccbf2024-11-12 20:10:58 +0100201#ifndef FEAT_CLIPBOARD
Christian Brabandt45e07042024-11-11 20:52:55 +0100202 // clipboard support not enabled in this build
203 else if (regname == '*' || regname == '+')
204 {
205 // Warn about missing clipboard support once
206 msg_warn_missing_clipboard();
207 return FALSE;
208 }
Christian Brabandt002ccbf2024-11-12 20:10:58 +0100209#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200210 return FALSE;
211}
212
213/*
214 * Set y_current and y_append, according to the value of "regname".
215 * Cannot handle the '_' register.
216 * Must only be called with a valid register name!
217 *
218 * If regname is 0 and writing, use register 0
219 * If regname is 0 and reading, use previous register
220 *
221 * Return TRUE when the register should be inserted literally (selection or
222 * clipboard).
223 */
224 int
225get_yank_register(int regname, int writing)
226{
227 int i;
228 int ret = FALSE;
229
230 y_append = FALSE;
231 if ((regname == 0 || regname == '"') && !writing && y_previous != NULL)
232 {
233 y_current = y_previous;
234 return ret;
235 }
236 i = regname;
237 if (VIM_ISDIGIT(i))
238 i -= '0';
239 else if (ASCII_ISLOWER(i))
240 i = CharOrdLow(i) + 10;
241 else if (ASCII_ISUPPER(i))
242 {
243 i = CharOrdUp(i) + 10;
244 y_append = TRUE;
245 }
246 else if (regname == '-')
247 i = DELETION_REGISTER;
248#ifdef FEAT_CLIPBOARD
249 // When selection is not available, use register 0 instead of '*'
250 else if (clip_star.available && regname == '*')
251 {
252 i = STAR_REGISTER;
253 ret = TRUE;
254 }
255 // When clipboard is not available, use register 0 instead of '+'
256 else if (clip_plus.available && regname == '+')
257 {
258 i = PLUS_REGISTER;
259 ret = TRUE;
260 }
261#endif
262#ifdef FEAT_DND
263 else if (!writing && regname == '~')
264 i = TILDE_REGISTER;
265#endif
266 else // not 0-9, a-z, A-Z or '-': use register 0
267 i = 0;
268 y_current = &(y_regs[i]);
269 if (writing) // remember the register we write into for do_put()
270 y_previous = y_current;
271 return ret;
272}
273
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200274/*
275 * Obtain the contents of a "normal" register. The register is made empty.
276 * The returned pointer has allocated memory, use put_register() later.
277 */
278 void *
279get_register(
280 int name,
281 int copy) // make a copy, if FALSE make register empty.
282{
283 yankreg_T *reg;
284 int i;
285
286#ifdef FEAT_CLIPBOARD
287 // When Visual area changed, may have to update selection. Obtain the
288 // selection too.
289 if (name == '*' && clip_star.available)
290 {
291 if (clip_isautosel_star())
292 clip_update_selection(&clip_star);
293 may_get_selection(name);
294 }
295 if (name == '+' && clip_plus.available)
296 {
297 if (clip_isautosel_plus())
298 clip_update_selection(&clip_plus);
299 may_get_selection(name);
300 }
301#endif
302
303 get_yank_register(name, 0);
304 reg = ALLOC_ONE(yankreg_T);
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000305 if (reg == NULL)
306 return (void *)NULL;
307
308 *reg = *y_current;
309 if (copy)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200310 {
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000311 // If we run out of memory some or all of the lines are empty.
Bram Moolenaard1ae8362023-05-09 17:09:30 +0100312 if (reg->y_size == 0 || y_current->y_array == NULL)
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000313 reg->y_array = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200314 else
John Marriott79f6ffd2024-10-31 10:06:54 +0100315 reg->y_array = ALLOC_MULT(string_T, reg->y_size);
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000316 if (reg->y_array != NULL)
317 {
318 for (i = 0; i < reg->y_size; ++i)
John Marriott79f6ffd2024-10-31 10:06:54 +0100319 {
320 reg->y_array[i].string = vim_strnsave(y_current->y_array[i].string,
321 y_current->y_array[i].length);
322 reg->y_array[i].length = y_current->y_array[i].length;
323 }
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000324 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200325 }
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000326 else
327 y_current->y_array = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200328 return (void *)reg;
329}
330
331/*
332 * Put "reg" into register "name". Free any previous contents and "reg".
333 */
334 void
335put_register(int name, void *reg)
336{
337 get_yank_register(name, 0);
338 free_yank_all();
339 *y_current = *(yankreg_T *)reg;
340 vim_free(reg);
341
342#ifdef FEAT_CLIPBOARD
343 // Send text written to clipboard register to the clipboard.
344 may_set_selection();
345#endif
346}
347
Bram Moolenaarfccbf062020-11-26 20:34:00 +0100348#if defined(FEAT_CLIPBOARD) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200349 void
350free_register(void *reg)
351{
352 yankreg_T tmp;
353
354 tmp = *y_current;
355 *y_current = *(yankreg_T *)reg;
356 free_yank_all();
357 vim_free(reg);
358 *y_current = tmp;
359}
360#endif
361
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200362/*
363 * return TRUE if the current yank register has type MLINE
364 */
365 int
366yank_register_mline(int regname)
367{
368 if (regname != 0 && !valid_yank_reg(regname, FALSE))
369 return FALSE;
370 if (regname == '_') // black hole is always empty
371 return FALSE;
372 get_yank_register(regname, FALSE);
373 return (y_current->y_type == MLINE);
374}
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200375
376/*
377 * Start or stop recording into a yank register.
378 *
379 * Return FAIL for failure, OK otherwise.
380 */
381 int
382do_record(int c)
383{
384 char_u *p;
385 static int regname;
386 yankreg_T *old_y_previous, *old_y_current;
387 int retval;
388
389 if (reg_recording == 0) // start recording
390 {
391 // registers 0-9, a-z and " are allowed
392 if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
393 retval = FAIL;
394 else
395 {
396 reg_recording = c;
397 showmode();
398 regname = c;
399 retval = OK;
400 }
401 }
402 else // stop recording
403 {
404 // Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
405 // needs to be removed again to put it in a register. exec_reg then
406 // adds the escaping back later.
407 reg_recording = 0;
408 msg("");
409 p = get_recorded();
410 if (p == NULL)
411 retval = FAIL;
412 else
413 {
414 // Remove escaping for CSI and K_SPECIAL in multi-byte chars.
415 vim_unescape_csi(p);
416
417 // We don't want to change the default register here, so save and
418 // restore the current register name.
419 old_y_previous = y_previous;
420 old_y_current = y_current;
421
John Marriott18bacc82025-02-26 19:14:06 +0100422 retval = stuff_yank(regname, p);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200423
424 y_previous = old_y_previous;
425 y_current = old_y_current;
426 }
427 }
428 return retval;
429}
430
431/*
432 * Stuff string "p" into yank register "regname" as a single line (append if
433 * uppercase). "p" must have been alloced.
434 *
435 * return FAIL for failure, OK otherwise
436 */
437 static int
John Marriott18bacc82025-02-26 19:14:06 +0100438stuff_yank(int regname, char_u *p)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200439{
John Marriott18bacc82025-02-26 19:14:06 +0100440 size_t plen;
441
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200442 // check for read-only register
443 if (regname != 0 && !valid_yank_reg(regname, TRUE))
444 {
445 vim_free(p);
446 return FAIL;
447 }
448 if (regname == '_') // black hole: don't do anything
449 {
450 vim_free(p);
451 return OK;
452 }
John Marriott79f6ffd2024-10-31 10:06:54 +0100453
John Marriott18bacc82025-02-26 19:14:06 +0100454 plen = STRLEN(p);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200455 get_yank_register(regname, TRUE);
456 if (y_append && y_current->y_array != NULL)
457 {
John Marriott79f6ffd2024-10-31 10:06:54 +0100458 string_T *pp;
459 char_u *tmp;
460 size_t tmplen;
461
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200462 pp = &(y_current->y_array[y_current->y_size - 1]);
John Marriott79f6ffd2024-10-31 10:06:54 +0100463 tmplen = pp->length + plen;
464 tmp = alloc(tmplen + 1);
465 if (tmp == NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200466 {
467 vim_free(p);
468 return FAIL;
469 }
John Marriott79f6ffd2024-10-31 10:06:54 +0100470 STRCPY(tmp, pp->string);
471 STRCPY(tmp + pp->length, p);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200472 vim_free(p);
John Marriott79f6ffd2024-10-31 10:06:54 +0100473 vim_free(pp->string);
474 pp->string = tmp;
475 pp->length = tmplen;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200476 }
477 else
478 {
479 free_yank_all();
John Marriott79f6ffd2024-10-31 10:06:54 +0100480 if ((y_current->y_array = ALLOC_ONE(string_T)) == NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200481 {
482 vim_free(p);
483 return FAIL;
484 }
John Marriott79f6ffd2024-10-31 10:06:54 +0100485 y_current->y_array[0].string = p;
486 y_current->y_array[0].length = plen;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200487 y_current->y_size = 1;
488 y_current->y_type = MCHAR; // used to be MLINE, why?
489#ifdef FEAT_VIMINFO
490 y_current->y_time_set = vim_time();
491#endif
492 }
493 return OK;
494}
495
Yegappan Lakshmanan41a7f822021-06-16 15:53:17 +0200496/*
497 * Last executed register (@ command)
498 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200499static int execreg_lastc = NUL;
500
Dominique Pelle748b3082022-01-08 12:41:16 +0000501#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200502 int
503get_execreg_lastc(void)
504{
505 return execreg_lastc;
506}
507
508 void
509set_execreg_lastc(int lastc)
510{
511 execreg_lastc = lastc;
512}
Dominique Pelle748b3082022-01-08 12:41:16 +0000513#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200514
515/*
Bram Moolenaar856c1112020-06-17 21:47:23 +0200516 * When executing a register as a series of ex-commands, if the
517 * line-continuation character is used for a line, then join it with one or
518 * more previous lines. Note that lines are processed backwards starting from
519 * the last line in the register.
520 *
521 * Arguments:
522 * lines - list of lines in the register
523 * idx - index of the line starting with \ or "\. Join this line with all the
524 * immediate predecessor lines that start with a \ and the first line
525 * that doesn't start with a \. Lines that start with a comment "\
526 * character are ignored.
527 *
528 * Returns the concatenated line. The index of the line that should be
529 * processed next is returned in idx.
530 */
531 static char_u *
John Marriott79f6ffd2024-10-31 10:06:54 +0100532execreg_line_continuation(string_T *lines, long *idx)
Bram Moolenaar856c1112020-06-17 21:47:23 +0200533{
534 garray_T ga;
535 long i = *idx;
536 char_u *p;
537 int cmd_start;
538 int cmd_end = i;
539 int j;
540 char_u *str;
541
Bram Moolenaar04935fb2022-01-08 16:19:22 +0000542 ga_init2(&ga, sizeof(char_u), 400);
Bram Moolenaar856c1112020-06-17 21:47:23 +0200543
544 // search backwards to find the first line of this command.
545 // Any line not starting with \ or "\ is the start of the
546 // command.
547 while (--i > 0)
548 {
John Marriott79f6ffd2024-10-31 10:06:54 +0100549 p = skipwhite(lines[i].string);
Bram Moolenaar856c1112020-06-17 21:47:23 +0200550 if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' '))
551 break;
552 }
553 cmd_start = i;
554
555 // join all the lines
John Marriott79f6ffd2024-10-31 10:06:54 +0100556 ga_concat(&ga, lines[cmd_start].string);
Bram Moolenaar856c1112020-06-17 21:47:23 +0200557 for (j = cmd_start + 1; j <= cmd_end; j++)
558 {
John Marriott79f6ffd2024-10-31 10:06:54 +0100559 p = skipwhite(lines[j].string);
Bram Moolenaar856c1112020-06-17 21:47:23 +0200560 if (*p == '\\')
561 {
562 // Adjust the growsize to the current length to
563 // speed up concatenating many lines.
564 if (ga.ga_len > 400)
565 {
566 if (ga.ga_len > 8000)
567 ga.ga_growsize = 8000;
568 else
569 ga.ga_growsize = ga.ga_len;
570 }
571 ga_concat(&ga, p + 1);
572 }
573 }
574 ga_append(&ga, NUL);
John Marriott79f6ffd2024-10-31 10:06:54 +0100575 str = vim_strnsave(ga.ga_data, ga.ga_len);
Bram Moolenaar856c1112020-06-17 21:47:23 +0200576 ga_clear(&ga);
577
578 *idx = i;
579 return str;
580}
581
582/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200583 * Execute a yank register: copy it into the stuff buffer.
584 *
585 * Return FAIL for failure, OK otherwise.
586 */
587 int
588do_execreg(
589 int regname,
590 int colon, // insert ':' before each line
591 int addcr, // always add '\n' to end of line
592 int silent) // set "silent" flag in typeahead buffer
593{
594 long i;
595 char_u *p;
596 int retval = OK;
597 int remap;
598
599 // repeat previous one
600 if (regname == '@')
601 {
602 if (execreg_lastc == NUL)
603 {
Bram Moolenaar677658a2022-01-05 16:09:06 +0000604 emsg(_(e_no_previously_used_register));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200605 return FAIL;
606 }
607 regname = execreg_lastc;
608 }
609 // check for valid regname
610 if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
611 {
612 emsg_invreg(regname);
613 return FAIL;
614 }
615 execreg_lastc = regname;
616
617#ifdef FEAT_CLIPBOARD
618 regname = may_get_selection(regname);
619#endif
620
621 // black hole: don't stuff anything
622 if (regname == '_')
623 return OK;
624
625 // use last command line
626 if (regname == ':')
627 {
628 if (last_cmdline == NULL)
629 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200630 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200631 return FAIL;
632 }
633 // don't keep the cmdline containing @:
634 VIM_CLEAR(new_last_cmdline);
635 // Escape all control characters with a CTRL-V
636 p = vim_strsave_escaped_ext(last_cmdline,
637 (char_u *)"\001\002\003\004\005\006\007"
638 "\010\011\012\013\014\015\016\017"
639 "\020\021\022\023\024\025\026\027"
640 "\030\031\032\033\034\035\036\037",
641 Ctrl_V, FALSE);
642 if (p != NULL)
643 {
644 // When in Visual mode "'<,'>" will be prepended to the command.
645 // Remove it when it's already there.
646 if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0)
647 retval = put_in_typebuf(p + 5, TRUE, TRUE, silent);
648 else
649 retval = put_in_typebuf(p, TRUE, TRUE, silent);
650 }
651 vim_free(p);
652 }
653#ifdef FEAT_EVAL
654 else if (regname == '=')
655 {
656 p = get_expr_line();
657 if (p == NULL)
658 return FAIL;
659 retval = put_in_typebuf(p, TRUE, colon, silent);
660 vim_free(p);
661 }
662#endif
663 else if (regname == '.') // use last inserted text
664 {
665 p = get_last_insert_save();
666 if (p == NULL)
667 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200668 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200669 return FAIL;
670 }
671 retval = put_in_typebuf(p, FALSE, colon, silent);
672 vim_free(p);
673 }
674 else
675 {
676 get_yank_register(regname, FALSE);
677 if (y_current->y_array == NULL)
678 return FAIL;
679
Bram Moolenaar4b96df52020-01-26 22:00:26 +0100680 // Disallow remapping for ":@r".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200681 remap = colon ? REMAP_NONE : REMAP_YES;
682
683 // Insert lines into typeahead buffer, from last one to first one.
684 put_reedit_in_typebuf(silent);
685 for (i = y_current->y_size; --i >= 0; )
686 {
687 char_u *escaped;
Bram Moolenaar856c1112020-06-17 21:47:23 +0200688 char_u *str;
689 int free_str = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200690
691 // insert NL between lines and after last line if type is MLINE
692 if (y_current->y_type == MLINE || i < y_current->y_size - 1
693 || addcr)
694 {
695 if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
696 return FAIL;
697 }
Bram Moolenaar856c1112020-06-17 21:47:23 +0200698
699 // Handle line-continuation for :@<register>
John Marriott79f6ffd2024-10-31 10:06:54 +0100700 str = y_current->y_array[i].string;
Bram Moolenaar856c1112020-06-17 21:47:23 +0200701 if (colon && i > 0)
702 {
703 p = skipwhite(str);
704 if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))
705 {
706 str = execreg_line_continuation(y_current->y_array, &i);
707 if (str == NULL)
708 return FAIL;
709 free_str = TRUE;
710 }
711 }
712 escaped = vim_strsave_escape_csi(str);
713 if (free_str)
714 vim_free(str);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200715 if (escaped == NULL)
716 return FAIL;
717 retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
718 vim_free(escaped);
719 if (retval == FAIL)
720 return FAIL;
721 if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
722 == FAIL)
723 return FAIL;
724 }
725 reg_executing = regname == 0 ? '"' : regname; // disable "q" command
zeertzjq615202b2023-12-19 20:35:40 +0100726 pending_end_reg_executing = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200727 }
728 return retval;
729}
730
731/*
732 * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
733 * used only after other typeahead has been processed.
734 */
735 static void
736put_reedit_in_typebuf(int silent)
737{
738 char_u buf[3];
739
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000740 if (restart_edit == NUL)
741 return;
742
743 if (restart_edit == 'V')
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200744 {
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000745 buf[0] = 'g';
746 buf[1] = 'R';
747 buf[2] = NUL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200748 }
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000749 else
750 {
751 buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
752 buf[1] = NUL;
753 }
754 if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
755 restart_edit = NUL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200756}
757
758/*
759 * Insert register contents "s" into the typeahead buffer, so that it will be
760 * executed again.
761 * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
762 * no remapping.
763 */
764 static int
765put_in_typebuf(
766 char_u *s,
767 int esc,
768 int colon, // add ':' before the line
769 int silent)
770{
771 int retval = OK;
772
773 put_reedit_in_typebuf(silent);
774 if (colon)
775 retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
776 if (retval == OK)
777 {
778 char_u *p;
779
780 if (esc)
781 p = vim_strsave_escape_csi(s);
782 else
783 p = s;
784 if (p == NULL)
785 retval = FAIL;
786 else
787 retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
788 0, TRUE, silent);
789 if (esc)
790 vim_free(p);
791 }
792 if (colon && retval == OK)
793 retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
794 return retval;
795}
796
797/*
798 * Insert a yank register: copy it into the Read buffer.
799 * Used by CTRL-R command and middle mouse button in insert mode.
800 *
801 * return FAIL for failure, OK otherwise
802 */
803 int
804insert_reg(
805 int regname,
806 int literally_arg) // insert literally, not as if typed
807{
808 long i;
809 int retval = OK;
810 char_u *arg;
811 int allocated;
812 int literally = literally_arg;
813
814 // It is possible to get into an endless loop by having CTRL-R a in
815 // register a and then, in insert mode, doing CTRL-R a.
816 // If you hit CTRL-C, the loop will be broken here.
817 ui_breakcheck();
818 if (got_int)
819 return FAIL;
820
821 // check for valid regname
822 if (regname != NUL && !valid_yank_reg(regname, FALSE))
823 return FAIL;
824
825#ifdef FEAT_CLIPBOARD
826 regname = may_get_selection(regname);
827#endif
828
829 if (regname == '.') // insert last inserted text
830 retval = stuff_inserted(NUL, 1L, TRUE);
831 else if (get_spec_reg(regname, &arg, &allocated, TRUE))
832 {
833 if (arg == NULL)
834 return FAIL;
835 stuffescaped(arg, literally);
836 if (allocated)
837 vim_free(arg);
838 }
839 else // name or number register
840 {
841 if (get_yank_register(regname, FALSE))
842 literally = TRUE;
843 if (y_current->y_array == NULL)
844 retval = FAIL;
845 else
846 {
847 for (i = 0; i < y_current->y_size; ++i)
848 {
phanium7e93d4c2025-04-18 18:32:52 +0200849 if (regname == '-' && y_current->y_type == MCHAR)
Bram Moolenaar032a2d02020-12-22 17:59:35 +0100850 {
Christian Brabandt5d5cbb22024-01-05 18:19:52 +0100851 int dir = BACKWARD;
852 if ((State & REPLACE_FLAG) != 0)
853 {
854 pos_T curpos;
zeertzjq424ec1f2024-01-12 17:43:05 +0100855 if (u_save_cursor() == FAIL)
856 return FAIL;
John Marriott79f6ffd2024-10-31 10:06:54 +0100857 del_chars((long)mb_charlen(y_current->y_array[0].string), TRUE);
Christian Brabandt5d5cbb22024-01-05 18:19:52 +0100858 curpos = curwin->w_cursor;
859 if (oneright() == FAIL)
860 // hit end of line, need to put forward (after the current position)
861 dir = FORWARD;
862 curwin->w_cursor = curpos;
863 }
864
Bram Moolenaar032a2d02020-12-22 17:59:35 +0100865 AppendCharToRedobuff(Ctrl_R);
866 AppendCharToRedobuff(regname);
Christian Brabandt5d5cbb22024-01-05 18:19:52 +0100867 do_put(regname, NULL, dir, 1L, PUT_CURSEND);
Bram Moolenaar032a2d02020-12-22 17:59:35 +0100868 }
869 else
phanium7e93d4c2025-04-18 18:32:52 +0200870 {
John Marriott79f6ffd2024-10-31 10:06:54 +0100871 stuffescaped(y_current->y_array[i].string, literally);
phanium7e93d4c2025-04-18 18:32:52 +0200872 // Insert a newline between lines and after last line if
873 // y_type is MLINE.
874 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
875 stuffcharReadbuff('\n');
876 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200877 }
878 }
879 }
880
881 return retval;
882}
883
884/*
885 * If "regname" is a special register, return TRUE and store a pointer to its
886 * value in "argp".
887 */
888 int
889get_spec_reg(
890 int regname,
891 char_u **argp,
892 int *allocated, // return: TRUE when value was allocated
893 int errmsg) // give error message when failing
894{
895 int cnt;
896
897 *argp = NULL;
898 *allocated = FALSE;
899 switch (regname)
900 {
901 case '%': // file name
902 if (errmsg)
903 check_fname(); // will give emsg if not set
904 *argp = curbuf->b_fname;
905 return TRUE;
906
907 case '#': // alternate file name
908 *argp = getaltfname(errmsg); // may give emsg if not set
909 return TRUE;
910
911#ifdef FEAT_EVAL
912 case '=': // result of expression
913 *argp = get_expr_line();
914 *allocated = TRUE;
915 return TRUE;
916#endif
917
918 case ':': // last command line
919 if (last_cmdline == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200920 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200921 *argp = last_cmdline;
922 return TRUE;
923
924 case '/': // last search-pattern
925 if (last_search_pat() == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200926 emsg(_(e_no_previous_regular_expression));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200927 *argp = last_search_pat();
928 return TRUE;
929
930 case '.': // last inserted text
931 *argp = get_last_insert_save();
932 *allocated = TRUE;
933 if (*argp == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200934 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200935 return TRUE;
936
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200937 case Ctrl_F: // Filename under cursor
938 case Ctrl_P: // Path under cursor, expand via "path"
939 if (!errmsg)
940 return FALSE;
941 *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP
942 | (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL);
943 *allocated = TRUE;
944 return TRUE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200945
946 case Ctrl_W: // word under cursor
947 case Ctrl_A: // WORD (mnemonic All) under cursor
948 if (!errmsg)
949 return FALSE;
950 cnt = find_ident_under_cursor(argp, regname == Ctrl_W
951 ? (FIND_IDENT|FIND_STRING) : FIND_STRING);
952 *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
953 *allocated = TRUE;
954 return TRUE;
955
956 case Ctrl_L: // Line under cursor
957 if (!errmsg)
958 return FALSE;
959
960 *argp = ml_get_buf(curwin->w_buffer,
961 curwin->w_cursor.lnum, FALSE);
962 return TRUE;
963
964 case '_': // black hole: always empty
965 *argp = (char_u *)"";
966 return TRUE;
967 }
968
969 return FALSE;
970}
971
972/*
973 * Paste a yank register into the command line.
974 * Only for non-special registers.
975 * Used by CTRL-R command in command-line mode
976 * insert_reg() can't be used here, because special characters from the
977 * register contents will be interpreted as commands.
978 *
979 * return FAIL for failure, OK otherwise
980 */
981 int
982cmdline_paste_reg(
983 int regname,
984 int literally_arg, // Insert text literally instead of "as typed"
985 int remcr) // don't add CR characters
986{
987 long i;
988 int literally = literally_arg;
989
990 if (get_yank_register(regname, FALSE))
991 literally = TRUE;
992 if (y_current->y_array == NULL)
993 return FAIL;
994
995 for (i = 0; i < y_current->y_size; ++i)
996 {
John Marriott79f6ffd2024-10-31 10:06:54 +0100997 cmdline_paste_str(y_current->y_array[i].string, literally);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200998
999 // Insert ^M between lines and after last line if type is MLINE.
1000 // Don't do this when "remcr" is TRUE.
1001 if ((y_current->y_type == MLINE || i < y_current->y_size - 1) && !remcr)
1002 cmdline_paste_str((char_u *)"\r", literally);
1003
1004 // Check for CTRL-C, in case someone tries to paste a few thousand
1005 // lines and gets bored.
1006 ui_breakcheck();
1007 if (got_int)
1008 return FAIL;
1009 }
1010 return OK;
1011}
1012
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001013/*
1014 * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
1015 */
1016 void
Yegappan Lakshmanana23a11b2023-02-21 14:27:41 +00001017shift_delete_registers(void)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001018{
1019 int n;
1020
1021 y_current = &y_regs[9];
1022 free_yank_all(); // free register nine
1023 for (n = 9; n > 1; --n)
1024 y_regs[n] = y_regs[n - 1];
1025 y_current = &y_regs[1];
1026 if (!y_append)
1027 y_previous = y_current;
1028 y_regs[1].y_array = NULL; // set register one to empty
1029}
1030
1031#if defined(FEAT_EVAL)
1032 void
1033yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
1034{
Bram Moolenaar3075a452021-11-17 15:51:52 +00001035 static int recursive = FALSE;
1036 dict_T *v_event;
1037 list_T *list;
1038 int n;
1039 char_u buf[NUMBUFLEN + 2];
1040 long reglen = 0;
1041 save_v_event_T save_v_event;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001042
1043 if (recursive)
1044 return;
1045
Bram Moolenaar3075a452021-11-17 15:51:52 +00001046 v_event = get_v_event(&save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001047
1048 list = list_alloc();
1049 if (list == NULL)
1050 return;
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001051
1052 // yanked text contents
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001053 for (n = 0; n < reg->y_size; n++)
John Marriott79f6ffd2024-10-31 10:06:54 +01001054 list_append_string(list, reg->y_array[n].string, -1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001055 list->lv_lock = VAR_FIXED;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001056 (void)dict_add_list(v_event, "regcontents", list);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001057
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001058 // register name or empty string for unnamed operation
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001059 buf[0] = (char_u)oap->regname;
1060 buf[1] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001061 (void)dict_add_string(v_event, "regname", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001062
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001063 // motion type: inclusive or exclusive
1064 (void)dict_add_bool(v_event, "inclusive", oap->inclusive);
1065
1066 // kind of operation (yank, delete, change)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001067 buf[0] = get_op_char(oap->op_type);
1068 buf[1] = get_extra_op_char(oap->op_type);
1069 buf[2] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001070 (void)dict_add_string(v_event, "operator", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001071
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001072 // register type
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001073 buf[0] = NUL;
1074 buf[1] = NUL;
1075 switch (get_reg_type(oap->regname, &reglen))
1076 {
1077 case MLINE: buf[0] = 'V'; break;
1078 case MCHAR: buf[0] = 'v'; break;
1079 case MBLOCK:
1080 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
1081 reglen + 1);
1082 break;
1083 }
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001084 (void)dict_add_string(v_event, "regtype", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001085
Bram Moolenaara016eeb2022-04-09 11:37:38 +01001086 // selection type - visual or not
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001087 (void)dict_add_bool(v_event, "visual", oap->is_VIsual);
Bram Moolenaar37d16732020-06-12 22:09:01 +02001088
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001089 // Lock the dictionary and its keys
1090 dict_set_items_ro(v_event);
1091
1092 recursive = TRUE;
zeertzjqcfe45652022-05-27 17:26:55 +01001093 textlock++;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001094 apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
zeertzjqcfe45652022-05-27 17:26:55 +01001095 textlock--;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001096 recursive = FALSE;
1097
1098 // Empty the dictionary, v:event is still valid
Bram Moolenaar3075a452021-11-17 15:51:52 +00001099 restore_v_event(v_event, &save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001100}
1101#endif
1102
1103/*
1104 * set all the yank registers to empty (called from main())
1105 */
1106 void
1107init_yank(void)
1108{
1109 int i;
1110
1111 for (i = 0; i < NUM_REGISTERS; ++i)
1112 y_regs[i].y_array = NULL;
1113}
1114
1115#if defined(EXITFREE) || defined(PROTO)
1116 void
1117clear_registers(void)
1118{
1119 int i;
1120
1121 for (i = 0; i < NUM_REGISTERS; ++i)
1122 {
1123 y_current = &y_regs[i];
1124 if (y_current->y_array != NULL)
1125 free_yank_all();
1126 }
1127}
1128#endif
1129
1130/*
1131 * Free "n" lines from the current yank register.
1132 * Called for normal freeing and in case of error.
1133 */
1134 static void
1135free_yank(long n)
1136{
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +00001137 if (y_current->y_array == NULL)
1138 return;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001139
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +00001140 long i;
1141
1142 for (i = n; --i >= 0; )
John Marriott79f6ffd2024-10-31 10:06:54 +01001143 VIM_CLEAR_STRING(y_current->y_array[i]);
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +00001144 VIM_CLEAR(y_current->y_array);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001145}
1146
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01001147 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001148free_yank_all(void)
1149{
1150 free_yank(y_current->y_size);
1151}
1152
1153/*
1154 * Yank the text between "oap->start" and "oap->end" into a yank register.
1155 * If we are to append (uppercase register), we first yank into a new yank
1156 * register and then concatenate the old and the new one (so we keep the old
1157 * one in case of out-of-memory).
1158 *
1159 * Return FAIL for failure, OK otherwise.
1160 */
1161 int
1162op_yank(oparg_T *oap, int deleting, int mess)
1163{
1164 long y_idx; // index in y_array[]
1165 yankreg_T *curr; // copy of y_current
1166 yankreg_T newreg; // new yank register when appending
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001167 linenr_T lnum; // current line number
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001168 int yanktype = oap->motion_type;
1169 long yanklines = oap->line_count;
1170 linenr_T yankendlnum = oap->end.lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001171 char_u *pnew;
1172 struct block_def bd;
1173#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1174 int did_star = FALSE;
1175#endif
1176
1177 // check for read-only register
1178 if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
1179 {
1180 beep_flush();
1181 return FAIL;
1182 }
1183 if (oap->regname == '_') // black hole: nothing to do
1184 return OK;
1185
1186#ifdef FEAT_CLIPBOARD
Christian Brabandt45e07042024-11-11 20:52:55 +01001187 if ((!clip_star.available && oap->regname == '*') ||
1188 (!clip_plus.available && oap->regname == '+'))
1189 {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001190 oap->regname = 0;
Christian Brabandt45e07042024-11-11 20:52:55 +01001191 msg_warn_missing_clipboard();
1192 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001193#endif
1194
1195 if (!deleting) // op_delete() already set y_current
1196 get_yank_register(oap->regname, TRUE);
1197
1198 curr = y_current;
1199 // append to existing contents
1200 if (y_append && y_current->y_array != NULL)
1201 y_current = &newreg;
1202 else
1203 free_yank_all(); // free previously yanked lines
1204
1205 // If the cursor was in column 1 before and after the movement, and the
1206 // operator is not inclusive, the yank is always linewise.
1207 if ( oap->motion_type == MCHAR
1208 && oap->start.col == 0
1209 && !oap->inclusive
1210 && (!oap->is_VIsual || *p_sel == 'o')
1211 && !oap->block_mode
1212 && oap->end.col == 0
1213 && yanklines > 1)
1214 {
1215 yanktype = MLINE;
1216 --yankendlnum;
1217 --yanklines;
1218 }
1219
1220 y_current->y_size = yanklines;
1221 y_current->y_type = yanktype; // set the yank register type
1222 y_current->y_width = 0;
John Marriott79f6ffd2024-10-31 10:06:54 +01001223 y_current->y_array = lalloc_clear(sizeof(string_T) * yanklines, TRUE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001224 if (y_current->y_array == NULL)
1225 {
1226 y_current = curr;
1227 return FAIL;
1228 }
1229#ifdef FEAT_VIMINFO
1230 y_current->y_time_set = vim_time();
1231#endif
1232
1233 y_idx = 0;
1234 lnum = oap->start.lnum;
1235
1236 if (oap->block_mode)
1237 {
1238 // Visual block mode
1239 y_current->y_type = MBLOCK; // set the yank register type
1240 y_current->y_width = oap->end_vcol - oap->start_vcol;
1241
1242 if (curwin->w_curswant == MAXCOL && y_current->y_width > 0)
1243 y_current->y_width--;
1244 }
1245
1246 for ( ; lnum <= yankendlnum; lnum++, y_idx++)
1247 {
1248 switch (y_current->y_type)
1249 {
1250 case MBLOCK:
1251 block_prep(oap, &bd, lnum, FALSE);
Christian Brabandt544a38e2021-06-10 19:39:11 +02001252 if (yank_copy_line(&bd, y_idx, oap->excl_tr_ws) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001253 goto fail;
1254 break;
1255
1256 case MLINE:
John Marriott79f6ffd2024-10-31 10:06:54 +01001257 y_current->y_array[y_idx].length = ml_get_len(lnum);
1258 if ((y_current->y_array[y_idx].string =
1259 vim_strnsave(ml_get(lnum),
1260 y_current->y_array[y_idx].length)) == NULL)
1261 {
1262 VIM_CLEAR_STRING(y_current->y_array[y_idx]);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001263 goto fail;
John Marriott79f6ffd2024-10-31 10:06:54 +01001264 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001265 break;
1266
1267 case MCHAR:
1268 {
John Marriott79f6ffd2024-10-31 10:06:54 +01001269 int tmp;
1270
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001271 charwise_block_prep(oap->start, oap->end, &bd, lnum, oap->inclusive);
John Marriott79f6ffd2024-10-31 10:06:54 +01001272
1273 // make sure bd.textlen is not longer than the text
1274 tmp = (int)STRLEN(bd.textstart);
1275 if (tmp < bd.textlen)
1276 bd.textlen = tmp;
1277
Christian Brabandt544a38e2021-06-10 19:39:11 +02001278 if (yank_copy_line(&bd, y_idx, FALSE) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001279 goto fail;
1280 break;
1281 }
1282 // NOTREACHED
1283 }
1284 }
1285
1286 if (curr != y_current) // append the new block to the old block
1287 {
John Marriott79f6ffd2024-10-31 10:06:54 +01001288 string_T *new_ptr;
1289 long j;
1290
1291 new_ptr = ALLOC_MULT(string_T, curr->y_size + y_current->y_size);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001292 if (new_ptr == NULL)
1293 goto fail;
1294 for (j = 0; j < curr->y_size; ++j)
1295 new_ptr[j] = curr->y_array[j];
1296 vim_free(curr->y_array);
1297 curr->y_array = new_ptr;
1298#ifdef FEAT_VIMINFO
1299 curr->y_time_set = vim_time();
1300#endif
1301
1302 if (yanktype == MLINE) // MLINE overrides MCHAR and MBLOCK
1303 curr->y_type = MLINE;
1304
1305 // Concatenate the last line of the old block with the first line of
1306 // the new block, unless being Vi compatible.
1307 if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL)
1308 {
John Marriott79f6ffd2024-10-31 10:06:54 +01001309 pnew = alloc(curr->y_array[curr->y_size - 1].length + y_current->y_array[0].length + 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001310 if (pnew == NULL)
1311 {
1312 y_idx = y_current->y_size - 1;
1313 goto fail;
1314 }
John Marriott79f6ffd2024-10-31 10:06:54 +01001315
1316 --j;
1317 STRCPY(pnew, curr->y_array[j].string);
1318 STRCPY(pnew + curr->y_array[j].length, y_current->y_array[0].string);
1319 vim_free(curr->y_array[j].string);
1320 curr->y_array[j].string = pnew;
1321 curr->y_array[j].length = curr->y_array[j].length + y_current->y_array[0].length;
1322 ++j;
1323 VIM_CLEAR_STRING(y_current->y_array[0]);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001324 y_idx = 1;
1325 }
1326 else
1327 y_idx = 0;
1328 while (y_idx < y_current->y_size)
1329 curr->y_array[j++] = y_current->y_array[y_idx++];
1330 curr->y_size = j;
1331 vim_free(y_current->y_array);
1332 y_current = curr;
1333 }
zeertzjq95d2e762022-03-19 11:42:16 +00001334
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001335 if (mess) // Display message about yank?
1336 {
1337 if (yanktype == MCHAR
1338 && !oap->block_mode
1339 && yanklines == 1)
1340 yanklines = 0;
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001341 // Some versions of Vi use ">=" here, some don't...
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001342 if (yanklines > p_report)
1343 {
1344 char namebuf[100];
1345
1346 if (oap->regname == NUL)
1347 *namebuf = NUL;
1348 else
1349 vim_snprintf(namebuf, sizeof(namebuf),
1350 _(" into \"%c"), oap->regname);
1351
1352 // redisplay now, so message is not deleted
1353 update_topline_redraw();
1354 if (oap->block_mode)
1355 {
1356 smsg(NGETTEXT("block of %ld line yanked%s",
1357 "block of %ld lines yanked%s", yanklines),
1358 yanklines, namebuf);
1359 }
1360 else
1361 {
1362 smsg(NGETTEXT("%ld line yanked%s",
1363 "%ld lines yanked%s", yanklines),
1364 yanklines, namebuf);
1365 }
1366 }
1367 }
1368
Bram Moolenaare1004402020-10-24 20:49:43 +02001369 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001370 {
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001371 // Set "'[" and "']" marks.
1372 curbuf->b_op_start = oap->start;
1373 curbuf->b_op_end = oap->end;
1374 if (yanktype == MLINE && !oap->block_mode)
1375 {
1376 curbuf->b_op_start.col = 0;
1377 curbuf->b_op_end.col = MAXCOL;
1378 }
Jim Zhou360a39a2025-03-03 19:53:26 +01001379 if (yanktype != MLINE && !oap->inclusive)
1380 // Exclude the end position.
1381 decl(&curbuf->b_op_end);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001382 }
1383
1384#ifdef FEAT_CLIPBOARD
1385 // If we were yanking to the '*' register, send result to clipboard.
1386 // If no register was specified, and "unnamed" in 'clipboard', make a copy
1387 // to the '*' register.
1388 if (clip_star.available
1389 && (curr == &(y_regs[STAR_REGISTER])
1390 || (!deleting && oap->regname == 0
1391 && ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
1392 {
1393 if (curr != &(y_regs[STAR_REGISTER]))
1394 // Copy the text from register 0 to the clipboard register.
1395 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1396
1397 clip_own_selection(&clip_star);
1398 clip_gen_set_selection(&clip_star);
1399# ifdef FEAT_X11
1400 did_star = TRUE;
1401# endif
1402 }
1403
1404# ifdef FEAT_X11
1405 // If we were yanking to the '+' register, send result to selection.
Bram Moolenaar37096af2021-03-02 19:04:11 +01001406 // Also copy to the '*' register, in case auto-select is off. But not when
Ernie Rael559f2302022-07-26 14:44:36 +01001407 // 'clipboard' has "unnamedplus" and not "unnamed"; and not when
1408 // deleting and both "unnamedplus" and "unnamed".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001409 if (clip_plus.available
1410 && (curr == &(y_regs[PLUS_REGISTER])
1411 || (!deleting && oap->regname == 0
1412 && ((clip_unnamed | clip_unnamed_saved) &
Bram Moolenaar37096af2021-03-02 19:04:11 +01001413 CLIP_UNNAMED_PLUS))))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001414 {
1415 if (curr != &(y_regs[PLUS_REGISTER]))
1416 // Copy the text from register 0 to the clipboard register.
1417 copy_yank_reg(&(y_regs[PLUS_REGISTER]));
1418
1419 clip_own_selection(&clip_plus);
1420 clip_gen_set_selection(&clip_plus);
Bram Moolenaar37096af2021-03-02 19:04:11 +01001421 if (!clip_isautosel_star()
1422 && !clip_isautosel_plus()
1423 && !((clip_unnamed | clip_unnamed_saved) == CLIP_UNNAMED_PLUS)
Ernie Rael559f2302022-07-26 14:44:36 +01001424 && !(deleting && (clip_unnamed | clip_unnamed_saved)
1425 == (CLIP_UNNAMED | CLIP_UNNAMED_PLUS))
Bram Moolenaar37096af2021-03-02 19:04:11 +01001426 && !did_star
1427 && curr == &(y_regs[PLUS_REGISTER]))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001428 {
1429 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1430 clip_own_selection(&clip_star);
1431 clip_gen_set_selection(&clip_star);
1432 }
1433 }
1434# endif
1435#endif
1436
1437#if defined(FEAT_EVAL)
1438 if (!deleting && has_textyankpost())
1439 yank_do_autocmd(oap, y_current);
1440#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001441 return OK;
1442
1443fail: // free the allocated lines
1444 free_yank(y_idx + 1);
1445 y_current = curr;
1446 return FAIL;
1447}
1448
Christian Brabandt544a38e2021-06-10 19:39:11 +02001449/*
1450 * Copy a block range into a register.
1451 * If "exclude_trailing_space" is set, do not copy trailing whitespaces.
1452 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001453 static int
Christian Brabandt544a38e2021-06-10 19:39:11 +02001454yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001455{
1456 char_u *pnew;
1457
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02001458 if (exclude_trailing_space)
1459 bd->endspaces = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001460 if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1))
1461 == NULL)
1462 return FAIL;
John Marriott79f6ffd2024-10-31 10:06:54 +01001463 y_current->y_array[y_idx].string = pnew;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001464 vim_memset(pnew, ' ', (size_t)bd->startspaces);
1465 pnew += bd->startspaces;
1466 mch_memmove(pnew, bd->textstart, (size_t)bd->textlen);
1467 pnew += bd->textlen;
1468 vim_memset(pnew, ' ', (size_t)bd->endspaces);
1469 pnew += bd->endspaces;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001470 if (exclude_trailing_space)
1471 {
1472 int s = bd->textlen + bd->endspaces;
1473
Bram Moolenaar44db8212022-01-25 21:26:17 +00001474 while (s > 0 && VIM_ISWHITE(*(bd->textstart + s - 1)))
Christian Brabandt544a38e2021-06-10 19:39:11 +02001475 {
1476 s = s - (*mb_head_off)(bd->textstart, bd->textstart + s - 1) - 1;
1477 pnew--;
1478 }
1479 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001480 *pnew = NUL;
John Marriott79f6ffd2024-10-31 10:06:54 +01001481
1482 y_current->y_array[y_idx].length = (size_t)(pnew - y_current->y_array[y_idx].string);
1483
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001484 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(
John Marriott79f6ffd2024-10-31 10:06:54 +01001501 sizeof(string_T) * y_current->y_size, TRUE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001502 if (y_current->y_array == NULL)
1503 y_current->y_size = 0;
1504 else
1505 for (j = 0; j < y_current->y_size; ++j)
John Marriott79f6ffd2024-10-31 10:06:54 +01001506 {
1507 if ((y_current->y_array[j].string = vim_strnsave(curr->y_array[j].string,
1508 curr->y_array[j].length)) == NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001509 {
1510 free_yank(j);
1511 y_current->y_size = 0;
1512 break;
1513 }
John Marriott79f6ffd2024-10-31 10:06:54 +01001514 y_current->y_array[j].length = curr->y_array[j].length;
1515 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001516 y_current = curr;
1517}
1518#endif
1519
1520/*
1521 * Put contents of register "regname" into the text.
1522 * Caller must check "regname" to be valid!
1523 * "flags": PUT_FIXINDENT make indent look nice
1524 * PUT_CURSEND leave cursor after end of new text
1525 * PUT_LINE force linewise put (":put")
Christian Brabandt2fa93842021-05-30 22:17:25 +02001526 * PUT_BLOCK_INNER in block mode, do not add trailing spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001527 */
1528 void
1529do_put(
1530 int regname,
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001531 char_u *expr_result, // result for regname "=" when compiled
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001532 int dir, // BACKWARD for 'P', FORWARD for 'p'
1533 long count,
1534 int flags)
1535{
1536 char_u *ptr;
John Marriott79f6ffd2024-10-31 10:06:54 +01001537 char_u *newp;
1538 char_u *oldp;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001539 int yanklen;
1540 int totlen = 0; // init for gcc
1541 linenr_T lnum;
1542 colnr_T col;
1543 long i; // index in y_array[]
1544 int y_type;
1545 long y_size;
1546 int oldlen;
1547 long y_width = 0;
1548 colnr_T vcol;
John Marriott79f6ffd2024-10-31 10:06:54 +01001549 string_T *y_array = NULL;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001550 yankreg_T *y_current_used = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001551 long nr_lines = 0;
John Marriott79f6ffd2024-10-31 10:06:54 +01001552 string_T insert_string;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001553 int allocated = FALSE;
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001554 pos_T orig_start = curbuf->b_op_start;
1555 pos_T orig_end = curbuf->b_op_end;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001556 unsigned int cur_ve_flags = get_ve_flags();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001557
1558#ifdef FEAT_CLIPBOARD
1559 // Adjust register name for "unnamed" in 'clipboard'.
1560 adjust_clip_reg(&regname);
1561 (void)may_get_selection(regname);
1562#endif
1563
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001564 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1565 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1566
1567 // Using inserted text works differently, because the register includes
1568 // special characters (newlines, etc.).
1569 if (regname == '.')
1570 {
1571 if (VIsual_active)
1572 stuffcharReadbuff(VIsual_mode);
1573 (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
1574 (count == -1 ? 'O' : 'i')), count, FALSE);
1575 // Putting the text is done later, so can't really move the cursor to
1576 // the next character. Use "l" to simulate it.
1577 if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
1578 stuffcharReadbuff('l');
1579 return;
1580 }
1581
1582 // For special registers '%' (file name), '#' (alternate file name) and
1583 // ':' (last command line), etc. we have to create a fake yank register.
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001584 // For compiled code "expr_result" holds the expression result.
John Marriott79f6ffd2024-10-31 10:06:54 +01001585 insert_string.string = NULL;
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001586 if (regname == '=' && expr_result != NULL)
John Marriott79f6ffd2024-10-31 10:06:54 +01001587 insert_string.string = expr_result;
1588 else if (get_spec_reg(regname, &insert_string.string, &allocated, TRUE)
1589 && insert_string.string == NULL)
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001590 return;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001591
1592 // Autocommands may be executed when saving lines for undo. This might
1593 // make "y_array" invalid, so we start undo now to avoid that.
1594 if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL)
1595 goto end;
1596
John Marriott79f6ffd2024-10-31 10:06:54 +01001597 if (insert_string.string != NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001598 {
John Marriott79f6ffd2024-10-31 10:06:54 +01001599 insert_string.length = STRLEN(insert_string.string);
1600
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001601 y_type = MCHAR;
1602#ifdef FEAT_EVAL
1603 if (regname == '=')
1604 {
John Marriott79f6ffd2024-10-31 10:06:54 +01001605 size_t ptrlen;
1606 char_u *tmp;
1607
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001608 // For the = register we need to split the string at NL
1609 // characters.
1610 // Loop twice: count the number of lines and save them.
1611 for (;;)
1612 {
1613 y_size = 0;
John Marriott79f6ffd2024-10-31 10:06:54 +01001614 ptr = insert_string.string;
1615 ptrlen = insert_string.length;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001616 while (ptr != NULL)
1617 {
1618 if (y_array != NULL)
John Marriott79f6ffd2024-10-31 10:06:54 +01001619 y_array[y_size].string = ptr;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001620 ++y_size;
John Marriott79f6ffd2024-10-31 10:06:54 +01001621 tmp = vim_strchr(ptr, '\n');
1622 if (tmp == NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001623 {
1624 if (y_array != NULL)
John Marriott79f6ffd2024-10-31 10:06:54 +01001625 y_array[y_size - 1].length = ptrlen;
1626 }
1627 else
1628 {
1629 if (y_array != NULL)
1630 {
1631 *tmp = NUL;
1632 y_array[y_size - 1].length = (size_t)(tmp - ptr);
1633 ptrlen -= y_array[y_size - 1].length + 1;
1634 }
1635 ++tmp;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001636 // A trailing '\n' makes the register linewise.
John Marriott79f6ffd2024-10-31 10:06:54 +01001637 if (*tmp == NUL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001638 {
1639 y_type = MLINE;
1640 break;
1641 }
1642 }
John Marriott79f6ffd2024-10-31 10:06:54 +01001643 ptr = tmp;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001644 }
1645 if (y_array != NULL)
1646 break;
John Marriott79f6ffd2024-10-31 10:06:54 +01001647 y_array = ALLOC_MULT(string_T, y_size);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001648 if (y_array == NULL)
1649 goto end;
1650 }
1651 }
1652 else
1653#endif
1654 {
1655 y_size = 1; // use fake one-line yank register
1656 y_array = &insert_string;
1657 }
1658 }
1659 else
1660 {
1661 get_yank_register(regname, FALSE);
1662
1663 y_type = y_current->y_type;
1664 y_width = y_current->y_width;
1665 y_size = y_current->y_size;
1666 y_array = y_current->y_array;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001667 y_current_used = y_current;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001668 }
1669
1670 if (y_type == MLINE)
1671 {
1672 if (flags & PUT_LINE_SPLIT)
1673 {
John Marriott79f6ffd2024-10-31 10:06:54 +01001674 char_u *p_orig;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001675 char_u *p;
John Marriott79f6ffd2024-10-31 10:06:54 +01001676 size_t plen;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001677
1678 // "p" or "P" in Visual mode: split the lines to put the text in
1679 // between.
1680 if (u_save_cursor() == FAIL)
1681 goto end;
John Marriott79f6ffd2024-10-31 10:06:54 +01001682 p_orig = p = ml_get_cursor();
1683 plen = ml_get_cursor_len();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001684 if (dir == FORWARD && *p != NUL)
1685 MB_PTR_ADV(p);
John Marriott79f6ffd2024-10-31 10:06:54 +01001686 ptr = vim_strnsave(p, plen - (size_t)(p - p_orig));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001687 if (ptr == NULL)
1688 goto end;
1689 ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE);
1690 vim_free(ptr);
1691
1692 oldp = ml_get_curline();
1693 p = oldp + curwin->w_cursor.col;
1694 if (dir == FORWARD && *p != NUL)
1695 MB_PTR_ADV(p);
John Marriott79f6ffd2024-10-31 10:06:54 +01001696 ptr = vim_strnsave(oldp, (size_t)(p - oldp));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001697 if (ptr == NULL)
1698 goto end;
1699 ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
1700 ++nr_lines;
1701 dir = FORWARD;
1702 }
1703 if (flags & PUT_LINE_FORWARD)
1704 {
1705 // Must be "p" for a Visual block, put lines below the block.
1706 curwin->w_cursor = curbuf->b_visual.vi_end;
1707 dir = FORWARD;
1708 }
1709 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1710 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1711 }
1712
1713 if (flags & PUT_LINE) // :put command or "p" in Visual line mode.
1714 y_type = MLINE;
1715
1716 if (y_size == 0 || y_array == NULL)
1717 {
Bram Moolenaarac78dd42022-01-02 19:25:26 +00001718 semsg(_(e_nothing_in_register_str),
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001719 regname == 0 ? (char_u *)"\"" : transchar(regname));
1720 goto end;
1721 }
1722
1723 if (y_type == MBLOCK)
1724 {
1725 lnum = curwin->w_cursor.lnum + y_size + 1;
1726 if (lnum > curbuf->b_ml.ml_line_count)
1727 lnum = curbuf->b_ml.ml_line_count + 1;
1728 if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
1729 goto end;
1730 }
1731 else if (y_type == MLINE)
1732 {
1733 lnum = curwin->w_cursor.lnum;
1734#ifdef FEAT_FOLDING
1735 // Correct line number for closed fold. Don't move the cursor yet,
1736 // u_save() uses it.
1737 if (dir == BACKWARD)
1738 (void)hasFolding(lnum, &lnum, NULL);
1739 else
1740 (void)hasFolding(lnum, NULL, &lnum);
1741#endif
1742 if (dir == FORWARD)
1743 ++lnum;
1744 // In an empty buffer the empty line is going to be replaced, include
1745 // it in the saved lines.
1746 if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL)
1747 goto end;
1748#ifdef FEAT_FOLDING
1749 if (dir == FORWARD)
1750 curwin->w_cursor.lnum = lnum - 1;
1751 else
1752 curwin->w_cursor.lnum = lnum;
1753 curbuf->b_op_start = curwin->w_cursor; // for mark_adjust()
1754#endif
1755 }
1756 else if (u_save_cursor() == FAIL)
1757 goto end;
1758
Gary Johnson53ba05b2021-07-26 22:19:10 +02001759 if (cur_ve_flags == VE_ALL && y_type == MCHAR)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001760 {
1761 if (gchar_cursor() == TAB)
1762 {
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001763 int viscol = getviscol();
1764 int ts = curbuf->b_p_ts;
1765
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001766 // Don't need to insert spaces when "p" on the last position of a
1767 // tab or "P" on the first position.
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001768 if (dir == FORWARD ?
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001769#ifdef FEAT_VARTABS
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001770 tabstop_padding(viscol, ts, curbuf->b_p_vts_array) != 1
1771#else
1772 ts - (viscol % ts) != 1
1773#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001774 : curwin->w_cursor.coladd > 0)
1775 coladvance_force(viscol);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001776 else
1777 curwin->w_cursor.coladd = 0;
1778 }
1779 else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
1780 coladvance_force(getviscol() + (dir == FORWARD));
1781 }
1782
1783 lnum = curwin->w_cursor.lnum;
1784 col = curwin->w_cursor.col;
1785
1786 // Block mode
1787 if (y_type == MBLOCK)
1788 {
John Marriott79f6ffd2024-10-31 10:06:54 +01001789 int delcount;
1790 int incr = 0;
1791 struct block_def bd;
1792 long j;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001793 int c = gchar_cursor();
1794 colnr_T endcol2 = 0;
1795
1796 if (dir == FORWARD && c != NUL)
1797 {
Gary Johnson53ba05b2021-07-26 22:19:10 +02001798 if (cur_ve_flags == VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001799 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1800 else
1801 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
1802
1803 if (has_mbyte)
1804 // move to start of next multi-byte character
1805 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
1806 else
Gary Johnson53ba05b2021-07-26 22:19:10 +02001807 if (c != TAB || cur_ve_flags != VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001808 ++curwin->w_cursor.col;
1809 ++col;
1810 }
1811 else
1812 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1813
1814 col += curwin->w_cursor.coladd;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001815 if (cur_ve_flags == VE_ALL
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001816 && (curwin->w_cursor.coladd > 0
1817 || endcol2 == curwin->w_cursor.col))
1818 {
1819 if (dir == FORWARD && c == NUL)
1820 ++col;
Bram Moolenaaref85a9b2020-07-10 20:24:07 +02001821 if (dir != FORWARD && c != NUL && curwin->w_cursor.coladd > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001822 ++curwin->w_cursor.col;
1823 if (c == TAB)
1824 {
1825 if (dir == BACKWARD && curwin->w_cursor.col)
1826 curwin->w_cursor.col--;
1827 if (dir == FORWARD && col - 1 == endcol2)
1828 curwin->w_cursor.col++;
1829 }
1830 }
1831 curwin->w_cursor.coladd = 0;
1832 bd.textcol = 0;
1833 for (i = 0; i < y_size; ++i)
1834 {
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001835 int spaces = 0;
1836 char shortline;
1837 chartabsize_T cts;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001838
1839 bd.startspaces = 0;
1840 bd.endspaces = 0;
1841 vcol = 0;
1842 delcount = 0;
1843
1844 // add a new line
1845 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
1846 {
1847 if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
1848 (colnr_T)1, FALSE) == FAIL)
1849 break;
1850 ++nr_lines;
1851 }
1852 // get the old line and advance to the position to insert at
1853 oldp = ml_get_curline();
zeertzjq94b7c322024-03-12 21:50:32 +01001854 oldlen = ml_get_curline_len();
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001855 init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0,
1856 oldp, oldp);
1857
1858 while (cts.cts_vcol < col && *cts.cts_ptr != NUL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001859 {
1860 // Count a tab for what it's worth (if list mode not on)
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001861 incr = lbr_chartabsize_adv(&cts);
1862 cts.cts_vcol += incr;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001863 }
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001864 vcol = cts.cts_vcol;
1865 ptr = cts.cts_ptr;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001866 bd.textcol = (colnr_T)(ptr - oldp);
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001867 clear_chartabsize_arg(&cts);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001868
1869 shortline = (vcol < col) || (vcol == col && !*ptr) ;
1870
dundargocc57b5bc2022-11-02 13:30:51 +00001871 if (vcol < col) // line too short, pad with spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001872 bd.startspaces = col - vcol;
1873 else if (vcol > col)
1874 {
1875 bd.endspaces = vcol - col;
1876 bd.startspaces = incr - bd.endspaces;
1877 --bd.textcol;
1878 delcount = 1;
1879 if (has_mbyte)
1880 bd.textcol -= (*mb_head_off)(oldp, oldp + bd.textcol);
1881 if (oldp[bd.textcol] != TAB)
1882 {
1883 // Only a Tab can be split into spaces. Other
1884 // characters will have to be moved to after the
1885 // block, causing misalignment.
1886 delcount = 0;
1887 bd.endspaces = 0;
1888 }
1889 }
1890
John Marriott79f6ffd2024-10-31 10:06:54 +01001891 yanklen = (int)y_array[i].length;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001892
Christian Brabandt2fa93842021-05-30 22:17:25 +02001893 if ((flags & PUT_BLOCK_INNER) == 0)
1894 {
1895 // calculate number of spaces required to fill right side of
1896 // block
1897 spaces = y_width + 1;
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001898 init_chartabsize_arg(&cts, curwin, 0, 0,
John Marriott79f6ffd2024-10-31 10:06:54 +01001899 y_array[i].string, y_array[i].string);
VanaIgr6638ec82024-01-25 21:50:41 +01001900
1901 while (*cts.cts_ptr != NUL)
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001902 {
VanaIgr6638ec82024-01-25 21:50:41 +01001903 spaces -= lbr_chartabsize_adv(&cts);
Bram Moolenaar7f9969c2022-07-25 18:13:54 +01001904 cts.cts_vcol = 0;
1905 }
1906 clear_chartabsize_arg(&cts);
Christian Brabandt2fa93842021-05-30 22:17:25 +02001907 if (spaces < 0)
1908 spaces = 0;
1909 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001910
ichizokfa537222021-11-16 12:50:46 +00001911 // Insert the new text.
1912 // First check for multiplication overflow.
1913 if (yanklen + spaces != 0
1914 && count > ((INT_MAX - (bd.startspaces + bd.endspaces))
1915 / (yanklen + spaces)))
1916 {
1917 emsg(_(e_resulting_text_too_long));
1918 break;
1919 }
1920
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001921 totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
1922 newp = alloc(totlen + oldlen + 1);
1923 if (newp == NULL)
1924 break;
ichizokfa537222021-11-16 12:50:46 +00001925
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001926 // copy part up to cursor to new line
1927 ptr = newp;
1928 mch_memmove(ptr, oldp, (size_t)bd.textcol);
1929 ptr += bd.textcol;
ichizokfa537222021-11-16 12:50:46 +00001930
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001931 // may insert some spaces before the new text
1932 vim_memset(ptr, ' ', (size_t)bd.startspaces);
1933 ptr += bd.startspaces;
ichizokfa537222021-11-16 12:50:46 +00001934
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001935 // insert the new text
1936 for (j = 0; j < count; ++j)
1937 {
John Marriott79f6ffd2024-10-31 10:06:54 +01001938 mch_memmove(ptr, y_array[i].string, (size_t)yanklen);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001939 ptr += yanklen;
1940
1941 // insert block's trailing spaces only if there's text behind
Bram Moolenaar1c73b652023-03-03 21:11:52 +00001942 if ((j < count - 1 || !shortline) && spaces > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001943 {
1944 vim_memset(ptr, ' ', (size_t)spaces);
1945 ptr += spaces;
1946 }
Bram Moolenaard25f0032022-06-30 12:30:19 +01001947 else
1948 totlen -= spaces; // didn't use these spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001949 }
ichizokfa537222021-11-16 12:50:46 +00001950
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001951 // may insert some spaces after the new text
1952 vim_memset(ptr, ' ', (size_t)bd.endspaces);
1953 ptr += bd.endspaces;
ichizokfa537222021-11-16 12:50:46 +00001954
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001955 // move the text after the cursor to the end of the line.
1956 mch_memmove(ptr, oldp + bd.textcol + delcount,
1957 (size_t)(oldlen - bd.textcol - delcount + 1));
1958 ml_replace(curwin->w_cursor.lnum, newp, FALSE);
1959
1960 ++curwin->w_cursor.lnum;
1961 if (i == 0)
1962 curwin->w_cursor.col += bd.startspaces;
1963 }
1964
1965 changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines);
1966
1967 // Set '[ mark.
1968 curbuf->b_op_start = curwin->w_cursor;
1969 curbuf->b_op_start.lnum = lnum;
1970
1971 // adjust '] mark
1972 curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
1973 curbuf->b_op_end.col = bd.textcol + totlen - 1;
Bram Moolenaar36343ae2022-10-15 19:04:05 +01001974 if (curbuf->b_op_end.col < 0)
1975 curbuf->b_op_end.col = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001976 curbuf->b_op_end.coladd = 0;
1977 if (flags & PUT_CURSEND)
1978 {
1979 colnr_T len;
1980
1981 curwin->w_cursor = curbuf->b_op_end;
1982 curwin->w_cursor.col++;
1983
1984 // in Insert mode we might be after the NUL, correct for that
zeertzjq94b7c322024-03-12 21:50:32 +01001985 len = ml_get_curline_len();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001986 if (curwin->w_cursor.col > len)
1987 curwin->w_cursor.col = len;
1988 }
1989 else
1990 curwin->w_cursor.lnum = lnum;
1991 }
1992 else
1993 {
John Marriott79f6ffd2024-10-31 10:06:54 +01001994 pos_T new_cursor;
1995
1996 yanklen = (int)y_array[0].length;
1997
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001998 // Character or Line mode
1999 if (y_type == MCHAR)
2000 {
2001 // if type is MCHAR, FORWARD is the same as BACKWARD on the next
2002 // char
2003 if (dir == FORWARD && gchar_cursor() != NUL)
2004 {
2005 if (has_mbyte)
2006 {
2007 int bytelen = (*mb_ptr2len)(ml_get_cursor());
2008
2009 // put it on the next of the multi-byte character.
2010 col += bytelen;
2011 if (yanklen)
2012 {
2013 curwin->w_cursor.col += bytelen;
2014 curbuf->b_op_end.col += bytelen;
2015 }
2016 }
2017 else
2018 {
2019 ++col;
2020 if (yanklen)
2021 {
2022 ++curwin->w_cursor.col;
2023 ++curbuf->b_op_end.col;
2024 }
2025 }
2026 }
2027 curbuf->b_op_start = curwin->w_cursor;
2028 }
2029 // Line mode: BACKWARD is the same as FORWARD on the previous line
2030 else if (dir == BACKWARD)
2031 --lnum;
2032 new_cursor = curwin->w_cursor;
2033
Bram Moolenaarcd942772020-08-22 21:08:44 +02002034 // simple case: insert into one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002035 if (y_type == MCHAR && y_size == 1)
2036 {
Bram Moolenaarcd942772020-08-22 21:08:44 +02002037 linenr_T end_lnum = 0; // init for gcc
2038 linenr_T start_lnum = lnum;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002039 int first_byte_off = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002040
2041 if (VIsual_active)
2042 {
2043 end_lnum = curbuf->b_visual.vi_end.lnum;
2044 if (end_lnum < curbuf->b_visual.vi_start.lnum)
2045 end_lnum = curbuf->b_visual.vi_start.lnum;
Bram Moolenaarcd942772020-08-22 21:08:44 +02002046 if (end_lnum > start_lnum)
2047 {
2048 pos_T pos;
2049
2050 // "col" is valid for the first line, in following lines
2051 // the virtual column needs to be used. Matters for
2052 // multi-byte characters.
2053 pos.lnum = lnum;
2054 pos.col = col;
2055 pos.coladd = 0;
2056 getvcol(curwin, &pos, NULL, &vcol, NULL);
2057 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002058 }
2059
ichizokfa537222021-11-16 12:50:46 +00002060 if (count == 0 || yanklen == 0)
2061 {
2062 if (VIsual_active)
2063 lnum = end_lnum;
2064 }
2065 else if (count > INT_MAX / yanklen)
2066 // multiplication overflow
2067 emsg(_(e_resulting_text_too_long));
2068 else
2069 {
Bram Moolenaare551ccf2021-11-02 23:11:00 +00002070 totlen = count * yanklen;
Hirohito Higashia4a00a72025-05-08 22:58:31 +02002071 do
2072 {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002073 oldp = ml_get(lnum);
zeertzjq94b7c322024-03-12 21:50:32 +01002074 oldlen = ml_get_len(lnum);
Bram Moolenaarcd942772020-08-22 21:08:44 +02002075 if (lnum > start_lnum)
2076 {
2077 pos_T pos;
2078
2079 pos.lnum = lnum;
2080 if (getvpos(&pos, vcol) == OK)
2081 col = pos.col;
2082 else
2083 col = MAXCOL;
2084 }
ichizokfa537222021-11-16 12:50:46 +00002085 if (VIsual_active && col > oldlen)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002086 {
2087 lnum++;
2088 continue;
2089 }
ichizokfa537222021-11-16 12:50:46 +00002090 newp = alloc(totlen + oldlen + 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002091 if (newp == NULL)
2092 goto end; // alloc() gave an error message
2093 mch_memmove(newp, oldp, (size_t)col);
2094 ptr = newp + col;
2095 for (i = 0; i < count; ++i)
2096 {
John Marriott79f6ffd2024-10-31 10:06:54 +01002097 mch_memmove(ptr, y_array[0].string, (size_t)yanklen);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002098 ptr += yanklen;
2099 }
John Marriott79f6ffd2024-10-31 10:06:54 +01002100 mch_memmove(ptr, oldp + col, (size_t)(oldlen - col) + 1); // +1 for NUL
Bram Moolenaarecb00c72022-08-07 14:55:14 +01002101
Bram Moolenaar4d072532021-11-25 19:31:15 +00002102 // compute the byte offset for the last character
2103 first_byte_off = mb_head_off(newp, ptr - 1);
2104
Bram Moolenaarc390cc12022-08-07 18:09:10 +01002105 // Note: this may free "newp"
2106 ml_replace(lnum, newp, FALSE);
2107
2108 inserted_bytes(lnum, col, totlen);
2109
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002110 // Place cursor on last putted char.
2111 if (lnum == curwin->w_cursor.lnum)
2112 {
2113 // make sure curwin->w_virtcol is updated
2114 changed_cline_bef_curs();
Bram Moolenaar85090142023-06-01 19:27:08 +01002115 invalidate_botline();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002116 curwin->w_cursor.col += (colnr_T)(totlen - 1);
2117 }
ichizokfa537222021-11-16 12:50:46 +00002118 if (VIsual_active)
2119 lnum++;
2120 } while (VIsual_active && lnum <= end_lnum);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002121
ichizokfa537222021-11-16 12:50:46 +00002122 if (VIsual_active) // reset lnum to the last visual line
2123 lnum--;
2124 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002125
Bram Moolenaar4d072532021-11-25 19:31:15 +00002126 // put '] at the first byte of the last character
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002127 curbuf->b_op_end = curwin->w_cursor;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002128 curbuf->b_op_end.col -= first_byte_off;
2129
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002130 // For "CTRL-O p" in Insert mode, put cursor after last char
2131 if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
2132 ++curwin->w_cursor.col;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002133 else
2134 curwin->w_cursor.col -= first_byte_off;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002135 }
2136 else
2137 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002138 linenr_T new_lnum = new_cursor.lnum;
John Marriott79f6ffd2024-10-31 10:06:54 +01002139 int indent;
2140 int orig_indent = 0;
2141 int indent_diff = 0; // init for gcc
2142 int first_indent = TRUE;
2143 int lendiff = 0;
2144 long cnt;
2145
2146 if (flags & PUT_FIXINDENT)
2147 orig_indent = get_indent();
Bram Moolenaar23003e52021-09-22 16:37:07 +02002148
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002149 // Insert at least one line. When y_type is MCHAR, break the first
2150 // line in two.
2151 for (cnt = 1; cnt <= count; ++cnt)
2152 {
2153 i = 0;
2154 if (y_type == MCHAR)
2155 {
2156 // Split the current line in two at the insert position.
2157 // First insert y_array[size - 1] in front of second line.
2158 // Then append y_array[0] to first line.
2159 lnum = new_cursor.lnum;
2160 ptr = ml_get(lnum) + col;
John Marriott79f6ffd2024-10-31 10:06:54 +01002161 totlen = (int)y_array[y_size - 1].length;
zeertzjq94b7c322024-03-12 21:50:32 +01002162 newp = alloc(ml_get_len(lnum) - col + totlen + 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002163 if (newp == NULL)
2164 goto error;
John Marriott79f6ffd2024-10-31 10:06:54 +01002165 STRCPY(newp, y_array[y_size - 1].string);
2166 STRCPY(newp + totlen, ptr);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002167 // insert second line
2168 ml_append(lnum, newp, (colnr_T)0, FALSE);
Bram Moolenaar23003e52021-09-22 16:37:07 +02002169 ++new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002170 vim_free(newp);
2171
2172 oldp = ml_get(lnum);
2173 newp = alloc(col + yanklen + 1);
2174 if (newp == NULL)
2175 goto error;
2176 // copy first part of line
2177 mch_memmove(newp, oldp, (size_t)col);
2178 // append to first line
John Marriott79f6ffd2024-10-31 10:06:54 +01002179 mch_memmove(newp + col, y_array[0].string, (size_t)(yanklen + 1));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002180 ml_replace(lnum, newp, FALSE);
2181
2182 curwin->w_cursor.lnum = lnum;
2183 i = 1;
2184 }
2185
2186 for (; i < y_size; ++i)
2187 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002188 if (y_type != MCHAR || i < y_size - 1)
2189 {
John Marriott79f6ffd2024-10-31 10:06:54 +01002190 if (ml_append(lnum, y_array[i].string, (colnr_T)0, FALSE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002191 == FAIL)
2192 goto error;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002193 new_lnum++;
2194 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002195 lnum++;
2196 ++nr_lines;
2197 if (flags & PUT_FIXINDENT)
2198 {
John Marriott79f6ffd2024-10-31 10:06:54 +01002199 pos_T old_pos = curwin->w_cursor;
2200
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002201 curwin->w_cursor.lnum = lnum;
2202 ptr = ml_get(lnum);
2203 if (cnt == count && i == y_size - 1)
zeertzjq94b7c322024-03-12 21:50:32 +01002204 lendiff = ml_get_len(lnum);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002205 if (*ptr == '#' && preprocs_left())
2206 indent = 0; // Leave # lines at start
John Marriott79f6ffd2024-10-31 10:06:54 +01002207 else if (*ptr == NUL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002208 indent = 0; // Ignore empty lines
2209 else if (first_indent)
2210 {
2211 indent_diff = orig_indent - get_indent();
2212 indent = orig_indent;
2213 first_indent = FALSE;
2214 }
2215 else if ((indent = get_indent() + indent_diff) < 0)
2216 indent = 0;
2217 (void)set_indent(indent, 0);
2218 curwin->w_cursor = old_pos;
2219 // remember how many chars were removed
2220 if (cnt == count && i == y_size - 1)
zeertzjq94b7c322024-03-12 21:50:32 +01002221 lendiff -= ml_get_len(lnum);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002222 }
2223 }
Bram Moolenaar23003e52021-09-22 16:37:07 +02002224 if (cnt == 1)
2225 new_lnum = lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002226 }
2227
2228error:
2229 // Adjust marks.
2230 if (y_type == MLINE)
2231 {
2232 curbuf->b_op_start.col = 0;
2233 if (dir == FORWARD)
2234 curbuf->b_op_start.lnum++;
2235 }
Brandon Simmonsda3dd7d2023-01-17 19:48:07 +00002236 mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002237 (linenr_T)MAXLNUM, nr_lines, 0L);
2238
2239 // note changed text for displaying and folding
2240 if (y_type == MCHAR)
2241 changed_lines(curwin->w_cursor.lnum, col,
2242 curwin->w_cursor.lnum + 1, nr_lines);
2243 else
2244 changed_lines(curbuf->b_op_start.lnum, 0,
2245 curbuf->b_op_start.lnum, nr_lines);
Bram Moolenaar9ac38122021-12-02 18:42:33 +00002246 if (y_current_used != NULL && (y_current_used != y_current
2247 || y_current->y_array != y_array))
2248 {
2249 // Something invoked through changed_lines() has changed the
2250 // yank buffer, e.g. a GUI clipboard callback.
2251 emsg(_(e_yank_register_changed_while_using_it));
2252 goto end;
2253 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002254
Bram Moolenaar4d072532021-11-25 19:31:15 +00002255 // Put the '] mark on the first byte of the last inserted character.
2256 // Correct the length for change in indent.
Bram Moolenaarf47ebf12021-10-19 20:08:45 +01002257 curbuf->b_op_end.lnum = new_lnum;
Christian Brabandte0029da2025-02-23 20:01:54 +01002258 col = MAX(0, (colnr_T)y_array[y_size - 1].length - lendiff);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002259 if (col > 1)
Bram Moolenaar2a585c82022-05-25 15:15:38 +01002260 {
2261 curbuf->b_op_end.col = col - 1;
John Marriott79f6ffd2024-10-31 10:06:54 +01002262 if (y_array[y_size - 1].length > 0)
2263 curbuf->b_op_end.col -= mb_head_off(y_array[y_size - 1].string,
2264 y_array[y_size - 1].string + y_array[y_size - 1].length - 1);
Bram Moolenaar2a585c82022-05-25 15:15:38 +01002265 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002266 else
2267 curbuf->b_op_end.col = 0;
2268
2269 if (flags & PUT_CURSLINE)
2270 {
2271 // ":put": put cursor on last inserted line
2272 curwin->w_cursor.lnum = lnum;
2273 beginline(BL_WHITE | BL_FIX);
2274 }
2275 else if (flags & PUT_CURSEND)
2276 {
2277 // put cursor after inserted text
2278 if (y_type == MLINE)
2279 {
2280 if (lnum >= curbuf->b_ml.ml_line_count)
2281 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
2282 else
2283 curwin->w_cursor.lnum = lnum + 1;
2284 curwin->w_cursor.col = 0;
2285 }
2286 else
2287 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002288 curwin->w_cursor.lnum = new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002289 curwin->w_cursor.col = col;
Bram Moolenaar56858e42021-09-22 16:43:59 +02002290 curbuf->b_op_end = curwin->w_cursor;
2291 if (col > 1)
2292 curbuf->b_op_end.col = col - 1;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002293 }
2294 }
2295 else if (y_type == MLINE)
2296 {
2297 // put cursor on first non-blank in first inserted line
2298 curwin->w_cursor.col = 0;
2299 if (dir == FORWARD)
2300 ++curwin->w_cursor.lnum;
2301 beginline(BL_WHITE | BL_FIX);
2302 }
2303 else // put cursor on first inserted character
2304 curwin->w_cursor = new_cursor;
2305 }
2306 }
2307
2308 msgmore(nr_lines);
2309 curwin->w_set_curswant = TRUE;
2310
Bram Moolenaar1c73b652023-03-03 21:11:52 +00002311 // Make sure the cursor is not after the NUL.
zeertzjq94b7c322024-03-12 21:50:32 +01002312 int len = ml_get_curline_len();
Bram Moolenaar1c73b652023-03-03 21:11:52 +00002313 if (curwin->w_cursor.col > len)
2314 {
2315 if (cur_ve_flags == VE_ALL)
2316 curwin->w_cursor.coladd = curwin->w_cursor.col - len;
2317 curwin->w_cursor.col = len;
2318 }
2319
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002320end:
Bram Moolenaare1004402020-10-24 20:49:43 +02002321 if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01002322 {
2323 curbuf->b_op_start = orig_start;
2324 curbuf->b_op_end = orig_end;
2325 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002326 if (allocated)
John Marriott79f6ffd2024-10-31 10:06:54 +01002327 vim_free(insert_string.string);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002328 if (regname == '=')
2329 vim_free(y_array);
2330
2331 VIsual_active = FALSE;
2332
2333 // If the cursor is past the end of the line put it at the end.
2334 adjust_cursor_eol();
2335}
2336
2337/*
2338 * Return the character name of the register with the given number.
2339 */
2340 int
2341get_register_name(int num)
2342{
2343 if (num == -1)
2344 return '"';
2345 else if (num < 10)
2346 return num + '0';
2347 else if (num == DELETION_REGISTER)
2348 return '-';
2349#ifdef FEAT_CLIPBOARD
2350 else if (num == STAR_REGISTER)
2351 return '*';
2352 else if (num == PLUS_REGISTER)
2353 return '+';
2354#endif
2355 else
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002356 return num + 'a' - 10;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002357}
2358
Dominique Pelle748b3082022-01-08 12:41:16 +00002359#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002360/*
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002361 * Return the index of the register "" points to.
2362 */
2363 int
Yegappan Lakshmanana23a11b2023-02-21 14:27:41 +00002364get_unname_register(void)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002365{
2366 return y_previous == NULL ? -1 : y_previous - &y_regs[0];
2367}
Dominique Pelle748b3082022-01-08 12:41:16 +00002368#endif
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002369
2370/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002371 * ":dis" and ":registers": Display the contents of the yank registers.
2372 */
2373 void
2374ex_display(exarg_T *eap)
2375{
2376 int i, n;
2377 long j;
2378 char_u *p;
2379 yankreg_T *yb;
2380 int name;
2381 int attr;
2382 char_u *arg = eap->arg;
2383 int clen;
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002384 int type;
John Marriott8ac0f732025-03-18 20:49:01 +01002385 string_T insert;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002386
2387 if (arg != NULL && *arg == NUL)
2388 arg = NULL;
2389 attr = HL_ATTR(HLF_8);
2390
2391 // Highlight title
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002392 msg_puts_title(_("\nType Name Content"));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002393 for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
2394 {
2395 name = get_register_name(i);
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002396 switch (get_reg_type(name, NULL))
2397 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002398 case MLINE: type = 'l'; break;
2399 case MCHAR: type = 'c'; break;
2400 default: type = 'b'; break;
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002401 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002402 if (arg != NULL && vim_strchr(arg, name) == NULL
2403#ifdef ONE_CLIPBOARD
2404 // Star register and plus register contain the same thing.
2405 && (name != '*' || vim_strchr(arg, '+') == NULL)
2406#endif
2407 )
2408 continue; // did not ask for this register
2409
2410#ifdef FEAT_CLIPBOARD
2411 // Adjust register name for "unnamed" in 'clipboard'.
2412 // When it's a clipboard register, fill it with the current contents
2413 // of the clipboard.
2414 adjust_clip_reg(&name);
2415 (void)may_get_selection(name);
2416#endif
2417
2418 if (i == -1)
2419 {
2420 if (y_previous != NULL)
2421 yb = y_previous;
2422 else
2423 yb = &(y_regs[0]);
2424 }
2425 else
2426 yb = &(y_regs[i]);
2427
2428#ifdef FEAT_EVAL
2429 if (name == MB_TOLOWER(redir_reg)
Christian Brabandtc0f0e232025-02-16 16:06:38 +01002430 || (vim_strchr((char_u *)"\"*+", redir_reg) != NULL &&
2431 (yb == y_previous || yb == &y_regs[0])))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002432 continue; // do not list register being written to, the
2433 // pointer can be freed
2434#endif
2435
2436 if (yb->y_array != NULL)
2437 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002438 int do_show = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002439
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002440 for (j = 0; !do_show && j < yb->y_size; ++j)
John Marriott79f6ffd2024-10-31 10:06:54 +01002441 do_show = !message_filtered(yb->y_array[j].string);
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002442
2443 if (do_show || yb->y_size == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002444 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002445 msg_putchar('\n');
2446 msg_puts(" ");
2447 msg_putchar(type);
2448 msg_puts(" ");
2449 msg_putchar('"');
2450 msg_putchar(name);
2451 msg_puts(" ");
2452
2453 n = (int)Columns - 11;
2454 for (j = 0; j < yb->y_size && n > 1; ++j)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002455 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002456 if (j)
2457 {
2458 msg_puts_attr("^J", attr);
2459 n -= 2;
2460 }
John Marriott79f6ffd2024-10-31 10:06:54 +01002461 for (p = yb->y_array[j].string;
Bram Moolenaarb4ad3b02022-03-30 10:57:45 +01002462 *p != NUL && (n -= ptr2cells(p)) >= 0; ++p)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002463 {
2464 clen = (*mb_ptr2len)(p);
2465 msg_outtrans_len(p, clen);
2466 p += clen - 1;
2467 }
2468 }
2469 if (n > 1 && yb->y_type == MLINE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002470 msg_puts_attr("^J", attr);
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002471 out_flush(); // show one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002472 }
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002473 ui_breakcheck();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002474 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002475 }
2476
2477 // display last inserted text
John Marriott8ac0f732025-03-18 20:49:01 +01002478 insert = get_last_insert();
2479 if ((p = insert.string) != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002480 && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
2481 && !message_filtered(p))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002482 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002483 msg_puts("\n c \". ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002484 dis_msg(p, TRUE);
2485 }
2486
2487 // display last command line
2488 if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002489 && !got_int && !message_filtered(last_cmdline))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002490 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002491 msg_puts("\n c \": ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002492 dis_msg(last_cmdline, FALSE);
2493 }
2494
2495 // display current file name
2496 if (curbuf->b_fname != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002497 && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int
2498 && !message_filtered(curbuf->b_fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002499 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002500 msg_puts("\n c \"% ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002501 dis_msg(curbuf->b_fname, FALSE);
2502 }
2503
2504 // display alternate file name
2505 if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
2506 {
2507 char_u *fname;
2508 linenr_T dummy;
2509
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002510 if (buflist_name_nr(0, &fname, &dummy) != FAIL
2511 && !message_filtered(fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002512 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002513 msg_puts("\n c \"# ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002514 dis_msg(fname, FALSE);
2515 }
2516 }
2517
2518 // display last search pattern
2519 if (last_search_pat() != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002520 && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int
2521 && !message_filtered(last_search_pat()))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002522 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002523 msg_puts("\n c \"/ ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002524 dis_msg(last_search_pat(), FALSE);
2525 }
2526
2527#ifdef FEAT_EVAL
2528 // display last used expression
2529 if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002530 && !got_int && !message_filtered(expr_line))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002531 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002532 msg_puts("\n c \"= ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002533 dis_msg(expr_line, FALSE);
2534 }
2535#endif
2536}
2537
2538/*
2539 * display a string for do_dis()
2540 * truncate at end of screen line
2541 */
2542 static void
2543dis_msg(
2544 char_u *p,
2545 int skip_esc) // if TRUE, ignore trailing ESC
2546{
2547 int n;
2548 int l;
2549
2550 n = (int)Columns - 6;
2551 while (*p != NUL
2552 && !(*p == ESC && skip_esc && *(p + 1) == NUL)
2553 && (n -= ptr2cells(p)) >= 0)
2554 {
2555 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
2556 {
2557 msg_outtrans_len(p, l);
2558 p += l;
2559 }
2560 else
2561 msg_outtrans_len(p++, 1);
2562 }
2563 ui_breakcheck();
2564}
2565
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002566#if defined(FEAT_DND) || defined(PROTO)
2567/*
2568 * Replace the contents of the '~' register with str.
2569 */
2570 void
2571dnd_yank_drag_data(char_u *str, long len)
2572{
2573 yankreg_T *curr;
2574
2575 curr = y_current;
2576 y_current = &y_regs[TILDE_REGISTER];
2577 free_yank_all();
2578 str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
2579 y_current = curr;
2580}
2581#endif
2582
2583
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002584/*
2585 * Return the type of a register.
2586 * Used for getregtype()
2587 * Returns MAUTO for error.
2588 */
2589 char_u
2590get_reg_type(int regname, long *reglen)
2591{
2592 switch (regname)
2593 {
2594 case '%': // file name
2595 case '#': // alternate file name
2596 case '=': // expression
2597 case ':': // last command line
2598 case '/': // last search-pattern
2599 case '.': // last inserted text
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002600 case Ctrl_F: // Filename under cursor
2601 case Ctrl_P: // Path under cursor, expand via "path"
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002602 case Ctrl_W: // word under cursor
2603 case Ctrl_A: // WORD (mnemonic All) under cursor
2604 case '_': // black hole: always empty
2605 return MCHAR;
2606 }
2607
2608# ifdef FEAT_CLIPBOARD
2609 regname = may_get_selection(regname);
2610# endif
2611
2612 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2613 return MAUTO;
2614
2615 get_yank_register(regname, FALSE);
2616
2617 if (y_current->y_array != NULL)
2618 {
2619 if (reglen != NULL && y_current->y_type == MBLOCK)
2620 *reglen = y_current->y_width;
2621 return y_current->y_type;
2622 }
2623 return MAUTO;
2624}
2625
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002626#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002627/*
2628 * When "flags" has GREG_LIST return a list with text "s".
2629 * Otherwise just return "s".
2630 */
2631 static char_u *
2632getreg_wrap_one_line(char_u *s, int flags)
2633{
2634 if (flags & GREG_LIST)
2635 {
2636 list_T *list = list_alloc();
2637
2638 if (list != NULL)
2639 {
2640 if (list_append_string(list, NULL, -1) == FAIL)
2641 {
2642 list_free(list);
2643 return NULL;
2644 }
2645 list->lv_first->li_tv.vval.v_string = s;
2646 }
2647 return (char_u *)list;
2648 }
2649 return s;
2650}
2651
2652/*
Bram Moolenaard672dde2020-02-26 13:43:51 +01002653 * Return the contents of a register as a single allocated string or as a list.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002654 * Used for "@r" in expressions and for getreg().
2655 * Returns NULL for error.
2656 * Flags:
2657 * GREG_NO_EXPR Do not allow expression register
2658 * GREG_EXPR_SRC For the expression register: return expression itself,
2659 * not the result of its evaluation.
Bram Moolenaard672dde2020-02-26 13:43:51 +01002660 * GREG_LIST Return a list of lines instead of a single string.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002661 */
2662 char_u *
2663get_reg_contents(int regname, int flags)
2664{
John Marriott79f6ffd2024-10-31 10:06:54 +01002665 linenr_T i;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002666 char_u *retval;
2667 int allocated;
2668 long len;
2669
2670 // Don't allow using an expression register inside an expression
2671 if (regname == '=')
2672 {
2673 if (flags & GREG_NO_EXPR)
2674 return NULL;
2675 if (flags & GREG_EXPR_SRC)
2676 return getreg_wrap_one_line(get_expr_line_src(), flags);
2677 return getreg_wrap_one_line(get_expr_line(), flags);
2678 }
2679
2680 if (regname == '@') // "@@" is used for unnamed register
2681 regname = '"';
2682
2683 // check for valid regname
2684 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2685 return NULL;
2686
2687# ifdef FEAT_CLIPBOARD
2688 regname = may_get_selection(regname);
2689# endif
2690
2691 if (get_spec_reg(regname, &retval, &allocated, FALSE))
2692 {
2693 if (retval == NULL)
2694 return NULL;
2695 if (allocated)
2696 return getreg_wrap_one_line(retval, flags);
2697 return getreg_wrap_one_line(vim_strsave(retval), flags);
2698 }
2699
2700 get_yank_register(regname, FALSE);
2701 if (y_current->y_array == NULL)
2702 return NULL;
2703
2704 if (flags & GREG_LIST)
2705 {
2706 list_T *list = list_alloc();
2707 int error = FALSE;
2708
2709 if (list == NULL)
2710 return NULL;
2711 for (i = 0; i < y_current->y_size; ++i)
John Marriott79f6ffd2024-10-31 10:06:54 +01002712 if (list_append_string(list, y_current->y_array[i].string, -1) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002713 error = TRUE;
2714 if (error)
2715 {
2716 list_free(list);
2717 return NULL;
2718 }
2719 return (char_u *)list;
2720 }
2721
2722 // Compute length of resulting string.
2723 len = 0;
2724 for (i = 0; i < y_current->y_size; ++i)
2725 {
John Marriott79f6ffd2024-10-31 10:06:54 +01002726 len += (long)y_current->y_array[i].length;
2727
2728 // Insert a newline between lines and after the last line if y_type is
2729 // MLINE.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002730 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2731 ++len;
2732 }
2733
2734 retval = alloc(len + 1);
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +00002735 if (retval == NULL)
2736 return NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002737
2738 // Copy the lines of the yank register into the string.
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +00002739 len = 0;
2740 for (i = 0; i < y_current->y_size; ++i)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002741 {
John Marriott79f6ffd2024-10-31 10:06:54 +01002742 STRCPY(retval + len, y_current->y_array[i].string);
2743 len += (long)y_current->y_array[i].length;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002744
John Marriott79f6ffd2024-10-31 10:06:54 +01002745 // Insert a newline between lines and after the last line if y_type is
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +00002746 // MLINE.
2747 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2748 retval[len++] = '\n';
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002749 }
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +00002750 retval[len] = NUL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002751
2752 return retval;
2753}
2754
2755 static int
2756init_write_reg(
2757 int name,
2758 yankreg_T **old_y_previous,
2759 yankreg_T **old_y_current,
2760 int must_append,
2761 int *yank_type UNUSED)
2762{
2763 if (!valid_yank_reg(name, TRUE)) // check for valid reg name
2764 {
2765 emsg_invreg(name);
2766 return FAIL;
2767 }
2768
2769 // Don't want to change the current (unnamed) register
2770 *old_y_previous = y_previous;
2771 *old_y_current = y_current;
2772
2773 get_yank_register(name, TRUE);
2774 if (!y_append && !must_append)
2775 free_yank_all();
2776 return OK;
2777}
2778
2779 static void
2780finish_write_reg(
2781 int name,
2782 yankreg_T *old_y_previous,
2783 yankreg_T *old_y_current)
2784{
2785# ifdef FEAT_CLIPBOARD
2786 // Send text of clipboard register to the clipboard.
2787 may_set_selection();
2788# endif
2789
2790 // ':let @" = "val"' should change the meaning of the "" register
2791 if (name != '"')
2792 y_previous = old_y_previous;
2793 y_current = old_y_current;
2794}
2795
2796/*
2797 * Store string "str" in register "name".
2798 * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
2799 * If "must_append" is TRUE, always append to the register. Otherwise append
2800 * if "name" is an uppercase letter.
2801 * Note: "maxlen" and "must_append" don't work for the "/" register.
2802 * Careful: 'str' is modified, you may have to use a copy!
2803 * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise.
2804 */
2805 void
2806write_reg_contents(
2807 int name,
2808 char_u *str,
2809 int maxlen,
2810 int must_append)
2811{
2812 write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
2813}
2814
2815 void
2816write_reg_contents_lst(
2817 int name,
2818 char_u **strings,
2819 int maxlen UNUSED,
2820 int must_append,
2821 int yank_type,
2822 long block_len)
2823{
2824 yankreg_T *old_y_previous, *old_y_current;
2825
2826 if (name == '/' || name == '=')
2827 {
2828 char_u *s;
2829
2830 if (strings[0] == NULL)
2831 s = (char_u *)"";
2832 else if (strings[1] != NULL)
2833 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00002834 emsg(_(e_search_pattern_and_expression_register_may_not_contain_two_or_more_lines));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002835 return;
2836 }
2837 else
2838 s = strings[0];
2839 write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
2840 return;
2841 }
2842
2843 if (name == '_') // black hole: nothing to do
2844 return;
2845
2846 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2847 &yank_type) == FAIL)
2848 return;
2849
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02002850 str_to_reg(y_current, yank_type, (char_u *)strings, -1, block_len, TRUE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002851
2852 finish_write_reg(name, old_y_previous, old_y_current);
2853}
2854
2855 void
2856write_reg_contents_ex(
2857 int name,
2858 char_u *str,
2859 int maxlen,
2860 int must_append,
2861 int yank_type,
2862 long block_len)
2863{
2864 yankreg_T *old_y_previous, *old_y_current;
2865 long len;
2866
2867 if (maxlen >= 0)
2868 len = maxlen;
2869 else
2870 len = (long)STRLEN(str);
2871
2872 // Special case: '/' search pattern
2873 if (name == '/')
2874 {
2875 set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
2876 return;
2877 }
2878
2879 if (name == '#')
2880 {
2881 buf_T *buf;
2882
2883 if (VIM_ISDIGIT(*str))
2884 {
2885 int num = atoi((char *)str);
2886
2887 buf = buflist_findnr(num);
2888 if (buf == NULL)
Bram Moolenaar40bcec12021-12-05 22:19:27 +00002889 semsg(_(e_buffer_nr_does_not_exist), (long)num);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002890 }
2891 else
John Marriott79f6ffd2024-10-31 10:06:54 +01002892 buf = buflist_findnr(buflist_findpat(str, str + len,
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002893 TRUE, FALSE, FALSE));
2894 if (buf == NULL)
2895 return;
2896 curwin->w_alt_fnum = buf->b_fnum;
2897 return;
2898 }
2899
2900 if (name == '=')
2901 {
2902 char_u *p, *s;
2903
John Marriott79f6ffd2024-10-31 10:06:54 +01002904 p = vim_strnsave(str, (size_t)len);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002905 if (p == NULL)
2906 return;
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002907 if (must_append && expr_line != NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002908 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002909 s = concat_str(expr_line, p);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002910 vim_free(p);
2911 p = s;
2912 }
Bram Moolenaarb4bcea42020-10-28 13:53:50 +01002913 set_expr_line(p, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002914 return;
2915 }
2916
2917 if (name == '_') // black hole: nothing to do
2918 return;
2919
2920 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2921 &yank_type) == FAIL)
2922 return;
2923
2924 str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
2925
2926 finish_write_reg(name, old_y_previous, old_y_current);
2927}
2928#endif // FEAT_EVAL
2929
2930#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
2931/*
2932 * Put a string into a register. When the register is not empty, the string
2933 * is appended.
2934 */
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01002935 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002936str_to_reg(
2937 yankreg_T *y_ptr, // pointer to yank register
2938 int yank_type, // MCHAR, MLINE, MBLOCK, MAUTO
2939 char_u *str, // string to put in register
2940 long len, // length of string
2941 long blocklen, // width of Visual block
2942 int str_list) // TRUE if str is char_u **
2943{
2944 int type; // MCHAR, MLINE or MBLOCK
2945 int lnum;
2946 long start;
2947 long i;
2948 int extra;
2949 int newlines; // number of lines added
2950 int extraline = 0; // extra line at the end
2951 int append = FALSE; // append to last line in register
2952 char_u *s;
2953 char_u **ss;
John Marriott79f6ffd2024-10-31 10:06:54 +01002954 string_T *pp;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002955 long maxlen;
2956
2957 if (y_ptr->y_array == NULL) // NULL means empty register
2958 y_ptr->y_size = 0;
2959
2960 if (yank_type == MAUTO)
2961 type = ((str_list || (len > 0 && (str[len - 1] == NL
2962 || str[len - 1] == CAR)))
2963 ? MLINE : MCHAR);
2964 else
2965 type = yank_type;
2966
2967 // Count the number of lines within the string
2968 newlines = 0;
2969 if (str_list)
2970 {
2971 for (ss = (char_u **) str; *ss != NULL; ++ss)
2972 ++newlines;
2973 }
2974 else
2975 {
2976 for (i = 0; i < len; i++)
2977 if (str[i] == '\n')
2978 ++newlines;
2979 if (type == MCHAR || len == 0 || str[len - 1] != '\n')
2980 {
2981 extraline = 1;
2982 ++newlines; // count extra newline at the end
2983 }
2984 if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR)
2985 {
2986 append = TRUE;
2987 --newlines; // uncount newline when appending first line
2988 }
2989 }
2990
2991 // Without any lines make the register empty.
2992 if (y_ptr->y_size + newlines == 0)
2993 {
2994 VIM_CLEAR(y_ptr->y_array);
2995 return;
2996 }
2997
2998 // Allocate an array to hold the pointers to the new register lines.
2999 // If the register was not empty, move the existing lines to the new array.
John Marriott79f6ffd2024-10-31 10:06:54 +01003000 pp = lalloc_clear((y_ptr->y_size + newlines) * sizeof(string_T), TRUE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003001 if (pp == NULL) // out of memory
3002 return;
3003 for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
3004 pp[lnum] = y_ptr->y_array[lnum];
3005 vim_free(y_ptr->y_array);
3006 y_ptr->y_array = pp;
3007 maxlen = 0;
3008
3009 // Find the end of each line and save it into the array.
3010 if (str_list)
3011 {
3012 for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
3013 {
John Marriott79f6ffd2024-10-31 10:06:54 +01003014 pp[lnum].length = STRLEN(*ss);
3015 pp[lnum].string = vim_strnsave(*ss, pp[lnum].length);
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02003016 if (type == MBLOCK)
3017 {
3018 int charlen = mb_string2cells(*ss, -1);
3019
3020 if (charlen > maxlen)
3021 maxlen = charlen;
3022 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003023 }
3024 }
3025 else
3026 {
3027 for (start = 0; start < len + extraline; start += i + 1)
3028 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02003029 int charlen = 0;
3030
Yee Cheng China17f8bf2025-02-08 18:19:15 +01003031 for (i = start; i < len;) // find the end of the line
Bram Moolenaar24951a62021-06-04 18:33:49 +02003032 {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003033 if (str[i] == '\n')
3034 break;
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02003035 if (type == MBLOCK)
3036 charlen += mb_ptr2cells_len(str + i, len - i);
Yee Cheng China17f8bf2025-02-08 18:19:15 +01003037
3038 if (str[i] == NUL)
3039 i++; // registers can have NUL chars
3040 else
3041 i += mb_ptr2len_len(str + i, len - i);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003042 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003043 i -= start; // i is now length of line
Bram Moolenaar6e0b5532021-06-04 17:11:47 +02003044 if (charlen > maxlen)
3045 maxlen = charlen;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003046 if (append)
3047 {
3048 --lnum;
John Marriott79f6ffd2024-10-31 10:06:54 +01003049 extra = (int)y_ptr->y_array[lnum].length;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003050 }
3051 else
3052 extra = 0;
3053 s = alloc(i + extra + 1);
3054 if (s == NULL)
3055 break;
3056 if (extra)
John Marriott79f6ffd2024-10-31 10:06:54 +01003057 mch_memmove(s, y_ptr->y_array[lnum].string, (size_t)extra);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003058 if (append)
John Marriott79f6ffd2024-10-31 10:06:54 +01003059 vim_free(y_ptr->y_array[lnum].string);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003060 if (i > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003061 mch_memmove(s + extra, str + start, (size_t)i);
3062 extra += i;
3063 s[extra] = NUL;
John Marriott79f6ffd2024-10-31 10:06:54 +01003064 y_ptr->y_array[lnum].string = s;
3065 y_ptr->y_array[lnum].length = extra;
3066 ++lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003067 while (--extra >= 0)
3068 {
3069 if (*s == NUL)
3070 *s = '\n'; // replace NUL with newline
3071 ++s;
3072 }
3073 append = FALSE; // only first line is appended
3074 }
3075 }
3076 y_ptr->y_type = type;
3077 y_ptr->y_size = lnum;
3078 if (type == MBLOCK)
3079 y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
3080 else
3081 y_ptr->y_width = 0;
3082# ifdef FEAT_VIMINFO
3083 y_ptr->y_time_set = vim_time();
3084# endif
3085}
3086#endif // FEAT_CLIPBOARD || FEAT_EVAL || PROTO