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

📄 ops.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
	    truncate_line(FALSE);   /* delete the rest of the line */
				    /* leave cursor past last char in line */
	}
	else
	{
	    del_lines(oap->line_count, TRUE, TRUE);
	    beginline(BL_WHITE | BL_FIX);
	}
	u_clearline();	/* "U" command should not be possible after "dd" */
    }
    else if (oap->line_count == 1)	/* delete characters within one line */
    {
	if (u_save_cursor() == FAIL)
	    return FAIL;
	    /* if 'cpoptions' contains '$', display '$' at end of change */
	if (	   vim_strchr(p_cpo, CPO_DOLLAR) != NULL
		&& oap->op_type == OP_CHANGE
		&& oap->end.lnum == curwin->w_cursor.lnum
		&& !oap->is_VIsual)
	    display_dollar(oap->end.col - !oap->inclusive);
	n = oap->end.col - oap->start.col + 1 - !oap->inclusive;
	(void)del_chars((long)n, restart_edit == NUL);
    }
    else				/* delete characters between lines */
    {
	if (u_save_cursor() == FAIL)	/* save first line for undo */
	    return FAIL;
#ifdef SYNTAX_HL
	/* recompute syntax hl., starting with current line */
	syn_changed(curwin->w_cursor.lnum);
#endif
	truncate_line(TRUE);		/* delete from cursor to end of line */

	oap->start = curwin->w_cursor;	/* remember curwin->w_cursor */
	++curwin->w_cursor.lnum;
					/* includes save for undo */
	del_lines((long)(oap->line_count - 2), TRUE, TRUE);

	if (u_save_cursor() == FAIL)	/* save last line for undo */
	    return FAIL;
	/* delete from start of line until op_end */
	curwin->w_cursor.col = 0;
	(void)del_chars((long)(oap->end.col + 1 - !oap->inclusive),
							 restart_edit == NUL);
	curwin->w_cursor = oap->start;	/* restore curwin->w_cursor */
	(void)do_join(FALSE, TRUE);
    }

    /*
     * For a change within one line, the screen is updated differently (to
     * take care of 'dollar').
     */
    if (oap->motion_type == MCHAR && oap->line_count == 1)
    {
	if (dollar_vcol)
	    must_redraw = 0;	    /* don't want a redraw now */
	else
	    update_screenline();
    }
    else if (!global_busy)	    /* no need to update screen for :global */
    {
	update_topline();
	update_screen(NOT_VALID);
    }

    msgmore(curbuf->b_ml.ml_line_count - old_lcount);

    /*
     * Set "'[" and "']" marks.
     */
    curbuf->b_op_start = oap->start;
    if (oap->block_mode)
    {
	curbuf->b_op_end.lnum = oap->end.lnum;
	curbuf->b_op_end.col = oap->start.col;
    }
    else
	curbuf->b_op_end = oap->start;

    return OK;
}

/*
 * op_tilde - handle the (non-standard vi) tilde operator
 */
    void
op_tilde(oap)
    OPARG	*oap;
{
    FPOS		pos;
    struct block_def	bd;

    if (u_save((linenr_t)(oap->start.lnum - 1),
				       (linenr_t)(oap->end.lnum + 1)) == FAIL)
	return;

    /*
     * Set '[ and '] marks.
     */
    curbuf->b_op_start = oap->start;
    curbuf->b_op_end = oap->end;

    pos = oap->start;
    if (oap->block_mode)		    /* Visual block mode */
    {
	for (; pos.lnum <= oap->end.lnum; ++pos.lnum)
	{
	    block_prep(oap, &bd, pos.lnum, FALSE);
	    pos.col = bd.textcol;
	    while (--bd.textlen >= 0)
	    {
		swapchar(oap->op_type, &pos);
		if (inc(&pos) == -1)	    /* at end of file */
		    break;
	    }
	}
    }
    else				    /* not block mode */
    {
	if (oap->motion_type == MLINE)
	{
	    pos.col = 0;
	    oap->end.col = STRLEN(ml_get(oap->end.lnum));
	    if (oap->end.col)
		--oap->end.col;
	}
	else if (!oap->inclusive)
	    dec(&(oap->end));

	while (ltoreq(pos, oap->end))
	{
	    swapchar(oap->op_type, &pos);
	    if (inc(&pos) == -1)    /* at end of file */
		break;
	}
    }

    if (oap->motion_type == MCHAR && oap->line_count == 1 && !oap->block_mode)
	update_screenline();
    else
    {
#ifdef SYNTAX_HL
	/* recompute syntax hl., starting with current line */
	syn_changed(oap->start.lnum);
#endif
	update_topline();
	update_screen(NOT_VALID);
    }

    if (oap->line_count > p_report)
	smsg((char_u *)"%ld line%s ~ed",
				    oap->line_count, plural(oap->line_count));
}

/*
 * If op_type == OP_UPPER: make uppercase,
 * if op_type == OP_LOWER: make lowercase,
 * else swap case of character at 'pos'
 */
    void
swapchar(op_type, pos)
    int	    op_type;
    FPOS    *pos;
{
    int	    c;

    c = gchar(pos);
    if (islower(c) && op_type != OP_LOWER)
    {
	pchar(*pos, TO_UPPER(c));
	changed();
    }
    else if (isupper(c) && op_type != OP_UPPER)
    {
	pchar(*pos, TO_LOWER(c));
	changed();
    }
}

/*
 * op_change - handle a change operation
 *
 * return TRUE if edit() returns because of a CTRL-O command
 */
    int
op_change(oap)
    OPARG	*oap;
{
    colnr_t	       l;

    l = oap->start.col;
    if (oap->motion_type == MLINE)
    {
	l = 0;
#ifdef SMARTINDENT
	if (curbuf->b_p_si)
	    can_si = TRUE;	/* It's like opening a new line, do si */
#endif
    }

    /* First delete the text in the region.  In an empty buffer only need to
     * save for undo */
    if (curbuf->b_ml.ml_flags & ML_EMPTY)
    {
	if (u_save_cursor() == FAIL)
	    return FALSE;
    }
    else if (op_delete(oap) == FAIL)
	return FALSE;

    if ((l > curwin->w_cursor.col) && !lineempty(curwin->w_cursor.lnum))
	inc_cursor();

#if defined(LISPINDENT) || defined(CINDENT)
    if (oap->motion_type == MLINE)
    {
# ifdef LISPINDENT
	if (curbuf->b_p_lisp && curbuf->b_p_ai)
	    fixthisline(get_lisp_indent);
# endif
# if defined(LISPINDENT) && defined(CINDENT)
	else
# endif
# ifdef CINDENT
	if (curbuf->b_p_cin)
	    fixthisline(get_c_indent);
# endif
    }
#endif

    return edit(NUL, FALSE, (linenr_t)1);
}

/*
 * set all the yank registers to empty (called from main())
 */
    void
init_yank()
{
    int		i;

    for (i = 0; i < NUM_REGISTERS; ++i)
	y_regs[i].y_array = NULL;
}

/*
 * Free "n" lines from the current yank register.
 * Called for normal freeing and in case of error.
 */
    static void
free_yank(n)
    long n;
{
    if (y_current->y_array != NULL)
    {
	long	    i;

	for (i = n; --i >= 0; )
	{
	    if ((i & 1023) == 1023)		    /* this may take a while */
	    {
		/*
		 * This message should never cause a hit-return message.
		 * Overwrite this message with any next message.
		 */
		++no_wait_return;
		smsg((char_u *)"freeing %ld lines", i + 1);
		--no_wait_return;
		msg_didout = FALSE;
		msg_col = 0;
	    }
	    vim_free(y_current->y_array[i]);
	}
	vim_free(y_current->y_array);
	y_current->y_array = NULL;
	if (n >= 1000)
	    MSG("");
    }
}

    static void
free_yank_all()
{
    free_yank(y_current->y_size);
}

/*
 * Yank the text between curwin->w_cursor and startpos into a yank register.
 * If we are to append (uppercase register), we first yank into a new yank
 * register and then concatenate the old and the new one (so we keep the old
 * one in case of out-of-memory).
 *
 * return FAIL for failure, OK otherwise
 */
    int
op_yank(oap, deleting, mess)
    OPARG   *oap;
    int	    deleting;
    int	    mess;
{
    long		y_idx;		/* index in y_array[] */
    struct yankreg	*curr;		/* copy of y_current */
    struct yankreg	newreg;		/* new yank register when appending */
    char_u		**new_ptr;
    linenr_t		lnum;		/* current line number */
    long		j;
    long		len;
    int			yanktype = oap->motion_type;
    long		yanklines = oap->line_count;
    linenr_t		yankendlnum = oap->end.lnum;
    char_u		*p;
    char_u		*pnew;
    struct block_def	bd;

				    /* check for read-only register */
    if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
    {
	beep_flush();
	return FAIL;
    }
    if (oap->regname == '_')	    /* black hole: nothing to do */
	return OK;

    if (!deleting)		    /* op_delete() already set y_current */
	get_yank_register(oap->regname, TRUE);

    curr = y_current;
				    /* append to existing contents */
    if (y_append && y_current->y_array != NULL)
	y_current = &newreg;
    else
	free_yank_all();	    /* free previously yanked lines */

/*
 * If the cursor was in column 1 before and after the movement, and the
 * operator is not inclusive, the yank is always linewise.
 */
    if (       oap->motion_type == MCHAR
	    && oap->start.col == 0
	    && !oap->inclusive
	    && (!oap->is_VIsual || *p_sel == 'o')
	    && oap->end.col == 0
	    && yanklines > 1)
    {
	yanktype = MLINE;
	--yankendlnum;
	--yanklines;
    }

    y_current->y_size = yanklines;
    y_current->y_type = yanktype;   /* set the yank register type */
    y_current->y_array = (char_u **)lalloc_clear((long_u)(sizeof(char_u *) *
							    yanklines), TRUE);

    if (y_current->y_array == NULL)
    {
	y_current = curr;
	return FAIL;
    }

    y_idx = 0;
    lnum = oap->start.lnum;

/*
 * Visual block mode
 */
    if (oap->block_mode)
    {
	y_current->y_type = MBLOCK;	    /* set the yank register type */
	for ( ; lnum <= yankendlnum; ++lnum)
	{
	    block_prep(oap, &bd, lnum, FALSE);

	    if ((pnew = alloc(bd.startspaces + bd.endspaces +
					  bd.textlen + 1)) == NULL)
		goto fail;
	    y_current->y_array[y_idx++] = pnew;

	    copy_spaces(pnew, (size_t)bd.startspaces);
	    pnew += bd.startspaces;

	    mch_memmove(pnew, bd.textstart, (size_t)bd.textlen);
	    pnew += bd.textlen;

	    copy_spaces(pnew, (size_t)bd.endspaces);
	    pnew += bd.endspaces;

	    *pnew = NUL;
	}
    }
    else
    {
	/*
	 * there are three parts for non-block mode:
	 * 1. if yanktype != MLINE yank last part of the top line
	 * 2. yank the lines between op_start and op_end, inclusive when
	 *    yanktype == MLINE
	 * 3. if yanktype != MLINE yank first part of the bot line
	 */
	if (yanktype != MLINE)
	{
	    if (yanklines == 1)	    /* op_start and op_end on same line */
	    {
		j = oap->end.col - oap->start.col + 1 - !oap->inclusive;
		/* Watch out for very big endcol (MAXCOL) */
		p = ml_get(lnum) + oap->start.col;
		len = STRLEN(p);
		if (j > len || j < 0)
		    j = len;
		if ((y_current->y_array[0] = vim_strnsave(p, (int)j)) == NULL)
		{
fail:
		    free_yank(y_idx);	/* free the allocated lines */
		    y_current = curr;
		    return FAIL;
		}
		goto success;
	    }
	    if ((y_current->y_array[0] =
			vim_strsave(ml_get(lnum++) + oap->start.col)) == NULL)
		goto fail;
	    ++y_idx;
	}

	while (yanktype == MLINE ? (lnum <= yankendlnum) : (lnum < yankendlnum))
	{
	    if ((y_current->y_array[y_idx] =
					 vim_strsave(ml_get(lnum++))) == NULL)
		goto fail;
	    ++y_idx;
	}
	if (yanktype != MLINE)
	{
	    if ((y_current->y_array[y_idx] = vim_strnsave(ml_get(yankendlnum),
				 oap->end.col + 1 - !oap->inclusive)) == NULL)
		goto fail;
	}
    }

success:
    if (curr != y_current)	/* append the new block to the old block */
    {
	new_ptr = (char_u **)lalloc((long_u)(sizeof(char_u *) *
				   (curr->y_size + y_current->y_size)), TRUE);
	if (new_ptr == NULL)
	    goto fail;
	for (j = 0; j < curr->y_size; ++j)
	    new_ptr[j] = curr->y_array[j];
	vim_free(curr->y_array);
	curr->y_array = new_ptr;

	if (yanktype == MLINE)	/* MLINE overrides MCHAR and MBLOCK */
	    curr->y_type = MLINE;

	/* concatenate the last line of the old block with the first line of
	 * the new block */
	if (curr->y_type == MCHAR)
	{
	    pnew = lalloc((long_u)(STRLEN(curr->y_array[curr->y_size - 1])
			      + STRLEN(y_current->y_array[0]) + 1), TRUE);
	    if (pnew == NULL)
	    {
		    y_idx = y_current->y_size - 1;
		    goto fail;
	    }
	    STRCPY(pnew, curr->y_array[--j]);
	    STRCAT(pnew, y_current->y_array[0]);
	    vim_free(curr->y_array[j]);
	    vim_free(y_current->y_array[0]);
	    curr->y_array[j++] = pnew;
	    y_idx = 1;
	}
	else
	    y_idx = 0;
	while (y_idx < y_current->y_size)
	    curr->y_array[j++] = y_current->y_array[y_idx++];
	curr->y_size = j;
	vim_free(y_current->y_array);
	y_current = curr;
    }
    if (mess)			/* Display message about yank? */
    {
	if (yanktype == MCHAR && !oap->block_mode && yanklines == 1)
	    yanklines = 0;
	/* Some versions of Vi use ">=" here, some don't...  */
	if (yanklines > p_report)
	{
	    /* redisplay now, so message is not deleted */
	    update_topline_redraw();
	    smsg((char_u *)"%ld line%s yanked", yanklines, plural(yanklines));
	}
    }

    /*
     * Set "'[" and "']" marks.
     */
    curbuf->b_op_start = oap->start;
    curbuf->b_op_end = oap->end;

#ifdef USE_CLIPBOARD
    /*
     * If we were yanking to the clipboard register, send result to clipboard.
     */
    if (curr == &(y_regs[CLIPBOARD_REGISTER]))
    {
	clip_own_selection();
	clip_mch_set_selection();
    }
#endif

    return OK;
}

/*
 * put contents of register "regname" into the text
 * For ":put" command count == -1.
 * flags: PUT_FIXINDENT	make indent look nice
 *	  PUT_CURSEND	leave cursor after end of new text

⌨️ 快捷键说明

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