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

📄 ex_getln.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_getln.c: Functions for entering and editing an Ex command line.
 */

#include "vim.h"

/*
 * Variables shared between getcmdline(), redrawcmdline() and others.
 * These need to be saved when using CTRL-R |, that's why they are in a
 * structure.
 */
struct cmdline_info
{
    char_u	*cmdbuff;	/* pointer to command line buffer */
    int		cmdbufflen;	/* length of cmdbuff */
    int		cmdlen;		/* number of chars on command line */
    int		cmdpos;		/* current cursor position */
    int		cmdspos;	/* cursor column on screen */
    int		cmdfirstc;	/* ':', '/', '?', '=' or NUL */
    int		cmdindent;	/* number of spaces before cmdline */
    char_u	*cmdprompt;	/* message in front of cmdline */
    int		cmdattr;	/* attributes for prompt */
    int		overstrike;	/* Typing mode on the command line.  Shared by
				   getcmdline() and put_on_cmdline(). */
};

static struct cmdline_info ccline;	/* current cmdline_info */

static int	cmd_numfiles = -1;	/* number of files found by
						    file name completion */
static char_u	**(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL};
static int	hisidx[HIST_COUNT] = {-1, -1, -1, -1};  /* last entered entry */
static int	hislen = 0;		/* actual length of history tables */

#ifdef RIGHTLEFT
static int	cmd_hkmap = 0;	    /* Hebrew mapping during command line */
#endif

#ifdef FKMAP
static int	    cmd_fkmap = 0;	/* Farsi mapping during command line */
#endif

static int	hist_char2type __ARGS((int c));
static void	init_history __ARGS((void));

static int	in_history __ARGS((int, char_u *, int));
static void	set_cmdspos __ARGS((void));
static void	alloc_cmdbuff __ARGS((int len));
static int	realloc_cmdbuff __ARGS((int len));
static void	putcmdline __ARGS((int));
static void	redrawcmdprompt __ARGS((void));
static void	redrawcmd __ARGS((void));
static void	cursorcmd __ARGS((void));
static int	ccheck_abbr __ARGS((int));
static int	nextwild __ARGS((int, int));
static int	showmatches __ARGS((void));
static void	set_expand_context __ARGS((void));
static int	ExpandFromContext __ARGS((char_u *, int *, char_u ***, int, int));

/*
 * getcmdline() - accept a command line starting with firstc.
 *
 * firstc == ':'	    get ":" command line.
 * firstc == '/' or '?'	    get search pattern
 * firstc == '='	    get expression
 * firstc == '@'	    get text for input() function
 * firstc == NUL	    get text for :insert command
 *
 * The line is collected in ccline.cmdbuff, which is reallocated to fit the
 * command line.
 *
 * Careful: getcmdline() can be called recursively!
 *
 * Return pointer to allocated string if there is a commandline, NULL
 * otherwise.
 */
    char_u *
getcmdline(firstc, count, indent)
    int		firstc;
    long	count;		/* only used for incremental search */
    int		indent;		/* indent for inside conditionals */
{
    int		c;
#ifdef DIGRAPHS
    int		cc;
#endif
    int		i;
    int		j;
    char_u	*p;
    int		hiscnt;			/* current history line in use */
    char_u	*lookfor = NULL;	/* string to match */
    int		gotesc = FALSE;		/* TRUE when <ESC> just typed */
    int		do_abbr;		/* when TRUE check for abbr. */
    int		histype;		/* history type to be used */
#ifdef EXTRA_SEARCH
    FPOS	old_cursor;
    colnr_t	old_curswant;
    colnr_t	old_leftcol;
    linenr_t	old_topline;
    linenr_t	old_botline;
    int		did_incsearch = FALSE;
    int		incsearch_postponed = FALSE;
#endif
    int		did_wild_list = FALSE;	/* did wild_list() recently */
    int		wim_index = 0;		/* index in wim_flags[] */
    int		res;
    int		save_msg_scroll = msg_scroll;
    int		save_State = State;	/* remember State when called */
    int		some_key_typed = FALSE;	/* one of the keys was typed */
#ifdef USE_MOUSE
    /* mouse drag and release events are ignored, unless they are
     * preceded with a mouse down event */
    int		ignore_drag_release = TRUE;
#endif
#ifdef USE_SNIFF
    want_sniff_request = 0;
#endif

    ccline.overstrike = FALSE;		    /* always start in insert mode */
#ifdef EXTRA_SEARCH
    old_cursor = curwin->w_cursor;	    /* needs to be restored later */
    old_curswant = curwin->w_curswant;
    old_leftcol = curwin->w_leftcol;
    old_topline = curwin->w_topline;
    old_botline = curwin->w_botline;
#endif

    /*
     * set some variables for redrawcmd()
     */
    ccline.cmdfirstc = (firstc == '@' ? 0 : firstc);
    ccline.cmdindent = indent;
    alloc_cmdbuff(exmode_active ? 250 : 0); /* alloc initial ccline.cmdbuff */
    if (ccline.cmdbuff == NULL)
	return NULL;			    /* out of memory */
    ccline.cmdlen = ccline.cmdpos = 0;

    redir_off = TRUE;		/* don't redirect the typed command */
    i = msg_scrolled;
    msg_scrolled = 0;		/* avoid wait_return message */
    gotocmdline(TRUE);
    msg_scrolled += i;
    redrawcmdprompt();		/* draw prompt or indent */
    set_cmdspos();

    /*
     * Avoid scrolling when called by a recursive do_cmdline(), e.g. when doing
     * ":@0" when register 0 doesn't contain a CR.
     */
    msg_scroll = FALSE;

    State = CMDLINE;
#ifdef USE_MOUSE
    setmouse();
#endif

    init_history();
    hiscnt = hislen;		/* set hiscnt to impossible history value */
    histype = hist_char2type(firstc);

#ifdef DIGRAPHS
    do_digraph(-1);		/* init digraph typahead */
#endif

    /* collect the command string, handling editing keys */
    for (;;)
    {
#ifdef USE_GUI_WIN32
	dont_scroll = FALSE;	/* allow scrolling here */
#endif
	quit_more = FALSE;	/* reset after CTRL-D which had a more-prompt */

	cursorcmd();		/* set the cursor on the right spot */
	c = vgetc();
	if (KeyTyped)
	{
	    some_key_typed = TRUE;
#ifdef RIGHTLEFT
	    if (cmd_hkmap)
		c = hkmap(c);
# ifdef FKMAP
	    if (cmd_fkmap)
		c = cmdl_fkmap(c);
# endif
#endif
	}

	/*
	 * Ignore got_int when CTRL-C was typed here.
	 * Don't ignore it in :global, we really need to break then, e.g., for
	 * ":g/pat/normal /pat" (without the <CR>).
	 * Don't ignore it for the input() function.
	 */
	if ((c == Ctrl('C')
#ifdef UNIX
		|| c == intr_char
#endif
				)
#ifdef WANT_EVAL
		&& firstc != '@'
#endif
		&& !global_busy)
	    got_int = FALSE;

	/* free old command line when finished moving around in the history
	 * list */
	if (lookfor
		&& c != K_S_DOWN && c != K_S_UP && c != K_DOWN && c != K_UP
		&& c != K_PAGEDOWN && c != K_PAGEUP
		&& c != K_KPAGEDOWN && c != K_KPAGEUP
		&& c != K_LEFT && c != K_RIGHT
		&& (cmd_numfiles > 0 || (c != Ctrl('P') && c != Ctrl('N'))))
	{
	    vim_free(lookfor);
	    lookfor = NULL;
	}

	/*
	 * <S-Tab> works like CTRL-P (unless 'wc' is <S-Tab>).
	 */
	if (c != p_wc && c == K_S_TAB && cmd_numfiles != -1)
	    c = Ctrl('P');

	/* free expanded names when finished walking through matches */
	if (cmd_numfiles != -1 && !(c == p_wc && KeyTyped)
		&& c != Ctrl('N') && c != Ctrl('P') && c != Ctrl('A')
		&& c != Ctrl('L'))
	{
	    (void)ExpandOne(NULL, NULL, 0, WILD_FREE);
	    did_wild_list = FALSE;
	    wim_index = 0;
	}

#ifdef DIGRAPHS
	c = do_digraph(c);
#endif

	if (c == '\n' || c == '\r' || c == K_KENTER || (c == ESC
			&& (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL)))
	{
	    gotesc = FALSE;	/* Might have typed ESC previously, don't
				   truncate the cmdline now. */
	    if (ccheck_abbr(c + ABBR_OFF))
		goto cmdline_changed;
	    windgoto(msg_row, 0);
	    out_flush();
	    break;
	}

	/*
	 * Completion for 'wildchar' key.
	 * - hitting <ESC> twice means: abandon command line.
	 * - wildcard expansion is only done when the key is really typed, not
	 *   when it comes from a macro
	 */
	if (c == p_wc && !gotesc && KeyTyped)
	{
	    if (cmd_numfiles > 0)   /* typed p_wc at least twice */
	    {
		/* if 'wildmode' contains "list", may still need to list */
		if (cmd_numfiles > 1
			&& !did_wild_list
			&& (wim_flags[wim_index] & WIM_LIST))
		{
		    showmatches();
		    redrawcmd();
		    did_wild_list = TRUE;
		}
		if (wim_flags[wim_index] & WIM_LONGEST)
		    res = nextwild(WILD_LONGEST, WILD_NO_BEEP);
		else if (wim_flags[wim_index] & WIM_FULL)
		    res = nextwild(WILD_NEXT, WILD_NO_BEEP);
		else
		    res = OK;	    /* don't insert 'wildchar' now */
	    }
	    else		    /* typed p_wc first time */
	    {
		j = ccline.cmdpos;
		/* if 'wildmode' first contains "longest", get longest
		 * common part */
		if (wim_flags[0] & WIM_LONGEST)
		    res = nextwild(WILD_LONGEST, WILD_NO_BEEP);
		else
		    res = nextwild(WILD_EXPAND_KEEP, WILD_NO_BEEP);
		/* when more than one match, and 'wildmode' first contains
		 * "list", or no change and 'wildmode' contains "longest,list",
		 * list all matches */
		if (res == OK && cmd_numfiles > 1)
		{
		    /* a "longest" that didn't do anything is skipped (but not
		     * "list:longest") */
		    if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == j)
			wim_index = 1;
		    if (wim_flags[wim_index] & WIM_LIST)
		    {
			if (!(wim_flags[0] & WIM_LONGEST))
			    nextwild(WILD_PREV, 0);	/* remove match */
			showmatches();
			redrawcmd();
			did_wild_list = TRUE;
			if (wim_flags[wim_index] & WIM_LONGEST)
			    nextwild(WILD_LONGEST, WILD_NO_BEEP);
			else if (wim_flags[wim_index] & WIM_FULL)
			    nextwild(WILD_NEXT, WILD_NO_BEEP);
		    }
		    else
			vim_beep();
		}
	    }
	    if (wim_index < 3)
		++wim_index;
	    if (c == ESC)
		gotesc = TRUE;
	    if (res == OK)
		goto cmdline_changed;
	}
	gotesc = FALSE;

	/* <S-Tab> goes to last match, in a clumsy way */
	if (c == K_S_TAB && KeyTyped)
	{
	    if (nextwild(WILD_EXPAND_KEEP, 0) == OK
		    && nextwild(WILD_PREV, 0) == OK
		    && nextwild(WILD_PREV, 0) == OK)
		goto cmdline_changed;
	}

	if (c == NUL || c == K_ZERO)	    /* NUL is stored as NL */
	    c = NL;

	do_abbr = TRUE;		/* default: check for abbreviation */
	switch (c)
	{
	case K_BS:
	case Ctrl('H'):
	case K_DEL:
	case Ctrl('W'):
#ifdef FKMAP
		if (cmd_fkmap && c == K_BS)
		    c = K_DEL;
#endif
		/*
		 * delete current character is the same as backspace on next
		 * character, except at end of line
		 */
		if (c == K_DEL && ccline.cmdpos != ccline.cmdlen)
		    ++ccline.cmdpos;
		if (ccline.cmdpos > 0)
		{
		    j = ccline.cmdpos;
		    if (c == Ctrl('W'))
		    {
			while (ccline.cmdpos &&
			       vim_isspace(ccline.cmdbuff[ccline.cmdpos - 1]))
			    --ccline.cmdpos;
			i = vim_iswordc(ccline.cmdbuff[ccline.cmdpos - 1]);
			while (ccline.cmdpos && !vim_isspace(
					 ccline.cmdbuff[ccline.cmdpos - 1]) &&
				vim_iswordc(
				      ccline.cmdbuff[ccline.cmdpos - 1]) == i)
			    --ccline.cmdpos;
		    }
		    else
			--ccline.cmdpos;
		    ccline.cmdlen -= j - ccline.cmdpos;
		    i = ccline.cmdpos;
		    while (i < ccline.cmdlen)
			ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
		    redrawcmd();
		}
		else if (ccline.cmdlen == 0 && c != Ctrl('W')
				   && ccline.cmdprompt == NULL && indent == 0)
		{
		    vim_free(ccline.cmdbuff);	/* no commandline to return */
		    ccline.cmdbuff = NULL;
		    msg_col = 0;
		    msg_putchar(' ');		/* delete ':' */
		    redraw_cmdline = TRUE;
		    goto returncmd;		/* back to cmd mode */
		}
		goto cmdline_changed;

	case K_INS:
#ifdef FKMAP
		/* if Farsi mode set, we are in reverse insert mode -
		   Do not change the mode */
		if (cmd_fkmap)
		    beep_flush();
		else
#endif
		ccline.overstrike = !ccline.overstrike;
#ifdef CURSOR_SHAPE
		ui_cursor_shape();	/* may show different cursor shape */
#endif
		goto cmdline_not_changed;

/*	case '@':   only in very old vi */
	case Ctrl('U'):
		ccline.cmdpos = 0;
		ccline.cmdlen = 0;
		set_cmdspos();
		redrawcmd();
		goto cmdline_changed;

	case ESC:	/* get here if p_wc != ESC or when ESC typed twice */
	case Ctrl('C'):
		gotesc = TRUE;	    /* will free ccline.cmdbuff after putting
				       it in history */
		goto returncmd;	    /* back to cmd mode */

	case Ctrl('R'):		    /* insert register */
#ifdef USE_GUI_WIN32
		dont_scroll = TRUE; /* disallow scrolling here */
#endif
		putcmdline('"');
		++no_mapping;
		c = vgetc();
		--no_mapping;
#ifdef WANT_EVAL
		/*
		 * Insert the result of an expression.
		 * Need to save the current command line, to be able to enter
		 * a new one...
		 */
		if (c == '=')
		{
		    struct cmdline_info	    save_ccline;

		    if (ccline.cmdfirstc == '=')/* can't do this recursively */
		    {
			beep_flush();
			c = ESC;
		    }
		    else
		    {
			save_ccline = ccline;
			c = get_expr_register();
			ccline = save_ccline;
		    }
		}
#endif
		if (c != ESC)	    /* use ESC to cancel inserting register */
		    cmdline_paste(c);
		redrawcmd();
		goto cmdline_changed;

	case Ctrl('D'):
		if (showmatches() == FAIL)
		    break;	/* Use ^D as normal char instead */

		redrawcmd();
		continue;	/* don't do incremental search now */

	case K_RIGHT:
	case K_S_RIGHT:
		do
		{
		    if (ccline.cmdpos >= ccline.cmdlen)
			break;
		    ccline.cmdspos += charsize(ccline.cmdbuff[ccline.cmdpos]);
		    ++ccline.cmdpos;
		}
		while ((c == K_S_RIGHT || (mod_mask & MOD_MASK_CTRL))
			&& ccline.cmdbuff[ccline.cmdpos] != ' ');
		goto cmdline_not_changed;

	case K_LEFT:
	case K_S_LEFT:
		do
		{
		    if (ccline.cmdpos <= 0)
			break;
		    --ccline.cmdpos;
		    ccline.cmdspos -= charsize(ccline.cmdbuff[ccline.cmdpos]);
		}
		while ((c == K_S_LEFT || (mod_mask & MOD_MASK_CTRL))
			&& ccline.cmdbuff[ccline.cmdpos - 1] != ' ');
		goto cmdline_not_changed;

#if defined(USE_MOUSE) || defined(FKMAP)
	case K_IGNORE:
#endif
#ifdef USE_MOUSE
	case K_MIDDLEDRAG:
	case K_MIDDLERELEASE:
		goto cmdline_not_changed;   /* Ignore mouse */

	case K_MIDDLEMOUSE:
# ifdef USE_GUI
		/* When GUI is active, also paste when 'mouse' is empty */
		if (!gui.in_use)
# endif
		    if (!mouse_has(MOUSE_COMMAND))
			goto cmdline_not_changed;   /* Ignore mouse */
# ifdef USE_GUI
		if (gui.in_use)
		    cmdline_paste('*');
		else
# endif
		    cmdline_paste(0);
		redrawcmd();
		goto cmdline_changed;

	case K_LEFTDRAG:
	case K_LEFTRELEASE:
	case K_RIGHTDRAG:
	case K_RIGHTRELEASE:
		if (ignore_drag_release)

⌨️ 快捷键说明

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