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

📄 ex_cmds.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* vi:set ts=8 sts=4 sw=4:
 *
 * 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.
 */

/*
 * ex_cmds.c: functions for command line commands
 */

#include "vim.h"

#ifdef EX_EXTRA
static int linelen __ARGS((int *has_tab));
#endif
static void do_filter __ARGS((linenr_t line1, linenr_t line2,
				    char_u *buff, int do_in, int do_out));
#ifdef VIMINFO
static char_u *viminfo_filename __ARGS((char_u	*));
static void do_viminfo __ARGS((FILE *fp_in, FILE *fp_out, int want_info,
					     int want_marks, int force_read));
static int read_viminfo_up_to_marks __ARGS((char_u *line, FILE *fp,
						   int forceit, int writing));
#endif

static int do_sub_msg __ARGS((void));
static int
#ifdef __BORLANDC__
_RTLENTRYF
#endif
help_compare __ARGS((const void *s1, const void *s2));

    void
do_ascii()
{
    int		c;
    char	buf1[20];
    char	buf2[20];
    char_u	buf3[3];
#ifdef MULTI_BYTE
    int		c2 = NUL;
#endif

    c = gchar_cursor();
    if (c == NUL)
    {
	MSG("empty line");
	return;
    }

#ifdef MULTI_BYTE
    /* split lead from trail */
    c2 = (((unsigned)c >> 8) & 0xff);
    c = (c & 0xff);
    if (c2)
    {
	buf2[0] = c;
	buf2[1] = c2;
	buf2[2] = NUL;
	sprintf((char *)IObuff, "%s  %d %d,  Hex %02x %02x,  Octal %03o %03o",
		buf2, c,c2, c,c2, c,c2);
    }
    else
#endif
    {
	if (c == NL)	    /* NUL is stored as NL */
	    c = NUL;
	if (vim_isprintc(c) && (c < ' ' || c > '~'))
	{
	    transchar_nonprint(buf3, c);
	    sprintf(buf1, "  <%s>", (char *)buf3);
	}
	else
	    buf1[0] = NUL;
	if (c >= 0x80)
	    sprintf(buf2, "  <M-%s>", transchar(c & 0x7f));
	else
	    buf2[0] = NUL;
	sprintf((char *)IObuff, "<%s>%s%s  %d,  Hex %02x,  Octal %03o",
		transchar(c), buf1, buf2, c, c, c);
    }
    msg(IObuff);
}

#ifdef EX_EXTRA
/*
 * Handle ":left", ":center" and ":right" commands: align text.
 */
    void
do_align(eap)
    EXARG	*eap;
{
    FPOS    save_curpos;
    int	    len;
    int	    indent = 0;
    int	    new_indent;
    int	    has_tab;
    int	    width;

#ifdef RIGHTLEFT
    if (curwin->w_p_rl)
    {
	/* switch left and right aligning */
	if (eap->cmdidx == CMD_right)
	    eap->cmdidx = CMD_left;
	else if (eap->cmdidx == CMD_left)
	    eap->cmdidx = CMD_right;
    }
#endif

    width = atoi((char *)eap->arg);
    save_curpos = curwin->w_cursor;
    if (eap->cmdidx == CMD_left)    /* width is used for new indent */
    {
	if (width >= 0)
	    indent = width;
    }
    else
    {
	/*
	 * if 'textwidth' set, use it
	 * else if 'wrapmargin' set, use it
	 * if invalid value, use 80
	 */
	if (width <= 0)
	    width = curbuf->b_p_tw;
	if (width == 0 && curbuf->b_p_wm > 0)
	    width = Columns - curbuf->b_p_wm;
	if (width <= 0)
	    width = 80;
    }

    if (u_save((linenr_t)(eap->line1 - 1), (linenr_t)(eap->line2 + 1)) == FAIL)
	return;
#ifdef SYNTAX_HL
    /* recompute syntax hl., starting with first line */
    syn_changed(eap->line1);
#endif
    for (curwin->w_cursor.lnum = eap->line1;
		 curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum)
    {
	if (eap->cmdidx == CMD_left)		/* left align */
	    new_indent = indent;
	else
	{
	    len = linelen(eap->cmdidx == CMD_right ? &has_tab
						   : NULL) - get_indent();

	    if (len <= 0)			/* skip blank lines */
		continue;

	    if (eap->cmdidx == CMD_center)
		new_indent = (width - len) / 2;
	    else
	    {
		new_indent = width - len;	/* right align */

		/*
		 * Make sure that embedded TABs don't make the text go too far
		 * to the right.
		 */
		if (has_tab)
		    while (new_indent > 0)
		    {
			set_indent(new_indent, TRUE);	/* set indent */
			if (linelen(NULL) <= width)
			{
			    /*
			     * Now try to move the line as much as possible to
			     * the right.  Stop when it moves too far.
			     */
			    do
				set_indent(++new_indent, TRUE);	/* set indent */
			    while (linelen(NULL) <= width);
			    --new_indent;
			    break;
			}
			--new_indent;
		    }
	    }
	}
	if (new_indent < 0)
	    new_indent = 0;
	set_indent(new_indent, TRUE);		/* set indent */
    }
    curwin->w_cursor = save_curpos;
    beginline(BL_WHITE | BL_FIX);

    /*
     * If the cursor is after the first changed line, its position needs to be
     * updated.
     */
    if (curwin->w_cursor.lnum > eap->line1)
    {
	changed_line_abv_curs();
	invalidate_botline();
    }
    else if (curwin->w_cursor.lnum == eap->line1)
	changed_cline_bef_curs();

    /*
     * If the start of the aligned lines is before botline, it may have become
     * approximated (lines got longer or shorter).
     */
    if (botline_approximated() && eap->line1 < curwin->w_botline)
	approximate_botline();
    update_screen(NOT_VALID);
}

/*
 * Get the length of the current line, excluding trailing white space.
 */
    static int
linelen(has_tab)
    int	    *has_tab;
{
    char_u  *line;
    char_u  *first;
    char_u  *last;
    int	    save;
    int	    len;

    /* find the first non-blank character */
    line = ml_get_curline();
    first = skipwhite(line);

    /* find the character after the last non-blank character */
    for (last = first + STRLEN(first);
				last > first && vim_iswhite(last[-1]); --last)
	;
    save = *last;
    *last = NUL;
    len = linetabsize(line);		/* get line length */
    if (has_tab != NULL)		/* check for embedded TAB */
	*has_tab = (vim_strrchr(first, TAB) != NULL);
    *last = save;

    return len;
}

/*
 * Handle ":retab" command.
 */
    void
do_retab(eap)
    EXARG	*eap;
{
    linenr_t	lnum;
    int		got_tab = FALSE;
    long	num_spaces = 0;
    long	num_tabs;
    long	len;
    long	col;
    long	vcol;
    long	start_col = 0;		/* For start of white-space string */
    long	start_vcol = 0;		/* For start of white-space string */
    int		temp;
    long	old_len;
    char_u	*ptr;
    char_u	*new_line = (char_u *)1;    /* init to non-NULL */
    int		did_something = FALSE;
    int		did_undo;		/* called u_save for current line */
    int		new_ts;
    int		save_list;

    save_list = curwin->w_p_list;
    curwin->w_p_list = 0;	    /* don't want list mode here */

#ifdef SYNTAX_HL
    /* recompute syntax hl. starting with line1 */
    syn_changed(eap->line1);
#endif

    new_ts = getdigits(&(eap->arg));
    if (new_ts == 0)
	new_ts = curbuf->b_p_ts;
    for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum)
    {
	ptr = ml_get(lnum);
	col = 0;
	vcol = 0;
	did_undo = FALSE;
	for (;;)
	{
	    if (vim_iswhite(ptr[col]))
	    {
		if (!got_tab && num_spaces == 0)
		{
		    /* First consecutive white-space */
		    start_vcol = vcol;
		    start_col = col;
		}
		if (ptr[col] == ' ')
		    num_spaces++;
		else
		    got_tab = TRUE;
	    }
	    else
	    {
		if (got_tab || (eap->forceit && num_spaces > 1))
		{
		    /* Retabulate this string of white-space */

		    /* len is virtual length of white string */
		    len = num_spaces = vcol - start_vcol;
		    num_tabs = 0;
		    if (!curbuf->b_p_et)
		    {
			temp = new_ts - (start_vcol % new_ts);
			if (num_spaces >= temp)
			{
			    num_spaces -= temp;
			    num_tabs++;
			}
			num_tabs += num_spaces / new_ts;
			num_spaces -= (num_spaces / new_ts) * new_ts;
		    }
		    if (curbuf->b_p_et || got_tab ||
					(num_spaces + num_tabs < len))
		    {
			if (did_undo == FALSE)
			{
			    did_undo = TRUE;
			    if (u_save((linenr_t)(lnum - 1),
						(linenr_t)(lnum + 1)) == FAIL)
			    {
				new_line = NULL;	/* flag out-of-memory */
				break;
			    }
			}

			/* len is actual number of white characters used */
			len = num_spaces + num_tabs;
			old_len = STRLEN(ptr);
			new_line = lalloc(old_len - col + start_col + len + 1,
									TRUE);
			if (new_line == NULL)
			    break;
			if (start_col > 0)
			    mch_memmove(new_line, ptr, (size_t)start_col);
			mch_memmove(new_line + start_col + len,
				      ptr + col, (size_t)(old_len - col + 1));
			ptr = new_line + start_col;
			for (col = 0; col < len; col++)
			    ptr[col] = (col < num_tabs) ? '\t' : ' ';
			ml_replace(lnum, new_line, FALSE);
			did_something = TRUE;
			ptr = new_line;
			col = start_col + len;
		    }
		}
		got_tab = FALSE;
		num_spaces = 0;
	    }
	    if (ptr[col] == NUL)
		break;
	    vcol += chartabsize(ptr[col++], (colnr_t)vcol);
	}
	if (new_line == NULL)		    /* out of memory */
	    break;
	line_breakcheck();
    }
    if (got_int)
	emsg(e_interr);
    if (did_something)
	changed();

    curwin->w_p_list = save_list;	/* restore 'list' */

    if (curbuf->b_p_ts != new_ts || did_something)
    {
	/*
	 * Cursor may need updating when change is before or at the cursor
	 * line.  w_botline may be wrong a bit now.
	 */
	if (curbuf->b_p_ts != new_ts || eap->line1 < curwin->w_cursor.lnum)
	    changed_line_abv_curs();	    /* recompute cursor pos compl. */
	else if (eap->line1 == curwin->w_cursor.lnum)
	    changed_cline_bef_curs();	    /* recompute curosr pos partly */
	approximate_botline();
    }
    curbuf->b_p_ts = new_ts;
    coladvance(curwin->w_curswant);

    u_clearline();
    update_screen(NOT_VALID);
}
#endif

/*
 * :move command - move lines line1-line2 to line dest
 *
 * return FAIL for failure, OK otherwise
 */
    int
do_move(line1, line2, dest)
    linenr_t	line1;
    linenr_t	line2;
    linenr_t	dest;
{
    char_u	*str;
    linenr_t	l;
    linenr_t	extra;	    /* Num lines added before line1 */
    linenr_t	num_lines;  /* Num lines moved */
    linenr_t	last_line;  /* Last line in file after adding new text */

    if (dest >= line1 && dest < line2)
    {
	EMSG("Move lines into themselves");
	return FAIL;
    }

    num_lines = line2 - line1 + 1;

    /*
     * First we copy the old text to its new location -- webb
     * Also copy the flag that ":global" command uses.
     */
    if (u_save(dest, dest + 1) == FAIL)
	return FAIL;
    for (extra = 0, l = line1; l <= line2; l++)
    {
	str = vim_strsave(ml_get(l + extra));
	if (str != NULL)
	{
	    ml_append(dest + l - line1, str, (colnr_t)0, FALSE);
	    vim_free(str);
	    if (dest < line1)
		extra++;
	}
    }

    /*
     * Now we must be careful adjusting our marks so that we don't overlap our
     * mark_adjust() calls.
     *
     * We adjust the marks within the old text so that they refer to the
     * last lines of the file (temporarily), because we know no other marks
     * will be set there since these line numbers did not exist until we added
     * our new lines.
     *
     * Then we adjust the marks on lines between the old and new text positions
     * (either forwards or backwards).
     *
     * And Finally we adjust the marks we put at the end of the file back to
     * their final destination at the new text position -- webb
     */
    last_line = curbuf->b_ml.ml_line_count;
    mark_adjust(line1, line2, last_line - line2, 0L);
    if (dest >= line2)
    {
	mark_adjust(line2 + 1, dest, -num_lines, 0L);
	curbuf->b_op_start.lnum = dest - num_lines + 1;
	curbuf->b_op_end.lnum = dest;
    }
    else
    {
	mark_adjust(dest + 1, line1 - 1, num_lines, 0L);
	curbuf->b_op_start.lnum = dest + 1;
	curbuf->b_op_end.lnum = dest + num_lines;
    }
    curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
    mark_adjust(last_line - num_lines + 1, last_line,
					     -(last_line - dest - extra), 0L);

    /*
     * Now we delete the original text -- webb
     */
    if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL)
	return FAIL;

    for (l = line1; l <= line2; l++)
	ml_delete(line1 + extra, TRUE);

    changed();
    if (!global_busy && num_lines > p_report)
	smsg((char_u *)"%ld line%s moved", num_lines, plural(num_lines));

    /*
     * Leave the cursor on the last of the moved lines.
     */
    if (dest >= line1)
	curwin->w_cursor.lnum = dest;
    else
	curwin->w_cursor.lnum = dest + (line2 - line1) + 1;
    changed_line_abv_curs();
    /*
     * TODO: should recompute w_botline for simple situations.
     */
    invalidate_botline();
    return OK;
}

/*
 * :copy command - copy lines line1-line2 to line n
 */
    void
do_copy(line1, line2, n)
    linenr_t	line1;
    linenr_t	line2;
    linenr_t	n;
{
    linenr_t	    lnum;
    char_u	    *p;

    lnum = line2 - line1 + 1;
    mark_adjust(n + 1, (linenr_t)MAXLNUM, lnum, 0L);
    curbuf->b_op_start.lnum = n + 1;
    curbuf->b_op_end.lnum = n + lnum;
    curbuf->b_op_start.col = curbuf->b_op_end.col = 0;

    /*
     * there are three situations:
     * 1. destination is above line1
     * 2. destination is between line1 and line2
     * 3. destination is below line2
     *
     * n = destination (when starting)

⌨️ 快捷键说明

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