📄 misc1.c
字号:
/* 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.
*/
/*
* misc1.c: functions that didn't seem to fit elsewhere
*/
#include "vim.h"
#ifdef HAVE_FCNTL_H
# include <fcntl.h> /* for chdir() */
#endif
static int get_indent_str __ARGS((char_u *ptr));
/*
* count the size of the indent in the current line
*/
int
get_indent()
{
return get_indent_str(ml_get_curline());
}
/*
* count the size of the indent in line "lnum"
*/
int
get_indent_lnum(lnum)
linenr_t lnum;
{
return get_indent_str(ml_get(lnum));
}
/*
* count the size of the indent in line "ptr"
*/
static int
get_indent_str(ptr)
char_u *ptr;
{
int count = 0;
for ( ; *ptr; ++ptr)
{
if (*ptr == TAB) /* count a tab for what it is worth */
count += (int)curbuf->b_p_ts - (count % (int)curbuf->b_p_ts);
else if (*ptr == ' ')
++count; /* count a space for one */
else
break;
}
return (count);
}
/*
* set the indent of the current line
* leaves the cursor on the first non-blank in the line
*/
void
set_indent(size, del_first)
int size;
int del_first;
{
int oldstate = State;
int c;
#ifdef RIGHTLEFT
int old_p_ri = p_ri;
p_ri = 0; /* don't want revins in ident */
#endif
State = INSERT; /* don't want REPLACE for State */
curwin->w_cursor.col = 0;
if (del_first) /* delete old indent */
{
/* vim_iswhite() is a define! */
while ((c = gchar_cursor()), vim_iswhite(c))
(void)del_char(FALSE);
}
if (!curbuf->b_p_et) /* if 'expandtab' is set, don't use TABs */
while (size >= (int)curbuf->b_p_ts)
{
ins_char(TAB);
size -= (int)curbuf->b_p_ts;
}
while (size)
{
ins_char(' ');
--size;
}
State = oldstate;
#ifdef RIGHTLEFT
p_ri = old_p_ri;
#endif
}
#if defined(CINDENT) || defined(SMARTINDENT)
static int cin_is_cinword __ARGS((char_u *line));
/*
* Return TRUE if the string "line" starts with a word from 'cinwords'.
*/
static int
cin_is_cinword(line)
char_u *line;
{
char_u *cinw;
char_u *cinw_buf;
int cinw_len;
int retval = FALSE;
int len;
cinw_len = STRLEN(curbuf->b_p_cinw) + 1;
cinw_buf = alloc((unsigned)cinw_len);
if (cinw_buf != NULL)
{
line = skipwhite(line);
for (cinw = curbuf->b_p_cinw; *cinw; )
{
len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
if (STRNCMP(line, cinw_buf, len) == 0 &&
(!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1])))
{
retval = TRUE;
break;
}
}
vim_free(cinw_buf);
}
return retval;
}
#endif
/*
* open_line: Add a new line below or above the current line.
*
* Caller must take care of undo.
*
* Return TRUE for success, FALSE for failure
*/
int
open_line(dir, redraw, del_spaces, old_indent)
int dir; /* FORWARD or BACKWARD */
int redraw; /* > 0: redraw afterwards, < 0: insert lines*/
int del_spaces; /* delete spaces after cursor */
int old_indent; /* indent for after ^^D in Insert mode */
{
char_u *saved_line; /* copy of the original line */
char_u *p_extra = NULL; /* what goes to next line */
int extra_len = 0; /* length of p_extra string */
FPOS old_cursor; /* old cursor position */
int newcol = 0; /* new cursor column */
int newindent = 0; /* auto-indent of the new line */
int n;
int trunc_line = FALSE; /* truncate current line afterwards */
int retval = FALSE; /* return value, default is FAIL */
int lead_len; /* length of comment leader */
char_u *lead_flags; /* position in 'comments' for comment leader */
char_u *leader = NULL; /* copy of comment leader */
char_u *allocated = NULL; /* allocated memory */
char_u *p;
int saved_char = NUL; /* init for GCC */
FPOS *pos;
int old_plines = 0; /* init for GCC */
int new_plines = 0; /* init for GCC */
#ifdef SMARTINDENT
int no_si = FALSE; /* reset did_si afterwards */
int first_char = NUL; /* init for GCC */
#endif
/*
* make a copy of the current line so we can mess with it
*/
saved_line = vim_strsave(ml_get_curline());
if (saved_line == NULL) /* out of memory! */
return FALSE;
if (State == INSERT || State == REPLACE)
{
p_extra = saved_line + curwin->w_cursor.col;
#ifdef SMARTINDENT
if (curbuf->b_p_si) /* need first char after new line break */
{
p = skipwhite(p_extra);
first_char = *p;
}
#endif
extra_len = STRLEN(p_extra);
saved_char = *p_extra;
*p_extra = NUL;
}
u_clearline(); /* cannot do "U" command when adding lines */
#ifdef SMARTINDENT
did_si = FALSE;
#endif
/*
* If 'autoindent' and/or 'smartindent' is set, try to figure out what
* indent to use for the new line.
*/
if (curbuf->b_p_ai
#ifdef SMARTINDENT
|| curbuf->b_p_si
#endif
)
{
/*
* count white space on current line
*/
newindent = get_indent();
if (newindent == 0)
newindent = old_indent; /* for ^^D command in insert mode */
/*
* If we just did an auto-indent, then we didn't type anything on
* the prior line, and it should be truncated.
*/
if (dir == FORWARD && did_ai)
trunc_line = TRUE;
#ifdef SMARTINDENT
/*
* Do smart indenting.
* In insert/replace mode (only when dir == FORWARD)
* we may move some text to the next line. If it starts with '{'
* don't add an indent. Fixes inserting a NL before '{' in line
* "if (condition) {"
*/
else if (curbuf->b_p_si && *saved_line != NUL &&
(p_extra == NULL || first_char != '{'))
{
char_u *ptr;
char_u last_char;
old_cursor = curwin->w_cursor;
ptr = saved_line;
lead_len = get_leader_len(ptr, NULL);
if (dir == FORWARD)
{
/*
* Skip preprocessor directives, unless they are
* recognised as comments.
*/
if (lead_len == 0 && ptr[0] == '#')
{
while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
ptr = ml_get(--curwin->w_cursor.lnum);
newindent = get_indent();
}
lead_len = get_leader_len(ptr, NULL);
if (lead_len > 0)
{
/*
* This case gets the following right:
* \*
* * A comment (read '\' as '/').
* *\
* #define IN_THE_WAY
* This should line up here;
*/
p = skipwhite(ptr);
if (p[0] == '/' && p[1] == '*')
p++;
if (p[0] == '*')
{
for (p++; *p; p++)
{
if (p[0] == '/' && p[-1] == '*')
{
/*
* End of C comment, indent should line up
* with the line containing the start of
* the comment
*/
curwin->w_cursor.col = p - ptr;
if ((pos = findmatch(NULL, NUL)) != NULL)
{
curwin->w_cursor.lnum = pos->lnum;
newindent = get_indent();
}
}
}
}
}
else /* Not a comment line */
{
/* Find last non-blank in line */
p = ptr + STRLEN(ptr) - 1;
while (p > ptr && vim_iswhite(*p))
--p;
last_char = *p;
/*
* find the character just before the '{' or ';'
*/
if (last_char == '{' || last_char == ';')
{
if (p > ptr)
--p;
while (p > ptr && vim_iswhite(*p))
--p;
}
/*
* Try to catch lines that are split over multiple
* lines. eg:
* if (condition &&
* condition) {
* Should line up here!
* }
*/
if (*p == ')')
{
curwin->w_cursor.col = p - ptr;
if ((pos = findmatch(NULL, '(')) != NULL)
{
curwin->w_cursor.lnum = pos->lnum;
newindent = get_indent();
ptr = ml_get_curline();
}
}
/*
* If last character is '{' do indent, without
* checking for "if" and the like.
*/
if (last_char == '{')
{
did_si = TRUE; /* do indent */
no_si = TRUE; /* don't delete it when '{' typed */
}
/*
* Look for "if" and the like, use 'cinwords'.
* Don't do this if the previous line ended in ';' or
* '}'.
*/
else if (last_char != ';' && last_char != '}'
&& cin_is_cinword(ptr))
did_si = TRUE;
}
}
else /* dir == BACKWARD */
{
/*
* Skip preprocessor directives, unless they are
* recognised as comments.
*/
if (lead_len == 0 && ptr[0] == '#')
{
int was_backslashed = FALSE;
while ((ptr[0] == '#' || was_backslashed) &&
curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
{
if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
was_backslashed = TRUE;
else
was_backslashed = FALSE;
ptr = ml_get(++curwin->w_cursor.lnum);
}
if (was_backslashed)
newindent = 0; /* Got to end of file */
else
newindent = get_indent();
}
p = skipwhite(ptr);
if (*p == '}') /* if line starts with '}': do indent */
did_si = TRUE;
else /* can delete indent when '{' typed */
can_si_back = TRUE;
}
curwin->w_cursor = old_cursor;
}
if (curbuf->b_p_si)
can_si = TRUE;
#endif /* SMARTINDENT */
did_ai = TRUE;
}
/*
* Find out if the current line starts with a comment leader.
* This may then be inserted in front of the new line.
*/
lead_len = get_leader_len(saved_line, &lead_flags);
if (lead_len > 0)
{
char_u *lead_repl = NULL; /* replaces comment leader */
int lead_repl_len = 0; /* length of *lead_repl */
char_u lead_middle[COM_MAX_LEN]; /* middle-comment string */
char_u lead_end[COM_MAX_LEN]; /* end-comment string */
char_u *comment_end = NULL; /* where lead_end has been found */
int extra_space = FALSE; /* append extra space */
int current_flag;
int require_blank = FALSE; /* requires blank after middle */
/*
* If the comment leader has the start, middle or end flag, it may not
* be used or may be replaced with the middle leader.
*/
for (p = lead_flags; *p && *p != ':'; ++p)
{
if (*p == COM_BLANK)
{
require_blank = TRUE;
continue;
}
if (*p == COM_START || *p == COM_MIDDLE)
{
current_flag = *p;
if (*p == COM_START)
{
/*
* Doing "O" on a start of comment does not insert leader.
*/
if (dir == BACKWARD)
{
lead_len = 0;
break;
}
/* find start of middle part */
(void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
require_blank = FALSE;
}
/*
* Isolate the strings of the middle and end leader.
*/
while (*p && p[-1] != ':') /* find end of middle flags */
{
if (*p == COM_BLANK)
require_blank = TRUE;
++p;
}
(void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
while (*p && p[-1] != ':') /* find end of end flags */
++p;
(void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
/*
* If the end of the comment is in the same line, don't use
* the comment leader.
*/
if (dir == FORWARD)
{
n = STRLEN(lead_end);
for (p = saved_line + lead_len; *p; ++p)
if (STRNCMP(p, lead_end, n) == 0)
{
comment_end = p;
lead_len = 0;
break;
}
}
/*
* Doing "o" on a start of comment inserts the middle leader.
*/
if (lead_len)
{
if (current_flag == COM_START)
{
lead_repl = lead_middle;
lead_repl_len = STRLEN(lead_middle);
}
/*
* If we have hit RETURN immediately after the start
* comment leader, then put a space after the middle
* comment leader on the next line.
*/
if (!vim_iswhite(saved_line[lead_len - 1])
&& ((p_extra != NULL
&& (int)curwin->w_cursor.col == lead_len)
|| (p_extra == NULL
&& saved_line[lead_len] == NUL)
|| require_blank))
extra_space = TRUE;
}
break;
}
if (*p == COM_END)
{
/*
* Doing "o" on the end of a comment does not insert leader.
* Remember where the end is, might want to use it to find the
* start (for C-comments).
*/
if (dir == FORWARD)
{
comment_end = skipwhite(saved_line);
lead_len = 0;
break;
}
/*
* Doing "O" on the end of a comment inserts the middle leader.
* Find the string for the middle leader, searching backwards.
*/
while (p > curbuf->b_p_com && *p != ',')
--p;
for (lead_repl = p; lead_repl > curbuf->b_p_com &&
lead_repl[-1] != ':'; --lead_repl)
;
lead_repl_len = p - lead_repl;
break;
}
if (*p == COM_FIRST)
{
/*
* Comment leader for first line only: Don't repeat leader
* when using "O", blank out leader when using "o".
*/
if (dir == BACKWARD)
lead_len = 0;
else
{
lead_repl = (char_u *)"";
lead_repl_len = 0;
}
break;
}
}
if (lead_len)
{
/* allocate buffer (may concatenate p_exta later) */
leader = alloc(lead_len + lead_repl_len + extra_space +
extra_len + 1);
allocated = leader; /* remember to free it later */
if (leader == NULL)
lead_len = 0;
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -