blob: 08a73fe9b75b3951a85d317c0fb31abb52b93c77 [file] [log] [blame]
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * register.c: functions for managing registers
12 */
13
14#include "vim.h"
15
16/*
17 * Registers:
18 * 0 = unnamed register, for normal yanks and puts
19 * 1..9 = registers '1' to '9', for deletes
20 * 10..35 = registers 'a' to 'z' ('A' to 'Z' for appending)
21 * 36 = delete register '-'
22 * 37 = Selection register '*'. Only if FEAT_CLIPBOARD defined
23 * 38 = Clipboard register '+'. Only if FEAT_CLIPBOARD and FEAT_X11 defined
24 */
25static yankreg_T y_regs[NUM_REGISTERS];
26
27static yankreg_T *y_current; // ptr to current yankreg
28static int y_append; // TRUE when appending
29static yankreg_T *y_previous = NULL; // ptr to last written yankreg
30
31static int stuff_yank(int, char_u *);
32static void put_reedit_in_typebuf(int silent);
33static int put_in_typebuf(char_u *s, int esc, int colon,
34 int silent);
Christian Brabandt544a38e2021-06-10 19:39:11 +020035static int yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020036#ifdef FEAT_CLIPBOARD
37static void copy_yank_reg(yankreg_T *reg);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020038#endif
39static void dis_msg(char_u *p, int skip_esc);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020040
Dominique Pelle748b3082022-01-08 12:41:16 +000041#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020042 yankreg_T *
43get_y_regs(void)
44{
45 return y_regs;
46}
Dominique Pelle748b3082022-01-08 12:41:16 +000047#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020048
Dominique Pelle748b3082022-01-08 12:41:16 +000049#if defined(FEAT_CLIPBOARD) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020050 yankreg_T *
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010051get_y_register(int reg)
52{
53 return &y_regs[reg];
54}
Dominique Pelle748b3082022-01-08 12:41:16 +000055#endif
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010056
Dominique Pelle748b3082022-01-08 12:41:16 +000057#if defined(FEAT_CLIPBOARD) || defined(FEAT_VIMINFO) || defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010058 yankreg_T *
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020059get_y_current(void)
60{
61 return y_current;
62}
Dominique Pelle748b3082022-01-08 12:41:16 +000063#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020064
Dominique Pelle748b3082022-01-08 12:41:16 +000065#if defined(FEAT_CLIPBOARD) || defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020066 yankreg_T *
67get_y_previous(void)
68{
69 return y_previous;
70}
Dominique Pelle748b3082022-01-08 12:41:16 +000071#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020072
Dominique Pelle748b3082022-01-08 12:41:16 +000073#if defined(FEAT_CLIPBOARD) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020074 void
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010075set_y_current(yankreg_T *yreg)
76{
77 y_current = yreg;
78}
Dominique Pelle748b3082022-01-08 12:41:16 +000079#endif
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010080
Dominique Pelle748b3082022-01-08 12:41:16 +000081#if defined(FEAT_CLIPBOARD) || defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar45fffdf2020-03-24 21:42:01 +010082 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020083set_y_previous(yankreg_T *yreg)
84{
85 y_previous = yreg;
86}
Dominique Pelle748b3082022-01-08 12:41:16 +000087#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020088
Christian Brabandt78eb9cc2021-09-14 18:55:51 +020089 void
90reset_y_append(void)
91{
92 y_append = FALSE;
93}
94
95
Bram Moolenaar4aea03e2019-09-25 22:37:17 +020096#if defined(FEAT_EVAL) || defined(PROTO)
97/*
98 * Keep the last expression line here, for repeating.
99 */
100static char_u *expr_line = NULL;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100101static exarg_T *expr_eap = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200102
103/*
104 * Get an expression for the "\"=expr1" or "CTRL-R =expr1"
105 * Returns '=' when OK, NUL otherwise.
106 */
107 int
108get_expr_register(void)
109{
110 char_u *new_line;
111
Bram Moolenaarc97f9a52021-12-28 20:59:56 +0000112 new_line = getcmdline('=', 0L, 0, 0);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200113 if (new_line == NULL)
114 return NUL;
115 if (*new_line == NUL) // use previous line
116 vim_free(new_line);
117 else
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100118 set_expr_line(new_line, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200119 return '=';
120}
121
122/*
123 * Set the expression for the '=' register.
124 * Argument must be an allocated string.
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100125 * "eap" may be used if the next line needs to be checked when evaluating the
126 * expression.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200127 */
128 void
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100129set_expr_line(char_u *new_line, exarg_T *eap)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200130{
131 vim_free(expr_line);
132 expr_line = new_line;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100133 expr_eap = eap;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200134}
135
136/*
137 * Get the result of the '=' register expression.
138 * Returns a pointer to allocated memory, or NULL for failure.
139 */
140 char_u *
141get_expr_line(void)
142{
143 char_u *expr_copy;
144 char_u *rv;
145 static int nested = 0;
146
147 if (expr_line == NULL)
148 return NULL;
149
150 // Make a copy of the expression, because evaluating it may cause it to be
151 // changed.
152 expr_copy = vim_strsave(expr_line);
153 if (expr_copy == NULL)
154 return NULL;
155
156 // When we are invoked recursively limit the evaluation to 10 levels.
157 // Then return the string as-is.
158 if (nested >= 10)
159 return expr_copy;
160
161 ++nested;
Bram Moolenaarb4bcea42020-10-28 13:53:50 +0100162 rv = eval_to_string_eap(expr_copy, TRUE, expr_eap);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200163 --nested;
164 vim_free(expr_copy);
165 return rv;
166}
167
168/*
169 * Get the '=' register expression itself, without evaluating it.
170 */
171 static char_u *
172get_expr_line_src(void)
173{
174 if (expr_line == NULL)
175 return NULL;
176 return vim_strsave(expr_line);
177}
178#endif // FEAT_EVAL
179
180/*
181 * Check if 'regname' is a valid name of a yank register.
182 * Note: There is no check for 0 (default register), caller should do this
183 */
184 int
185valid_yank_reg(
186 int regname,
187 int writing) // if TRUE check for writable registers
188{
189 if ( (regname > 0 && ASCII_ISALNUM(regname))
190 || (!writing && vim_strchr((char_u *)
191#ifdef FEAT_EVAL
192 "/.%:="
193#else
194 "/.%:"
195#endif
196 , regname) != NULL)
197 || regname == '#'
198 || regname == '"'
199 || regname == '-'
200 || regname == '_'
201#ifdef FEAT_CLIPBOARD
202 || regname == '*'
203 || regname == '+'
204#endif
205#ifdef FEAT_DND
206 || (!writing && regname == '~')
207#endif
208 )
209 return TRUE;
210 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);
305 if (reg != NULL)
306 {
307 *reg = *y_current;
308 if (copy)
309 {
310 // If we run out of memory some or all of the lines are empty.
311 if (reg->y_size == 0)
312 reg->y_array = NULL;
313 else
314 reg->y_array = ALLOC_MULT(char_u *, reg->y_size);
315 if (reg->y_array != NULL)
316 {
317 for (i = 0; i < reg->y_size; ++i)
318 reg->y_array[i] = vim_strsave(y_current->y_array[i]);
319 }
320 }
321 else
322 y_current->y_array = NULL;
323 }
324 return (void *)reg;
325}
326
327/*
328 * Put "reg" into register "name". Free any previous contents and "reg".
329 */
330 void
331put_register(int name, void *reg)
332{
333 get_yank_register(name, 0);
334 free_yank_all();
335 *y_current = *(yankreg_T *)reg;
336 vim_free(reg);
337
338#ifdef FEAT_CLIPBOARD
339 // Send text written to clipboard register to the clipboard.
340 may_set_selection();
341#endif
342}
343
Bram Moolenaarfccbf062020-11-26 20:34:00 +0100344#if defined(FEAT_CLIPBOARD) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200345 void
346free_register(void *reg)
347{
348 yankreg_T tmp;
349
350 tmp = *y_current;
351 *y_current = *(yankreg_T *)reg;
352 free_yank_all();
353 vim_free(reg);
354 *y_current = tmp;
355}
356#endif
357
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200358/*
359 * return TRUE if the current yank register has type MLINE
360 */
361 int
362yank_register_mline(int regname)
363{
364 if (regname != 0 && !valid_yank_reg(regname, FALSE))
365 return FALSE;
366 if (regname == '_') // black hole is always empty
367 return FALSE;
368 get_yank_register(regname, FALSE);
369 return (y_current->y_type == MLINE);
370}
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200371
372/*
373 * Start or stop recording into a yank register.
374 *
375 * Return FAIL for failure, OK otherwise.
376 */
377 int
378do_record(int c)
379{
380 char_u *p;
381 static int regname;
382 yankreg_T *old_y_previous, *old_y_current;
383 int retval;
384
385 if (reg_recording == 0) // start recording
386 {
387 // registers 0-9, a-z and " are allowed
388 if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
389 retval = FAIL;
390 else
391 {
392 reg_recording = c;
393 showmode();
394 regname = c;
395 retval = OK;
396 }
397 }
398 else // stop recording
399 {
400 // Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
401 // needs to be removed again to put it in a register. exec_reg then
402 // adds the escaping back later.
403 reg_recording = 0;
404 msg("");
405 p = get_recorded();
406 if (p == NULL)
407 retval = FAIL;
408 else
409 {
410 // Remove escaping for CSI and K_SPECIAL in multi-byte chars.
411 vim_unescape_csi(p);
412
413 // We don't want to change the default register here, so save and
414 // restore the current register name.
415 old_y_previous = y_previous;
416 old_y_current = y_current;
417
418 retval = stuff_yank(regname, p);
419
420 y_previous = old_y_previous;
421 y_current = old_y_current;
422 }
423 }
424 return retval;
425}
426
427/*
428 * Stuff string "p" into yank register "regname" as a single line (append if
429 * uppercase). "p" must have been alloced.
430 *
431 * return FAIL for failure, OK otherwise
432 */
433 static int
434stuff_yank(int regname, char_u *p)
435{
436 char_u *lp;
437 char_u **pp;
438
439 // check for read-only register
440 if (regname != 0 && !valid_yank_reg(regname, TRUE))
441 {
442 vim_free(p);
443 return FAIL;
444 }
445 if (regname == '_') // black hole: don't do anything
446 {
447 vim_free(p);
448 return OK;
449 }
450 get_yank_register(regname, TRUE);
451 if (y_append && y_current->y_array != NULL)
452 {
453 pp = &(y_current->y_array[y_current->y_size - 1]);
454 lp = alloc(STRLEN(*pp) + STRLEN(p) + 1);
455 if (lp == NULL)
456 {
457 vim_free(p);
458 return FAIL;
459 }
460 STRCPY(lp, *pp);
461 STRCAT(lp, p);
462 vim_free(p);
463 vim_free(*pp);
464 *pp = lp;
465 }
466 else
467 {
468 free_yank_all();
469 if ((y_current->y_array = ALLOC_ONE(char_u *)) == NULL)
470 {
471 vim_free(p);
472 return FAIL;
473 }
474 y_current->y_array[0] = p;
475 y_current->y_size = 1;
476 y_current->y_type = MCHAR; // used to be MLINE, why?
477#ifdef FEAT_VIMINFO
478 y_current->y_time_set = vim_time();
479#endif
480 }
481 return OK;
482}
483
Yegappan Lakshmanan41a7f822021-06-16 15:53:17 +0200484/*
485 * Last executed register (@ command)
486 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200487static int execreg_lastc = NUL;
488
Dominique Pelle748b3082022-01-08 12:41:16 +0000489#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200490 int
491get_execreg_lastc(void)
492{
493 return execreg_lastc;
494}
495
496 void
497set_execreg_lastc(int lastc)
498{
499 execreg_lastc = lastc;
500}
Dominique Pelle748b3082022-01-08 12:41:16 +0000501#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200502
503/*
Bram Moolenaar856c1112020-06-17 21:47:23 +0200504 * When executing a register as a series of ex-commands, if the
505 * line-continuation character is used for a line, then join it with one or
506 * more previous lines. Note that lines are processed backwards starting from
507 * the last line in the register.
508 *
509 * Arguments:
510 * lines - list of lines in the register
511 * idx - index of the line starting with \ or "\. Join this line with all the
512 * immediate predecessor lines that start with a \ and the first line
513 * that doesn't start with a \. Lines that start with a comment "\
514 * character are ignored.
515 *
516 * Returns the concatenated line. The index of the line that should be
517 * processed next is returned in idx.
518 */
519 static char_u *
520execreg_line_continuation(char_u **lines, long *idx)
521{
522 garray_T ga;
523 long i = *idx;
524 char_u *p;
525 int cmd_start;
526 int cmd_end = i;
527 int j;
528 char_u *str;
529
530 ga_init2(&ga, (int)sizeof(char_u), 400);
531
532 // search backwards to find the first line of this command.
533 // Any line not starting with \ or "\ is the start of the
534 // command.
535 while (--i > 0)
536 {
537 p = skipwhite(lines[i]);
538 if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' '))
539 break;
540 }
541 cmd_start = i;
542
543 // join all the lines
544 ga_concat(&ga, lines[cmd_start]);
545 for (j = cmd_start + 1; j <= cmd_end; j++)
546 {
547 p = skipwhite(lines[j]);
548 if (*p == '\\')
549 {
550 // Adjust the growsize to the current length to
551 // speed up concatenating many lines.
552 if (ga.ga_len > 400)
553 {
554 if (ga.ga_len > 8000)
555 ga.ga_growsize = 8000;
556 else
557 ga.ga_growsize = ga.ga_len;
558 }
559 ga_concat(&ga, p + 1);
560 }
561 }
562 ga_append(&ga, NUL);
563 str = vim_strsave(ga.ga_data);
564 ga_clear(&ga);
565
566 *idx = i;
567 return str;
568}
569
570/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200571 * Execute a yank register: copy it into the stuff buffer.
572 *
573 * Return FAIL for failure, OK otherwise.
574 */
575 int
576do_execreg(
577 int regname,
578 int colon, // insert ':' before each line
579 int addcr, // always add '\n' to end of line
580 int silent) // set "silent" flag in typeahead buffer
581{
582 long i;
583 char_u *p;
584 int retval = OK;
585 int remap;
586
587 // repeat previous one
588 if (regname == '@')
589 {
590 if (execreg_lastc == NUL)
591 {
Bram Moolenaar677658a2022-01-05 16:09:06 +0000592 emsg(_(e_no_previously_used_register));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200593 return FAIL;
594 }
595 regname = execreg_lastc;
596 }
597 // check for valid regname
598 if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
599 {
600 emsg_invreg(regname);
601 return FAIL;
602 }
603 execreg_lastc = regname;
604
605#ifdef FEAT_CLIPBOARD
606 regname = may_get_selection(regname);
607#endif
608
609 // black hole: don't stuff anything
610 if (regname == '_')
611 return OK;
612
613 // use last command line
614 if (regname == ':')
615 {
616 if (last_cmdline == NULL)
617 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200618 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200619 return FAIL;
620 }
621 // don't keep the cmdline containing @:
622 VIM_CLEAR(new_last_cmdline);
623 // Escape all control characters with a CTRL-V
624 p = vim_strsave_escaped_ext(last_cmdline,
625 (char_u *)"\001\002\003\004\005\006\007"
626 "\010\011\012\013\014\015\016\017"
627 "\020\021\022\023\024\025\026\027"
628 "\030\031\032\033\034\035\036\037",
629 Ctrl_V, FALSE);
630 if (p != NULL)
631 {
632 // When in Visual mode "'<,'>" will be prepended to the command.
633 // Remove it when it's already there.
634 if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0)
635 retval = put_in_typebuf(p + 5, TRUE, TRUE, silent);
636 else
637 retval = put_in_typebuf(p, TRUE, TRUE, silent);
638 }
639 vim_free(p);
640 }
641#ifdef FEAT_EVAL
642 else if (regname == '=')
643 {
644 p = get_expr_line();
645 if (p == NULL)
646 return FAIL;
647 retval = put_in_typebuf(p, TRUE, colon, silent);
648 vim_free(p);
649 }
650#endif
651 else if (regname == '.') // use last inserted text
652 {
653 p = get_last_insert_save();
654 if (p == NULL)
655 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200656 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200657 return FAIL;
658 }
659 retval = put_in_typebuf(p, FALSE, colon, silent);
660 vim_free(p);
661 }
662 else
663 {
664 get_yank_register(regname, FALSE);
665 if (y_current->y_array == NULL)
666 return FAIL;
667
Bram Moolenaar4b96df52020-01-26 22:00:26 +0100668 // Disallow remapping for ":@r".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200669 remap = colon ? REMAP_NONE : REMAP_YES;
670
671 // Insert lines into typeahead buffer, from last one to first one.
672 put_reedit_in_typebuf(silent);
673 for (i = y_current->y_size; --i >= 0; )
674 {
675 char_u *escaped;
Bram Moolenaar856c1112020-06-17 21:47:23 +0200676 char_u *str;
677 int free_str = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200678
679 // insert NL between lines and after last line if type is MLINE
680 if (y_current->y_type == MLINE || i < y_current->y_size - 1
681 || addcr)
682 {
683 if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
684 return FAIL;
685 }
Bram Moolenaar856c1112020-06-17 21:47:23 +0200686
687 // Handle line-continuation for :@<register>
688 str = y_current->y_array[i];
689 if (colon && i > 0)
690 {
691 p = skipwhite(str);
692 if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))
693 {
694 str = execreg_line_continuation(y_current->y_array, &i);
695 if (str == NULL)
696 return FAIL;
697 free_str = TRUE;
698 }
699 }
700 escaped = vim_strsave_escape_csi(str);
701 if (free_str)
702 vim_free(str);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200703 if (escaped == NULL)
704 return FAIL;
705 retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
706 vim_free(escaped);
707 if (retval == FAIL)
708 return FAIL;
709 if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
710 == FAIL)
711 return FAIL;
712 }
713 reg_executing = regname == 0 ? '"' : regname; // disable "q" command
714 }
715 return retval;
716}
717
718/*
719 * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
720 * used only after other typeahead has been processed.
721 */
722 static void
723put_reedit_in_typebuf(int silent)
724{
725 char_u buf[3];
726
727 if (restart_edit != NUL)
728 {
729 if (restart_edit == 'V')
730 {
731 buf[0] = 'g';
732 buf[1] = 'R';
733 buf[2] = NUL;
734 }
735 else
736 {
737 buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
738 buf[1] = NUL;
739 }
740 if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
741 restart_edit = NUL;
742 }
743}
744
745/*
746 * Insert register contents "s" into the typeahead buffer, so that it will be
747 * executed again.
748 * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
749 * no remapping.
750 */
751 static int
752put_in_typebuf(
753 char_u *s,
754 int esc,
755 int colon, // add ':' before the line
756 int silent)
757{
758 int retval = OK;
759
760 put_reedit_in_typebuf(silent);
761 if (colon)
762 retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
763 if (retval == OK)
764 {
765 char_u *p;
766
767 if (esc)
768 p = vim_strsave_escape_csi(s);
769 else
770 p = s;
771 if (p == NULL)
772 retval = FAIL;
773 else
774 retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
775 0, TRUE, silent);
776 if (esc)
777 vim_free(p);
778 }
779 if (colon && retval == OK)
780 retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
781 return retval;
782}
783
784/*
785 * Insert a yank register: copy it into the Read buffer.
786 * Used by CTRL-R command and middle mouse button in insert mode.
787 *
788 * return FAIL for failure, OK otherwise
789 */
790 int
791insert_reg(
792 int regname,
793 int literally_arg) // insert literally, not as if typed
794{
795 long i;
796 int retval = OK;
797 char_u *arg;
798 int allocated;
799 int literally = literally_arg;
800
801 // It is possible to get into an endless loop by having CTRL-R a in
802 // register a and then, in insert mode, doing CTRL-R a.
803 // If you hit CTRL-C, the loop will be broken here.
804 ui_breakcheck();
805 if (got_int)
806 return FAIL;
807
808 // check for valid regname
809 if (regname != NUL && !valid_yank_reg(regname, FALSE))
810 return FAIL;
811
812#ifdef FEAT_CLIPBOARD
813 regname = may_get_selection(regname);
814#endif
815
816 if (regname == '.') // insert last inserted text
817 retval = stuff_inserted(NUL, 1L, TRUE);
818 else if (get_spec_reg(regname, &arg, &allocated, TRUE))
819 {
820 if (arg == NULL)
821 return FAIL;
822 stuffescaped(arg, literally);
823 if (allocated)
824 vim_free(arg);
825 }
826 else // name or number register
827 {
828 if (get_yank_register(regname, FALSE))
829 literally = TRUE;
830 if (y_current->y_array == NULL)
831 retval = FAIL;
832 else
833 {
834 for (i = 0; i < y_current->y_size; ++i)
835 {
Bram Moolenaar032a2d02020-12-22 17:59:35 +0100836 if (regname == '-')
837 {
838 AppendCharToRedobuff(Ctrl_R);
839 AppendCharToRedobuff(regname);
840 do_put(regname, NULL, BACKWARD, 1L, PUT_CURSEND);
841 }
842 else
843 stuffescaped(y_current->y_array[i], literally);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200844 // Insert a newline between lines and after last line if
845 // y_type is MLINE.
846 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
847 stuffcharReadbuff('\n');
848 }
849 }
850 }
851
852 return retval;
853}
854
855/*
856 * If "regname" is a special register, return TRUE and store a pointer to its
857 * value in "argp".
858 */
859 int
860get_spec_reg(
861 int regname,
862 char_u **argp,
863 int *allocated, // return: TRUE when value was allocated
864 int errmsg) // give error message when failing
865{
866 int cnt;
867
868 *argp = NULL;
869 *allocated = FALSE;
870 switch (regname)
871 {
872 case '%': // file name
873 if (errmsg)
874 check_fname(); // will give emsg if not set
875 *argp = curbuf->b_fname;
876 return TRUE;
877
878 case '#': // alternate file name
879 *argp = getaltfname(errmsg); // may give emsg if not set
880 return TRUE;
881
882#ifdef FEAT_EVAL
883 case '=': // result of expression
884 *argp = get_expr_line();
885 *allocated = TRUE;
886 return TRUE;
887#endif
888
889 case ':': // last command line
890 if (last_cmdline == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200891 emsg(_(e_no_previous_command_line));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200892 *argp = last_cmdline;
893 return TRUE;
894
895 case '/': // last search-pattern
896 if (last_search_pat() == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200897 emsg(_(e_no_previous_regular_expression));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200898 *argp = last_search_pat();
899 return TRUE;
900
901 case '.': // last inserted text
902 *argp = get_last_insert_save();
903 *allocated = TRUE;
904 if (*argp == NULL && errmsg)
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200905 emsg(_(e_no_inserted_text_yet));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200906 return TRUE;
907
908#ifdef FEAT_SEARCHPATH
909 case Ctrl_F: // Filename under cursor
910 case Ctrl_P: // Path under cursor, expand via "path"
911 if (!errmsg)
912 return FALSE;
913 *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP
914 | (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL);
915 *allocated = TRUE;
916 return TRUE;
917#endif
918
919 case Ctrl_W: // word under cursor
920 case Ctrl_A: // WORD (mnemonic All) under cursor
921 if (!errmsg)
922 return FALSE;
923 cnt = find_ident_under_cursor(argp, regname == Ctrl_W
924 ? (FIND_IDENT|FIND_STRING) : FIND_STRING);
925 *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
926 *allocated = TRUE;
927 return TRUE;
928
929 case Ctrl_L: // Line under cursor
930 if (!errmsg)
931 return FALSE;
932
933 *argp = ml_get_buf(curwin->w_buffer,
934 curwin->w_cursor.lnum, FALSE);
935 return TRUE;
936
937 case '_': // black hole: always empty
938 *argp = (char_u *)"";
939 return TRUE;
940 }
941
942 return FALSE;
943}
944
945/*
946 * Paste a yank register into the command line.
947 * Only for non-special registers.
948 * Used by CTRL-R command in command-line mode
949 * insert_reg() can't be used here, because special characters from the
950 * register contents will be interpreted as commands.
951 *
952 * return FAIL for failure, OK otherwise
953 */
954 int
955cmdline_paste_reg(
956 int regname,
957 int literally_arg, // Insert text literally instead of "as typed"
958 int remcr) // don't add CR characters
959{
960 long i;
961 int literally = literally_arg;
962
963 if (get_yank_register(regname, FALSE))
964 literally = TRUE;
965 if (y_current->y_array == NULL)
966 return FAIL;
967
968 for (i = 0; i < y_current->y_size; ++i)
969 {
970 cmdline_paste_str(y_current->y_array[i], literally);
971
972 // Insert ^M between lines and after last line if type is MLINE.
973 // Don't do this when "remcr" is TRUE.
974 if ((y_current->y_type == MLINE || i < y_current->y_size - 1) && !remcr)
975 cmdline_paste_str((char_u *)"\r", literally);
976
977 // Check for CTRL-C, in case someone tries to paste a few thousand
978 // lines and gets bored.
979 ui_breakcheck();
980 if (got_int)
981 return FAIL;
982 }
983 return OK;
984}
985
Bram Moolenaar4aea03e2019-09-25 22:37:17 +0200986/*
987 * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
988 */
989 void
990shift_delete_registers()
991{
992 int n;
993
994 y_current = &y_regs[9];
995 free_yank_all(); // free register nine
996 for (n = 9; n > 1; --n)
997 y_regs[n] = y_regs[n - 1];
998 y_current = &y_regs[1];
999 if (!y_append)
1000 y_previous = y_current;
1001 y_regs[1].y_array = NULL; // set register one to empty
1002}
1003
1004#if defined(FEAT_EVAL)
1005 void
1006yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
1007{
Bram Moolenaar3075a452021-11-17 15:51:52 +00001008 static int recursive = FALSE;
1009 dict_T *v_event;
1010 list_T *list;
1011 int n;
1012 char_u buf[NUMBUFLEN + 2];
1013 long reglen = 0;
1014 save_v_event_T save_v_event;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001015
1016 if (recursive)
1017 return;
1018
Bram Moolenaar3075a452021-11-17 15:51:52 +00001019 v_event = get_v_event(&save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001020
1021 list = list_alloc();
1022 if (list == NULL)
1023 return;
1024 for (n = 0; n < reg->y_size; n++)
1025 list_append_string(list, reg->y_array[n], -1);
1026 list->lv_lock = VAR_FIXED;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001027 (void)dict_add_list(v_event, "regcontents", list);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001028
1029 buf[0] = (char_u)oap->regname;
1030 buf[1] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001031 (void)dict_add_string(v_event, "regname", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001032
1033 buf[0] = get_op_char(oap->op_type);
1034 buf[1] = get_extra_op_char(oap->op_type);
1035 buf[2] = NUL;
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001036 (void)dict_add_string(v_event, "operator", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001037
1038 buf[0] = NUL;
1039 buf[1] = NUL;
1040 switch (get_reg_type(oap->regname, &reglen))
1041 {
1042 case MLINE: buf[0] = 'V'; break;
1043 case MCHAR: buf[0] = 'v'; break;
1044 case MBLOCK:
1045 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
1046 reglen + 1);
1047 break;
1048 }
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001049 (void)dict_add_string(v_event, "regtype", buf);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001050
Bram Moolenaar6d90c612020-06-29 20:23:32 +02001051 (void)dict_add_bool(v_event, "visual", oap->is_VIsual);
Bram Moolenaar37d16732020-06-12 22:09:01 +02001052
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001053 // Lock the dictionary and its keys
1054 dict_set_items_ro(v_event);
1055
1056 recursive = TRUE;
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02001057 textwinlock++;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001058 apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02001059 textwinlock--;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001060 recursive = FALSE;
1061
1062 // Empty the dictionary, v:event is still valid
Bram Moolenaar3075a452021-11-17 15:51:52 +00001063 restore_v_event(v_event, &save_v_event);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001064}
1065#endif
1066
1067/*
1068 * set all the yank registers to empty (called from main())
1069 */
1070 void
1071init_yank(void)
1072{
1073 int i;
1074
1075 for (i = 0; i < NUM_REGISTERS; ++i)
1076 y_regs[i].y_array = NULL;
1077}
1078
1079#if defined(EXITFREE) || defined(PROTO)
1080 void
1081clear_registers(void)
1082{
1083 int i;
1084
1085 for (i = 0; i < NUM_REGISTERS; ++i)
1086 {
1087 y_current = &y_regs[i];
1088 if (y_current->y_array != NULL)
1089 free_yank_all();
1090 }
1091}
1092#endif
1093
1094/*
1095 * Free "n" lines from the current yank register.
1096 * Called for normal freeing and in case of error.
1097 */
1098 static void
1099free_yank(long n)
1100{
1101 if (y_current->y_array != NULL)
1102 {
1103 long i;
1104
1105 for (i = n; --i >= 0; )
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001106 vim_free(y_current->y_array[i]);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001107 VIM_CLEAR(y_current->y_array);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001108 }
1109}
1110
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01001111 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001112free_yank_all(void)
1113{
1114 free_yank(y_current->y_size);
1115}
1116
1117/*
1118 * Yank the text between "oap->start" and "oap->end" into a yank register.
1119 * If we are to append (uppercase register), we first yank into a new yank
1120 * register and then concatenate the old and the new one (so we keep the old
1121 * one in case of out-of-memory).
1122 *
1123 * Return FAIL for failure, OK otherwise.
1124 */
1125 int
1126op_yank(oparg_T *oap, int deleting, int mess)
1127{
1128 long y_idx; // index in y_array[]
1129 yankreg_T *curr; // copy of y_current
1130 yankreg_T newreg; // new yank register when appending
1131 char_u **new_ptr;
1132 linenr_T lnum; // current line number
1133 long j;
1134 int yanktype = oap->motion_type;
1135 long yanklines = oap->line_count;
1136 linenr_T yankendlnum = oap->end.lnum;
1137 char_u *p;
1138 char_u *pnew;
1139 struct block_def bd;
1140#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1141 int did_star = FALSE;
1142#endif
1143
1144 // check for read-only register
1145 if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
1146 {
1147 beep_flush();
1148 return FAIL;
1149 }
1150 if (oap->regname == '_') // black hole: nothing to do
1151 return OK;
1152
1153#ifdef FEAT_CLIPBOARD
1154 if (!clip_star.available && oap->regname == '*')
1155 oap->regname = 0;
1156 else if (!clip_plus.available && oap->regname == '+')
1157 oap->regname = 0;
1158#endif
1159
1160 if (!deleting) // op_delete() already set y_current
1161 get_yank_register(oap->regname, TRUE);
1162
1163 curr = y_current;
1164 // append to existing contents
1165 if (y_append && y_current->y_array != NULL)
1166 y_current = &newreg;
1167 else
1168 free_yank_all(); // free previously yanked lines
1169
1170 // If the cursor was in column 1 before and after the movement, and the
1171 // operator is not inclusive, the yank is always linewise.
1172 if ( oap->motion_type == MCHAR
1173 && oap->start.col == 0
1174 && !oap->inclusive
1175 && (!oap->is_VIsual || *p_sel == 'o')
1176 && !oap->block_mode
1177 && oap->end.col == 0
1178 && yanklines > 1)
1179 {
1180 yanktype = MLINE;
1181 --yankendlnum;
1182 --yanklines;
1183 }
1184
1185 y_current->y_size = yanklines;
1186 y_current->y_type = yanktype; // set the yank register type
1187 y_current->y_width = 0;
1188 y_current->y_array = lalloc_clear(sizeof(char_u *) * yanklines, TRUE);
1189 if (y_current->y_array == NULL)
1190 {
1191 y_current = curr;
1192 return FAIL;
1193 }
1194#ifdef FEAT_VIMINFO
1195 y_current->y_time_set = vim_time();
1196#endif
1197
1198 y_idx = 0;
1199 lnum = oap->start.lnum;
1200
1201 if (oap->block_mode)
1202 {
1203 // Visual block mode
1204 y_current->y_type = MBLOCK; // set the yank register type
1205 y_current->y_width = oap->end_vcol - oap->start_vcol;
1206
1207 if (curwin->w_curswant == MAXCOL && y_current->y_width > 0)
1208 y_current->y_width--;
1209 }
1210
1211 for ( ; lnum <= yankendlnum; lnum++, y_idx++)
1212 {
1213 switch (y_current->y_type)
1214 {
1215 case MBLOCK:
1216 block_prep(oap, &bd, lnum, FALSE);
Christian Brabandt544a38e2021-06-10 19:39:11 +02001217 if (yank_copy_line(&bd, y_idx, oap->excl_tr_ws) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001218 goto fail;
1219 break;
1220
1221 case MLINE:
1222 if ((y_current->y_array[y_idx] =
Christian Brabandt544a38e2021-06-10 19:39:11 +02001223 vim_strsave(ml_get(lnum))) == NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001224 goto fail;
1225 break;
1226
1227 case MCHAR:
1228 {
1229 colnr_T startcol = 0, endcol = MAXCOL;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001230 int is_oneChar = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001231 colnr_T cs, ce;
1232
1233 p = ml_get(lnum);
1234 bd.startspaces = 0;
1235 bd.endspaces = 0;
1236
1237 if (lnum == oap->start.lnum)
1238 {
1239 startcol = oap->start.col;
1240 if (virtual_op)
1241 {
1242 getvcol(curwin, &oap->start, &cs, NULL, &ce);
1243 if (ce != cs && oap->start.coladd > 0)
1244 {
1245 // Part of a tab selected -- but don't
1246 // double-count it.
1247 bd.startspaces = (ce - cs + 1)
1248 - oap->start.coladd;
1249 startcol++;
1250 }
1251 }
1252 }
1253
1254 if (lnum == oap->end.lnum)
1255 {
1256 endcol = oap->end.col;
1257 if (virtual_op)
1258 {
1259 getvcol(curwin, &oap->end, &cs, NULL, &ce);
1260 if (p[endcol] == NUL || (cs + oap->end.coladd < ce
1261 // Don't add space for double-wide
1262 // char; endcol will be on last byte
1263 // of multi-byte char.
1264 && (*mb_head_off)(p, p + endcol) == 0))
1265 {
1266 if (oap->start.lnum == oap->end.lnum
1267 && oap->start.col == oap->end.col)
1268 {
1269 // Special case: inside a single char
1270 is_oneChar = TRUE;
1271 bd.startspaces = oap->end.coladd
1272 - oap->start.coladd + oap->inclusive;
1273 endcol = startcol;
1274 }
1275 else
1276 {
1277 bd.endspaces = oap->end.coladd
1278 + oap->inclusive;
1279 endcol -= oap->inclusive;
1280 }
1281 }
1282 }
1283 }
1284 if (endcol == MAXCOL)
1285 endcol = (colnr_T)STRLEN(p);
1286 if (startcol > endcol || is_oneChar)
1287 bd.textlen = 0;
1288 else
1289 bd.textlen = endcol - startcol + oap->inclusive;
1290 bd.textstart = p + startcol;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001291 if (yank_copy_line(&bd, y_idx, FALSE) == FAIL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001292 goto fail;
1293 break;
1294 }
1295 // NOTREACHED
1296 }
1297 }
1298
1299 if (curr != y_current) // append the new block to the old block
1300 {
1301 new_ptr = ALLOC_MULT(char_u *, curr->y_size + y_current->y_size);
1302 if (new_ptr == NULL)
1303 goto fail;
1304 for (j = 0; j < curr->y_size; ++j)
1305 new_ptr[j] = curr->y_array[j];
1306 vim_free(curr->y_array);
1307 curr->y_array = new_ptr;
1308#ifdef FEAT_VIMINFO
1309 curr->y_time_set = vim_time();
1310#endif
1311
1312 if (yanktype == MLINE) // MLINE overrides MCHAR and MBLOCK
1313 curr->y_type = MLINE;
1314
1315 // Concatenate the last line of the old block with the first line of
1316 // the new block, unless being Vi compatible.
1317 if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL)
1318 {
1319 pnew = alloc(STRLEN(curr->y_array[curr->y_size - 1])
1320 + STRLEN(y_current->y_array[0]) + 1);
1321 if (pnew == NULL)
1322 {
1323 y_idx = y_current->y_size - 1;
1324 goto fail;
1325 }
1326 STRCPY(pnew, curr->y_array[--j]);
1327 STRCAT(pnew, y_current->y_array[0]);
1328 vim_free(curr->y_array[j]);
1329 vim_free(y_current->y_array[0]);
1330 curr->y_array[j++] = pnew;
1331 y_idx = 1;
1332 }
1333 else
1334 y_idx = 0;
1335 while (y_idx < y_current->y_size)
1336 curr->y_array[j++] = y_current->y_array[y_idx++];
1337 curr->y_size = j;
1338 vim_free(y_current->y_array);
1339 y_current = curr;
1340 }
1341 if (curwin->w_p_rnu)
1342 redraw_later(SOME_VALID); // cursor moved to start
1343 if (mess) // Display message about yank?
1344 {
1345 if (yanktype == MCHAR
1346 && !oap->block_mode
1347 && yanklines == 1)
1348 yanklines = 0;
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001349 // Some versions of Vi use ">=" here, some don't...
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001350 if (yanklines > p_report)
1351 {
1352 char namebuf[100];
1353
1354 if (oap->regname == NUL)
1355 *namebuf = NUL;
1356 else
1357 vim_snprintf(namebuf, sizeof(namebuf),
1358 _(" into \"%c"), oap->regname);
1359
1360 // redisplay now, so message is not deleted
1361 update_topline_redraw();
1362 if (oap->block_mode)
1363 {
1364 smsg(NGETTEXT("block of %ld line yanked%s",
1365 "block of %ld lines yanked%s", yanklines),
1366 yanklines, namebuf);
1367 }
1368 else
1369 {
1370 smsg(NGETTEXT("%ld line yanked%s",
1371 "%ld lines yanked%s", yanklines),
1372 yanklines, namebuf);
1373 }
1374 }
1375 }
1376
Bram Moolenaare1004402020-10-24 20:49:43 +02001377 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001378 {
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001379 // Set "'[" and "']" marks.
1380 curbuf->b_op_start = oap->start;
1381 curbuf->b_op_end = oap->end;
1382 if (yanktype == MLINE && !oap->block_mode)
1383 {
1384 curbuf->b_op_start.col = 0;
1385 curbuf->b_op_end.col = MAXCOL;
1386 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001387 }
1388
1389#ifdef FEAT_CLIPBOARD
1390 // If we were yanking to the '*' register, send result to clipboard.
1391 // If no register was specified, and "unnamed" in 'clipboard', make a copy
1392 // to the '*' register.
1393 if (clip_star.available
1394 && (curr == &(y_regs[STAR_REGISTER])
1395 || (!deleting && oap->regname == 0
1396 && ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
1397 {
1398 if (curr != &(y_regs[STAR_REGISTER]))
1399 // Copy the text from register 0 to the clipboard register.
1400 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1401
1402 clip_own_selection(&clip_star);
1403 clip_gen_set_selection(&clip_star);
1404# ifdef FEAT_X11
1405 did_star = TRUE;
1406# endif
1407 }
1408
1409# ifdef FEAT_X11
1410 // If we were yanking to the '+' register, send result to selection.
Bram Moolenaar37096af2021-03-02 19:04:11 +01001411 // Also copy to the '*' register, in case auto-select is off. But not when
1412 // 'clipboard' has "unnamedplus" and not "unnamed".
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001413 if (clip_plus.available
1414 && (curr == &(y_regs[PLUS_REGISTER])
1415 || (!deleting && oap->regname == 0
1416 && ((clip_unnamed | clip_unnamed_saved) &
Bram Moolenaar37096af2021-03-02 19:04:11 +01001417 CLIP_UNNAMED_PLUS))))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001418 {
1419 if (curr != &(y_regs[PLUS_REGISTER]))
1420 // Copy the text from register 0 to the clipboard register.
1421 copy_yank_reg(&(y_regs[PLUS_REGISTER]));
1422
1423 clip_own_selection(&clip_plus);
1424 clip_gen_set_selection(&clip_plus);
Bram Moolenaar37096af2021-03-02 19:04:11 +01001425 if (!clip_isautosel_star()
1426 && !clip_isautosel_plus()
1427 && !((clip_unnamed | clip_unnamed_saved) == CLIP_UNNAMED_PLUS)
1428 && !did_star
1429 && curr == &(y_regs[PLUS_REGISTER]))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001430 {
1431 copy_yank_reg(&(y_regs[STAR_REGISTER]));
1432 clip_own_selection(&clip_star);
1433 clip_gen_set_selection(&clip_star);
1434 }
1435 }
1436# endif
1437#endif
1438
1439#if defined(FEAT_EVAL)
1440 if (!deleting && has_textyankpost())
1441 yank_do_autocmd(oap, y_current);
1442#endif
1443
1444 return OK;
1445
1446fail: // free the allocated lines
1447 free_yank(y_idx + 1);
1448 y_current = curr;
1449 return FAIL;
1450}
1451
Christian Brabandt544a38e2021-06-10 19:39:11 +02001452/*
1453 * Copy a block range into a register.
1454 * If "exclude_trailing_space" is set, do not copy trailing whitespaces.
1455 */
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001456 static int
Christian Brabandt544a38e2021-06-10 19:39:11 +02001457yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001458{
1459 char_u *pnew;
1460
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02001461 if (exclude_trailing_space)
1462 bd->endspaces = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001463 if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1))
1464 == NULL)
1465 return FAIL;
1466 y_current->y_array[y_idx] = pnew;
1467 vim_memset(pnew, ' ', (size_t)bd->startspaces);
1468 pnew += bd->startspaces;
1469 mch_memmove(pnew, bd->textstart, (size_t)bd->textlen);
1470 pnew += bd->textlen;
1471 vim_memset(pnew, ' ', (size_t)bd->endspaces);
1472 pnew += bd->endspaces;
Christian Brabandt544a38e2021-06-10 19:39:11 +02001473 if (exclude_trailing_space)
1474 {
1475 int s = bd->textlen + bd->endspaces;
1476
1477 while (VIM_ISWHITE(*(bd->textstart + s - 1)) && s > 0)
1478 {
1479 s = s - (*mb_head_off)(bd->textstart, bd->textstart + s - 1) - 1;
1480 pnew--;
1481 }
1482 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001483 *pnew = NUL;
1484 return OK;
1485}
1486
1487#ifdef FEAT_CLIPBOARD
1488/*
1489 * Make a copy of the y_current register to register "reg".
1490 */
1491 static void
1492copy_yank_reg(yankreg_T *reg)
1493{
1494 yankreg_T *curr = y_current;
1495 long j;
1496
1497 y_current = reg;
1498 free_yank_all();
1499 *y_current = *curr;
1500 y_current->y_array = lalloc_clear(
1501 sizeof(char_u *) * y_current->y_size, TRUE);
1502 if (y_current->y_array == NULL)
1503 y_current->y_size = 0;
1504 else
1505 for (j = 0; j < y_current->y_size; ++j)
1506 if ((y_current->y_array[j] = vim_strsave(curr->y_array[j])) == NULL)
1507 {
1508 free_yank(j);
1509 y_current->y_size = 0;
1510 break;
1511 }
1512 y_current = curr;
1513}
1514#endif
1515
1516/*
1517 * Put contents of register "regname" into the text.
1518 * Caller must check "regname" to be valid!
1519 * "flags": PUT_FIXINDENT make indent look nice
1520 * PUT_CURSEND leave cursor after end of new text
1521 * PUT_LINE force linewise put (":put")
Christian Brabandt2fa93842021-05-30 22:17:25 +02001522 * PUT_BLOCK_INNER in block mode, do not add trailing spaces
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001523 */
1524 void
1525do_put(
1526 int regname,
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001527 char_u *expr_result, // result for regname "=" when compiled
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001528 int dir, // BACKWARD for 'P', FORWARD for 'p'
1529 long count,
1530 int flags)
1531{
1532 char_u *ptr;
1533 char_u *newp, *oldp;
1534 int yanklen;
1535 int totlen = 0; // init for gcc
1536 linenr_T lnum;
1537 colnr_T col;
1538 long i; // index in y_array[]
1539 int y_type;
1540 long y_size;
1541 int oldlen;
1542 long y_width = 0;
1543 colnr_T vcol;
1544 int delcount;
1545 int incr = 0;
1546 long j;
1547 struct block_def bd;
1548 char_u **y_array = NULL;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001549 yankreg_T *y_current_used = NULL;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001550 long nr_lines = 0;
1551 pos_T new_cursor;
1552 int indent;
1553 int orig_indent = 0; // init for gcc
1554 int indent_diff = 0; // init for gcc
1555 int first_indent = TRUE;
1556 int lendiff = 0;
1557 pos_T old_pos;
1558 char_u *insert_string = NULL;
1559 int allocated = FALSE;
1560 long cnt;
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01001561 pos_T orig_start = curbuf->b_op_start;
1562 pos_T orig_end = curbuf->b_op_end;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001563 unsigned int cur_ve_flags = get_ve_flags();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001564
1565#ifdef FEAT_CLIPBOARD
1566 // Adjust register name for "unnamed" in 'clipboard'.
1567 adjust_clip_reg(&regname);
1568 (void)may_get_selection(regname);
1569#endif
1570
1571 if (flags & PUT_FIXINDENT)
1572 orig_indent = get_indent();
1573
1574 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1575 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1576
1577 // Using inserted text works differently, because the register includes
1578 // special characters (newlines, etc.).
1579 if (regname == '.')
1580 {
1581 if (VIsual_active)
1582 stuffcharReadbuff(VIsual_mode);
1583 (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
1584 (count == -1 ? 'O' : 'i')), count, FALSE);
1585 // Putting the text is done later, so can't really move the cursor to
1586 // the next character. Use "l" to simulate it.
1587 if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
1588 stuffcharReadbuff('l');
1589 return;
1590 }
1591
1592 // For special registers '%' (file name), '#' (alternate file name) and
1593 // ':' (last command line), etc. we have to create a fake yank register.
Bram Moolenaarc3516f72020-09-08 22:45:35 +02001594 // For compiled code "expr_result" holds the expression result.
1595 if (regname == '=' && expr_result != NULL)
1596 insert_string = expr_result;
1597 else if (get_spec_reg(regname, &insert_string, &allocated, TRUE)
1598 && insert_string == NULL)
1599 return;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001600
1601 // Autocommands may be executed when saving lines for undo. This might
1602 // make "y_array" invalid, so we start undo now to avoid that.
1603 if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL)
1604 goto end;
1605
1606 if (insert_string != NULL)
1607 {
1608 y_type = MCHAR;
1609#ifdef FEAT_EVAL
1610 if (regname == '=')
1611 {
1612 // For the = register we need to split the string at NL
1613 // characters.
1614 // Loop twice: count the number of lines and save them.
1615 for (;;)
1616 {
1617 y_size = 0;
1618 ptr = insert_string;
1619 while (ptr != NULL)
1620 {
1621 if (y_array != NULL)
1622 y_array[y_size] = ptr;
1623 ++y_size;
1624 ptr = vim_strchr(ptr, '\n');
1625 if (ptr != NULL)
1626 {
1627 if (y_array != NULL)
1628 *ptr = NUL;
1629 ++ptr;
1630 // A trailing '\n' makes the register linewise.
1631 if (*ptr == NUL)
1632 {
1633 y_type = MLINE;
1634 break;
1635 }
1636 }
1637 }
1638 if (y_array != NULL)
1639 break;
1640 y_array = ALLOC_MULT(char_u *, y_size);
1641 if (y_array == NULL)
1642 goto end;
1643 }
1644 }
1645 else
1646#endif
1647 {
1648 y_size = 1; // use fake one-line yank register
1649 y_array = &insert_string;
1650 }
1651 }
1652 else
1653 {
1654 get_yank_register(regname, FALSE);
1655
1656 y_type = y_current->y_type;
1657 y_width = y_current->y_width;
1658 y_size = y_current->y_size;
1659 y_array = y_current->y_array;
Bram Moolenaar9ac38122021-12-02 18:42:33 +00001660 y_current_used = y_current;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001661 }
1662
1663 if (y_type == MLINE)
1664 {
1665 if (flags & PUT_LINE_SPLIT)
1666 {
1667 char_u *p;
1668
1669 // "p" or "P" in Visual mode: split the lines to put the text in
1670 // between.
1671 if (u_save_cursor() == FAIL)
1672 goto end;
1673 p = ml_get_cursor();
1674 if (dir == FORWARD && *p != NUL)
1675 MB_PTR_ADV(p);
1676 ptr = vim_strsave(p);
1677 if (ptr == NULL)
1678 goto end;
1679 ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE);
1680 vim_free(ptr);
1681
1682 oldp = ml_get_curline();
1683 p = oldp + curwin->w_cursor.col;
1684 if (dir == FORWARD && *p != NUL)
1685 MB_PTR_ADV(p);
1686 ptr = vim_strnsave(oldp, p - oldp);
1687 if (ptr == NULL)
1688 goto end;
1689 ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
1690 ++nr_lines;
1691 dir = FORWARD;
1692 }
1693 if (flags & PUT_LINE_FORWARD)
1694 {
1695 // Must be "p" for a Visual block, put lines below the block.
1696 curwin->w_cursor = curbuf->b_visual.vi_end;
1697 dir = FORWARD;
1698 }
1699 curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
1700 curbuf->b_op_end = curwin->w_cursor; // default for '] mark
1701 }
1702
1703 if (flags & PUT_LINE) // :put command or "p" in Visual line mode.
1704 y_type = MLINE;
1705
1706 if (y_size == 0 || y_array == NULL)
1707 {
Bram Moolenaarac78dd42022-01-02 19:25:26 +00001708 semsg(_(e_nothing_in_register_str),
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001709 regname == 0 ? (char_u *)"\"" : transchar(regname));
1710 goto end;
1711 }
1712
1713 if (y_type == MBLOCK)
1714 {
1715 lnum = curwin->w_cursor.lnum + y_size + 1;
1716 if (lnum > curbuf->b_ml.ml_line_count)
1717 lnum = curbuf->b_ml.ml_line_count + 1;
1718 if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
1719 goto end;
1720 }
1721 else if (y_type == MLINE)
1722 {
1723 lnum = curwin->w_cursor.lnum;
1724#ifdef FEAT_FOLDING
1725 // Correct line number for closed fold. Don't move the cursor yet,
1726 // u_save() uses it.
1727 if (dir == BACKWARD)
1728 (void)hasFolding(lnum, &lnum, NULL);
1729 else
1730 (void)hasFolding(lnum, NULL, &lnum);
1731#endif
1732 if (dir == FORWARD)
1733 ++lnum;
1734 // In an empty buffer the empty line is going to be replaced, include
1735 // it in the saved lines.
1736 if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL)
1737 goto end;
1738#ifdef FEAT_FOLDING
1739 if (dir == FORWARD)
1740 curwin->w_cursor.lnum = lnum - 1;
1741 else
1742 curwin->w_cursor.lnum = lnum;
1743 curbuf->b_op_start = curwin->w_cursor; // for mark_adjust()
1744#endif
1745 }
1746 else if (u_save_cursor() == FAIL)
1747 goto end;
1748
1749 yanklen = (int)STRLEN(y_array[0]);
1750
Gary Johnson53ba05b2021-07-26 22:19:10 +02001751 if (cur_ve_flags == VE_ALL && y_type == MCHAR)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001752 {
1753 if (gchar_cursor() == TAB)
1754 {
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001755 int viscol = getviscol();
1756 int ts = curbuf->b_p_ts;
1757
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001758 // Don't need to insert spaces when "p" on the last position of a
1759 // tab or "P" on the first position.
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001760 if (dir == FORWARD ?
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001761#ifdef FEAT_VARTABS
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01001762 tabstop_padding(viscol, ts, curbuf->b_p_vts_array) != 1
1763#else
1764 ts - (viscol % ts) != 1
1765#endif
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001766 : curwin->w_cursor.coladd > 0)
1767 coladvance_force(viscol);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001768 else
1769 curwin->w_cursor.coladd = 0;
1770 }
1771 else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
1772 coladvance_force(getviscol() + (dir == FORWARD));
1773 }
1774
1775 lnum = curwin->w_cursor.lnum;
1776 col = curwin->w_cursor.col;
1777
1778 // Block mode
1779 if (y_type == MBLOCK)
1780 {
1781 int c = gchar_cursor();
1782 colnr_T endcol2 = 0;
1783
1784 if (dir == FORWARD && c != NUL)
1785 {
Gary Johnson53ba05b2021-07-26 22:19:10 +02001786 if (cur_ve_flags == VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001787 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1788 else
1789 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
1790
1791 if (has_mbyte)
1792 // move to start of next multi-byte character
1793 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
1794 else
Gary Johnson53ba05b2021-07-26 22:19:10 +02001795 if (c != TAB || cur_ve_flags != VE_ALL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001796 ++curwin->w_cursor.col;
1797 ++col;
1798 }
1799 else
1800 getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
1801
1802 col += curwin->w_cursor.coladd;
Gary Johnson53ba05b2021-07-26 22:19:10 +02001803 if (cur_ve_flags == VE_ALL
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001804 && (curwin->w_cursor.coladd > 0
1805 || endcol2 == curwin->w_cursor.col))
1806 {
1807 if (dir == FORWARD && c == NUL)
1808 ++col;
Bram Moolenaaref85a9b2020-07-10 20:24:07 +02001809 if (dir != FORWARD && c != NUL && curwin->w_cursor.coladd > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001810 ++curwin->w_cursor.col;
1811 if (c == TAB)
1812 {
1813 if (dir == BACKWARD && curwin->w_cursor.col)
1814 curwin->w_cursor.col--;
1815 if (dir == FORWARD && col - 1 == endcol2)
1816 curwin->w_cursor.col++;
1817 }
1818 }
1819 curwin->w_cursor.coladd = 0;
1820 bd.textcol = 0;
1821 for (i = 0; i < y_size; ++i)
1822 {
Christian Brabandt2fa93842021-05-30 22:17:25 +02001823 int spaces = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001824 char shortline;
1825
1826 bd.startspaces = 0;
1827 bd.endspaces = 0;
1828 vcol = 0;
1829 delcount = 0;
1830
1831 // add a new line
1832 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
1833 {
1834 if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
1835 (colnr_T)1, FALSE) == FAIL)
1836 break;
1837 ++nr_lines;
1838 }
1839 // get the old line and advance to the position to insert at
1840 oldp = ml_get_curline();
1841 oldlen = (int)STRLEN(oldp);
1842 for (ptr = oldp; vcol < col && *ptr; )
1843 {
1844 // Count a tab for what it's worth (if list mode not on)
1845 incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol);
1846 vcol += incr;
1847 }
1848 bd.textcol = (colnr_T)(ptr - oldp);
1849
1850 shortline = (vcol < col) || (vcol == col && !*ptr) ;
1851
1852 if (vcol < col) // line too short, padd with spaces
1853 bd.startspaces = col - vcol;
1854 else if (vcol > col)
1855 {
1856 bd.endspaces = vcol - col;
1857 bd.startspaces = incr - bd.endspaces;
1858 --bd.textcol;
1859 delcount = 1;
1860 if (has_mbyte)
1861 bd.textcol -= (*mb_head_off)(oldp, oldp + bd.textcol);
1862 if (oldp[bd.textcol] != TAB)
1863 {
1864 // Only a Tab can be split into spaces. Other
1865 // characters will have to be moved to after the
1866 // block, causing misalignment.
1867 delcount = 0;
1868 bd.endspaces = 0;
1869 }
1870 }
1871
1872 yanklen = (int)STRLEN(y_array[i]);
1873
Christian Brabandt2fa93842021-05-30 22:17:25 +02001874 if ((flags & PUT_BLOCK_INNER) == 0)
1875 {
1876 // calculate number of spaces required to fill right side of
1877 // block
1878 spaces = y_width + 1;
1879 for (j = 0; j < yanklen; j++)
1880 spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
1881 if (spaces < 0)
1882 spaces = 0;
1883 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001884
ichizokfa537222021-11-16 12:50:46 +00001885 // Insert the new text.
1886 // First check for multiplication overflow.
1887 if (yanklen + spaces != 0
1888 && count > ((INT_MAX - (bd.startspaces + bd.endspaces))
1889 / (yanklen + spaces)))
1890 {
1891 emsg(_(e_resulting_text_too_long));
1892 break;
1893 }
1894
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001895 totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
1896 newp = alloc(totlen + oldlen + 1);
1897 if (newp == NULL)
1898 break;
ichizokfa537222021-11-16 12:50:46 +00001899
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001900 // copy part up to cursor to new line
1901 ptr = newp;
1902 mch_memmove(ptr, oldp, (size_t)bd.textcol);
1903 ptr += bd.textcol;
ichizokfa537222021-11-16 12:50:46 +00001904
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001905 // may insert some spaces before the new text
1906 vim_memset(ptr, ' ', (size_t)bd.startspaces);
1907 ptr += bd.startspaces;
ichizokfa537222021-11-16 12:50:46 +00001908
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001909 // insert the new text
1910 for (j = 0; j < count; ++j)
1911 {
1912 mch_memmove(ptr, y_array[i], (size_t)yanklen);
1913 ptr += yanklen;
1914
1915 // insert block's trailing spaces only if there's text behind
1916 if ((j < count - 1 || !shortline) && spaces)
1917 {
1918 vim_memset(ptr, ' ', (size_t)spaces);
1919 ptr += spaces;
1920 }
1921 }
ichizokfa537222021-11-16 12:50:46 +00001922
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001923 // may insert some spaces after the new text
1924 vim_memset(ptr, ' ', (size_t)bd.endspaces);
1925 ptr += bd.endspaces;
ichizokfa537222021-11-16 12:50:46 +00001926
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02001927 // move the text after the cursor to the end of the line.
1928 mch_memmove(ptr, oldp + bd.textcol + delcount,
1929 (size_t)(oldlen - bd.textcol - delcount + 1));
1930 ml_replace(curwin->w_cursor.lnum, newp, FALSE);
1931
1932 ++curwin->w_cursor.lnum;
1933 if (i == 0)
1934 curwin->w_cursor.col += bd.startspaces;
1935 }
1936
1937 changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines);
1938
1939 // Set '[ mark.
1940 curbuf->b_op_start = curwin->w_cursor;
1941 curbuf->b_op_start.lnum = lnum;
1942
1943 // adjust '] mark
1944 curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
1945 curbuf->b_op_end.col = bd.textcol + totlen - 1;
1946 curbuf->b_op_end.coladd = 0;
1947 if (flags & PUT_CURSEND)
1948 {
1949 colnr_T len;
1950
1951 curwin->w_cursor = curbuf->b_op_end;
1952 curwin->w_cursor.col++;
1953
1954 // in Insert mode we might be after the NUL, correct for that
1955 len = (colnr_T)STRLEN(ml_get_curline());
1956 if (curwin->w_cursor.col > len)
1957 curwin->w_cursor.col = len;
1958 }
1959 else
1960 curwin->w_cursor.lnum = lnum;
1961 }
1962 else
1963 {
1964 // Character or Line mode
1965 if (y_type == MCHAR)
1966 {
1967 // if type is MCHAR, FORWARD is the same as BACKWARD on the next
1968 // char
1969 if (dir == FORWARD && gchar_cursor() != NUL)
1970 {
1971 if (has_mbyte)
1972 {
1973 int bytelen = (*mb_ptr2len)(ml_get_cursor());
1974
1975 // put it on the next of the multi-byte character.
1976 col += bytelen;
1977 if (yanklen)
1978 {
1979 curwin->w_cursor.col += bytelen;
1980 curbuf->b_op_end.col += bytelen;
1981 }
1982 }
1983 else
1984 {
1985 ++col;
1986 if (yanklen)
1987 {
1988 ++curwin->w_cursor.col;
1989 ++curbuf->b_op_end.col;
1990 }
1991 }
1992 }
1993 curbuf->b_op_start = curwin->w_cursor;
1994 }
1995 // Line mode: BACKWARD is the same as FORWARD on the previous line
1996 else if (dir == BACKWARD)
1997 --lnum;
1998 new_cursor = curwin->w_cursor;
1999
Bram Moolenaarcd942772020-08-22 21:08:44 +02002000 // simple case: insert into one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002001 if (y_type == MCHAR && y_size == 1)
2002 {
Bram Moolenaarcd942772020-08-22 21:08:44 +02002003 linenr_T end_lnum = 0; // init for gcc
2004 linenr_T start_lnum = lnum;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002005 int first_byte_off = 0;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002006
2007 if (VIsual_active)
2008 {
2009 end_lnum = curbuf->b_visual.vi_end.lnum;
2010 if (end_lnum < curbuf->b_visual.vi_start.lnum)
2011 end_lnum = curbuf->b_visual.vi_start.lnum;
Bram Moolenaarcd942772020-08-22 21:08:44 +02002012 if (end_lnum > start_lnum)
2013 {
2014 pos_T pos;
2015
2016 // "col" is valid for the first line, in following lines
2017 // the virtual column needs to be used. Matters for
2018 // multi-byte characters.
2019 pos.lnum = lnum;
2020 pos.col = col;
2021 pos.coladd = 0;
2022 getvcol(curwin, &pos, NULL, &vcol, NULL);
2023 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002024 }
2025
ichizokfa537222021-11-16 12:50:46 +00002026 if (count == 0 || yanklen == 0)
2027 {
2028 if (VIsual_active)
2029 lnum = end_lnum;
2030 }
2031 else if (count > INT_MAX / yanklen)
2032 // multiplication overflow
2033 emsg(_(e_resulting_text_too_long));
2034 else
2035 {
Bram Moolenaare551ccf2021-11-02 23:11:00 +00002036 totlen = count * yanklen;
ichizokfa537222021-11-16 12:50:46 +00002037 do {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002038 oldp = ml_get(lnum);
ichizokfa537222021-11-16 12:50:46 +00002039 oldlen = (int)STRLEN(oldp);
Bram Moolenaarcd942772020-08-22 21:08:44 +02002040 if (lnum > start_lnum)
2041 {
2042 pos_T pos;
2043
2044 pos.lnum = lnum;
2045 if (getvpos(&pos, vcol) == OK)
2046 col = pos.col;
2047 else
2048 col = MAXCOL;
2049 }
ichizokfa537222021-11-16 12:50:46 +00002050 if (VIsual_active && col > oldlen)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002051 {
2052 lnum++;
2053 continue;
2054 }
ichizokfa537222021-11-16 12:50:46 +00002055 newp = alloc(totlen + oldlen + 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002056 if (newp == NULL)
2057 goto end; // alloc() gave an error message
2058 mch_memmove(newp, oldp, (size_t)col);
2059 ptr = newp + col;
2060 for (i = 0; i < count; ++i)
2061 {
2062 mch_memmove(ptr, y_array[0], (size_t)yanklen);
2063 ptr += yanklen;
2064 }
2065 STRMOVE(ptr, oldp + col);
2066 ml_replace(lnum, newp, FALSE);
Bram Moolenaar4d072532021-11-25 19:31:15 +00002067
2068 // compute the byte offset for the last character
2069 first_byte_off = mb_head_off(newp, ptr - 1);
2070
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002071 // Place cursor on last putted char.
2072 if (lnum == curwin->w_cursor.lnum)
2073 {
2074 // make sure curwin->w_virtcol is updated
2075 changed_cline_bef_curs();
2076 curwin->w_cursor.col += (colnr_T)(totlen - 1);
2077 }
ichizokfa537222021-11-16 12:50:46 +00002078 if (VIsual_active)
2079 lnum++;
2080 } while (VIsual_active && lnum <= end_lnum);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002081
ichizokfa537222021-11-16 12:50:46 +00002082 if (VIsual_active) // reset lnum to the last visual line
2083 lnum--;
2084 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002085
Bram Moolenaar4d072532021-11-25 19:31:15 +00002086 // put '] at the first byte of the last character
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002087 curbuf->b_op_end = curwin->w_cursor;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002088 curbuf->b_op_end.col -= first_byte_off;
2089
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002090 // For "CTRL-O p" in Insert mode, put cursor after last char
2091 if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
2092 ++curwin->w_cursor.col;
Bram Moolenaar4d072532021-11-25 19:31:15 +00002093 else
2094 curwin->w_cursor.col -= first_byte_off;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002095 changed_bytes(lnum, col);
2096 }
2097 else
2098 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002099 linenr_T new_lnum = new_cursor.lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002100 size_t len;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002101
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002102 // Insert at least one line. When y_type is MCHAR, break the first
2103 // line in two.
2104 for (cnt = 1; cnt <= count; ++cnt)
2105 {
2106 i = 0;
2107 if (y_type == MCHAR)
2108 {
2109 // Split the current line in two at the insert position.
2110 // First insert y_array[size - 1] in front of second line.
2111 // Then append y_array[0] to first line.
2112 lnum = new_cursor.lnum;
2113 ptr = ml_get(lnum) + col;
2114 totlen = (int)STRLEN(y_array[y_size - 1]);
2115 newp = alloc(STRLEN(ptr) + totlen + 1);
2116 if (newp == NULL)
2117 goto error;
2118 STRCPY(newp, y_array[y_size - 1]);
2119 STRCAT(newp, ptr);
2120 // insert second line
2121 ml_append(lnum, newp, (colnr_T)0, FALSE);
Bram Moolenaar23003e52021-09-22 16:37:07 +02002122 ++new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002123 vim_free(newp);
2124
2125 oldp = ml_get(lnum);
2126 newp = alloc(col + yanklen + 1);
2127 if (newp == NULL)
2128 goto error;
2129 // copy first part of line
2130 mch_memmove(newp, oldp, (size_t)col);
2131 // append to first line
2132 mch_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
2133 ml_replace(lnum, newp, FALSE);
2134
2135 curwin->w_cursor.lnum = lnum;
2136 i = 1;
2137 }
2138
2139 for (; i < y_size; ++i)
2140 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002141 if (y_type != MCHAR || i < y_size - 1)
2142 {
2143 if (ml_append(lnum, y_array[i], (colnr_T)0, FALSE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002144 == FAIL)
2145 goto error;
Bram Moolenaar23003e52021-09-22 16:37:07 +02002146 new_lnum++;
2147 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002148 lnum++;
2149 ++nr_lines;
2150 if (flags & PUT_FIXINDENT)
2151 {
2152 old_pos = curwin->w_cursor;
2153 curwin->w_cursor.lnum = lnum;
2154 ptr = ml_get(lnum);
2155 if (cnt == count && i == y_size - 1)
2156 lendiff = (int)STRLEN(ptr);
2157#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
2158 if (*ptr == '#' && preprocs_left())
2159 indent = 0; // Leave # lines at start
2160 else
2161#endif
2162 if (*ptr == NUL)
2163 indent = 0; // Ignore empty lines
2164 else if (first_indent)
2165 {
2166 indent_diff = orig_indent - get_indent();
2167 indent = orig_indent;
2168 first_indent = FALSE;
2169 }
2170 else if ((indent = get_indent() + indent_diff) < 0)
2171 indent = 0;
2172 (void)set_indent(indent, 0);
2173 curwin->w_cursor = old_pos;
2174 // remember how many chars were removed
2175 if (cnt == count && i == y_size - 1)
2176 lendiff -= (int)STRLEN(ml_get(lnum));
2177 }
2178 }
Bram Moolenaar23003e52021-09-22 16:37:07 +02002179 if (cnt == 1)
2180 new_lnum = lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002181 }
2182
2183error:
2184 // Adjust marks.
2185 if (y_type == MLINE)
2186 {
2187 curbuf->b_op_start.col = 0;
2188 if (dir == FORWARD)
2189 curbuf->b_op_start.lnum++;
2190 }
2191 // Skip mark_adjust when adding lines after the last one, there
2192 // can't be marks there. But still needed in diff mode.
2193 if (curbuf->b_op_start.lnum + (y_type == MCHAR) - 1 + nr_lines
2194 < curbuf->b_ml.ml_line_count
2195#ifdef FEAT_DIFF
2196 || curwin->w_p_diff
2197#endif
2198 )
2199 mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
2200 (linenr_T)MAXLNUM, nr_lines, 0L);
2201
2202 // note changed text for displaying and folding
2203 if (y_type == MCHAR)
2204 changed_lines(curwin->w_cursor.lnum, col,
2205 curwin->w_cursor.lnum + 1, nr_lines);
2206 else
2207 changed_lines(curbuf->b_op_start.lnum, 0,
2208 curbuf->b_op_start.lnum, nr_lines);
Bram Moolenaar9ac38122021-12-02 18:42:33 +00002209 if (y_current_used != NULL && (y_current_used != y_current
2210 || y_current->y_array != y_array))
2211 {
2212 // Something invoked through changed_lines() has changed the
2213 // yank buffer, e.g. a GUI clipboard callback.
2214 emsg(_(e_yank_register_changed_while_using_it));
2215 goto end;
2216 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002217
Bram Moolenaar4d072532021-11-25 19:31:15 +00002218 // Put the '] mark on the first byte of the last inserted character.
2219 // Correct the length for change in indent.
Bram Moolenaarf47ebf12021-10-19 20:08:45 +01002220 curbuf->b_op_end.lnum = new_lnum;
Bram Moolenaar85be8562021-11-25 20:40:11 +00002221 len = STRLEN(y_array[y_size - 1]);
2222 col = (colnr_T)len - lendiff;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002223 if (col > 1)
Bram Moolenaar4d072532021-11-25 19:31:15 +00002224 curbuf->b_op_end.col = col - 1
2225 - mb_head_off(y_array[y_size - 1],
Bram Moolenaar85be8562021-11-25 20:40:11 +00002226 y_array[y_size - 1] + len - 1);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002227 else
2228 curbuf->b_op_end.col = 0;
2229
2230 if (flags & PUT_CURSLINE)
2231 {
2232 // ":put": put cursor on last inserted line
2233 curwin->w_cursor.lnum = lnum;
2234 beginline(BL_WHITE | BL_FIX);
2235 }
2236 else if (flags & PUT_CURSEND)
2237 {
2238 // put cursor after inserted text
2239 if (y_type == MLINE)
2240 {
2241 if (lnum >= curbuf->b_ml.ml_line_count)
2242 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
2243 else
2244 curwin->w_cursor.lnum = lnum + 1;
2245 curwin->w_cursor.col = 0;
2246 }
2247 else
2248 {
Bram Moolenaar23003e52021-09-22 16:37:07 +02002249 curwin->w_cursor.lnum = new_lnum;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002250 curwin->w_cursor.col = col;
Bram Moolenaar56858e42021-09-22 16:43:59 +02002251 curbuf->b_op_end = curwin->w_cursor;
2252 if (col > 1)
2253 curbuf->b_op_end.col = col - 1;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002254 }
2255 }
2256 else if (y_type == MLINE)
2257 {
2258 // put cursor on first non-blank in first inserted line
2259 curwin->w_cursor.col = 0;
2260 if (dir == FORWARD)
2261 ++curwin->w_cursor.lnum;
2262 beginline(BL_WHITE | BL_FIX);
2263 }
2264 else // put cursor on first inserted character
2265 curwin->w_cursor = new_cursor;
2266 }
2267 }
2268
2269 msgmore(nr_lines);
2270 curwin->w_set_curswant = TRUE;
2271
2272end:
Bram Moolenaare1004402020-10-24 20:49:43 +02002273 if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
Bram Moolenaarf4a1d1c2019-11-16 13:50:25 +01002274 {
2275 curbuf->b_op_start = orig_start;
2276 curbuf->b_op_end = orig_end;
2277 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002278 if (allocated)
2279 vim_free(insert_string);
2280 if (regname == '=')
2281 vim_free(y_array);
2282
2283 VIsual_active = FALSE;
2284
2285 // If the cursor is past the end of the line put it at the end.
2286 adjust_cursor_eol();
2287}
2288
2289/*
2290 * Return the character name of the register with the given number.
2291 */
2292 int
2293get_register_name(int num)
2294{
2295 if (num == -1)
2296 return '"';
2297 else if (num < 10)
2298 return num + '0';
2299 else if (num == DELETION_REGISTER)
2300 return '-';
2301#ifdef FEAT_CLIPBOARD
2302 else if (num == STAR_REGISTER)
2303 return '*';
2304 else if (num == PLUS_REGISTER)
2305 return '+';
2306#endif
2307 else
2308 {
2309#ifdef EBCDIC
2310 int i;
2311
2312 // EBCDIC is really braindead ...
2313 i = 'a' + (num - 10);
2314 if (i > 'i')
2315 i += 7;
2316 if (i > 'r')
2317 i += 8;
2318 return i;
2319#else
2320 return num + 'a' - 10;
2321#endif
2322 }
2323}
2324
Dominique Pelle748b3082022-01-08 12:41:16 +00002325#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002326/*
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002327 * Return the index of the register "" points to.
2328 */
2329 int
2330get_unname_register()
2331{
2332 return y_previous == NULL ? -1 : y_previous - &y_regs[0];
2333}
Dominique Pelle748b3082022-01-08 12:41:16 +00002334#endif
Bram Moolenaarbb861e22020-06-07 18:16:36 +02002335
2336/*
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002337 * ":dis" and ":registers": Display the contents of the yank registers.
2338 */
2339 void
2340ex_display(exarg_T *eap)
2341{
2342 int i, n;
2343 long j;
2344 char_u *p;
2345 yankreg_T *yb;
2346 int name;
2347 int attr;
2348 char_u *arg = eap->arg;
2349 int clen;
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002350 int type;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002351
2352 if (arg != NULL && *arg == NUL)
2353 arg = NULL;
2354 attr = HL_ATTR(HLF_8);
2355
2356 // Highlight title
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002357 msg_puts_title(_("\nType Name Content"));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002358 for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
2359 {
2360 name = get_register_name(i);
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002361 switch (get_reg_type(name, NULL))
2362 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002363 case MLINE: type = 'l'; break;
2364 case MCHAR: type = 'c'; break;
2365 default: type = 'b'; break;
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002366 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002367 if (arg != NULL && vim_strchr(arg, name) == NULL
2368#ifdef ONE_CLIPBOARD
2369 // Star register and plus register contain the same thing.
2370 && (name != '*' || vim_strchr(arg, '+') == NULL)
2371#endif
2372 )
2373 continue; // did not ask for this register
2374
2375#ifdef FEAT_CLIPBOARD
2376 // Adjust register name for "unnamed" in 'clipboard'.
2377 // When it's a clipboard register, fill it with the current contents
2378 // of the clipboard.
2379 adjust_clip_reg(&name);
2380 (void)may_get_selection(name);
2381#endif
2382
2383 if (i == -1)
2384 {
2385 if (y_previous != NULL)
2386 yb = y_previous;
2387 else
2388 yb = &(y_regs[0]);
2389 }
2390 else
2391 yb = &(y_regs[i]);
2392
2393#ifdef FEAT_EVAL
2394 if (name == MB_TOLOWER(redir_reg)
2395 || (redir_reg == '"' && yb == y_previous))
2396 continue; // do not list register being written to, the
2397 // pointer can be freed
2398#endif
2399
2400 if (yb->y_array != NULL)
2401 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002402 int do_show = FALSE;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002403
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002404 for (j = 0; !do_show && j < yb->y_size; ++j)
2405 do_show = !message_filtered(yb->y_array[j]);
2406
2407 if (do_show || yb->y_size == 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002408 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002409 msg_putchar('\n');
2410 msg_puts(" ");
2411 msg_putchar(type);
2412 msg_puts(" ");
2413 msg_putchar('"');
2414 msg_putchar(name);
2415 msg_puts(" ");
2416
2417 n = (int)Columns - 11;
2418 for (j = 0; j < yb->y_size && n > 1; ++j)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002419 {
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002420 if (j)
2421 {
2422 msg_puts_attr("^J", attr);
2423 n -= 2;
2424 }
2425 for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0;
2426 ++p)
2427 {
2428 clen = (*mb_ptr2len)(p);
2429 msg_outtrans_len(p, clen);
2430 p += clen - 1;
2431 }
2432 }
2433 if (n > 1 && yb->y_type == MLINE)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002434 msg_puts_attr("^J", attr);
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002435 out_flush(); // show one line at a time
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002436 }
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002437 ui_breakcheck();
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002438 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002439 }
2440
2441 // display last inserted text
2442 if ((p = get_last_insert()) != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002443 && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
2444 && !message_filtered(p))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002445 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002446 msg_puts("\n c \". ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002447 dis_msg(p, TRUE);
2448 }
2449
2450 // display last command line
2451 if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002452 && !got_int && !message_filtered(last_cmdline))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002453 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002454 msg_puts("\n c \": ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002455 dis_msg(last_cmdline, FALSE);
2456 }
2457
2458 // display current file name
2459 if (curbuf->b_fname != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002460 && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int
2461 && !message_filtered(curbuf->b_fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002462 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002463 msg_puts("\n c \"% ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002464 dis_msg(curbuf->b_fname, FALSE);
2465 }
2466
2467 // display alternate file name
2468 if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
2469 {
2470 char_u *fname;
2471 linenr_T dummy;
2472
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002473 if (buflist_name_nr(0, &fname, &dummy) != FAIL
2474 && !message_filtered(fname))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002475 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002476 msg_puts("\n c \"# ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002477 dis_msg(fname, FALSE);
2478 }
2479 }
2480
2481 // display last search pattern
2482 if (last_search_pat() != NULL
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002483 && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int
2484 && !message_filtered(last_search_pat()))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002485 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002486 msg_puts("\n c \"/ ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002487 dis_msg(last_search_pat(), FALSE);
2488 }
2489
2490#ifdef FEAT_EVAL
2491 // display last used expression
2492 if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
Bram Moolenaar8fc42962019-10-26 17:33:13 +02002493 && !got_int && !message_filtered(expr_line))
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002494 {
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002495 msg_puts("\n c \"= ");
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002496 dis_msg(expr_line, FALSE);
2497 }
2498#endif
2499}
2500
2501/*
2502 * display a string for do_dis()
2503 * truncate at end of screen line
2504 */
2505 static void
2506dis_msg(
2507 char_u *p,
2508 int skip_esc) // if TRUE, ignore trailing ESC
2509{
2510 int n;
2511 int l;
2512
2513 n = (int)Columns - 6;
2514 while (*p != NUL
2515 && !(*p == ESC && skip_esc && *(p + 1) == NUL)
2516 && (n -= ptr2cells(p)) >= 0)
2517 {
2518 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
2519 {
2520 msg_outtrans_len(p, l);
2521 p += l;
2522 }
2523 else
2524 msg_outtrans_len(p++, 1);
2525 }
2526 ui_breakcheck();
2527}
2528
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002529#if defined(FEAT_DND) || defined(PROTO)
2530/*
2531 * Replace the contents of the '~' register with str.
2532 */
2533 void
2534dnd_yank_drag_data(char_u *str, long len)
2535{
2536 yankreg_T *curr;
2537
2538 curr = y_current;
2539 y_current = &y_regs[TILDE_REGISTER];
2540 free_yank_all();
2541 str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
2542 y_current = curr;
2543}
2544#endif
2545
2546
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002547/*
2548 * Return the type of a register.
2549 * Used for getregtype()
2550 * Returns MAUTO for error.
2551 */
2552 char_u
2553get_reg_type(int regname, long *reglen)
2554{
2555 switch (regname)
2556 {
2557 case '%': // file name
2558 case '#': // alternate file name
2559 case '=': // expression
2560 case ':': // last command line
2561 case '/': // last search-pattern
2562 case '.': // last inserted text
2563# ifdef FEAT_SEARCHPATH
2564 case Ctrl_F: // Filename under cursor
2565 case Ctrl_P: // Path under cursor, expand via "path"
2566# endif
2567 case Ctrl_W: // word under cursor
2568 case Ctrl_A: // WORD (mnemonic All) under cursor
2569 case '_': // black hole: always empty
2570 return MCHAR;
2571 }
2572
2573# ifdef FEAT_CLIPBOARD
2574 regname = may_get_selection(regname);
2575# endif
2576
2577 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2578 return MAUTO;
2579
2580 get_yank_register(regname, FALSE);
2581
2582 if (y_current->y_array != NULL)
2583 {
2584 if (reglen != NULL && y_current->y_type == MBLOCK)
2585 *reglen = y_current->y_width;
2586 return y_current->y_type;
2587 }
2588 return MAUTO;
2589}
2590
Bram Moolenaar3691f1e2019-10-24 20:17:00 +02002591#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002592/*
2593 * When "flags" has GREG_LIST return a list with text "s".
2594 * Otherwise just return "s".
2595 */
2596 static char_u *
2597getreg_wrap_one_line(char_u *s, int flags)
2598{
2599 if (flags & GREG_LIST)
2600 {
2601 list_T *list = list_alloc();
2602
2603 if (list != NULL)
2604 {
2605 if (list_append_string(list, NULL, -1) == FAIL)
2606 {
2607 list_free(list);
2608 return NULL;
2609 }
2610 list->lv_first->li_tv.vval.v_string = s;
2611 }
2612 return (char_u *)list;
2613 }
2614 return s;
2615}
2616
2617/*
Bram Moolenaard672dde2020-02-26 13:43:51 +01002618 * Return the contents of a register as a single allocated string or as a list.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002619 * Used for "@r" in expressions and for getreg().
2620 * Returns NULL for error.
2621 * Flags:
2622 * GREG_NO_EXPR Do not allow expression register
2623 * GREG_EXPR_SRC For the expression register: return expression itself,
2624 * not the result of its evaluation.
Bram Moolenaard672dde2020-02-26 13:43:51 +01002625 * GREG_LIST Return a list of lines instead of a single string.
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002626 */
2627 char_u *
2628get_reg_contents(int regname, int flags)
2629{
2630 long i;
2631 char_u *retval;
2632 int allocated;
2633 long len;
2634
2635 // Don't allow using an expression register inside an expression
2636 if (regname == '=')
2637 {
2638 if (flags & GREG_NO_EXPR)
2639 return NULL;
2640 if (flags & GREG_EXPR_SRC)
2641 return getreg_wrap_one_line(get_expr_line_src(), flags);
2642 return getreg_wrap_one_line(get_expr_line(), flags);
2643 }
2644
2645 if (regname == '@') // "@@" is used for unnamed register
2646 regname = '"';
2647
2648 // check for valid regname
2649 if (regname != NUL && !valid_yank_reg(regname, FALSE))
2650 return NULL;
2651
2652# ifdef FEAT_CLIPBOARD
2653 regname = may_get_selection(regname);
2654# endif
2655
2656 if (get_spec_reg(regname, &retval, &allocated, FALSE))
2657 {
2658 if (retval == NULL)
2659 return NULL;
2660 if (allocated)
2661 return getreg_wrap_one_line(retval, flags);
2662 return getreg_wrap_one_line(vim_strsave(retval), flags);
2663 }
2664
2665 get_yank_register(regname, FALSE);
2666 if (y_current->y_array == NULL)
2667 return NULL;
2668
2669 if (flags & GREG_LIST)
2670 {
2671 list_T *list = list_alloc();
2672 int error = FALSE;
2673
2674 if (list == NULL)
2675 return NULL;
2676 for (i = 0; i < y_current->y_size; ++i)
2677 if (list_append_string(list, y_current->y_array[i], -1) == FAIL)
2678 error = TRUE;
2679 if (error)
2680 {
2681 list_free(list);
2682 return NULL;
2683 }
2684 return (char_u *)list;
2685 }
2686
2687 // Compute length of resulting string.
2688 len = 0;
2689 for (i = 0; i < y_current->y_size; ++i)
2690 {
2691 len += (long)STRLEN(y_current->y_array[i]);
2692 // Insert a newline between lines and after last line if
2693 // y_type is MLINE.
2694 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2695 ++len;
2696 }
2697
2698 retval = alloc(len + 1);
2699
2700 // Copy the lines of the yank register into the string.
2701 if (retval != NULL)
2702 {
2703 len = 0;
2704 for (i = 0; i < y_current->y_size; ++i)
2705 {
2706 STRCPY(retval + len, y_current->y_array[i]);
2707 len += (long)STRLEN(retval + len);
2708
2709 // Insert a NL between lines and after the last line if y_type is
2710 // MLINE.
2711 if (y_current->y_type == MLINE || i < y_current->y_size - 1)
2712 retval[len++] = '\n';
2713 }
2714 retval[len] = NUL;
2715 }
2716
2717 return retval;
2718}
2719
2720 static int
2721init_write_reg(
2722 int name,
2723 yankreg_T **old_y_previous,
2724 yankreg_T **old_y_current,
2725 int must_append,
2726 int *yank_type UNUSED)
2727{
2728 if (!valid_yank_reg(name, TRUE)) // check for valid reg name
2729 {
2730 emsg_invreg(name);
2731 return FAIL;
2732 }
2733
2734 // Don't want to change the current (unnamed) register
2735 *old_y_previous = y_previous;
2736 *old_y_current = y_current;
2737
2738 get_yank_register(name, TRUE);
2739 if (!y_append && !must_append)
2740 free_yank_all();
2741 return OK;
2742}
2743
2744 static void
2745finish_write_reg(
2746 int name,
2747 yankreg_T *old_y_previous,
2748 yankreg_T *old_y_current)
2749{
2750# ifdef FEAT_CLIPBOARD
2751 // Send text of clipboard register to the clipboard.
2752 may_set_selection();
2753# endif
2754
2755 // ':let @" = "val"' should change the meaning of the "" register
2756 if (name != '"')
2757 y_previous = old_y_previous;
2758 y_current = old_y_current;
2759}
2760
2761/*
2762 * Store string "str" in register "name".
2763 * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
2764 * If "must_append" is TRUE, always append to the register. Otherwise append
2765 * if "name" is an uppercase letter.
2766 * Note: "maxlen" and "must_append" don't work for the "/" register.
2767 * Careful: 'str' is modified, you may have to use a copy!
2768 * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise.
2769 */
2770 void
2771write_reg_contents(
2772 int name,
2773 char_u *str,
2774 int maxlen,
2775 int must_append)
2776{
2777 write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
2778}
2779
2780 void
2781write_reg_contents_lst(
2782 int name,
2783 char_u **strings,
2784 int maxlen UNUSED,
2785 int must_append,
2786 int yank_type,
2787 long block_len)
2788{
2789 yankreg_T *old_y_previous, *old_y_current;
2790
2791 if (name == '/' || name == '=')
2792 {
2793 char_u *s;
2794
2795 if (strings[0] == NULL)
2796 s = (char_u *)"";
2797 else if (strings[1] != NULL)
2798 {
Bram Moolenaard82a47d2022-01-05 20:24:39 +00002799 emsg(_(e_search_pattern_and_expression_register_may_not_contain_two_or_more_lines));
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002800 return;
2801 }
2802 else
2803 s = strings[0];
2804 write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
2805 return;
2806 }
2807
2808 if (name == '_') // black hole: nothing to do
2809 return;
2810
2811 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2812 &yank_type) == FAIL)
2813 return;
2814
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02002815 str_to_reg(y_current, yank_type, (char_u *)strings, -1, block_len, TRUE);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002816
2817 finish_write_reg(name, old_y_previous, old_y_current);
2818}
2819
2820 void
2821write_reg_contents_ex(
2822 int name,
2823 char_u *str,
2824 int maxlen,
2825 int must_append,
2826 int yank_type,
2827 long block_len)
2828{
2829 yankreg_T *old_y_previous, *old_y_current;
2830 long len;
2831
2832 if (maxlen >= 0)
2833 len = maxlen;
2834 else
2835 len = (long)STRLEN(str);
2836
2837 // Special case: '/' search pattern
2838 if (name == '/')
2839 {
2840 set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
2841 return;
2842 }
2843
2844 if (name == '#')
2845 {
2846 buf_T *buf;
2847
2848 if (VIM_ISDIGIT(*str))
2849 {
2850 int num = atoi((char *)str);
2851
2852 buf = buflist_findnr(num);
2853 if (buf == NULL)
Bram Moolenaar40bcec12021-12-05 22:19:27 +00002854 semsg(_(e_buffer_nr_does_not_exist), (long)num);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002855 }
2856 else
2857 buf = buflist_findnr(buflist_findpat(str, str + STRLEN(str),
2858 TRUE, FALSE, FALSE));
2859 if (buf == NULL)
2860 return;
2861 curwin->w_alt_fnum = buf->b_fnum;
2862 return;
2863 }
2864
2865 if (name == '=')
2866 {
2867 char_u *p, *s;
2868
Bram Moolenaar71ccd032020-06-12 22:59:11 +02002869 p = vim_strnsave(str, len);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002870 if (p == NULL)
2871 return;
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002872 if (must_append && expr_line != NULL)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002873 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002874 s = concat_str(expr_line, p);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002875 vim_free(p);
2876 p = s;
2877 }
Bram Moolenaarb4bcea42020-10-28 13:53:50 +01002878 set_expr_line(p, NULL);
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002879 return;
2880 }
2881
2882 if (name == '_') // black hole: nothing to do
2883 return;
2884
2885 if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
2886 &yank_type) == FAIL)
2887 return;
2888
2889 str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
2890
2891 finish_write_reg(name, old_y_previous, old_y_current);
2892}
2893#endif // FEAT_EVAL
2894
2895#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
2896/*
2897 * Put a string into a register. When the register is not empty, the string
2898 * is appended.
2899 */
Bram Moolenaar45fffdf2020-03-24 21:42:01 +01002900 void
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002901str_to_reg(
2902 yankreg_T *y_ptr, // pointer to yank register
2903 int yank_type, // MCHAR, MLINE, MBLOCK, MAUTO
2904 char_u *str, // string to put in register
2905 long len, // length of string
2906 long blocklen, // width of Visual block
2907 int str_list) // TRUE if str is char_u **
2908{
2909 int type; // MCHAR, MLINE or MBLOCK
2910 int lnum;
2911 long start;
2912 long i;
2913 int extra;
2914 int newlines; // number of lines added
2915 int extraline = 0; // extra line at the end
2916 int append = FALSE; // append to last line in register
2917 char_u *s;
2918 char_u **ss;
2919 char_u **pp;
2920 long maxlen;
2921
2922 if (y_ptr->y_array == NULL) // NULL means empty register
2923 y_ptr->y_size = 0;
2924
2925 if (yank_type == MAUTO)
2926 type = ((str_list || (len > 0 && (str[len - 1] == NL
2927 || str[len - 1] == CAR)))
2928 ? MLINE : MCHAR);
2929 else
2930 type = yank_type;
2931
2932 // Count the number of lines within the string
2933 newlines = 0;
2934 if (str_list)
2935 {
2936 for (ss = (char_u **) str; *ss != NULL; ++ss)
2937 ++newlines;
2938 }
2939 else
2940 {
2941 for (i = 0; i < len; i++)
2942 if (str[i] == '\n')
2943 ++newlines;
2944 if (type == MCHAR || len == 0 || str[len - 1] != '\n')
2945 {
2946 extraline = 1;
2947 ++newlines; // count extra newline at the end
2948 }
2949 if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR)
2950 {
2951 append = TRUE;
2952 --newlines; // uncount newline when appending first line
2953 }
2954 }
2955
2956 // Without any lines make the register empty.
2957 if (y_ptr->y_size + newlines == 0)
2958 {
2959 VIM_CLEAR(y_ptr->y_array);
2960 return;
2961 }
2962
2963 // Allocate an array to hold the pointers to the new register lines.
2964 // If the register was not empty, move the existing lines to the new array.
2965 pp = lalloc_clear((y_ptr->y_size + newlines) * sizeof(char_u *), TRUE);
2966 if (pp == NULL) // out of memory
2967 return;
2968 for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
2969 pp[lnum] = y_ptr->y_array[lnum];
2970 vim_free(y_ptr->y_array);
2971 y_ptr->y_array = pp;
2972 maxlen = 0;
2973
2974 // Find the end of each line and save it into the array.
2975 if (str_list)
2976 {
2977 for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
2978 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002979 pp[lnum] = vim_strsave(*ss);
2980 if (type == MBLOCK)
2981 {
2982 int charlen = mb_string2cells(*ss, -1);
2983
2984 if (charlen > maxlen)
2985 maxlen = charlen;
2986 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002987 }
2988 }
2989 else
2990 {
2991 for (start = 0; start < len + extraline; start += i + 1)
2992 {
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002993 int charlen = 0;
2994
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002995 for (i = start; i < len; ++i) // find the end of the line
Bram Moolenaar24951a62021-06-04 18:33:49 +02002996 {
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02002997 if (str[i] == '\n')
2998 break;
Bram Moolenaar6c4c4042021-06-04 19:17:07 +02002999 if (type == MBLOCK)
3000 charlen += mb_ptr2cells_len(str + i, len - i);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003001 }
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003002 i -= start; // i is now length of line
Bram Moolenaar6e0b5532021-06-04 17:11:47 +02003003 if (charlen > maxlen)
3004 maxlen = charlen;
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003005 if (append)
3006 {
3007 --lnum;
3008 extra = (int)STRLEN(y_ptr->y_array[lnum]);
3009 }
3010 else
3011 extra = 0;
3012 s = alloc(i + extra + 1);
3013 if (s == NULL)
3014 break;
3015 if (extra)
3016 mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
3017 if (append)
3018 vim_free(y_ptr->y_array[lnum]);
Bram Moolenaar24951a62021-06-04 18:33:49 +02003019 if (i > 0)
Bram Moolenaar4aea03e2019-09-25 22:37:17 +02003020 mch_memmove(s + extra, str + start, (size_t)i);
3021 extra += i;
3022 s[extra] = NUL;
3023 y_ptr->y_array[lnum++] = s;
3024 while (--extra >= 0)
3025 {
3026 if (*s == NUL)
3027 *s = '\n'; // replace NUL with newline
3028 ++s;
3029 }
3030 append = FALSE; // only first line is appended
3031 }
3032 }
3033 y_ptr->y_type = type;
3034 y_ptr->y_size = lnum;
3035 if (type == MBLOCK)
3036 y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
3037 else
3038 y_ptr->y_width = 0;
3039# ifdef FEAT_VIMINFO
3040 y_ptr->y_time_set = vim_time();
3041# endif
3042}
3043#endif // FEAT_CLIPBOARD || FEAT_EVAL || PROTO