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

📄 getchar.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
	    c2 = vgetorpeek(TRUE);	/* no mapping for these chars */
	    c = vgetorpeek(TRUE);
	    --no_mapping;
	    if (c2 == KS_MODIFIER)
	    {
		mod_mask = c;
		continue;
	    }
	    c = TO_SPECIAL(c2, c);

#ifdef USE_GUI_WIN32
	    /* Handle K_TEAROFF here, the caller of vgetc() doesn't need to
	     * know that a menu was torn off */
	    if (c == K_TEAROFF)
	    {
		char_u	name[200];
		int	i;

		/* get menu path, it ends with a <CR> */
		for (i = 0; (c = vgetorpeek(TRUE)) != '\r'; )
		{
		    name[i] = c;
		    if (i < 199)
			++i;
		}
		name[i] = NUL;
		gui_make_tearoff(name);
		continue;
	    }
#endif
	}
#ifdef MSDOS
	/*
	 * If K_NUL was typed, it is replaced by K_NUL, 3 in mch_inchar().
	 * Delete the 3 here.
	 */
	else if (c == K_NUL && vpeekc() == 3)
	    (void)vgetorpeek(TRUE);
#endif

	return c;
    }
}

    int
vpeekc()
{
    return (vgetorpeek(FALSE));
}

/*
 * Call vpeekc() without causing anything to be mapped.
 * Return TRUE if a character is available, FALSE otherwise.
 */
    int
char_avail()
{
    int	    retval;

    ++no_mapping;
    retval = vgetorpeek(FALSE);
    --no_mapping;
    return (retval != NUL);
}

    void
vungetc(c)	/* unget one character (can only be done once!) */
    int	    c;
{
    old_char = c;
}

/*
 * get a character: 1. from a previously ungotten character
 *		    2. from the stuffbuffer
 *		    3. from the typeahead buffer
 *		    4. from the user
 *
 * if "advance" is TRUE (vgetc()):
 *	really get the character.
 *	KeyTyped is set to TRUE in the case the user typed the key.
 *	KeyStuffed is TRUE if the character comes from the stuff buffer.
 * if "advance" is FALSE (vpeekc()):
 *	just look whether there is a character available.
 */

    static int
vgetorpeek(advance)
    int	    advance;
{
    int		    c, c1;
    int		    keylen = 0;		    /* init for gcc */
    char_u	    *s;
    struct mapblock *mp;
    int		    timedout = FALSE;	    /* waited for more than 1 second
						for mapping to complete */
    int		    mapdepth = 0;	    /* check for recursive mapping */
    int		    mode_deleted = FALSE;   /* set when mode has been deleted */
    int		    local_State;
    int		    mlen;
    int		    max_mlen;
#ifdef SHOWCMD
    int		    i;
    int		    new_wcol, new_wrow;
#endif
#ifdef USE_GUI
    int		    idx;
    int		    shape_changed = FALSE;  /* adjusted cursor shape */
#endif
    int		    n;
#ifdef HAVE_LANGMAP
    int		    c2;
#endif
    int		    old_wcol, old_wrow;

    /*
     * This function doesn't work very well when called recursively.  This may
     * happen though, because of:
     * 1. The call to add_to_showcmd().	char_avail() is then used to check if
     * there is a character available, which calls this function.  In that
     * case we must return NUL, to indicate no character is available.
     * 2. A GUI callback function writes to the screen, causing a
     * wait_return().
     */
    if (vgetc_busy)
	return NUL;

    local_State = get_real_state();

/*
 * get a character: 1. from a previously ungotten character
 */
    if (old_char >= 0)
    {
	c = old_char;
	if (advance)
	    old_char = -1;
	return c;
    }

    vgetc_busy = TRUE;

    if (advance)
	KeyStuffed = FALSE;

    init_typebuf();
    start_stuff();
    if (advance && typemaplen == 0)
	Exec_reg = FALSE;
    do
    {
/*
 * get a character: 2. from the stuffbuffer
 */
	c = read_stuff(advance);
	if (c != NUL && !got_int)
	{
	    if (advance)
	    {
		KeyTyped = FALSE;
		KeyStuffed = TRUE;
	    }
	    if (no_abbr_cnt == 0)
		no_abbr_cnt = 1;	/* no abbreviations now */
	}
	else
	{
	    /*
	     * Loop until we either find a matching mapped key, or we
	     * are sure that it is not a mapped key.
	     * If a mapped key sequence is found we go back to the start to
	     * try re-mapping.
	     */
	    for (;;)
	    {
		/*
		 * ui_breakcheck() is slow, don't use it too often when
		 * inside a mapping.  But call it each time for typed
		 * characters.
		 */
		if (typemaplen)
		    line_breakcheck();
		else
		    ui_breakcheck();		/* check for CTRL-C */
		if (got_int)
		{
		    /* flush all input */
		    c = inchar(typebuf, typebuflen - 1, 0L);
		    /*
		     * If inchar returns TRUE (script file was active) or we
		     * are inside a mapping, get out of insert mode.
		     * Otherwise we behave like having gotten a CTRL-C.
		     * As a result typing CTRL-C in insert mode will
		     * really insert a CTRL-C.
		     */
		    if ((c || typemaplen) && (State & (INSERT + CMDLINE)))
			c = ESC;
		    else
			c = Ctrl('C');
		    flush_buffers(TRUE);	/* flush all typeahead */
		    break;
		}
		else if (typelen > 0)	/* check for a mappable key sequence */
		{
		    /*
		     * walk through one maphash[] list until we find an
		     * entry that matches.
		     *
		     * Don't look for mappings if:
		     * - timed out
		     * - no_mapping set: mapping disabled (e.g. for CTRL-V)
		     * - maphash_valid not set: no mappings present.
		     * - typebuf[typeoff] should not be remapped
		     * - in insert or cmdline mode and 'paste' option set
		     * - waiting for "hit return to continue" and CR or SPACE
		     *	 typed
		     * - waiting for a char with --more--
		     * - in Ctrl-X mode, and we get a valid char for that mode
		     */
		    mp = NULL;
		    max_mlen = 0;
		    if (!timedout && no_mapping == 0 && maphash_valid
			    && (typemaplen == 0 ||
				    (p_remap && noremapbuf[typeoff] == FALSE))
			    && !(p_paste && (State & (INSERT + CMDLINE)))
			    && !(State == HITRETURN && (typebuf[typeoff] == CR
						  || typebuf[typeoff] == ' '))
			    && State != ASKMORE
			    && State != CONFIRM
#ifdef INSERT_EXPAND
			    && !(ctrl_x_mode
				       && vim_is_ctrl_x_key(typebuf[typeoff]))
#endif
			    )
		    {
			c1 = typebuf[typeoff];
#ifdef HAVE_LANGMAP
			LANGMAP_ADJUST(c1, TRUE);
#endif
			for (mp = maphash[MAP_HASH(local_State, c1)];
						  mp != NULL; mp = mp->m_next)
			{
			    /*
			     * Only consider an entry if the first character
			     * matches and it is for the current state.
			     */
			    if (mp->m_keys[0] == c1 &&
						   (mp->m_mode & local_State))
			    {
				/* find the match length of this mapping */
				for (mlen = 1; mlen < typelen; ++mlen)
				{
#ifdef HAVE_LANGMAP
				    c2 = typebuf[typeoff + mlen];
				    LANGMAP_ADJUST(c2, TRUE);
				    if (mp->m_keys[mlen] != c2)
#else
				    if (mp->m_keys[mlen] !=
						    typebuf[typeoff + mlen])
#endif
					break;
				}

				/*
				 * Check an entry whether it matches.
				 * - Full match: mlen == keylen
				 * - Partly match: mlen == typelen
				 */
				keylen = mp->m_keylen;
				if (mlen == keylen ||
					(mlen == typelen && typelen < keylen))
				{
				    /*
				     * If one of the typed keys cannot be
				     * remapped, skip the entry.
				     */
				    s = noremapbuf + typeoff;
				    for (n = mlen; --n >= 0; )
					if (*s++)
					    break;
				    if (n >= 0)
					continue;

				    /*
				     * Need more chars for partly match.
				     */
				    if (keylen > typelen)
					keylen = M_NEEDMORET;
				    break;
				}

				/*
				 * no match, may have to check for termcode at
				 * next character
				 */
				if (max_mlen < mlen)
				    max_mlen = mlen;
			    }
			}
		    }
		    if (mp == NULL)	    /* no matching mapping found */
		    {
			/*
			 * Check if we have a terminal code, when:
			 *  mapping is allowed,
			 *  keys have not been mapped,
			 *  and not an ESC sequence, not in insert mode or
			 *	p_ek is on,
			 *  and when not timed out,
			 */
			if ((no_mapping == 0 || allow_keys != 0) &&
				(typemaplen == 0 ||
					 (p_remap && !noremapbuf[typeoff])) &&
				!timedout)
			{
			    keylen = check_termcode(max_mlen + 1);

			    /*
			     * When getting a partial match, but the last
			     * characters were not typed, don't wait for a
			     * typed character to complete the termcode.
			     * This helps a lot when a ":normal" command ends
			     * in an ESC.
			     */
			    if (keylen < 0 && typelen == typemaplen)
				keylen = 0;
			}
			else
			    keylen = 0;
			if (keylen == 0)	/* no matching terminal code */
			{
#ifdef AMIGA			/* check for window bounds report */
			    if (typemaplen == 0 &&
					    (typebuf[typeoff] & 0xff) == CSI)
			    {
				for (s = typebuf + typeoff + 1;
					s < typebuf + typeoff + typelen &&
					(isdigit(*s) || *s == ';' || *s == ' ');
					++s)
				    ;
				if (*s == 'r' || *s == '|') /* found one */
				{
				    del_typebuf((int)(s + 1 -
						       (typebuf + typeoff)), 0);
					/* get size and redraw screen */
				    set_winsize(0, 0, FALSE);
				    continue;
				}
				if (*s == NUL)	    /* need more characters */
				    keylen = K_NEEDMORET;
			    }
			    if (keylen >= 0)
#endif
			    {
/*
 * get a character: 3. from the typeahead buffer
 */
				c = typebuf[typeoff] & 255;
				if (advance)	/* remove chars from typebuf */
				{
				    if (typemaplen)
					KeyTyped = FALSE;
				    else
				    {
					KeyTyped = TRUE;
					++maptick;
					/* write char to script file(s) */
					gotchars(typebuf + typeoff, 1);
				    }
				    del_typebuf(1, 0);
				}
				break;	    /* got character, break for loop */
			    }
			}
			if (keylen > 0)	    /* full matching terminal code */
			{
#ifdef USE_GUI
			    if (typebuf[typeoff] == K_SPECIAL &&
					      typebuf[typeoff + 1] == KS_MENU)
			    {
				/*
				 * Using a menu may cause a break in undo!
				 * It's like using gotchars(), but without
				 * recording or writing to a script file.
				 */
				may_sync_undo();
				del_typebuf(3, 0);
				idx = gui_get_menu_index(current_menu,
								 local_State);
				if (idx != MENU_INDEX_INVALID)
				{
				    /*
				     * In Select mode, a Visual mode menu is
				     * used.  Switch to Visual mode
				     * temporarily.  Append K_SELECT to switch
				     * back to Select mode.
				     */
				    if (VIsual_active && VIsual_select)
				    {
					VIsual_select = FALSE;
					(void)ins_typebuf(K_SELECT_STRING, -1,
							  0, TRUE);
				    }

				    ins_typebuf(current_menu->strings[idx],
					current_menu->noremap[idx] ? -1 : 0,
					0, TRUE);
				}
			    }
#endif /* USE_GUI */
			    continue;	/* try mapping again */
			}

			/* partial match: get some more characters */
			keylen = K_NEEDMORET;
		    }
		    /* complete match */
		    if (keylen >= 0 && keylen <= typelen)
		    {
			/* write chars to script file(s) */
			if (keylen > typemaplen)
			    gotchars(typebuf + typeoff + typemaplen,
							keylen - typemaplen);

			del_typebuf(keylen, 0);	/* remove the mapped keys */

			/*
			 * Put the replacement string in front of mapstr.
			 * The depth check catches ":map x y" and ":map y x".
			 */
			if (++mapdepth >= p_mmd)
			{
			    EMSG("recursive mapping");
			    if (State == CMDLINE)
				redrawcmdline();
			    else
				setcursor();
			    flush_buffers(FALSE);
			    mapdepth = 0;	/* for next one */
			    c = -1;
			    break;
			}

			/*
			 * In Select mode, a Visual mode mapping is used.
			 * Switch to Visual mode temporarily.  Append K_SELECT
			 * to switch back to Select mode.
			 */
			if (VIsual_active && VIsual_select)
			{
			    VIsual_select = FALSE;
			    (void)ins_typebuf(K_SELECT_STRING, -1, 0, TRUE);
			}

			/*
			 * Insert the 'to' part in the typebuf.
			 * If 'from' field is the same as the start of the
			 * 'to' field, don't remap the first character.
			 * If m_noremap is set, don't remap the whole 'to'
			 * part.
			 */
			if (ins_typebuf(mp->m_str,
				mp->m_noremap ? -1
					      : STRNCMP(mp->m_str, mp->m_keys,
						      (size_t)keylen) ? 0 : 1,
				0, TRUE) == FAIL)
			{
			    c = -1;
			    break;
			}
			continue;
		    }
		}

		/*
		 * special case: if we get an <ESC> in insert mode and there
		 * are no more characters at once, we pretend to go out of
		 * insert mode.  This prevents the one second delay after
		 * typing an <ESC>.  If we get something after all, we may
		 * have to redisplay the mode. That the cursor is in the wrong
		 * place does not matter.
		 */
		c = 0;
#ifdef SHOWCMD
		new_wcol = curwin->w_wcol;
		new_wrow = curwin->w_wrow;
#endif
		if (	   advance
			&& typelen == 1
			&& typebuf[typeoff] == ESC
			&& !no_mapping
			&& typemaplen == 0
			&& (State & INSERT)
			&& (p_timeout || (keylen == K_NEEDMORET && p_ttimeout))
			&& (c = inchar(typebuf + typeoff + typelen, 3, 25L))
									 == 0)
		{
		    colnr_t	col, vcol;
		    char_u	*ptr;

		    if (p_smd)
		    {
			unshowmode(TRUE);
			mode_deleted = TRUE;
		    }
#ifdef USE_GUI
		    /* may show different cursor shape */
		    if (gui.in_use)
		    {
			int	    save_State;

			save_State = State;
			State = NORMAL;
			gui_update_cursor(TRUE, FALSE);
			State = save_State;
			shape_changed = TRUE;
		    }
#endif
		    validate_cursor();
		    old_wcol = curwin->w_wcol;
		    old_wrow = curwin->w_wrow;

		    /* move cursor left, if possible */
		    if (curwin->w_cursor.col != 0)
		    {
			if (curwin->w_wcol)
			{
			    if (did_ai)
			    {
				/*
				 * We are expecting to truncate the trailing
				 * white-space, so find the last non-white

⌨️ 快捷键说明

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