⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ops.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
 */
    void
do_put(regname, dir, count, flags)
    int		regname;
    int		dir;		/* BACKWARD for 'P', FORWARD for 'p' */
    long	count;
    int		flags;
{
    char_u	*ptr;
    char_u	*newp, *oldp;
    int		yanklen;
    int		oldlen;
    int		totlen = 0;		/* init for gcc */
    linenr_t	lnum;
    colnr_t	col;
    long	i;			/* index in y_array[] */
    int		y_type;
    long	y_size;
    char_u	**y_array = NULL;
    long	nr_lines = 0;
    colnr_t	vcol;
    int		delcount;
    int		incr = 0;
    long	j;
    FPOS	new_cursor;
    int		indent;
    int		orig_indent = 0;	/* init for gcc */
    int		indent_diff = 0;	/* init for gcc */
    int		first_indent = TRUE;
    FPOS	old_pos;
    struct block_def bd;
    char_u	*insert_string = NULL;
    int		allocated = FALSE;
#ifdef MULTI_BYTE
    int		bMultiByteCode = 0;
#endif

#ifdef USE_CLIPBOARD
    if (regname == '*')
	clip_get_selection();
#endif

    if (flags & PUT_FIXINDENT)
	orig_indent = get_indent();

    curbuf->b_op_start = curwin->w_cursor;	/* default for '[ mark */

    if (dir == FORWARD)
    {
#ifdef MULTI_BYTE
	/* put it on the next of the multi-byte character. */
	if (is_dbcs)
	{
	    ptr = ml_get(curwin->w_cursor.lnum) + curwin->w_cursor.col;
	    if (IsLeadByte(*ptr) && (*(ptr + 1) != '\0'))
	    {
		bMultiByteCode = 1;
		curbuf->b_op_start.col++;
	    }
	}
#endif
	curbuf->b_op_start.col++;
    }

    curbuf->b_op_end = curwin->w_cursor;	/* default for '] mark */

    /*
     * Using inserted text works differently, because the register includes
     * special characters (newlines, etc.).
     */
    if (regname == '.')
    {
	(void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
				    (count == -1 ? 'O' : 'i')), count, FALSE);
	/* Putting the text is done later, so can't really move the cursor to
	 * the nex character.  Use "l" to simulate it. */
	if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
	    stuffcharReadbuff('l');
	return;
    }

    /*
     * For special registers '%' (file name), '#' (alternate file name) and
     * ':' (last command line), etc. we have to create a fake yank register.
     */
    if (get_spec_reg(regname, &insert_string, &allocated, TRUE))
    {
	if (insert_string == NULL)
	    return;
    }

    if (insert_string != NULL)
    {
	y_type = MCHAR;
	if (regname == '=')
	{
	    /* For the = register we need to split the string at NL
	     * characters. */
	    /* Loop twice: count the number of lines and save them. */
	    for (;;)
	    {
		y_size = 0;
		ptr = insert_string;
		while (ptr != NULL)
		{
		    if (y_array != NULL)
			y_array[y_size] = ptr;
		    ++y_size;
		    ptr = vim_strchr(ptr, '\n');
		    if (ptr != NULL)
		    {
			if (y_array != NULL)
			    *ptr = NUL;
			++ptr;
			/* A trailing '\n' makes the string linewise */
			if (*ptr == NUL)
			{
			    y_type = MLINE;
			    break;
			}
		    }
		}
		if (y_array != NULL)
		    break;
		y_array = (char_u **)alloc((unsigned)
						 (y_size * sizeof(char_u *)));
		if (y_array == NULL)
		    goto end;
	    }
	}
	else
	{
	    y_size = 1;		/* use fake one-line yank register */
	    y_array = &insert_string;
	}
    }
    else
    {
	get_yank_register(regname, FALSE);

	y_type = y_current->y_type;
	y_size = y_current->y_size;
	y_array = y_current->y_array;
    }

    if (count == -1)	    /* :put command */
    {
	y_type = MLINE;
	count = 1;
    }

    if (y_size == 0 || y_array == NULL)
    {
	EMSG2("Nothing in register %s",
		  regname == 0 ? (char_u *)"\"" : transchar(regname));
	goto end;
    }

    if (y_type == MBLOCK)
    {
	lnum = curwin->w_cursor.lnum + y_size + 1;
	if (lnum > curbuf->b_ml.ml_line_count)
	    lnum = curbuf->b_ml.ml_line_count + 1;
	if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
	    goto end;
    }
    else if (u_save_cursor() == FAIL)
	goto end;

    yanklen = STRLEN(y_array[0]);
    changed();

    lnum = curwin->w_cursor.lnum;
    col = curwin->w_cursor.col;
    approximate_botline();	    /* w_botline might not be valid now */
    changed_cline_bef_curs();	    /* cursor posn on screen may change */

/*
 * block mode
 */
    if (y_type == MBLOCK)
    {
	if (dir == FORWARD && gchar_cursor() != NUL)
	{
	    getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);

#ifdef MULTI_BYTE
	    if (is_dbcs)
	    {
		/* put it on the next of the multi-byte character. */
		col += bMultiByteCode + 1;
		curwin->w_cursor.col += bMultiByteCode + 1;
	    }
	    else
#endif
	    {
		++col;
		++curwin->w_cursor.col;
	    }
	}
	else
	    getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
#ifdef SYNTAX_HL
	/* recompute syntax hl., starting with current line */
	syn_changed(curwin->w_cursor.lnum);
#endif
	for (i = 0; i < y_size; ++i)
	{
	    bd.startspaces = 0;
	    bd.endspaces = 0;
	    bd.textcol = 0;
	    vcol = 0;
	    delcount = 0;

	    /* add a new line */
	    if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
	    {
		ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
							   (colnr_t)1, FALSE);
		++nr_lines;
	    }
	    oldp = ml_get_curline();
	    oldlen = STRLEN(oldp);
	    for (ptr = oldp; vcol < col && *ptr; ++ptr)
	    {
		/* Count a tab for what it's worth (if list mode not on) */
		incr = lbr_chartabsize(ptr, (colnr_t)vcol);
		vcol += incr;
		++bd.textcol;
	    }
	    if (vcol < col) /* line too short, padd with spaces */
	    {
		bd.startspaces = col - vcol;
	    }
	    else if (vcol > col)
	    {
		bd.endspaces = vcol - col;
		bd.startspaces = incr - bd.endspaces;
		--bd.textcol;
		delcount = 1;
	    }
	    yanklen = STRLEN(y_array[i]);
	    totlen = count * yanklen + bd.startspaces + bd.endspaces;
	    newp = alloc_check((unsigned)totlen + oldlen + 1);
	    if (newp == NULL)
		break;
	    /* copy part up to cursor to new line */
	    ptr = newp;
	    mch_memmove(ptr, oldp, (size_t)bd.textcol);
	    ptr += bd.textcol;
	    /* may insert some spaces before the new text */
	    copy_spaces(ptr, (size_t)bd.startspaces);
	    ptr += bd.startspaces;
	    /* insert the new text */
	    for (j = 0; j < count; ++j)
	    {
		mch_memmove(ptr, y_array[i], (size_t)yanklen);
		ptr += yanklen;
	    }
	    /* may insert some spaces after the new text */
	    copy_spaces(ptr, (size_t)bd.endspaces);
	    ptr += bd.endspaces;
	    /* move the text after the cursor to the end of the line. */
	    mch_memmove(ptr, oldp + bd.textcol + delcount,
				(size_t)(oldlen - bd.textcol - delcount + 1));
	    ml_replace(curwin->w_cursor.lnum, newp, FALSE);

	    ++curwin->w_cursor.lnum;
	    if (i == 0)
		curwin->w_cursor.col += bd.startspaces;
	}
						/* adjust '] mark */
	curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
	curbuf->b_op_end.col = bd.textcol + totlen - 1;
	if (flags & PUT_CURSEND)
	{
	    curwin->w_cursor = curbuf->b_op_end;
	    curwin->w_cursor.col++;
	}
	else
	    curwin->w_cursor.lnum = lnum;
	update_topline();
	if (flags & PUT_CURSEND)
	    update_screen(NOT_VALID);
	else
	    update_screen(VALID_TO_CURSCHAR);
    }
    else	/* not block mode */
    {
	if (y_type == MCHAR)
	{
    /* if type is MCHAR, FORWARD is the same as BACKWARD on the next char */
	    if (dir == FORWARD && gchar_cursor() != NUL)
	    {
#ifdef MULTI_BYTE
		if (is_dbcs)
		{
		    /* put it on the next of the multi-byte character. */
		    col += bMultiByteCode + 1;
		    if (yanklen)
		    {
			curwin->w_cursor.col += bMultiByteCode + 1;
			curbuf->b_op_end.col += bMultiByteCode + 1;
		    }
		}
		else
#endif
		{
		    ++col;
		    if (yanklen)
		    {
			++curwin->w_cursor.col;
			++curbuf->b_op_end.col;
		    }
		}
	    }
	    new_cursor = curwin->w_cursor;
	}
	else if (dir == BACKWARD)
    /* if type is MLINE, BACKWARD is the same as FORWARD on the previous line */
	    --lnum;

/*
 * simple case: insert into current line
 */
	if (y_type == MCHAR && y_size == 1)
	{
	    totlen = count * yanklen;
	    if (totlen)
	    {
		oldp = ml_get(lnum);
		newp = alloc_check((unsigned)(STRLEN(oldp) + totlen + 1));
		if (newp == NULL)
		    goto end;		/* alloc() will give error message */
		mch_memmove(newp, oldp, (size_t)col);
		ptr = newp + col;
		for (i = 0; i < count; ++i)
		{
		    mch_memmove(ptr, y_array[0], (size_t)yanklen);
		    ptr += yanklen;
		}
		mch_memmove(ptr, oldp + col, STRLEN(oldp + col) + 1);
		ml_replace(lnum, newp, FALSE);
		/* Put cursor on last putted char. */
		curwin->w_cursor.col += (colnr_t)(totlen - 1);
	    }
	    curbuf->b_op_end = curwin->w_cursor;
	    /* For "CTRL-O p" in Insert mode, put cursor after last char */
	    if (totlen && (restart_edit || (flags & PUT_CURSEND)))
		++curwin->w_cursor.col;
	    update_screenline();
	}
	else
	{
#ifdef SYNTAX_HL
	    /* recompute syntax hl., starting with current line */
	    syn_changed(lnum);
#endif
	    while (--count >= 0)
	    {
		i = 0;
		if (y_type == MCHAR)
		{
		    /*
		     * Split the current line in two at the insert position.
		     * First insert y_array[size - 1] in front of second line.
		     * Then append y_array[0] to first line.
		     */
		    ptr = ml_get(lnum) + col;
		    totlen = STRLEN(y_array[y_size - 1]);
		    newp = alloc_check((unsigned)(STRLEN(ptr) + totlen + 1));
		    if (newp == NULL)
			goto error;
		    STRCPY(newp, y_array[y_size - 1]);
		    STRCAT(newp, ptr);
			/* insert second line */
		    ml_append(lnum, newp, (colnr_t)0, FALSE);
		    vim_free(newp);

		    oldp = ml_get(lnum);
		    newp = alloc_check((unsigned)(col + yanklen + 1));
		    if (newp == NULL)
			goto error;
					    /* copy first part of line */
		    mch_memmove(newp, oldp, (size_t)col);
					    /* append to first line */
		    mch_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
		    ml_replace(lnum, newp, FALSE);

		    curwin->w_cursor.lnum = lnum;
		    i = 1;
		}

		while (i < y_size)
		{
		    if ((y_type != MCHAR || i < y_size - 1) &&
			ml_append(lnum, y_array[i], (colnr_t)0, FALSE) == FAIL)
			    goto error;
		    lnum++;
		    i++;
		    if (flags & PUT_FIXINDENT)
		    {
			old_pos = curwin->w_cursor;
			curwin->w_cursor.lnum = lnum;
			ptr = ml_get(lnum);
#if defined(SMARTINDENT) || defined(CINDENT)
			if (*ptr == '#'
# ifdef SMARTINDENT
			   && curbuf->b_p_si
# endif
# ifdef CINDENT
			   && curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE)
# endif
					    )
			    indent = 0;     /* Leave # lines at start */
			else
#endif
			     if (*ptr == NUL)
			    indent = 0;     /* Ignore empty lines */
			else if (first_indent)
			{
			    indent_diff = orig_indent - get_indent();
			    indent = orig_indent;
			    first_indent = FALSE;
			}
			else if ((indent = get_indent() + indent_diff) < 0)
			    indent = 0;
			set_indent(indent, TRUE);
			curwin->w_cursor = old_pos;
		    }
		    ++nr_lines;
		}
	    }

	    /* put '] mark at last inserted character */
	    curbuf->b_op_end.lnum = lnum;
	    col = STRLEN(y_array[y_size - 1]);
	    if (col > 1)
		curbuf->b_op_end.col = col - 1;
	    else
		curbuf->b_op_end.col = 0;

	    if (flags & PUT_CURSEND)
	    {
		/* put cursor after inserted text */
		if (y_type == MLINE)
		{
		    if (lnum >= curbuf->b_ml.ml_line_count)
			curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
		    else
			curwin->w_cursor.lnum = lnum + 1;
		    curwin->w_cursor.col = 0;
		}
		else
		{
		    curwin->w_cursor.lnum = lnum;
		    curwin->w_cursor.col = col;
		}
		/* the text before the cursor needs redrawing */
		redraw_curbuf_later(NOT_VALID);
	    }
	    else if (y_type == MLINE)
	    {
		/* put cursor onfirst non-blank in first inserted line */
		curwin->w_cursor.col = 0;
		if (dir == FORWARD)
		    ++curwin->w_cursor.lnum;
		beginline(BL_WHITE | BL_FIX);
	    }
	    else	/* put cursor on first inserted character */
		curwin->w_cursor = new_cursor;

error:
	    if (y_type == MLINE)	/* adjust '[ mark */
	    {
		curbuf->b_op_start.col = 0;
		if (dir == FORWARD)
		    curbuf->b_op_start.lnum++;
	    }
	    mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
					     (linenr_t)MAXLNUM, nr_lines, 0L);
	    update_topline();
	    update_screen(VALID_TO_CURSCHAR);
	}
    }

    msgmore(nr_lines);
    curwin->w_set_curswant = TRUE;

end:
    if (allocated)
    {
	vim_free(insert_string);
	if (regname == '=')
	    vim_free(y_array);
    }
    if ((flags & PUT_CURSEND) && gchar_cursor() == NUL && curwin->w_cursor.col
				       && !(restart_edit || (State & INSERT)))
	--curwin->w_cursor.col;
}

/* Return the character name of the register with the given number */
    int
get_register_name(num)
    int num;
{
    if (num == -1)
	return '"';
    else if (num < 10)
	return num + '0';
    else if (num == DELETION_REGISTER)
	return '-';
#ifdef USE_CLIPBOARD
    else if (num == CLIPBOARD_REGISTER)
	return '*';
#endif
    else
	return num + 'a' - 10;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -