📄 misc1.c
字号:
int oldlen;
int extra;
colnr_t col = curwin->w_cursor.col;
linenr_t lnum = curwin->w_cursor.lnum;
oldp = ml_get(lnum);
oldlen = STRLEN(oldp) + 1;
if (State != REPLACE || *(oldp + col) == NUL)
extra = 1;
else
extra = 0;
/*
* A character has to be put on the replace stack if there is a
* character that is replaced, so it can be put back when BS is used.
*/
if (State == REPLACE)
{
replace_push(NUL);
if (!extra)
replace_push(*(oldp + col));
}
newp = alloc_check((unsigned)(oldlen + extra));
if (newp == NULL)
return;
mch_memmove(newp, oldp, (size_t)col);
p = newp + col;
mch_memmove(p + extra, oldp + col, (size_t)(oldlen - col));
#ifdef MULTI_BYTE
/*
* We define that "[]" is a multi-byte character. For example. If
* replace(R) is done over "a[]" with "[]". finnaly, "[]]" is
* constructed. but the following line replaces "[]]" with "[] ".
*/
if (is_dbcs && State == REPLACE && IsLeadByte(*p) && p[1] != NUL)
p[1] = ' ';
#endif
*p = c;
ml_replace(lnum, newp, FALSE);
/*
* If we're in insert or replace mode and 'showmatch' is set, then check for
* right parens and braces. If there isn't a match, then beep. If there
* is a match AND it's on the screen, then flash to it briefly. If it
* isn't on the screen, don't do anything.
*/
#ifdef RIGHTLEFT
if (p_sm && (State & INSERT) &&
((!(curwin->w_p_rl ^ p_ri) && (c == ')' || c == '}' || c == ']')) ||
((curwin->w_p_rl ^ p_ri) && (c == '(' || c == '{' || c == '['))))
#else
if (p_sm && (State & INSERT) && (c == ')' || c == '}' || c == ']'))
#endif
showmatch();
#ifdef RIGHTLEFT
if (!p_ri || State == REPLACE) /* normal insert: cursor right */
#endif
++curwin->w_cursor.col;
changed();
/*
* TODO: should try to update w_row here, to avoid recomputing it later.
*/
changed_cline_bef_curs();
approximate_botline(); /* w_botline might have changed */
}
/*
* Insert a string at the cursor position.
* Note: Nothing special for replace mode.
*/
void
ins_str(s)
char_u *s;
{
char_u *oldp, *newp;
int newlen = STRLEN(s);
int oldlen;
colnr_t col = curwin->w_cursor.col;
linenr_t lnum = curwin->w_cursor.lnum;
oldp = ml_get(lnum);
oldlen = STRLEN(oldp);
newp = alloc_check((unsigned)(oldlen + newlen + 1));
if (newp == NULL)
return;
mch_memmove(newp, oldp, (size_t)col);
mch_memmove(newp + col, s, (size_t)newlen);
mch_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
ml_replace(lnum, newp, FALSE);
curwin->w_cursor.col += newlen;
changed();
changed_cline_bef_curs();
approximate_botline(); /* w_botline might have changed */
}
/*
* Delete one character under the cursor.
* If 'fixpos' is TRUE, don't let the cursor on the NUL after the line.
*
* return FAIL for failure, OK otherwise
*/
int
del_char(fixpos)
int fixpos;
{
#ifdef MULTI_BYTE
if (is_dbcs)
{
/* delete two-bytes, when the character is an multi-byte character */
if (AdjustCursorForMultiByteCharacter())
return del_chars(2L, fixpos); /* do BACKSPACE key */
else
{
char_u *p; /* do DELETE key */
p = ml_get_cursor();
if (p == NULL || p[0] == NUL)
return FALSE;
if (p[1] != NUL && IsLeadByte(p[0]))
return del_chars(2L, fixpos);
else
return del_chars(1L, fixpos);
}
}
else
#endif
return del_chars(1L, fixpos);
}
/*
* Delete 'count' characters under the cursor.
* If 'fixpos' is TRUE, don't leave the cursor on the NUL after the line.
*
* return FAIL for failure, OK otherwise
*/
int
del_chars(count, fixpos)
long count;
int fixpos;
{
char_u *oldp, *newp;
colnr_t oldlen;
linenr_t lnum = curwin->w_cursor.lnum;
colnr_t col = curwin->w_cursor.col;
int was_alloced;
long movelen;
oldp = ml_get(lnum);
oldlen = STRLEN(oldp);
/*
* Can't do anything when the cursor is on the NUL after the line.
*/
if (col >= oldlen)
return FAIL;
/*
* When count is too big, reduce it.
*/
movelen = (long)oldlen - (long)col - count + 1; /* includes trailing NUL */
if (movelen <= 1)
{
/*
* If we just took off the last character of a non-blank line, and
* fixpos is TRUE, we don't want to end up positioned at the NUL.
*/
if (col > 0 && fixpos)
--curwin->w_cursor.col;
count = oldlen - col;
movelen = 1;
}
/*
* If the old line has been allocated the deletion can be done in the
* existing line. Otherwise a new line has to be allocated
*/
was_alloced = ml_line_alloced(); /* check if oldp was allocated */
if (was_alloced)
newp = oldp; /* use same allocated memory */
else
{ /* need to allocated a new line */
newp = alloc((unsigned)(oldlen + 1 - count));
if (newp == NULL)
return FAIL;
mch_memmove(newp, oldp, (size_t)col);
}
mch_memmove(newp + col, oldp + col + count, (size_t)movelen);
if (!was_alloced)
ml_replace(lnum, newp, FALSE);
changed();
/*
* When the new character under the cursor is a TAB, the cursor will move
* on the screen, so we can't use changed_cline_aft_curs() here.
*/
changed_cline_bef_curs();
approximate_botline(); /* w_botline might have changed */
return OK;
}
/*
* Delete from cursor to end of line.
*
* return FAIL for failure, OK otherwise
*/
int
truncate_line(fixpos)
int fixpos; /* if TRUE fix the cursor position when done */
{
char_u *newp;
linenr_t lnum = curwin->w_cursor.lnum;
colnr_t col = curwin->w_cursor.col;
if (col == 0)
newp = vim_strsave((char_u *)"");
else
newp = vim_strnsave(ml_get(lnum), col);
if (newp == NULL)
return FAIL;
ml_replace(lnum, newp, FALSE);
/*
* If "fixpos" is TRUE we don't want to end up positioned at the NUL.
*/
if (fixpos && curwin->w_cursor.col > 0)
--curwin->w_cursor.col;
changed();
changed_cline_bef_curs();
approximate_botline(); /* w_botline might have changed */
return OK;
}
void
del_lines(nlines, dowindow, undo)
long nlines; /* number of lines to delete */
int dowindow; /* if true, update the window */
int undo; /* if true, prepare for undo */
{
int num_plines = 0;
int offset = 0;
if (nlines <= 0)
return;
/*
* There's no point in keeping the window updated if redrawing is disabled
* or we're deleting more than a window's worth of lines.
*/
if (!redrawing() || !botline_approximated())
dowindow = FALSE;
else
{
validate_cursor();
if (nlines > (curwin->w_height - curwin->w_wrow) && dowindow)
{
dowindow = FALSE;
/* flaky way to clear rest of window */
win_del_lines(curwin, curwin->w_wrow, curwin->w_height, TRUE, TRUE);
}
}
/*
* Assume that w_botline won't change much. If it does, there is a small
* risc of an extra redraw or scroll-up.
*/
approximate_botline();
/* save the deleted lines for undo */
if (undo && u_savedel(curwin->w_cursor.lnum, nlines) == FAIL)
return;
/* adjust marks for deleted lines and lines that follow */
mark_adjust(curwin->w_cursor.lnum, curwin->w_cursor.lnum + nlines - 1,
(linenr_t)MAXLNUM, -nlines);
while (nlines-- > 0)
{
if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */
break;
/*
* Set up to delete the correct number of physical lines on the
* window
*/
if (dowindow)
num_plines += plines(curwin->w_cursor.lnum);
ml_delete(curwin->w_cursor.lnum, TRUE);
changed();
/* If we delete the last line in the file, stop */
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
{
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
offset = 1;
break;
}
}
curwin->w_cursor.col = 0;
/*
* The cursor will stay in the same line number, but the contents will be
* different, so need to update it's screen posision later.
*/
changed_cline_bef_curs();
/*
* Delete the correct number of physical lines on the window
*/
if (dowindow && num_plines > 0)
{
validate_cline_row();
win_del_lines(curwin, curwin->w_cline_row + offset, num_plines,
TRUE, TRUE);
}
}
int
gchar(pos)
FPOS *pos;
{
char_u *ptr = ml_get_pos(pos);
#ifdef MULTI_BYTE
if (ptr[0] && (is_unicode || (is_dbcs && IsLeadByte(*ptr))))
return ptr[0] + (ptr[1] << 8);
#endif
return (int)*ptr;
}
int
gchar_cursor()
{
char_u *ptr = ml_get_cursor();
#ifdef MULTI_BYTE
if (ptr[0] && (is_unicode || (is_dbcs && IsLeadByte(*ptr))))
return ptr[0] + (ptr[1] << 8);
#endif
return (int)*ptr;
}
/*
* Write a character at the current cursor position.
* It is directly written into the block.
*/
void
pchar_cursor(c)
int c;
{
*(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) +
curwin->w_cursor.col) = c;
}
/*
* Put *pos at end of current buffer
*/
void
goto_endofbuf(pos)
FPOS *pos;
{
char_u *p;
pos->lnum = curbuf->b_ml.ml_line_count;
pos->col = 0;
p = ml_get(pos->lnum);
while (*p++)
++pos->col;
}
/*
* When extra == 0: Return TRUE if the cursor is before or on the first
* non-blank in the line.
* When extra == 1: Return TRUE if the cursor is before the first non-blank in
* the line.
*/
int
inindent(extra)
int extra;
{
char_u *ptr;
colnr_t col;
for (col = 0, ptr = ml_get_curline(); vim_iswhite(*ptr); ++col)
++ptr;
if (col >= curwin->w_cursor.col + extra)
return TRUE;
else
return FALSE;
}
/*
* Skip to next part of an option argument: Skip space and comma.
*/
char_u *
skip_to_option_part(p)
char_u *p;
{
if (*p == ',')
++p;
while (*p == ' ')
++p;
return p;
}
char *
plural(n)
long n;
{
static char buf[2] = "s";
if (n == 1)
return &(buf[1]);
return &(buf[0]);
}
/*
* changed() is called when something in the current buffer is changed
*/
void
changed()
{
int save_msg_scroll = msg_scroll;
if (!curbuf->b_changed)
{
change_warning(0);
if (curbuf->b_may_swap) /* still need to create a swap file */
{
ml_open_file(curbuf);
/* The ml_open_file() can cause an ATTENTION message.
* Wait two seconds, to make sure the user reads this unexpected
* message. Since we could be anywhere, call wait_return() now,
* and don't let the emsg() set msg_scroll. */
if (need_wait_return)
{
out_flush();
ui_delay(2000L, TRUE);
wait_return(TRUE);
msg_scroll = save_msg_scroll;
}
}
curbuf->b_changed = TRUE;
check_status(curbuf);
}
modified = TRUE; /* used for redrawing */
tag_modified = TRUE; /* used for tag searching check */
}
/*
* unchanged() is called when the changed flag must be reset for buffer 'buf'
*/
void
unchanged(buf, ff)
BUF *buf;
int ff; /* also reset 'fileformat' */
{
if (buf->b_changed || (ff && buf->b_start_ffc != *buf->b_p_ff))
{
buf->b_changed = 0;
if (ff)
buf->b_start_ffc = *buf->b_p_ff; /* keep this fileformat */
check_status(buf);
}
}
/*
* check_status: called when the status bars for the buffer 'buf'
* need to be updated
*/
void
check_status(buf)
BUF *buf;
{
WIN *wp;
int i;
i = 0;
for (wp = firstwin; wp != NULL; wp = wp->w_next)
if (wp->w_buffer == buf && wp->w_status_height)
{
wp->w_redr_status = TRUE;
++i;
}
if (i)
redraw_later(NOT_VALID);
}
/*
* If the file is readonly, give a warning message with the first change.
* Don't do this for autocommands.
* Don't use emsg(), because it flushes the macro buffer.
* If we have undone all changes b_changed will be FALSE, but b_did_warn
* will be TRUE.
*/
void
change_warning(col)
int col; /* column for message; non-zero when in insert
mode and 'showmode' is on */
{
if (curbuf->b_did_warn == FALSE
&& curbuf_changed() == 0
&& !p_im
#ifdef AUTOCMD
&& !autocmd_busy
#endif
&& curbuf->b_p_ro)
{
/*
* Do what msg() does, but with a column offset if the warning should
* be after the mode message.
*/
msg_start();
if (msg_row == Rows - 1)
msg_col = col;
MSG_PUTS_ATTR("Warning: Changing a readonly file", hl_attr(HLF_W));
msg_clr_eos();
(void)msg_end();
ui_delay(1000L, TRUE); /* give him some time to think about it */
curbuf->b_did_warn = TRUE;
redraw_cmdline = FALSE; /* don't redraw and erase the message */
if (msg_row < Rows - 1)
showmode();
}
}
/*
* Ask for a reply from the user, a 'y' or a 'n'.
* No other characters are accepted, the message is repeated until a valid
* reply is entered or CTRL-C is hit.
* If direct is TRUE, don't use vgetc() but ui_inchar(), don't get characters
* from any buffers but directly from the user.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -