📄 ui.c
字号:
break;
}
cb->prev.lnum = row;
cb->prev.col = col;
#ifdef DEBUG_SELECTION
printf("Selection is: (%u,%u) to (%u,%u)\n", cb->start.lnum,
cb->start.col, cb->end.lnum, cb->end.col);
#endif
}
/*
* Called after an Expose event to redraw the selection
*/
void
clip_redraw_selection(x, y, w, h)
int x;
int y;
int w;
int h;
{
VimClipboard *cb = &clipboard;
int row1, col1, row2, col2;
int row;
int start;
int end;
if (cb->state == SELECT_CLEARED)
return;
#ifdef USE_GUI /* TODO: how do we invert for non-GUI versions? */
row1 = check_row(Y_2_ROW(y));
col1 = check_col(X_2_COL(x));
row2 = check_row(Y_2_ROW(y + h - 1));
col2 = check_col(X_2_COL(x + w - 1));
/* Limit the rows that need to be re-drawn */
if (cb->start.lnum > row1)
row1 = cb->start.lnum;
if (cb->end.lnum < row2)
row2 = cb->end.lnum;
/* Look at each row that might need to be re-drawn */
for (row = row1; row <= row2; row++)
{
/* For the first selection row, use the starting selection column */
if (row == cb->start.lnum)
start = cb->start.col;
else
start = 0;
/* For the last selection row, use the ending selection column */
if (row == cb->end.lnum)
end = cb->end.col;
else
end = Columns;
if (col1 > start)
start = col1;
if (col2 < end)
end = col2 + 1;
if (end > start)
gui_mch_invert_rectangle(row, start, 1, end - start);
}
#endif
}
/*
* Redraw the selection if character at "row,col" is inside of it.
*/
void
clip_may_redraw_selection(row, col)
int row, col;
{
if (clipboard.state != SELECT_CLEARED
&& ((row == clipboard.start.lnum
&& col >= (int)clipboard.start.col)
|| row > clipboard.start.lnum)
&& ((row == clipboard.end.lnum
&& col < (int)clipboard.end.col)
|| row < clipboard.end.lnum))
clip_invert_area(row, col, row, col + 1);
}
/*
* Called from outside to clear selected region from the display
*/
void
clip_clear_selection()
{
VimClipboard *cb = &clipboard;
if (cb->state == SELECT_CLEARED)
return;
clip_invert_area((int)cb->start.lnum, cb->start.col, (int)cb->end.lnum,
cb->end.col);
cb->state = SELECT_CLEARED;
}
/*
* Clear the selection if any lines from "row1" to "row2" are inside of it.
*/
void
clip_may_clear_selection(row1, row2)
int row1, row2;
{
if (clipboard.state == SELECT_DONE
&& row2 >= clipboard.start.lnum
&& row1 <= clipboard.end.lnum)
clip_clear_selection();
}
/*
* Called before the screen is scrolled up or down. Adjusts the line numbers
* of the selection. Call with big number when clearing the screen.
*/
void
clip_scroll_selection(rows)
int rows; /* negative for scroll down */
{
int lnum;
if (clipboard.state == SELECT_CLEARED)
return;
lnum = clipboard.start.lnum - rows;
if (lnum <= 0)
clipboard.start.lnum = 0;
else if (lnum >= screen_Rows) /* scrolled off of the screen */
clipboard.state = SELECT_CLEARED;
else
clipboard.start.lnum = lnum;
lnum = clipboard.end.lnum - rows;
if (lnum < 0) /* scrolled off of the screen */
clipboard.state = SELECT_CLEARED;
else if (lnum >= screen_Rows)
clipboard.end.lnum = screen_Rows - 1;
else
clipboard.end.lnum = lnum;
}
/*
* Invert a region of the display between a starting and ending row and column
*/
static void
clip_invert_area(row1, col1, row2, col2)
int row1;
int col1;
int row2;
int col2;
{
#ifdef USE_GUI /* TODO: how do we invert for non-GUI versions? */
/* Swap the from and to positions so the from is always before */
if (clip_compare_pos(row1, col1, row2, col2) > 0)
{
int tmp_row, tmp_col;
tmp_row = row1;
tmp_col = col1;
row1 = row2;
col1 = col2;
row2 = tmp_row;
col2 = tmp_col;
}
/* If all on the same line, do it the easy way */
if (row1 == row2)
{
gui_mch_invert_rectangle(row1, col1, 1, col2 - col1);
return;
}
/* Handle a piece of the first line */
if (col1 > 0)
{
gui_mch_invert_rectangle(row1, col1, 1, (int)Columns - col1);
row1++;
}
/* Handle a piece of the last line */
if (col2 < Columns - 1)
{
gui_mch_invert_rectangle(row2, 0, 1, col2);
row2--;
}
/* Handle the rectangle thats left */
if (row2 >= row1)
gui_mch_invert_rectangle(row1, 0, row2 - row1 + 1, (int)Columns);
#endif
}
/*
* Yank the currently selected area into the special selection buffer so it
* will be available for pasting.
*/
static void
clip_yank_non_visual_selection(row1, col1, row2, col2)
int row1;
int col1;
int row2;
int col2;
{
char_u *buffer;
char_u *bufp;
int row;
int start_col;
int end_col;
int line_end_col;
int add_newline_flag = FALSE;
/*
* Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
*/
if (row1 > row2)
{
row = row1; row1 = row2; row2 = row;
row = col1; col1 = col2; col2 = row;
}
else if (row1 == row2 && col1 > col2)
{
row = col1; col1 = col2; col2 = row;
}
/* Create a temporary buffer for storing the text */
buffer = lalloc((row2 - row1 + 1) * Columns + 1, TRUE);
if (buffer == NULL) /* out of memory */
return;
/* Process each row in the selection */
for (bufp = buffer, row = row1; row <= row2; row++)
{
if (row == row1)
start_col = col1;
else
start_col = 0;
if (row == row2)
end_col = col2;
else
end_col = Columns;
line_end_col = clip_get_line_end(row);
/* See if we need to nuke some trailing whitespace */
if (end_col >= Columns && (row < row2 || end_col > line_end_col))
{
/* Get rid of trailing whitespace */
end_col = line_end_col;
if (end_col < start_col)
end_col = start_col;
/* If the last line extended to the end, add an extra newline */
if (row == row2)
add_newline_flag = TRUE;
}
/* If after the first row, we need to always add a newline */
if (row > row1)
*bufp++ = NL;
if (row < screen_Rows && end_col <= screen_Columns)
{
STRNCPY(bufp, &LinePointers[row][start_col], end_col - start_col);
bufp += end_col - start_col;
}
}
/* Add a newline at the end if the selection ended there */
if (add_newline_flag)
*bufp++ = NL;
clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer));
vim_free(buffer);
}
/*
* Find the starting and ending positions of the word at the given row and
* column.
*/
static void
clip_get_word_boundaries(cb, row, col)
VimClipboard *cb;
int row;
int col;
{
char start_class;
int temp_col;
if (row >= screen_Rows || col >= screen_Columns)
return;
start_class = char_class(LinePointers[row][col]);
temp_col = col;
for ( ; temp_col > 0; temp_col--)
if (char_class(LinePointers[row][temp_col - 1]) != start_class)
break;
cb->word_start_col = temp_col;
temp_col = col;
for ( ; temp_col < screen_Columns; temp_col++)
if (char_class(LinePointers[row][temp_col]) != start_class)
break;
cb->word_end_col = temp_col;
#ifdef DEBUG_SELECTION
printf("Current word: col %u to %u\n", cb->word_start_col,
cb->word_end_col);
#endif
}
/*
* Find the column position for the last non-whitespace character on the given
* line.
*/
static int
clip_get_line_end(row)
int row;
{
int i;
if (row >= screen_Rows)
return 0;
for (i = screen_Columns; i > 0; i--)
if (LinePointers[row][i - 1] != ' ')
break;
return i;
}
/*
* Update the currently selected region by adding and/or subtracting from the
* beginning or end and inverting the changed area(s).
*/
static void
clip_update_non_visual_selection(cb, row1, col1, row2, col2)
VimClipboard *cb;
int row1;
int col1;
int row2;
int col2;
{
/* See if we changed at the beginning of the selection */
if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
{
clip_invert_area(row1, col1, (int)cb->start.lnum, cb->start.col);
cb->start.lnum = row1;
cb->start.col = col1;
}
/* See if we changed at the end of the selection */
if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
{
clip_invert_area(row2, col2, (int)cb->end.lnum, cb->end.col);
cb->end.lnum = row2;
cb->end.col = col2;
}
}
#else /* If USE_GUI not defined */
/*
* Called from outside to clear selected region from the display
*/
void
clip_clear_selection()
{
/*
* Dummy version for now... the point of this code is to set the selected
* area back to "normal" colour if we are clearing the selection. As we
* don't have GUI-style mouse selection, we can ignore this for now.
* Eventually we could actually invert the area in a terminal by redrawing
* in reverse mode, but we don't do that yet.
*/
clipboard.state = SELECT_CLEARED;
}
#endif /* USE_GUI */
#endif /* USE_CLIPBOARD */
/*****************************************************************************
* Functions that handle the input buffer.
* This is used for any GUI version, and the unix terminal version.
*
* For Unix, the input characters are buffered to be able to check for a
* CTRL-C. This should be done with signals, but I don't know how to do that
* in a portable way for a tty in RAW mode.
*/
#if defined(UNIX) || defined(USE_GUI) || defined(OS2) || defined(VMS)
/*
* Internal typeahead buffer. Includes extra space for long key code
* descriptions which would otherwise overflow. The buffer is considered full
* when only this extra space (or part of it) remains.
*/
#define INBUFLEN 250
static char_u inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
static int inbufcount = 0; /* number of chars in inbuf[] */
/*
* vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and
* trash_input_buf() are functions for manipulating the input buffer. These
* are used by the gui_* calls when a GUI is used to handle keyboard input.
*/
int
vim_is_input_buf_full()
{
return (inbufcount >= INBUFLEN);
}
int
vim_is_input_buf_empty()
{
return (inbufcount == 0);
}
int
vim_free_in_input_buf()
{
return (INBUFLEN - inbufcount);
}
/* Add the given bytes to the input buffer */
void
add_to_input_buf(s, len)
char_u *s;
int len;
{
if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
return; /* Shouldn't ever happen! */
while (len--)
inbuf[inbufcount++] = *s++;
}
/* Remove everything from the input buffer. Called when ^C is found */
void
trash_input_buf()
{
inbufcount = 0;
}
/*
* Read as much data from the input buffer as possible up to maxlen, and store
* it in buf.
* Note: this function used to be Read() in unix.c
*/
int
read_from_input_buf(buf, maxlen)
char_u *buf;
long maxlen;
{
if (inbufcount == 0) /* if the buffer is empty, fill it */
fill_input_buf(TRUE);
if (maxlen > inbufcount)
maxlen = inbufcount;
mch_memmove(buf, inbuf, (size_t)maxlen);
inbufcount -= maxlen;
if (inbufcount)
mch_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
return (int)maxlen;
}
void
fill_input_buf(exit_on_error)
int exit_on_error;
{
#if defined(UNIX) || defined(OS2) || defined(VMS)
int len;
int try;
static int did_read_something = FALSE;
#endif
#ifdef VMS
extern char ibuf[];
#endif
#ifdef USE_GUI
if (gui.in_use)
{
gui_mch_update();
return;
}
#endif
#if defined(UNIX) || defined(OS2) || defined(VMS)
if (vim_is_input_buf_full())
return;
/*
* Fill_input_buf() is only called when we really need a character.
* If we can't get any, but there is some in the buffer, just return.
* If we can't get any, and there isn't any in the buffer, we give up and
* exit Vim.
*/
# ifdef __BEOS__
/*
* On the BeBox version (for now), all input is secretly performed within
* beos_select() which is called from RealWaitForChar().
*/
while (!vim_is_input_buf_full() && RealWaitForChar(read_cmd_fd, 0))
;
len = inbufcount;
inbufcount = 0;
# else
#ifdef USE_SNIFF
if (sniff_request_waiting)
{
add_to_input_buf((char_u *)"\233sniff",6); /* results in K_SNIFF */
sniff_request_waiting = 0;
want_sniff_request = 0;
return;
}
#endif
# ifdef VMS
while (!vim_is_input_buf_full() && RealWaitForChar(0, 0L))
{
add_to_input_buf((char_u *)ibuf, 1);
}
if (inbufcount < 1 && !exit_on_error)
return;
len = inbufcount;
inbufcount = 0;
# else
for (try = 0; try < 100; ++try)
{
len = read(read_cmd_fd, (char *)inbuf + inbufcount,
(size_t)(INBUFLEN - inbufcount));
if (len > 0 || got_int)
break;
/*
* If reading stdin results in an error, continue reading stderr.
* This helps when using "foo | xargs vim".
*/
if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0)
read_cmd_fd = 2;
if (!exit_on_error)
return;
}
# endif /* VMS */
# endif
if (len <= 0 && !got_int)
read_error_exit();
did_read_something = TRUE;
if (got_int)
{
inbuf[inbufcount] = 3;
inbufcount = 1;
}
else
while (len-- > 0)
{
/*
* if a CTRL-C was typed, remove it from the buffer and set got_int
*/
if (inbuf[inbufcount] == 3)
{
/* remove everything typed before the CTRL-C */
mch_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
inbufcount = 0;
got_int = TRUE;
}
++inbufcount;
}
#endif /* UNIX or OS2 or VMS*/
}
#endif /* defined(UNIX) || defined(USE_GUI) || defined(OS2) || defined(VMS) */
/*
* Exit because of an input read error.
*/
void
read_error_exit()
{
if (silent_mode) /* Normal way to exit for "ex -s" */
getout(0);
STRCPY(IObuff, "Vim: Error reading input, exiting...\n");
preserve_exit();
}
#if defined(CURSOR_SHAPE) || defined(PROTO)
/*
* May update the shape of the cursor.
*/
void
ui_cursor_shape()
{
#ifdef USE_GUI
if (gui.in_use)
gui_upd_cursor_shape();
#endif
#if defined(MSDOS) || (defined(WIN32) && !defined(USE_GUI_WIN32))
mch_update_cursor();
#endif
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -