/* 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. * See README.txt for an overview of the Vim source code. */ /* * misc1.c: functions that didn't seem to fit elsewhere */ #include "vim.h"#include "version.h" #ifdef HAVE_FCNTL_H# include <fcntl.h> /* for chdir() */#endif static char_u *vim_version_dir __ARGS((char_u *vimdir));static char_u *remove_tail __ARGS((char_u *p, char_u *pend, char_u *name));static int copy_indent __ARGS((int size, char_u *src)); /* * Count the size (in window cells) of the indent in the current line. */ intget_indent(){ return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts);} /* * Count the size (in window cells) of the indent in line "lnum". */ intget_indent_lnum(lnum) linenr_T lnum;{ return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts);} #if defined(FEAT_FOLDING) || defined(PROTO)/* * Count the size (in window cells) of the indent in line "lnum" of buffer * "buf". */ intget_indent_buf(buf, lnum) buf_T *buf; linenr_T lnum;{ return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts);}#endif /* * count the size (in window cells) of the indent in line "ptr", with * 'tabstop' at "ts" */ intget_indent_str(ptr, ts) char_u *ptr; int ts;{ int count = 0; for ( ; *ptr; ++ptr) { if (*ptr == TAB) /* count a tab for what it is worth */ count += ts - (count % 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. * Caller must take care of undo. * "flags": * SIN_CHANGED: call changed_bytes() if the line was changed. * SIN_INSERT: insert the indent in front of the line. * SIN_UNDO: save line for undo before changing it. * Returns TRUE if the line was changed. */ intset_indent(size, flags) int size; int flags;{ char_u *p; char_u *newline; char_u *oldline; char_u *s; int todo; int ind_len; int line_len; int doit = FALSE; int ind_done; int tab_pad; int retval = FALSE; /* * First check if there is anything to do and compute the number of * characters needed for the indent. */ todo = size; ind_len = 0; p = oldline = ml_get_curline(); /* Calculate the buffer size for the new indent, and check to see if it * isn't already set */ /* if 'expandtab' isn't set: use TABs */ if (!curbuf->b_p_et) { /* If 'preserveindent' is set then reuse as much as possible of * the existing indent structure for the new indent */ if (!(flags & SIN_INSERT) && curbuf->b_p_pi) { ind_done = 0; /* count as many characters as we can use */ while (todo > 0 && vim_iswhite(*p)) { if (*p == TAB) { tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); /* stop if this tab will overshoot the target */ if (todo < tab_pad) break; todo -= tab_pad; ++ind_len; ind_done += tab_pad; } else { --todo; ++ind_len; ++ind_done; } ++p; } /* Fill to next tabstop with a tab, if possible */ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); if (todo >= tab_pad) { doit = TRUE; todo -= tab_pad; ++ind_len; /* ind_done += tab_pad; */ } } /* count tabs required for indent */ while (todo >= (int)curbuf->b_p_ts) { if (*p != TAB) doit = TRUE; else ++p; todo -= (int)curbuf->b_p_ts; ++ind_len; /* ind_done += (int)curbuf->b_p_ts; */ } } /* count spaces required for indent */ while (todo > 0) { if (*p != ' ') doit = TRUE; else ++p; --todo; ++ind_len; /* ++ind_done; */ } /* Return if the indent is OK already. */ if (!doit && !vim_iswhite(*p) && !(flags & SIN_INSERT)) return FALSE; /* Allocate memory for the new line. */ if (flags & SIN_INSERT) p = oldline; else p = skipwhite(p); line_len = (int)STRLEN(p) + 1; newline = alloc(ind_len + line_len); if (newline == NULL) return FALSE; /* Put the characters in the new line. */ s = newline; todo = size; /* if 'expandtab' isn't set: use TABs */ if (!curbuf->b_p_et) { /* If 'preserveindent' is set then reuse as much as possible of * the existing indent structure for the new indent */ if (!(flags & SIN_INSERT) && curbuf->b_p_pi) { p = oldline; ind_done = 0; while (todo > 0 && vim_iswhite(*p)) { if (*p == TAB) { tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); /* stop if this tab will overshoot the target */ if (todo < tab_pad) break; todo -= tab_pad; ind_done += tab_pad; } else { --todo; ++ind_done; } *s++ = *p++; } /* Fill to next tabstop with a tab, if possible */ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); if (todo >= tab_pad) { *s++ = TAB; todo -= tab_pad; } p = skipwhite(p); } while (todo >= (int)curbuf->b_p_ts) { *s++ = TAB; todo -= (int)curbuf->b_p_ts; } } while (todo > 0) { *s++ = ' '; --todo; } mch_memmove(s, p, (size_t)line_len); /* Replace the line (unless undo fails). */ if (!(flags & SIN_UNDO) || u_savesub(curwin->w_cursor.lnum) == OK) { ml_replace(curwin->w_cursor.lnum, newline, FALSE); if (flags & SIN_CHANGED) changed_bytes(curwin->w_cursor.lnum, 0); /* Correct saved cursor position if it's after the indent. */ if (saved_cursor.lnum == curwin->w_cursor.lnum && saved_cursor.col >= (colnr_T)(p - oldline)) saved_cursor.col += ind_len - (colnr_T)(p - oldline); retval = TRUE; } else vim_free(newline); curwin->w_cursor.col = ind_len; return retval;} /* * Copy the indent from ptr to the current line (and fill to size) * Leaves the cursor on the first non-blank in the line. * Returns TRUE if the line was changed. */ static intcopy_indent(size, src) int size; char_u *src;{ char_u *p = NULL; char_u *line = NULL; char_u *s; int todo; int ind_len; int line_len = 0; int tab_pad; int ind_done; int round; /* Round 1: compute the number of characters needed for the indent * Round 2: copy the characters. */ for (round = 1; round <= 2; ++round) { todo = size; ind_len = 0; ind_done = 0; s = src; /* Count/copy the usable portion of the source line */ while (todo > 0 && vim_iswhite(*s)) { if (*s == TAB) { tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); /* Stop if this tab will overshoot the target */ if (todo < tab_pad) break; todo -= tab_pad; ind_done += tab_pad; } else { --todo; ++ind_done; } ++ind_len; if (p != NULL) *p++ = *s; ++s; } /* Fill to next tabstop with a tab, if possible */ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); if (todo >= tab_pad) { todo -= tab_pad; ++ind_len; if (p != NULL) *p++ = TAB; } /* Add tabs required for indent */ while (todo >= (int)curbuf->b_p_ts) { todo -= (int)curbuf->b_p_ts; ++ind_len; if (p != NULL) *p++ = TAB; } /* Count/add spaces required for indent */ while (todo > 0) { --todo; ++ind_len; if (p != NULL) *p++ = ' '; } if (p == NULL) { /* Allocate memory for the result: the copied indent, new indent * and the rest of the line. */ line_len = (int)STRLEN(ml_get_curline()) + 1; line = alloc(ind_len + line_len); if (line == NULL) return FALSE; p = line; } } /* Append the original line */ mch_memmove(p, ml_get_curline(), (size_t)line_len); /* Replace the line */ ml_replace(curwin->w_cursor.lnum, line, FALSE); /* Put the cursor after the indent. */ curwin->w_cursor.col = ind_len; return TRUE;} /* * Return the indent of the current line after a number. Return -1 if no * number was found. Used for 'n' in 'formatoptions': numbered list. * Since a pattern is used it can actually handle more than numbers. */ intget_number_indent(lnum) linenr_T lnum;{ colnr_T col; pos_T pos; regmmatch_T regmatch; if (lnum > curbuf->b_ml.ml_line_count) return -1; pos.lnum = 0; regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC); if (regmatch.regprog != NULL) { regmatch.rmm_ic = FALSE; regmatch.rmm_maxcol = 0; if (vim_regexec_multi(®match, curwin, curbuf, lnum, (colnr_T)0)) { pos.lnum = regmatch.endpos[0].lnum + lnum; pos.col = regmatch.endpos[0].col;#ifdef FEAT_VIRTUALEDIT pos.coladd = 0;#endif } vim_free(regmatch.regprog); } if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL) return -1; getvcol(curwin, &pos, &col, NULL, NULL); return (int)col;} #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT) static int cin_is_cinword __ARGS((char_u *line)); /* * Return TRUE if the string "line" starts with a word from 'cinwords'. */ static intcin_is_cinword(line) char_u *line;{ char_u *cinw; char_u *cinw_buf; int cinw_len; int retval = FALSE; int len; cinw_len = (int)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. * * For VREPLACE mode, we only add a new line when we get to the end of the * file, otherwise we just start replacing the next line. * * Caller must take care of undo. Since VREPLACE may affect any number of * lines however, it may call u_save_cursor() again when starting to change a * new line. * "flags": OPENLINE_DELSPACES delete spaces after cursor * OPENLINE_DO_COM format comments * OPENLINE_KEEPTRAIL keep trailing spaces * OPENLINE_MARKFIX adjust mark positions after the line break * * Return TRUE for success, FALSE for failure */ intopen_line(dir, flags, old_indent) int dir; /* FORWARD or BACKWARD */ int flags; int old_indent; /* indent for after ^^D in Insert mode */{ char_u *saved_line; /* copy of the original line */ char_u *next_line = NULL; /* copy of the next line */ char_u *p_extra = NULL; /* what goes to next line */ int less_cols = 0; /* less columns for mark in new line */ int less_cols_off = 0; /* columns to skip for mark adjust */ pos_T 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 */#ifdef FEAT_COMMENTS int extra_len = 0; /* length of p_extra string */ 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 */#endif char_u *allocated = NULL; /* allocated memory */#if defined(FEAT_SMARTINDENT) || defined(FEAT_VREPLACE) || defined(FEAT_LISP) \ || defined(FEAT_CINDENT) || defined(FEAT_COMMENTS) char_u *p;#endif int saved_char = NUL; /* init for GCC */Lines 1–500 of 9419. Load more
/* 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. * See README.txt for an overview of the Vim source code. */ /* * misc1.c: functions that didn't seem to fit elsewhere */ #include "vim.h" #include "version.h" #ifdef HAVE_FCNTL_H # include <fcntl.h> /* for chdir() */ #endif static char_u *vim_version_dir __ARGS((char_u *vimdir)); static char_u *remove_tail __ARGS((char_u *p, char_u *pend, char_u *name)); static int copy_indent __ARGS((int size, char_u *src)); /* * Count the size (in window cells) of the indent in the current line. */ int get_indent() { return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts); } /* * Count the size (in window cells) of the indent in line "lnum". */ int get_indent_lnum(lnum) linenr_T lnum; { return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts); } #if defined(FEAT_FOLDING) || defined(PROTO) /* * Count the size (in window cells) of the indent in line "lnum" of buffer * "buf". */ int get_indent_buf(buf, lnum) buf_T *buf; linenr_T lnum; { return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts); } #endif /* * count the size (in window cells) of the indent in line "ptr", with * 'tabstop' at "ts" */ int get_indent_str(ptr, ts) char_u *ptr; int ts; { int count = 0; for ( ; *ptr; ++ptr) { if (*ptr == TAB) /* count a tab for what it is worth */ count += ts - (count % 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. * Caller must take care of undo. * "flags": * SIN_CHANGED: call changed_bytes() if the line was changed. * SIN_INSERT: insert the indent in front of the line. * SIN_UNDO: save line for undo before changing it. * Returns TRUE if the line was changed. */ int set_indent(size, flags) int size; int flags; { char_u *p; char_u *newline; char_u *oldline; char_u *s; int todo; int ind_len; int line_len; int doit = FALSE; int ind_done; int tab_pad; int retval = FALSE; /* * First check if there is anything to do and compute the number of * characters needed for the indent. */ todo = size; ind_len = 0; p = oldline = ml_get_curline(); /* Calculate the buffer size for the new indent, and check to see if it * isn't already set */ /* if 'expandtab' isn't set: use TABs */ if (!curbuf->b_p_et) { /* If 'preserveindent' is set then reuse as much as possible of * the existing indent structure for the new indent */ if (!(flags & SIN_INSERT) && curbuf->b_p_pi) { ind_done = 0; /* count as many characters as we can use */ while (todo > 0 && vim_iswhite(*p)) { if (*p == TAB) { tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); /* stop if this tab will overshoot the target */ if (todo < tab_pad) break; todo -= tab_pad; ++ind_len; ind_done += tab_pad; } else { --todo; ++ind_len; ++ind_done; } ++p; } /* Fill to next tabstop with a tab, if possible */ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); if (todo >= tab_pad) { doit = TRUE; todo -= tab_pad; ++ind_len; /* ind_done += tab_pad; */ } } /* count tabs required for indent */ while (todo >= (int)curbuf->b_p_ts) { if (*p != TAB) doit = TRUE; else ++p; todo -= (int)curbuf->b_p_ts; ++ind_len; /* ind_done += (int)curbuf->b_p_ts; */ } } /* count spaces required for indent */ while (todo > 0) { if (*p != ' ') doit = TRUE; else ++p; --todo; ++ind_len; /* ++ind_done; */ } /* Return if the indent is OK already. */ if (!doit && !vim_iswhite(*p) && !(flags & SIN_INSERT)) return FALSE; /* Allocate memory for the new line. */ if (flags & SIN_INSERT) p = oldline; else p = skipwhite(p); line_len = (int)STRLEN(p) + 1; newline = alloc(ind_len + line_len); if (newline == NULL) return FALSE; /* Put the characters in the new line. */ s = newline; todo = size; /* if 'expandtab' isn't set: use TABs */ if (!curbuf->b_p_et) { /* If 'preserveindent' is set then reuse as much as possible of * the existing indent structure for the new indent */ if (!(flags & SIN_INSERT) && curbuf->b_p_pi) { p = oldline; ind_done = 0; while (todo > 0 && vim_iswhite(*p)) { if (*p == TAB) { tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); /* stop if this tab will overshoot the target */ if (todo < tab_pad) break; todo -= tab_pad; ind_done += tab_pad; } else { --todo; ++ind_done; } *s++ = *p++; } /* Fill to next tabstop with a tab, if possible */ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); if (todo >= tab_pad) { *s++ = TAB; todo -= tab_pad; } p = skipwhite(p); } while (todo >= (int)curbuf->b_p_ts) { *s++ = TAB; todo -= (int)curbuf->b_p_ts; } } while (todo > 0) { *s++ = ' '; --todo; } mch_memmove(s, p, (size_t)line_len); /* Replace the line (unless undo fails). */ if (!(flags & SIN_UNDO) || u_savesub(curwin->w_cursor.lnum) == OK) { ml_replace(curwin->w_cursor.lnum, newline, FALSE); if (flags & SIN_CHANGED) changed_bytes(curwin->w_cursor.lnum, 0); /* Correct saved cursor position if it's after the indent. */ if (saved_cursor.lnum == curwin->w_cursor.lnum && saved_cursor.col >= (colnr_T)(p - oldline)) saved_cursor.col += ind_len - (colnr_T)(p - oldline); retval = TRUE; } else vim_free(newline); curwin->w_cursor.col = ind_len; return retval; } /* * Copy the indent from ptr to the current line (and fill to size) * Leaves the cursor on the first non-blank in the line. * Returns TRUE if the line was changed. */ static int copy_indent(size, src) int size; char_u *src; { char_u *p = NULL; char_u *line = NULL; char_u *s; int todo; int ind_len; int line_len = 0; int tab_pad; int ind_done; int round; /* Round 1: compute the number of characters needed for the indent * Round 2: copy the characters. */ for (round = 1; round <= 2; ++round) { todo = size; ind_len = 0; ind_done = 0; s = src; /* Count/copy the usable portion of the source line */ while (todo > 0 && vim_iswhite(*s)) { if (*s == TAB) { tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); /* Stop if this tab will overshoot the target */ if (todo < tab_pad) break; todo -= tab_pad; ind_done += tab_pad; } else { --todo; ++ind_done; } ++ind_len; if (p != NULL) *p++ = *s; ++s; } /* Fill to next tabstop with a tab, if possible */ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); if (todo >= tab_pad) { todo -= tab_pad; ++ind_len; if (p != NULL) *p++ = TAB; } /* Add tabs required for indent */ while (todo >= (int)curbuf->b_p_ts) { todo -= (int)curbuf->b_p_ts; ++ind_len; if (p != NULL) *p++ = TAB; } /* Count/add spaces required for indent */ while (todo > 0) { --todo; ++ind_len; if (p != NULL) *p++ = ' '; } if (p == NULL) { /* Allocate memory for the result: the copied indent, new indent * and the rest of the line. */ line_len = (int)STRLEN(ml_get_curline()) + 1; line = alloc(ind_len + line_len); if (line == NULL) return FALSE; p = line; } } /* Append the original line */ mch_memmove(p, ml_get_curline(), (size_t)line_len); /* Replace the line */ ml_replace(curwin->w_cursor.lnum, line, FALSE); /* Put the cursor after the indent. */ curwin->w_cursor.col = ind_len; return TRUE; } /* * Return the indent of the current line after a number. Return -1 if no * number was found. Used for 'n' in 'formatoptions': numbered list. * Since a pattern is used it can actually handle more than numbers. */ int get_number_indent(lnum) linenr_T lnum; { colnr_T col; pos_T pos; regmmatch_T regmatch; if (lnum > curbuf->b_ml.ml_line_count) return -1; pos.lnum = 0; regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC); if (regmatch.regprog != NULL) { regmatch.rmm_ic = FALSE; regmatch.rmm_maxcol = 0; if (vim_regexec_multi(®match, curwin, curbuf, lnum, (colnr_T)0)) { pos.lnum = regmatch.endpos[0].lnum + lnum; pos.col = regmatch.endpos[0].col; #ifdef FEAT_VIRTUALEDIT pos.coladd = 0; #endif } vim_free(regmatch.regprog); } if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL) return -1; getvcol(curwin, &pos, &col, NULL, NULL); return (int)col; } #if defined(FEAT_CINDENT) || defined(FEAT_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 = (int)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. * * For VREPLACE mode, we only add a new line when we get to the end of the * file, otherwise we just start replacing the next line. * * Caller must take care of undo. Since VREPLACE may affect any number of * lines however, it may call u_save_cursor() again when starting to change a * new line. * "flags": OPENLINE_DELSPACES delete spaces after cursor * OPENLINE_DO_COM format comments * OPENLINE_KEEPTRAIL keep trailing spaces * OPENLINE_MARKFIX adjust mark positions after the line break * * Return TRUE for success, FALSE for failure */ int open_line(dir, flags, old_indent) int dir; /* FORWARD or BACKWARD */ int flags; int old_indent; /* indent for after ^^D in Insert mode */ { char_u *saved_line; /* copy of the original line */ char_u *next_line = NULL; /* copy of the next line */ char_u *p_extra = NULL; /* what goes to next line */ int less_cols = 0; /* less columns for mark in new line */ int less_cols_off = 0; /* columns to skip for mark adjust */ pos_T 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 */ #ifdef FEAT_COMMENTS int extra_len = 0; /* length of p_extra string */ 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 */ #endif char_u *allocated = NULL; /* allocated memory */ #if defined(FEAT_SMARTINDENT) || defined(FEAT_VREPLACE) || defined(FEAT_LISP) \ || defined(FEAT_CINDENT) || defined(FEAT_COMMENTS) char_u *p; #endif int saved_char = NUL; /* init for GCC */