diff options
| author | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-12 02:25:17 +0200 |
|---|---|---|
| committer | Eliseo Martínez <eliseomarmol@gmail.com> | 2014-05-15 20:46:01 +0200 |
| commit | da51dc9cf202772f60bd2da975dbef257bd9237c (patch) | |
| tree | 5c16b93238a153f55634e9323077f30c8133970c /src/ops.c | |
| parent | ffe61e5ba1721340ca51d56bae3ddaca415fb5bc (diff) | |
| download | rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.gz rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.bz2 rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.zip | |
Introduce nvim namespace: Move files.
Move files from src/ to src/nvim/.
- src/nvim/ becomes the new root dir for nvim executable sources.
- src/libnvim/ is planned to become root dir of the neovim library.
Diffstat (limited to 'src/ops.c')
| -rw-r--r-- | src/ops.c | 5174 |
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 |