aboutsummaryrefslogtreecommitdiff
path: root/src/ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ops.c')
-rw-r--r--src/ops.c5174
1 files changed, 0 insertions, 5174 deletions
diff --git a/src/ops.c b/src/ops.c
deleted file mode 100644
index 30606b077e..0000000000
--- a/src/ops.c
+++ /dev/null
@@ -1,5174 +0,0 @@
-/*
- * VIM - Vi IMproved by Bram Moolenaar
- *
- * Do ":help uganda" in Vim to read copying and usage conditions.
- * Do ":help credits" in Vim to see a list of people who contributed.
- * See README.txt for an overview of the Vim source code.
- */
-
-/*
- * ops.c: implementation of various operators: op_shift, op_delete, op_tilde,
- * op_change, op_yank, do_put, do_join
- */
-
-#include <string.h>
-
-#include "vim.h"
-#include "ops.h"
-#include "buffer.h"
-#include "charset.h"
-#include "edit.h"
-#include "eval.h"
-#include "ex_cmds.h"
-#include "ex_cmds2.h"
-#include "ex_getln.h"
-#include "fold.h"
-#include "getchar.h"
-#include "indent.h"
-#include "mark.h"
-#include "mbyte.h"
-#include "memline.h"
-#include "memory.h"
-#include "message.h"
-#include "misc1.h"
-#include "misc2.h"
-#include "move.h"
-#include "normal.h"
-#include "option.h"
-#include "path.h"
-#include "screen.h"
-#include "search.h"
-#include "term.h"
-#include "ui.h"
-#include "undo.h"
-#include "window.h"
-
-/*
- * Registers:
- * 0 = unnamed register, for normal yanks and puts
- * 1..9 = registers '1' to '9', for deletes
- * 10..35 = registers 'a' to 'z'
- * 36 = delete register '-'
- */
-#define NUM_REGISTERS 37
-#define DELETION_REGISTER 36
-
-/*
- * Each yank register is an array of pointers to lines.
- */
-static struct yankreg {
- char_u **y_array; /* pointer to array of line pointers */
- linenr_T y_size; /* number of lines in y_array */
- char_u y_type; /* MLINE, MCHAR or MBLOCK */
- colnr_T y_width; /* only set if y_type == MBLOCK */
-} y_regs[NUM_REGISTERS];
-
-static struct yankreg *y_current; /* ptr to current yankreg */
-static int y_append; /* TRUE when appending */
-static struct yankreg *y_previous = NULL; /* ptr to last written yankreg */
-
-/*
- * structure used by block_prep, op_delete and op_yank for blockwise operators
- * also op_change, op_shift, op_insert, op_replace - AKelly
- */
-struct block_def {
- int startspaces; /* 'extra' cols before first char */
- int endspaces; /* 'extra' cols after last char */
- int textlen; /* chars in block */
- char_u *textstart; /* pointer to 1st char (partially) in block */
- colnr_T textcol; /* index of chars (partially) in block */
- colnr_T start_vcol; /* start col of 1st char wholly inside block */
- colnr_T end_vcol; /* start col of 1st char wholly after block */
- int is_short; /* TRUE if line is too short to fit in block */
- int is_MAX; /* TRUE if curswant==MAXCOL when starting */
- int is_oneChar; /* TRUE if block within one character */
- int pre_whitesp; /* screen cols of ws before block */
- int pre_whitesp_c; /* chars of ws before block */
- colnr_T end_char_vcols; /* number of vcols of post-block char */
- colnr_T start_char_vcols; /* number of vcols of pre-block char */
-};
-
-static void shift_block(oparg_T *oap, int amount);
-static void block_insert(oparg_T *oap, char_u *s, int b_insert,
- struct block_def*bdp);
-static int stuff_yank(int, char_u *);
-static void put_reedit_in_typebuf(int silent);
-static int put_in_typebuf(char_u *s, int esc, int colon,
- int silent);
-static void stuffescaped(char_u *arg, int literally);
-static void mb_adjust_opend(oparg_T *oap);
-static void free_yank(long);
-static void free_yank_all(void);
-static void yank_copy_line(struct block_def *bd, long y_idx);
-static void dis_msg(char_u *p, int skip_esc);
-static char_u *skip_comment(char_u *line, int process,
- int include_space,
- int *is_comment);
-static void block_prep(oparg_T *oap, struct block_def *, linenr_T, int);
-static void str_to_reg(struct yankreg *y_ptr, int type, char_u *str,
- long len,
- long blocklen);
-static int ends_in_white(linenr_T lnum);
-static int same_leader(linenr_T lnum, int, char_u *, int, char_u *);
-static int fmt_check_par(linenr_T, int *, char_u **, int do_comments);
-
-/*
- * The names of operators.
- * IMPORTANT: Index must correspond with defines in vim.h!!!
- * The third field indicates whether the operator always works on lines.
- */
-static char opchars[][3] =
-{
- {NUL, NUL, FALSE}, /* OP_NOP */
- {'d', NUL, FALSE}, /* OP_DELETE */
- {'y', NUL, FALSE}, /* OP_YANK */
- {'c', NUL, FALSE}, /* OP_CHANGE */
- {'<', NUL, TRUE}, /* OP_LSHIFT */
- {'>', NUL, TRUE}, /* OP_RSHIFT */
- {'!', NUL, TRUE}, /* OP_FILTER */
- {'g', '~', FALSE}, /* OP_TILDE */
- {'=', NUL, TRUE}, /* OP_INDENT */
- {'g', 'q', TRUE}, /* OP_FORMAT */
- {':', NUL, TRUE}, /* OP_COLON */
- {'g', 'U', FALSE}, /* OP_UPPER */
- {'g', 'u', FALSE}, /* OP_LOWER */
- {'J', NUL, TRUE}, /* DO_JOIN */
- {'g', 'J', TRUE}, /* DO_JOIN_NS */
- {'g', '?', FALSE}, /* OP_ROT13 */
- {'r', NUL, FALSE}, /* OP_REPLACE */
- {'I', NUL, FALSE}, /* OP_INSERT */
- {'A', NUL, FALSE}, /* OP_APPEND */
- {'z', 'f', TRUE}, /* OP_FOLD */
- {'z', 'o', TRUE}, /* OP_FOLDOPEN */
- {'z', 'O', TRUE}, /* OP_FOLDOPENREC */
- {'z', 'c', TRUE}, /* OP_FOLDCLOSE */
- {'z', 'C', TRUE}, /* OP_FOLDCLOSEREC */
- {'z', 'd', TRUE}, /* OP_FOLDDEL */
- {'z', 'D', TRUE}, /* OP_FOLDDELREC */
- {'g', 'w', TRUE}, /* OP_FORMAT2 */
- {'g', '@', FALSE}, /* OP_FUNCTION */
-};
-
-/*
- * Translate a command name into an operator type.
- * Must only be called with a valid operator name!
- */
-int get_op_type(int char1, int char2)
-{
- int i;
-
- if (char1 == 'r') /* ignore second character */
- return OP_REPLACE;
- if (char1 == '~') /* when tilde is an operator */
- return OP_TILDE;
- for (i = 0;; ++i)
- if (opchars[i][0] == char1 && opchars[i][1] == char2)
- break;
- return i;
-}
-
-/*
- * Return TRUE if operator "op" always works on whole lines.
- */
-int op_on_lines(int op)
-{
- return opchars[op][2];
-}
-
-/*
- * Get first operator command character.
- * Returns 'g' or 'z' if there is another command character.
- */
-int get_op_char(int optype)
-{
- return opchars[optype][0];
-}
-
-/*
- * Get second operator command character.
- */
-int get_extra_op_char(int optype)
-{
- return opchars[optype][1];
-}
-
-/*
- * op_shift - handle a shift operation
- */
-void op_shift(oparg_T *oap, int curs_top, int amount)
-{
- long i;
- int first_char;
- char_u *s;
- int block_col = 0;
-
- if (u_save((linenr_T)(oap->start.lnum - 1),
- (linenr_T)(oap->end.lnum + 1)) == FAIL)
- return;
-
- if (oap->block_mode)
- block_col = curwin->w_cursor.col;
-
- for (i = oap->line_count; --i >= 0; ) {
- first_char = *ml_get_curline();
- if (first_char == NUL) /* empty line */
- curwin->w_cursor.col = 0;
- else if (oap->block_mode)
- shift_block(oap, amount);
- else
- /* Move the line right if it doesn't start with '#', 'smartindent'
- * isn't set or 'cindent' isn't set or '#' isn't in 'cino'. */
- if (first_char != '#' || !preprocs_left()) {
- shift_line(oap->op_type == OP_LSHIFT, p_sr, amount, FALSE);
- }
- ++curwin->w_cursor.lnum;
- }
-
- changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
- /* The cursor line is not in a closed fold */
- foldOpenCursor();
-
- if (oap->block_mode) {
- curwin->w_cursor.lnum = oap->start.lnum;
- curwin->w_cursor.col = block_col;
- } else if (curs_top) { /* put cursor on first line, for ">>" */
- curwin->w_cursor.lnum = oap->start.lnum;
- beginline(BL_SOL | BL_FIX); /* shift_line() may have set cursor.col */
- } else
- --curwin->w_cursor.lnum; /* put cursor on last line, for ":>" */
-
- if (oap->line_count > p_report) {
- if (oap->op_type == OP_RSHIFT)
- s = (char_u *)">";
- else
- s = (char_u *)"<";
- if (oap->line_count == 1) {
- if (amount == 1)
- sprintf((char *)IObuff, _("1 line %sed 1 time"), s);
- else
- sprintf((char *)IObuff, _("1 line %sed %d times"), s, amount);
- } else {
- if (amount == 1)
- sprintf((char *)IObuff, _("%" PRId64 " lines %sed 1 time"),
- (int64_t)oap->line_count, s);
- else
- sprintf((char *)IObuff, _("%" PRId64 " lines %sed %d times"),
- (int64_t)oap->line_count, s, amount);
- }
- msg(IObuff);
- }
-
- /*
- * Set "'[" and "']" marks.
- */
- curbuf->b_op_start = oap->start;
- curbuf->b_op_end.lnum = oap->end.lnum;
- curbuf->b_op_end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
- if (curbuf->b_op_end.col > 0)
- --curbuf->b_op_end.col;
-}
-
-/*
- * shift the current line one shiftwidth left (if left != 0) or right
- * leaves cursor on first blank in the line
- */
-void
-shift_line (
- int left,
- int round,
- int amount,
- int call_changed_bytes /* call changed_bytes() */
-)
-{
- int count;
- int i, j;
- int p_sw = (int)get_sw_value(curbuf);
-
- count = get_indent(); /* get current indent */
-
- if (round) { /* round off indent */
- i = count / p_sw; /* number of p_sw rounded down */
- j = count % p_sw; /* extra spaces */
- if (j && left) /* first remove extra spaces */
- --amount;
- if (left) {
- i -= amount;
- if (i < 0)
- i = 0;
- } else
- i += amount;
- count = i * p_sw;
- } else { /* original vi indent */
- if (left) {
- count -= p_sw * amount;
- if (count < 0)
- count = 0;
- } else
- count += p_sw * amount;
- }
-
- /* Set new indent */
- if (State & VREPLACE_FLAG)
- change_indent(INDENT_SET, count, FALSE, NUL, call_changed_bytes);
- else
- (void)set_indent(count, call_changed_bytes ? SIN_CHANGED : 0);
-}
-
-/*
- * Shift one line of the current block one shiftwidth right or left.
- * Leaves cursor on first character in block.
- */
-static void shift_block(oparg_T *oap, int amount)
-{
- int left = (oap->op_type == OP_LSHIFT);
- int oldstate = State;
- int total;
- char_u *newp, *oldp;
- int oldcol = curwin->w_cursor.col;
- int p_sw = (int)get_sw_value(curbuf);
- int p_ts = (int)curbuf->b_p_ts;
- struct block_def bd;
- int incr;
- colnr_T ws_vcol;
- int i = 0, j = 0;
- int len;
- int old_p_ri = p_ri;
-
- p_ri = 0; /* don't want revins in indent */
-
- State = INSERT; /* don't want REPLACE for State */
- block_prep(oap, &bd, curwin->w_cursor.lnum, TRUE);
- if (bd.is_short)
- return;
-
- /* total is number of screen columns to be inserted/removed */
- total = amount * p_sw;
- oldp = ml_get_curline();
-
- if (!left) {
- /*
- * 1. Get start vcol
- * 2. Total ws vcols
- * 3. Divvy into TABs & spp
- * 4. Construct new string
- */
- total += bd.pre_whitesp; /* all virtual WS upto & incl a split TAB */
- ws_vcol = bd.start_vcol - bd.pre_whitesp;
- if (bd.startspaces) {
- if (has_mbyte)
- bd.textstart += (*mb_ptr2len)(bd.textstart);
- else
- ++bd.textstart;
- }
- for (; vim_iswhite(*bd.textstart); ) {
- incr = lbr_chartabsize_adv(&bd.textstart, (colnr_T)(bd.start_vcol));
- total += incr;
- bd.start_vcol += incr;
- }
- /* OK, now total=all the VWS reqd, and textstart points at the 1st
- * non-ws char in the block. */
- if (!curbuf->b_p_et)
- i = ((ws_vcol % p_ts) + total) / p_ts; /* number of tabs */
- if (i)
- j = ((ws_vcol % p_ts) + total) % p_ts; /* number of spp */
- else
- j = total;
- /* if we're splitting a TAB, allow for it */
- bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0);
- len = (int)STRLEN(bd.textstart) + 1;
- newp = (char_u *) xmalloc((size_t)(bd.textcol + i + j + len));
- memset(newp, NUL, (size_t)(bd.textcol + i + j + len));
- memmove(newp, oldp, (size_t)bd.textcol);
- copy_chars(newp + bd.textcol, (size_t)i, TAB);
- copy_spaces(newp + bd.textcol + i, (size_t)j);
- /* the end */
- memmove(newp + bd.textcol + i + j, bd.textstart, (size_t)len);
- } else { /* left */
- colnr_T destination_col; /* column to which text in block will
- be shifted */
- char_u *verbatim_copy_end; /* end of the part of the line which is
- copied verbatim */
- colnr_T verbatim_copy_width; /* the (displayed) width of this part
- of line */
- unsigned fill; /* nr of spaces that replace a TAB */
- unsigned new_line_len; /* the length of the line after the
- block shift */
- size_t block_space_width;
- size_t shift_amount;
- char_u *non_white = bd.textstart;
- colnr_T non_white_col;
-
- /*
- * Firstly, let's find the first non-whitespace character that is
- * displayed after the block's start column and the character's column
- * number. Also, let's calculate the width of all the whitespace
- * characters that are displayed in the block and precede the searched
- * non-whitespace character.
- */
-
- /* If "bd.startspaces" is set, "bd.textstart" points to the character,
- * the part of which is displayed at the block's beginning. Let's start
- * searching from the next character. */
- if (bd.startspaces)
- mb_ptr_adv(non_white);
-
- /* The character's column is in "bd.start_vcol". */
- non_white_col = bd.start_vcol;
-
- while (vim_iswhite(*non_white)) {
- incr = lbr_chartabsize_adv(&non_white, non_white_col);
- non_white_col += incr;
- }
-
- block_space_width = non_white_col - oap->start_vcol;
- /* We will shift by "total" or "block_space_width", whichever is less.
- */
- shift_amount = (block_space_width < (size_t)total
- ? block_space_width : (size_t)total);
-
- /* The column to which we will shift the text. */
- destination_col = (colnr_T)(non_white_col - shift_amount);
-
- /* Now let's find out how much of the beginning of the line we can
- * reuse without modification. */
- verbatim_copy_end = bd.textstart;
- verbatim_copy_width = bd.start_vcol;
-
- /* If "bd.startspaces" is set, "bd.textstart" points to the character
- * preceding the block. We have to subtract its width to obtain its
- * column number. */
- if (bd.startspaces)
- verbatim_copy_width -= bd.start_char_vcols;
- while (verbatim_copy_width < destination_col) {
- incr = lbr_chartabsize(verbatim_copy_end, verbatim_copy_width);
- if (verbatim_copy_width + incr > destination_col)
- break;
- verbatim_copy_width += incr;
- mb_ptr_adv(verbatim_copy_end);
- }
-
- /* If "destination_col" is different from the width of the initial
- * part of the line that will be copied, it means we encountered a tab
- * character, which we will have to partly replace with spaces. */
- fill = destination_col - verbatim_copy_width;
-
- /* The replacement line will consist of:
- * - the beginning of the original line up to "verbatim_copy_end",
- * - "fill" number of spaces,
- * - the rest of the line, pointed to by non_white. */
- new_line_len = (unsigned)(verbatim_copy_end - oldp)
- + fill
- + (unsigned)STRLEN(non_white) + 1;
-
- newp = (char_u *) xmalloc((size_t)(new_line_len));
- memmove(newp, oldp, (size_t)(verbatim_copy_end - oldp));
- copy_spaces(newp + (verbatim_copy_end - oldp), (size_t)fill);
- STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white);
- }
- /* replace the line */
- ml_replace(curwin->w_cursor.lnum, newp, FALSE);
- changed_bytes(curwin->w_cursor.lnum, (colnr_T)bd.textcol);
- State = oldstate;
- curwin->w_cursor.col = oldcol;
- p_ri = old_p_ri;
-}
-
-/*
- * Insert string "s" (b_insert ? before : after) block :AKelly
- * Caller must prepare for undo.
- */
-static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def *bdp)
-{
- int p_ts;
- int count = 0; /* extra spaces to replace a cut TAB */
- int spaces = 0; /* non-zero if cutting a TAB */
- colnr_T offset; /* pointer along new line */
- unsigned s_len; /* STRLEN(s) */
- char_u *newp, *oldp; /* new, old lines */
- linenr_T lnum; /* loop var */
- int oldstate = State;
-
- State = INSERT; /* don't want REPLACE for State */
- s_len = (unsigned)STRLEN(s);
-
- for (lnum = oap->start.lnum + 1; lnum <= oap->end.lnum; lnum++) {
- block_prep(oap, bdp, lnum, TRUE);
- if (bdp->is_short && b_insert)
- continue; /* OP_INSERT, line ends before block start */
-
- oldp = ml_get(lnum);
-
- if (b_insert) {
- p_ts = bdp->start_char_vcols;
- spaces = bdp->startspaces;
- if (spaces != 0)
- count = p_ts - 1; /* we're cutting a TAB */
- offset = bdp->textcol;
- } else { /* append */
- p_ts = bdp->end_char_vcols;
- if (!bdp->is_short) { /* spaces = padding after block */
- spaces = (bdp->endspaces ? p_ts - bdp->endspaces : 0);
- if (spaces != 0)
- count = p_ts - 1; /* we're cutting a TAB */
- offset = bdp->textcol + bdp->textlen - (spaces != 0);
- } else { /* spaces = padding to block edge */
- /* if $ used, just append to EOL (ie spaces==0) */
- if (!bdp->is_MAX)
- spaces = (oap->end_vcol - bdp->end_vcol) + 1;
- count = spaces;
- offset = bdp->textcol + bdp->textlen;
- }
- }
-
- newp = (char_u *) xmalloc((size_t)(STRLEN(oldp) + s_len + count + 1));
-
- /* copy up to shifted part */
- memmove(newp, oldp, (size_t)(offset));
- oldp += offset;
-
- /* insert pre-padding */
- copy_spaces(newp + offset, (size_t)spaces);
-
- /* copy the new text */
- memmove(newp + offset + spaces, s, (size_t)s_len);
- offset += s_len;
-
- if (spaces && !bdp->is_short) {
- /* insert post-padding */
- copy_spaces(newp + offset + spaces, (size_t)(p_ts - spaces));
- /* We're splitting a TAB, don't copy it. */
- oldp++;
- /* We allowed for that TAB, remember this now */
- count++;
- }
-
- if (spaces > 0)
- offset += count;
- STRMOVE(newp + offset, oldp);
-
- ml_replace(lnum, newp, FALSE);
-
- if (lnum == oap->end.lnum) {
- /* Set "']" mark to the end of the block instead of the end of
- * the insert in the first line. */
- curbuf->b_op_end.lnum = oap->end.lnum;
- curbuf->b_op_end.col = offset;
- }
- } /* for all lnum */
-
- changed_lines(oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L);
-
- State = oldstate;
-}
-
-/*
- * op_reindent - handle reindenting a block of lines.
- */
-void op_reindent(oap, how)
-oparg_T *oap;
-int (*how)(void);
-{
- long i;
- char_u *l;
- int count;
- linenr_T first_changed = 0;
- linenr_T last_changed = 0;
- linenr_T start_lnum = curwin->w_cursor.lnum;
-
- /* Don't even try when 'modifiable' is off. */
- if (!curbuf->b_p_ma) {
- EMSG(_(e_modifiable));
- return;
- }
-
- for (i = oap->line_count; --i >= 0 && !got_int; ) {
- /* it's a slow thing to do, so give feedback so there's no worry that
- * the computer's just hung. */
-
- if (i > 1
- && (i % 50 == 0 || i == oap->line_count - 1)
- && oap->line_count > p_report)
- smsg((char_u *)_("%" PRId64 " lines to indent... "), (int64_t)i);
-
- /*
- * Be vi-compatible: For lisp indenting the first line is not
- * indented, unless there is only one line.
- */
- if (i != oap->line_count - 1 || oap->line_count == 1
- || how != get_lisp_indent) {
- l = skipwhite(ml_get_curline());
- if (*l == NUL) /* empty or blank line */
- count = 0;
- else
- count = how(); /* get the indent for this line */
-
- if (set_indent(count, SIN_UNDO)) {
- /* did change the indent, call changed_lines() later */
- if (first_changed == 0)
- first_changed = curwin->w_cursor.lnum;
- last_changed = curwin->w_cursor.lnum;
- }
- }
- ++curwin->w_cursor.lnum;
- curwin->w_cursor.col = 0; /* make sure it's valid */
- }
-
- /* put cursor on first non-blank of indented line */
- curwin->w_cursor.lnum = start_lnum;
- beginline(BL_SOL | BL_FIX);
-
- /* Mark changed lines so that they will be redrawn. When Visual
- * highlighting was present, need to continue until the last line. When
- * there is no change still need to remove the Visual highlighting. */
- if (last_changed != 0)
- changed_lines(first_changed, 0,
- oap->is_VIsual ? start_lnum + oap->line_count :
- last_changed + 1, 0L);
- else if (oap->is_VIsual)
- redraw_curbuf_later(INVERTED);
-
- if (oap->line_count > p_report) {
- i = oap->line_count - (i + 1);
- if (i == 1)
- MSG(_("1 line indented "));
- else
- smsg((char_u *)_("%" PRId64 " lines indented "), (int64_t)i);
- }
- /* set '[ and '] marks */
- curbuf->b_op_start = oap->start;
- curbuf->b_op_end = oap->end;
-}
-
-/*
- * Keep the last expression line here, for repeating.
- */
-static char_u *expr_line = NULL;
-
-/*
- * Get an expression for the "\"=expr1" or "CTRL-R =expr1"
- * Returns '=' when OK, NUL otherwise.
- */
-int get_expr_register(void)
-{
- char_u *new_line;
-
- new_line = getcmdline('=', 0L, 0);
- if (new_line == NULL)
- return NUL;
- if (*new_line == NUL) /* use previous line */
- free(new_line);
- else
- set_expr_line(new_line);
- return '=';
-}
-
-/*
- * Set the expression for the '=' register.
- * Argument must be an allocated string.
- */
-void set_expr_line(char_u *new_line)
-{
- free(expr_line);
- expr_line = new_line;
-}
-
-/*
- * Get the result of the '=' register expression.
- * Returns a pointer to allocated memory, or NULL for failure.
- */
-char_u *get_expr_line(void)
-{
- char_u *expr_copy;
- char_u *rv;
- static int nested = 0;
-
- if (expr_line == NULL)
- return NULL;
-
- /* Make a copy of the expression, because evaluating it may cause it to be
- * changed. */
- expr_copy = vim_strsave(expr_line);
- if (expr_copy == NULL)
- return NULL;
-
- /* When we are invoked recursively limit the evaluation to 10 levels.
- * Then return the string as-is. */
- if (nested >= 10)
- return expr_copy;
-
- ++nested;
- rv = eval_to_string(expr_copy, NULL, TRUE);
- --nested;
- free(expr_copy);
- return rv;
-}
-
-/*
- * Get the '=' register expression itself, without evaluating it.
- */
-char_u *get_expr_line_src(void)
-{
- if (expr_line == NULL)
- return NULL;
- return vim_strsave(expr_line);
-}
-
-/*
- * Check if 'regname' is a valid name of a yank register.
- * Note: There is no check for 0 (default register), caller should do this
- */
-int
-valid_yank_reg (
- int regname,
- int writing /* if TRUE check for writable registers */
-)
-{
- if ( (regname > 0 && ASCII_ISALNUM(regname))
- || (!writing && vim_strchr((char_u *)
- "/.%#:="
- , regname) != NULL)
- || regname == '"'
- || regname == '-'
- || regname == '_'
- )
- return TRUE;
- return FALSE;
-}
-
-/*
- * Set y_current and y_append, according to the value of "regname".
- * Cannot handle the '_' register.
- * Must only be called with a valid register name!
- *
- * If regname is 0 and writing, use register 0
- * If regname is 0 and reading, use previous register
- */
-void get_yank_register(int regname, int writing)
-{
- int i;
-
- y_append = FALSE;
- if ((regname == 0 || regname == '"') && !writing && y_previous != NULL) {
- y_current = y_previous;
- return;
- }
- i = regname;
- if (VIM_ISDIGIT(i))
- i -= '0';
- else if (ASCII_ISLOWER(i))
- i = CharOrdLow(i) + 10;
- else if (ASCII_ISUPPER(i)) {
- i = CharOrdUp(i) + 10;
- y_append = TRUE;
- } else if (regname == '-')
- i = DELETION_REGISTER;
- else /* not 0-9, a-z, A-Z or '-': use register 0 */
- i = 0;
- y_current = &(y_regs[i]);
- if (writing) /* remember the register we write into for do_put() */
- y_previous = y_current;
-}
-
-
-/*
- * Obtain the contents of a "normal" register. The register is made empty.
- * The returned pointer has allocated memory, use put_register() later.
- */
-void *
-get_register (
- int name,
- int copy /* make a copy, if FALSE make register empty. */
-)
-{
- get_yank_register(name, 0);
-
- struct yankreg *reg = xmalloc(sizeof(struct yankreg));
- *reg = *y_current;
- if (copy) {
- if (reg->y_size == 0) {
- reg->y_array = NULL;
- } else {
- reg->y_array = xmalloc(reg->y_size * sizeof(char_u *));
- for (linenr_T i = 0; i < reg->y_size; ++i) {
- reg->y_array[i] = vim_strsave(y_current->y_array[i]);
- }
- }
- } else
- y_current->y_array = NULL;
-
- return (void *)reg;
-}
-
-/*
- * Put "reg" into register "name". Free any previous contents and "reg".
- */
-void put_register(int name, void *reg)
-{
- get_yank_register(name, 0);
- free_yank_all();
- *y_current = *(struct yankreg *)reg;
- free(reg);
-
-}
-
-/*
- * return TRUE if the current yank register has type MLINE
- */
-int yank_register_mline(int regname)
-{
- if (regname != 0 && !valid_yank_reg(regname, FALSE))
- return FALSE;
- if (regname == '_') /* black hole is always empty */
- return FALSE;
- get_yank_register(regname, FALSE);
- return y_current->y_type == MLINE;
-}
-
-/*
- * Start or stop recording into a yank register.
- *
- * Return FAIL for failure, OK otherwise.
- */
-int do_record(int c)
-{
- char_u *p;
- static int regname;
- struct yankreg *old_y_previous, *old_y_current;
- int retval;
-
- if (Recording == FALSE) { /* start recording */
- /* registers 0-9, a-z and " are allowed */
- if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
- retval = FAIL;
- else {
- Recording = TRUE;
- showmode();
- regname = c;
- retval = OK;
- }
- } else { /* stop recording */
- /*
- * Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
- * needs to be removed again to put it in a register. exec_reg then
- * adds the escaping back later.
- */
- Recording = FALSE;
- MSG("");
- p = get_recorded();
- if (p == NULL)
- retval = FAIL;
- else {
- /* Remove escaping for CSI and K_SPECIAL in multi-byte chars. */
- vim_unescape_csi(p);
-
- /*
- * We don't want to change the default register here, so save and
- * restore the current register name.
- */
- old_y_previous = y_previous;
- old_y_current = y_current;
-
- retval = stuff_yank(regname, p);
-
- y_previous = old_y_previous;
- y_current = old_y_current;
- }
- }
- return retval;
-}
-
-/*
- * Stuff string "p" into yank register "regname" as a single line (append if
- * uppercase). "p" must have been alloced.
- *
- * return FAIL for failure, OK otherwise
- */
-static int stuff_yank(int regname, char_u *p)
-{
- /* check for read-only register */
- if (regname != 0 && !valid_yank_reg(regname, TRUE)) {
- free(p);
- return FAIL;
- }
- if (regname == '_') { /* black hole: don't do anything */
- free(p);
- return OK;
- }
- get_yank_register(regname, TRUE);
- if (y_append && y_current->y_array != NULL) {
- char_u **pp = &(y_current->y_array[y_current->y_size - 1]);
- char_u *lp = xmalloc(STRLEN(*pp) + STRLEN(p) + 1);
- STRCPY(lp, *pp);
- // TODO(philix): use xstpcpy() in stuff_yank()
- STRCAT(lp, p);
- free(p);
- free(*pp);
- *pp = lp;
- } else {
- free_yank_all();
- y_current->y_array = (char_u **)alloc((unsigned)sizeof(char_u *));
- y_current->y_array[0] = p;
- y_current->y_size = 1;
- y_current->y_type = MCHAR; /* used to be MLINE, why? */
- }
- return OK;
-}
-
-static int execreg_lastc = NUL;
-
-/*
- * execute a yank register: copy it into the stuff buffer
- *
- * return FAIL for failure, OK otherwise
- */
-int
-do_execreg (
- int regname,
- int colon, /* insert ':' before each line */
- int addcr, /* always add '\n' to end of line */
- int silent /* set "silent" flag in typeahead buffer */
-)
-{
- long i;
- char_u *p;
- int retval = OK;
- int remap;
-
- if (regname == '@') { /* repeat previous one */
- if (execreg_lastc == NUL) {
- EMSG(_("E748: No previously used register"));
- return FAIL;
- }
- regname = execreg_lastc;
- }
- /* check for valid regname */
- if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE)) {
- emsg_invreg(regname);
- return FAIL;
- }
- execreg_lastc = regname;
-
-
- if (regname == '_') /* black hole: don't stuff anything */
- return OK;
-
- if (regname == ':') { /* use last command line */
- if (last_cmdline == NULL) {
- EMSG(_(e_nolastcmd));
- return FAIL;
- }
- free(new_last_cmdline); /* don't keep the cmdline containing @: */
- new_last_cmdline = NULL;
- /* Escape all control characters with a CTRL-V */
- p = vim_strsave_escaped_ext(
- last_cmdline,
- (char_u *)
- "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037",
- Ctrl_V, FALSE);
- if (p != NULL) {
- /* When in Visual mode "'<,'>" will be prepended to the command.
- * Remove it when it's already there. */
- if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0)
- retval = put_in_typebuf(p + 5, TRUE, TRUE, silent);
- else
- retval = put_in_typebuf(p, TRUE, TRUE, silent);
- }
- free(p);
- } else if (regname == '=') {
- p = get_expr_line();
- if (p == NULL)
- return FAIL;
- retval = put_in_typebuf(p, TRUE, colon, silent);
- free(p);
- } else if (regname == '.') { /* use last inserted text */
- p = get_last_insert_save();
- if (p == NULL) {
- EMSG(_(e_noinstext));
- return FAIL;
- }
- retval = put_in_typebuf(p, FALSE, colon, silent);
- free(p);
- } else {
- get_yank_register(regname, FALSE);
- if (y_current->y_array == NULL)
- return FAIL;
-
- /* Disallow remaping for ":@r". */
- remap = colon ? REMAP_NONE : REMAP_YES;
-
- /*
- * Insert lines into typeahead buffer, from last one to first one.
- */
- put_reedit_in_typebuf(silent);
- for (i = y_current->y_size; --i >= 0; ) {
- char_u *escaped;
-
- /* insert NL between lines and after last line if type is MLINE */
- if (y_current->y_type == MLINE || i < y_current->y_size - 1
- || addcr) {
- if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
- return FAIL;
- }
- escaped = vim_strsave_escape_csi(y_current->y_array[i]);
- if (escaped == NULL)
- return FAIL;
- retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
- free(escaped);
- if (retval == FAIL)
- return FAIL;
- if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
- == FAIL)
- return FAIL;
- }
- Exec_reg = TRUE; /* disable the 'q' command */
- }
- return retval;
-}
-
-/*
- * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
- * used only after other typeahead has been processed.
- */
-static void put_reedit_in_typebuf(int silent)
-{
- char_u buf[3];
-
- if (restart_edit != NUL) {
- if (restart_edit == 'V') {
- buf[0] = 'g';
- buf[1] = 'R';
- buf[2] = NUL;
- } else {
- buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
- buf[1] = NUL;
- }
- if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
- restart_edit = NUL;
- }
-}
-
-/*
- * Insert register contents "s" into the typeahead buffer, so that it will be
- * executed again.
- * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
- * no remapping.
- */
-static int
-put_in_typebuf (
- char_u *s,
- int esc,
- int colon, /* add ':' before the line */
- int silent
-)
-{
- int retval = OK;
-
- put_reedit_in_typebuf(silent);
- if (colon)
- retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
- if (retval == OK) {
- char_u *p;
-
- if (esc)
- p = vim_strsave_escape_csi(s);
- else
- p = s;
- if (p == NULL)
- retval = FAIL;
- else
- retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
- 0, TRUE, silent);
- if (esc)
- free(p);
- }
- if (colon && retval == OK)
- retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
- return retval;
-}
-
-/*
- * Insert a yank register: copy it into the Read buffer.
- * Used by CTRL-R command and middle mouse button in insert mode.
- *
- * return FAIL for failure, OK otherwise
- */
-int
-insert_reg (
- int regname,
- int literally /* insert literally, not as if typed */
-)
-{
- long i;
- int retval = OK;
- char_u *arg;
- int allocated;
-
- /*
- * It is possible to get into an endless loop by having CTRL-R a in
- * register a and then, in insert mode, doing CTRL-R a.
- * If you hit CTRL-C, the loop will be broken here.
- */
- ui_breakcheck();
- if (got_int)
- return FAIL;
-
- /* check for valid regname */
- if (regname != NUL && !valid_yank_reg(regname, FALSE))
- return FAIL;
-
-
- if (regname == '.') /* insert last inserted text */