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

📄 ui.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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.
 */

/*
 * ui.c: functions that handle the user interface.
 * 1. Keyboard input stuff, and a bit of windowing stuff.  These are called
 *    before the machine specific stuff (mch_*) so that we can call the GUI
 *    stuff instead if the GUI is running.
 * 2. Clipboard stuff.
 * 3. Input buffer stuff.
 */

#include "vim.h"

    void
ui_write(s, len)
    char_u  *s;
    int	    len;
{
#ifdef USE_GUI
    if (gui.in_use && !gui.dying)
    {
	gui_write(s, len);
	if (p_wd)
	    gui_wait_for_chars(p_wd);
	return;
    }
#endif
#ifndef NO_CONSOLE
    /* Don't output anything in silent mode ("ex -s") */
    if (!silent_mode)
	mch_write(s, len);
#endif
}

/*
 * ui_inchar(): low level input funcion.
 * Get a characters from the keyboard.
 * Return the number of characters that are available.
 * If wtime == 0 do not wait for characters.
 * If wtime == -1 wait forever for characters.
 * If wtime > 0 wait wtime milliseconds for a character.
 */
    int
ui_inchar(buf, maxlen, wtime)
    char_u  *buf;
    int	    maxlen;
    long    wtime;	    /* don't use "time", MIPS cannot handle it */
{
#ifdef NO_CONSOLE
    /* Don't wait for character input when the window hasn't been opened yet.
     * Must return something, otherwise we'll loop forever.  */
    if (!gui.in_use || gui.starting)
    {
	buf[0] = CR;
	return 1;
    }
#endif
#ifdef USE_GUI
    if (gui.in_use)
    {
	if (!gui_wait_for_chars(wtime))
	    return 0;
	return read_from_input_buf(buf, (long)maxlen);
    }
#endif
#ifndef NO_CONSOLE
    return mch_inchar(buf, maxlen, wtime);
#endif
}

/*
 * return non-zero if a character is available
 */
    int
ui_char_avail()
{
#ifdef USE_GUI
    if (gui.in_use)
    {
	gui_mch_update();
	return !vim_is_input_buf_empty();
    }
#endif
#ifndef NO_CONSOLE
    return mch_char_avail();
#else
    return 0;
#endif
}

/*
 * Delay for the given number of milliseconds.	If ignoreinput is FALSE then we
 * cancel the delay if a key is hit.
 */
    void
ui_delay(msec, ignoreinput)
    long	msec;
    int		ignoreinput;
{
#ifdef USE_GUI
    if (gui.in_use && !ignoreinput)
	gui_wait_for_chars(msec);
    else
#endif
	mch_delay(msec, ignoreinput);
}

/*
 * If the machine has job control, use it to suspend the program,
 * otherwise fake it by starting a new shell.
 * When running the GUI iconify the window.
 */
    void
ui_suspend()
{
#ifdef USE_GUI
    if (gui.in_use)
    {
	gui_mch_iconify();
	return;
    }
#endif
    mch_suspend();
}

/*
 * When the OS can't really suspend, call this function to start a shell.
 */
    void
suspend_shell()
{
    MSG_PUTS("new shell started\n");
    (void)mch_call_shell(NULL, SHELL_COOKED);
    need_check_timestamps = TRUE;
}

    int
ui_can_restore_title()
{
#ifdef USE_GUI
    /*
     * If GUI is (going to be) used, we can always set the window title.
     * Saves a bit of time, because the X11 display server does not need to be
     * contacted.
     */
    if (gui.starting || gui.in_use)
	return TRUE;
#endif
    return mch_can_restore_title();
}

    int
ui_can_restore_icon()
{
#ifdef USE_GUI
    /*
     * If GUI is (going to be) used, we can always set the icon name.
     * Saves a bit of time, because the X11 display server does not need to be
     * contacted.
     */
    if (gui.starting || gui.in_use)
	return TRUE;
#endif
    return mch_can_restore_icon();
}

/*
 * Try to get the current window size.	Put the result in Rows and Columns.
 * Return OK when size could be determined, FAIL otherwise.
 */
    int
ui_get_winsize()
{
    int	    retval;

#ifdef USE_GUI
    if (gui.in_use)
	retval = gui_get_winsize();
    else
#endif
	retval = mch_get_winsize();

    /* adjust the default for 'lines' and 'columns' */
    if (retval == OK)
    {
	set_number_default("lines", Rows);
	set_number_default("columns", Columns);
    }
    return retval;
}

/*
 * Set the size of the window according to Rows and Columns, if possible.
 */
    void
ui_set_winsize()
{
#ifdef USE_GUI
    if (gui.in_use)
	gui_set_winsize(
#ifdef WIN32
		TRUE
#else
		FALSE
#endif
		);
    else
#endif
	mch_set_winsize();
}

    void
ui_breakcheck()
{
#ifdef USE_GUI
    if (gui.in_use)
	gui_mch_update();
    else
#endif /* USE_GUI */
	mch_breakcheck();
}

/*****************************************************************************
 * Functions for copying and pasting text between applications.
 * This is always included in a GUI version, but may also be included when the
 * clipboard and mouse is available to a terminal version such as xterm.
 * Note: there are some more functions in ops.c that handle selection stuff.
 */

#ifdef USE_CLIPBOARD

static void clip_invert_area __ARGS((int, int, int, int));
static void clip_yank_non_visual_selection __ARGS((int, int, int, int));
static void clip_get_word_boundaries __ARGS((VimClipboard *, int, int));
static int  clip_get_line_end __ARGS((int));
static void clip_update_non_visual_selection __ARGS((VimClipboard *, int, int,
						    int, int));

#define char_class(c)	(c <= ' ' ? ' ' : vim_iswordc(c))

/*
 * Selection stuff using Visual mode, for cutting and pasting text to other
 * windows.
 */

/*
 * Call this to initialise the clipboard.  Pass it FALSE if the clipboard code
 * is included, but the clipboard can not be used, or TRUE if the clipboard can
 * be used.  Eg unix may call this with FALSE, then call it again with TRUE if
 * the GUI starts.
 */
    void
clip_init(can_use)
    int	    can_use;
{
    clipboard.available = can_use;
    clipboard.owned = FALSE;
    clipboard.start.lnum = 0;
    clipboard.start.col = 0;
    clipboard.end.lnum = 0;
    clipboard.end.col = 0;
    clipboard.state = SELECT_CLEARED;
}

/*
 * Check whether the VIsual area has changed, and if so try to become the owner
 * of the selection, and free any old converted selection we may still have
 * lying around.  If the VIsual mode has ended, make a copy of what was
 * selected so we can still give it to others.	Will probably have to make sure
 * this is called whenever VIsual mode is ended.
 */
    void
clip_update_selection()
{
    FPOS    start, end;

    /* If visual mode is only due to a redo command ("."), then ignore it */
    if (!redo_VIsual_busy && VIsual_active)
    {
	if (lt(VIsual, curwin->w_cursor))
	{
	    start = VIsual;
	    end = curwin->w_cursor;
	}
	else
	{
	    start = curwin->w_cursor;
	    end = VIsual;
	}
	if (!equal(clipboard.start, start) || !equal(clipboard.end, end)
					    || clipboard.vmode != VIsual_mode)
	{
	    clip_clear_selection();
	    clipboard.start = start;
	    clipboard.end = end;
	    clipboard.vmode = VIsual_mode;
	    clip_free_selection();
	    clip_own_selection();
	    clip_mch_set_selection();
	}
    }
}

    void
clip_own_selection()
{
    /*
     * Also want to check somehow that we are reading from the keyboard rather
     * than a mapping etc.
     */
    if (!clipboard.owned)
	clipboard.owned = (clip_mch_own_selection() == OK);
}

    void
clip_lose_selection()
{
    clip_free_selection();
    clipboard.owned = FALSE;
    clip_clear_selection();
    clip_mch_lose_selection();
}

    void
clip_copy_selection()
{
    if (VIsual_active)
    {
	if (vim_strchr(p_guioptions, GO_ASEL) == NULL)
	    clip_update_selection();
	clip_free_selection();
	clip_own_selection();
	if (clipboard.owned)
	    clip_get_selection();
	clip_mch_set_selection();
    }
}

    void
clip_auto_select()
{
    if (vim_strchr(p_guioptions, GO_ASEL) != NULL)
	clip_copy_selection();
}


#ifdef USE_GUI

/*
 * Stuff for general mouse selection, without using Visual mode.
 */

static int clip_compare_pos __ARGS((int row1, int col1, int row2, int col2));

/*
 * Compare two screen positions ala strcmp()
 */
    static int
clip_compare_pos(row1, col1, row2, col2)
    int	    row1;
    int	    col1;
    int	    row2;
    int	    col2;
{
    if (row1 > row2) return( 1);
    if (row1 < row2) return(-1);
    if (col1 > col2) return( 1);
    if (col1 < col2) return(-1);
		     return( 0);
}

/*
 * Start out the selection
 */
/* ARGSUSED */
    void
clip_start_selection(button, x, y, repeated_click, modifiers)
    int	    button;
    int	    x;
    int	    y;
    int	    repeated_click;
    int_u   modifiers;
{
    VimClipboard    *cb = &clipboard;

    if (cb->state == SELECT_DONE)
	clip_clear_selection();

    cb->start.lnum  = check_row(Y_2_ROW(y));
    cb->start.col   = check_col(X_2_COL(x));
    cb->end	    = cb->start;
    cb->origin_row  = (short_u)cb->start.lnum;
    cb->state	    = SELECT_IN_PROGRESS;

    if (repeated_click)
    {
	if (++(cb->mode) > SELECT_MODE_LINE)
	    cb->mode = SELECT_MODE_CHAR;
    }
    else
	cb->mode = SELECT_MODE_CHAR;

#ifdef USE_GUI
    /* clear the cursor until the selection is made */
    gui_undraw_cursor();
#endif

    switch (cb->mode)
    {
	case SELECT_MODE_CHAR:
	    cb->origin_start_col = cb->start.col;
	    cb->word_end_col = clip_get_line_end((int)cb->start.lnum);
	    break;

	case SELECT_MODE_WORD:
	    clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col);
	    cb->origin_start_col = cb->word_start_col;
	    cb->origin_end_col	 = cb->word_end_col;

	    clip_invert_area((int)cb->start.lnum, cb->word_start_col,
			    (int)cb->end.lnum, cb->word_end_col);
	    cb->start.col = cb->word_start_col;
	    cb->end.col   = cb->word_end_col;
	    break;

	case SELECT_MODE_LINE:
	    clip_invert_area((int)cb->start.lnum, 0, (int)cb->start.lnum,
			    (int)Columns);
	    cb->start.col = 0;
	    cb->end.col   = Columns;
	    break;
    }

    cb->prev = cb->start;

#ifdef DEBUG_SELECTION
    printf("Selection started at (%u,%u)\n", cb->start.lnum, cb->start.col);
#endif
}

/*
 * Continue processing the selection
 */
/* ARGSUSED */
    void
clip_process_selection(button, x, y, repeated_click, modifiers)
    int	    button;
    int	    x;
    int	    y;
    int	    repeated_click;
    int_u   modifiers;
{
    VimClipboard    *cb = &clipboard;
    int		    row;
    int_u	    col;
    int		    diff;

    if (button == MOUSE_RELEASE)
    {
	/* Check to make sure we have something selected */
	if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
	{
#ifdef USE_GUI
	    if (gui.in_use)
		gui_update_cursor(FALSE, FALSE);
#endif
	    cb->state = SELECT_CLEARED;
	    return;
	}

#ifdef DEBUG_SELECTION
	printf("Selection ended: (%u,%u) to (%u,%u)\n", cb->start.lnum,
		cb->start.col, cb->end.lnum, cb->end.col);
#endif
	clip_free_selection();
	clip_own_selection();
	clip_yank_non_visual_selection((int)cb->start.lnum, cb->start.col,
					      (int)cb->end.lnum, cb->end.col);
	clip_mch_set_selection();
#ifdef USE_GUI
	if (gui.in_use)
	    gui_update_cursor(FALSE, FALSE);
#endif

	cb->state = SELECT_DONE;
	return;
    }

    row = check_row(Y_2_ROW(y));
    col = check_col(X_2_COL(x));

    if (col == cb->prev.col && row == cb->prev.lnum)
	return;

    /*
     * When extending the selection with the right mouse button, swap the
     * start and end if the position is before half the selection
     */
    if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
    {
	/*
	 * If the click is before the start, or the click is inside the
	 * selection and the start is the closest side, set the origin to the
	 * end of the selection.
	 */
	if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0
		|| (clip_compare_pos(row, col,
					   (int)cb->end.lnum, cb->end.col) < 0
		    && (((cb->start.lnum == cb->end.lnum
			    && cb->end.col - col > col - cb->start.col))
			|| ((diff = (cb->end.lnum - row) -
						   (row - cb->start.lnum)) > 0
			    || (diff == 0 && col < (cb->start.col +
							 cb->end.col) / 2)))))
	{
	    cb->origin_row = (short_u)cb->end.lnum;
	    cb->origin_start_col = cb->end.col - 1;
	    cb->origin_end_col = cb->end.col;
	}
	else
	{
	    cb->origin_row = (short_u)cb->start.lnum;
	    cb->origin_start_col = cb->start.col;
	    cb->origin_end_col = cb->start.col;
	}
	if (cb->mode == SELECT_MODE_WORD)
	{
	    clip_get_word_boundaries(cb, cb->origin_row, cb->origin_start_col);
	    cb->origin_start_col = cb->word_start_col;
	    cb->origin_end_col	 = cb->word_end_col;
	}
    }

    /* set state, for when using the right mouse button */
    cb->state = SELECT_IN_PROGRESS;

#ifdef DEBUG_SELECTION
    printf("Selection extending to (%d,%d)\n", row, col);
#endif

    switch (cb->mode)
    {
	case SELECT_MODE_CHAR:
	    /* If we're on a different line, find where the line ends */
	    if (row != cb->prev.lnum)
		cb->word_end_col = clip_get_line_end(row);

	    /* See if we are before or after the origin of the selection */
	    if (clip_compare_pos(row, col, cb->origin_row,
						   cb->origin_start_col) >= 0)
	    {
		if (col >= (int)cb->word_end_col)
		    clip_update_non_visual_selection(cb, cb->origin_row,
			    cb->origin_start_col, row, (int)Columns);
		else
		    clip_update_non_visual_selection(cb, cb->origin_row,
			    cb->origin_start_col, row, col + 1);
	    }
	    else
	    {
		if (col >= (int)cb->word_end_col)
		    clip_update_non_visual_selection(cb, row, cb->word_end_col,
			    cb->origin_row, cb->origin_start_col + 1);
		else
		    clip_update_non_visual_selection(cb, row, col,
			    cb->origin_row, cb->origin_start_col + 1);
	    }
	    break;

	case SELECT_MODE_WORD:
	    /* If we are still within the same word, do nothing */
	    if (row == cb->prev.lnum && col >= (int)cb->word_start_col
		    && col < (int)cb->word_end_col)
		return;

	    /* Get new word boundaries */
	    clip_get_word_boundaries(cb, row, col);

	    /* Handle being after the origin point of selection */
	    if (clip_compare_pos(row, col, cb->origin_row,
		    cb->origin_start_col) >= 0)
		clip_update_non_visual_selection(cb, cb->origin_row,
			cb->origin_start_col, row, cb->word_end_col);
	    else
		clip_update_non_visual_selection(cb, row, cb->word_start_col,
			cb->origin_row, cb->origin_end_col);
	    break;

	case SELECT_MODE_LINE:
	    if (row == cb->prev.lnum)
		return;

	    if (clip_compare_pos(row, col, cb->origin_row,
		    cb->origin_start_col) >= 0)
		clip_update_non_visual_selection(cb, cb->origin_row, 0, row,
			(int)Columns);
	    else
		clip_update_non_visual_selection(cb, row, 0, cb->origin_row,
			(int)Columns);

⌨️ 快捷键说明

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