edit.c
资源名称:vim53src.zip [点击查看]
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:128k
源码类别:
编辑器/阅读器
开发平台:
DOS
- * Use ins_char() to insert the text, it is a bit slower than
- * ins_str(), but it takes care of replace mode.
- */
- ptr = curr_match->str + curwin->w_cursor.col - complete_col;
- while (*ptr)
- ins_char(*ptr++);
- update_screenline();
- if (temp > 1)
- {
- if (ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
- ptr = (char_u *)"All %d matches have now been found";
- else if (ctrl_x_mode == CTRL_X_FILES)
- ptr = (char_u *)"There are %d matching file names";
- else if (ctrl_x_mode == CTRL_X_TAGS)
- ptr = (char_u *)"There are %d matching tags";
- else
- ptr = (char_u *)"There are %d matches";
- sprintf((char *)IObuff, (char *)ptr, temp);
- if (dollar_vcol)
- curs_columns(FALSE);
- msg_attr(IObuff, hl_attr(HLF_R));
- if (!char_avail())
- {
- setcursor();
- out_flush();
- ui_delay(1500L, FALSE);
- }
- }
- showmode();
- if (edit_submode_extra != NULL)
- {
- if (!p_smd)
- msg_attr(edit_submode_extra,
- edit_submode_highl < HLF_COUNT
- ? hl_attr(edit_submode_highl) : 0);
- if (!char_avail())
- {
- setcursor();
- out_flush();
- ui_delay(1500L, FALSE);
- }
- edit_submode_extra = NULL;
- }
- /*
- * Show the file name for the match (if any)
- * Truncate the file name to avoid a wait for return.
- */
- if (curr_match->fname != NULL)
- {
- STRCPY(IObuff, "match in file ");
- i = (vim_strsize(curr_match->fname) + 16) - sc_col;
- if (i <= 0)
- i = 0;
- else
- STRCAT(IObuff, "<");
- STRCAT(IObuff, curr_match->fname + i);
- msg(IObuff);
- redraw_cmdline = FALSE; /* don't overwrite! */
- }
- return TRUE;
- }
- /*
- * Looks in the first "len" chars. of "src" for search-metachars.
- * If dest is not NULL the chars. are copied there quoting (with
- * a backslash) the metachars, and dest would be NUL terminated.
- * Returns the length (needed) of dest
- */
- static int
- quote_meta(dest, src, len)
- char_u *dest;
- char_u *src;
- int len;
- {
- int m;
- for (m = len; --len >= 0; src++)
- {
- switch (*src)
- {
- case '.':
- case '*':
- case '[':
- if (ctrl_x_mode == CTRL_X_DICTIONARY)
- break;
- case '~':
- if (!p_magic) /* quote these only if magic is set */
- break;
- case '\':
- if (ctrl_x_mode == CTRL_X_DICTIONARY)
- break;
- case '^': /* currently it's not needed. */
- case '$':
- m++;
- if (dest)
- *dest++ = '\';
- break;
- }
- if (dest)
- *dest++ = *src;
- }
- if (dest)
- *dest = NUL;
- return m;
- }
- #endif /* INSERT_EXPAND */
- /*
- * Next character is interpreted literally.
- * A one, two or three digit decimal number is interpreted as its byte value.
- * If one or two digits are entered, the next character is given to vungetc().
- */
- int
- get_literal()
- {
- int cc;
- int nc;
- int i;
- int hexmode = 0, octalmode = 0;
- if (got_int)
- return Ctrl('C');
- #ifdef USE_GUI
- /*
- * In GUI there is no point inserting the internal code for a special key.
- * It is more useful to insert the string "<KEY>" instead. This would
- * probably be useful in a text window too, but it would not be
- * vi-compatible (maybe there should be an option for it?) -- webb
- */
- if (gui.in_use)
- ++allow_keys;
- #endif
- #ifdef USE_GUI_WIN32
- dont_scroll = TRUE; /* disallow scrolling here */
- #endif
- ++no_mapping; /* don't map the next key hits */
- cc = 0;
- i = 0;
- for (;;)
- {
- do
- nc = vgetc();
- while (nc == K_IGNORE || nc == K_SCROLLBAR || nc == K_HORIZ_SCROLLBAR);
- #ifdef SHOWCMD
- if (!(State & CMDLINE)
- #ifdef MULTI_BYTE
- && (is_dbcs && !IsLeadByte(nc))
- #endif
- )
- add_to_showcmd(nc);
- #endif
- if (nc == 'x' || nc == 'X')
- hexmode++;
- else if (nc == 'o' || nc == 'O')
- octalmode++;
- else
- {
- if (hexmode)
- {
- if (!vim_isdigit(nc) && !isxdigit(nc))
- break;
- nc = tolower(nc);
- if (nc >= 'a')
- nc = 10 + nc - 'a';
- else
- nc = nc - '0';
- cc = cc * 16 + nc ;
- }
- else if (octalmode)
- {
- if (!vim_isdigit(nc) || (nc > '7'))
- break;
- cc = cc * 8 + nc - '0';
- }
- else
- {
- if (!vim_isdigit(nc))
- break;
- cc = cc * 10 + nc - '0';
- }
- ++i;
- }
- if (cc > 255)
- cc = 255; /* limit range to 0-255 */
- nc = 0;
- if (hexmode && (i >= 2))
- break;
- if (!hexmode && (i >= 3))
- break;
- }
- if (i == 0) /* no number entered */
- {
- if (nc == K_ZERO) /* NUL is stored as NL */
- {
- cc = 'n';
- nc = 0;
- }
- else
- {
- cc = nc;
- nc = 0;
- }
- }
- if (cc == 0) /* NUL is stored as NL */
- cc = 'n';
- --no_mapping;
- #ifdef USE_GUI
- if (gui.in_use)
- --allow_keys;
- #endif
- if (nc)
- vungetc(nc);
- got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
- return cc;
- }
- /*
- * Insert character, taking care of special keys and mod_mask
- */
- static void
- insert_special(c, allow_modmask, ctrlv)
- int c;
- int allow_modmask;
- int ctrlv; /* c was typed after CTRL-V */
- {
- char_u *p;
- int len;
- /*
- * Special function key, translate into "<Key>". Up to the last '>' is
- * inserted with ins_str(), so as not to replace characters in replace
- * mode.
- * Only use mod_mask for special keys, to avoid things like <S-Space>,
- * unless 'allow_modmask' is TRUE.
- */
- if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
- {
- p = get_special_key_name(c, mod_mask);
- len = STRLEN(p);
- c = p[len - 1];
- if (len > 2)
- {
- p[len - 1] = NUL;
- ins_str(p);
- AppendToRedobuff(p);
- ctrlv = FALSE;
- }
- }
- insertchar(c, FALSE, -1, ctrlv);
- }
- /*
- * Special characters in this context are those that need processing other
- * than the simple insertion that can be performed here. This includes ESC
- * which terminates the insert, and CR/NL which need special processing to
- * open up a new line. This routine tries to optimize insertions performed by
- * the "redo", "undo" or "put" commands, so it needs to know when it should
- * stop and defer processing to the "normal" mechanism.
- * '0' and '^' are special, because they can be followed by CTRL-D.
- */
- #define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
- void
- insertchar(c, force_formatting, second_indent, ctrlv)
- unsigned c;
- int force_formatting; /* format line regardless of p_fo */
- int second_indent; /* indent for second line if >= 0 */
- int ctrlv; /* c typed just after CTRL-V */
- {
- int haveto_redraw = FALSE;
- int textwidth;
- colnr_t leader_len;
- int first_line = TRUE;
- int fo_ins_blank;
- int save_char = NUL;
- int cc;
- stop_arrow();
- textwidth = comp_textwidth(force_formatting);
- fo_ins_blank = has_format_option(FO_INS_BLANK);
- /*
- * Try to break the line in two or more pieces when:
- * - Always do this if we have been called to do formatting only.
- * - Otherwise:
- * - Don't do this if inserting a blank
- * - Don't do this if an existing character is being replaced.
- * - Do this if the cursor is not on the line where insert started
- * or - 'formatoptions' doesn't have 'l' or the line was not too long
- * before the insert.
- * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
- * before 'textwidth'
- */
- if (textwidth
- && (force_formatting
- || (!vim_iswhite(c)
- && !(State == REPLACE && *ml_get_cursor() != NUL)
- && (curwin->w_cursor.lnum != Insstart.lnum
- || ((!has_format_option(FO_INS_LONG)
- || Insstart_textlen <= (colnr_t)textwidth)
- && (!fo_ins_blank
- || Insstart_blank_vcol <= (colnr_t)textwidth
- ))))))
- {
- /*
- * When 'ai' is off we don't want a space under the cursor to be
- * deleted. Replace it with an 'x' temporarily.
- */
- if (!curbuf->b_p_ai)
- {
- cc = gchar_cursor();
- if (vim_iswhite(cc))
- {
- save_char = cc;
- pchar_cursor('x');
- }
- }
- /*
- * Repeat breaking lines, until the current line is not too long.
- */
- while (!got_int)
- {
- int startcol; /* Cursor column at entry */
- int wantcol; /* column at textwidth border */
- int foundcol; /* column for start of spaces */
- int end_foundcol = 0; /* column for start of word */
- colnr_t len;
- colnr_t virtcol;
- virtcol = get_nolist_virtcol();
- if (virtcol < (colnr_t)textwidth)
- break;
- if (!force_formatting && has_format_option(FO_WRAP_COMS))
- fo_do_comments = TRUE;
- /* Don't break until after the comment leader */
- leader_len = get_leader_len(ml_get_curline(), NULL);
- if (!force_formatting && leader_len == 0 &&
- !has_format_option(FO_WRAP))
- {
- textwidth = 0;
- break;
- }
- if ((startcol = curwin->w_cursor.col) == 0)
- break;
- /* find column of textwidth border */
- coladvance((colnr_t)textwidth);
- wantcol = curwin->w_cursor.col;
- curwin->w_cursor.col = startcol - 1;
- foundcol = 0;
- /*
- * Find position to break at.
- * Stop at start of line.
- * Stop at first entered white when 'formatoptions' has 'v'
- */
- while (curwin->w_cursor.col > 0 &&
- ((!fo_ins_blank && !has_format_option(FO_INS_VI)) ||
- curwin->w_cursor.lnum != Insstart.lnum ||
- curwin->w_cursor.col >= Insstart.col))
- {
- cc = gchar_cursor();
- if (vim_iswhite(cc))
- {
- /* remember position of blank just before text */
- end_foundcol = curwin->w_cursor.col;
- while (curwin->w_cursor.col > 0 && vim_iswhite(cc))
- {
- --curwin->w_cursor.col;
- cc = gchar_cursor();
- }
- if (curwin->w_cursor.col == 0 && vim_iswhite(cc))
- break; /* only spaces in front of text */
- /* Don't break until after the comment leader */
- if (curwin->w_cursor.col < leader_len)
- break;
- foundcol = curwin->w_cursor.col + 1;
- if (curwin->w_cursor.col < (colnr_t)wantcol)
- break;
- }
- --curwin->w_cursor.col;
- }
- if (foundcol == 0) /* no spaces, cannot break line */
- {
- curwin->w_cursor.col = startcol;
- break;
- }
- /*
- * offset between cursor position and line break is used by
- * replace stack functions
- */
- replace_offset = startcol - end_foundcol - 1;
- /*
- * adjust startcol for spaces that will be deleted and
- * characters that will remain on top line
- */
- curwin->w_cursor.col = foundcol;
- while (cc = gchar_cursor(), vim_iswhite(cc))
- {
- ++curwin->w_cursor.col;
- --startcol;
- }
- startcol -= foundcol;
- if (startcol < 0)
- startcol = 0;
- /* put cursor after pos. to break line */
- curwin->w_cursor.col = foundcol;
- /*
- * Split the line before just the margin.
- * Only insert/delete lines, but don't really redraw the window.
- */
- open_line(FORWARD, (redrawing() && !force_formatting) ? -1 : 0,
- TRUE, old_indent);
- old_indent = 0;
- replace_offset = 0;
- if (second_indent >= 0 && first_line)
- set_indent(second_indent, TRUE);
- first_line = FALSE;
- /*
- * check if cursor is not past the NUL off the line, cindent may
- * have added or removed indent.
- */
- curwin->w_cursor.col += startcol;
- len = STRLEN(ml_get_curline());
- if (curwin->w_cursor.col > len)
- curwin->w_cursor.col = len;
- haveto_redraw = TRUE;
- #ifdef CINDENT
- can_cindent = TRUE;
- #endif
- /* moved the cursor, don't autoindent or cindent now */
- did_ai = FALSE;
- #ifdef SMARTINDENT
- did_si = FALSE;
- can_si = FALSE;
- can_si_back = FALSE;
- #endif
- line_breakcheck();
- }
- if (save_char) /* put back space after cursor */
- pchar_cursor(save_char);
- if (c == NUL) /* formatting only */
- return;
- fo_do_comments = FALSE;
- if (haveto_redraw)
- {
- update_topline();
- update_screen(NOT_VALID);
- }
- }
- if (c == NUL) /* only formatting was wanted */
- return;
- did_ai = FALSE;
- #ifdef SMARTINDENT
- did_si = FALSE;
- can_si = FALSE;
- can_si_back = FALSE;
- #endif
- /*
- * If there's any pending input, grab up to INPUT_BUFLEN at once.
- * This speeds up normal text input considerably.
- * Don't do this when 'cindent' is set, because we might need to re-indent
- * at a ':', or any other character.
- */
- #ifdef USE_GUI_WIN32
- dont_scroll = FALSE; /* allow scrolling here */
- #endif
- #define INPUT_BUFLEN 100
- if ( !ISSPECIAL(c)
- && vpeekc() != NUL
- && State != REPLACE
- #ifdef CINDENT
- && !curbuf->b_p_cin
- #endif
- #ifdef RIGHTLEFT
- && !p_ri
- #endif
- )
- {
- char_u p[INPUT_BUFLEN + 1];
- int i;
- colnr_t virtcol = 0;
- p[0] = c;
- i = 1;
- if (textwidth)
- virtcol = get_nolist_virtcol();
- while ( (c = vpeekc()) != NUL
- && !ISSPECIAL(c)
- && i < INPUT_BUFLEN
- && (textwidth == 0
- || (virtcol += charsize(p[i - 1])) < (colnr_t)textwidth)
- && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(p[i - 1])))
- {
- #ifdef RIGHTLEFT
- c = vgetc();
- if (p_hkmap && KeyTyped)
- c = hkmap(c); /* Hebrew mode mapping */
- #ifdef FKMAP
- if (p_fkmap && KeyTyped)
- c = fkmap(c); /* Farsi mode mapping */
- #endif
- p[i++] = c;
- #else
- p[i++] = vgetc();
- #endif
- }
- #ifdef DIGRAPHS
- do_digraph(-1); /* clear digraphs */
- do_digraph(p[i-1]); /* may be the start of a digraph */
- #endif
- p[i] = NUL;
- ins_str(p);
- if (ctrlv)
- {
- redo_literal(*p);
- i = 1;
- }
- else
- i = 0;
- if (p[i] != NUL)
- AppendToRedobuff(p + i);
- }
- else
- {
- ins_char(c);
- if (ctrlv)
- redo_literal(c);
- else
- AppendCharToRedobuff(c);
- }
- }
- /*
- * Find out textwidth to be used for formatting:
- * if 'textwidth' option is set, use it
- * else if 'wrapmargin' option is set, use Columns - 'wrapmargin'
- * if invalid value, use 0.
- * Set default to window width (maximum 79) for "Q" command.
- */
- int
- comp_textwidth(ff)
- int ff; /* force formatting (for "Q" command) */
- {
- int textwidth;
- textwidth = curbuf->b_p_tw;
- if (textwidth == 0 && curbuf->b_p_wm)
- textwidth = Columns - curbuf->b_p_wm;
- if (textwidth < 0)
- textwidth = 0;
- if (ff && textwidth == 0)
- {
- textwidth = Columns - 1;
- if (textwidth > 79)
- textwidth = 79;
- }
- return textwidth;
- }
- /*
- * Put a character in the redo buffer, for when just after a CTRL-V.
- */
- static void
- redo_literal(c)
- int c;
- {
- char_u buf[10];
- /* Only digits need special treatment. Translate them into a string of
- * three digits. */
- if (vim_isdigit(c))
- {
- sprintf((char *)buf, "%03d", c);
- AppendToRedobuff(buf);
- }
- else
- AppendCharToRedobuff(c);
- }
- /*
- * start_arrow() is called when an arrow key is used in insert mode.
- * It resembles hitting the <ESC> key.
- */
- static void
- start_arrow(end_insert_pos)
- FPOS *end_insert_pos;
- {
- if (!arrow_used) /* something has been inserted */
- {
- AppendToRedobuff(ESC_STR);
- arrow_used = TRUE; /* this means we stopped the current insert */
- stop_insert(end_insert_pos);
- }
- }
- /*
- * stop_arrow() is called before a change is made in insert mode.
- * If an arrow key has been used, start a new insertion.
- */
- void
- stop_arrow()
- {
- if (arrow_used)
- {
- (void)u_save_cursor(); /* errors are ignored! */
- Insstart = curwin->w_cursor; /* new insertion starts here */
- Insstart_textlen = linetabsize(ml_get_curline());
- ResetRedobuff();
- AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
- arrow_used = FALSE;
- }
- }
- /*
- * do a few things to stop inserting
- */
- static void
- stop_insert(end_insert_pos)
- FPOS *end_insert_pos; /* where insert ended */
- {
- int cc;
- stop_redo_ins();
- replace_flush(); /* abandon replace stack */
- /*
- * save the inserted text for later redo with ^@
- */
- vim_free(last_insert);
- last_insert = get_inserted();
- last_insert_skip = new_insert_skip;
- /*
- * If we just did an auto-indent, remove the white space from the end of
- * the line, and put the cursor back.
- */
- if (did_ai && !arrow_used)
- {
- if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
- --curwin->w_cursor.col;
- while (cc = gchar_cursor(), vim_iswhite(cc))
- (void)del_char(TRUE);
- if (cc != NUL)
- ++curwin->w_cursor.col; /* put cursor back on the NUL */
- /* the deletion is only seen in list mode and when 'hls' is set */
- if (curwin->w_p_list || p_hls)
- update_screenline();
- }
- did_ai = FALSE;
- #ifdef SMARTINDENT
- did_si = FALSE;
- can_si = FALSE;
- can_si_back = FALSE;
- #endif
- /* set '[ and '] to the inserted text */
- curbuf->b_op_start = Insstart;
- curbuf->b_op_end = *end_insert_pos;
- }
- /*
- * Set the last inserted text to a single character.
- * Used for the replace command.
- */
- void
- set_last_insert(c)
- int c;
- {
- vim_free(last_insert);
- last_insert = alloc(4);
- if (last_insert != NULL)
- {
- last_insert[0] = Ctrl('V');
- last_insert[1] = c;
- last_insert[2] = ESC;
- last_insert[3] = NUL;
- /* Use the CTRL-V only when not entering a digit */
- last_insert_skip = isdigit(c) ? 1 : 0;
- }
- }
- /*
- * move cursor to start of line
- * if flags & BL_WHITE move to first non-white
- * if flags & BL_SOL move to first non-white if startofline is set,
- * otherwise keep "curswant" column
- * if flags & BL_FIX don't leave the cursor on a NUL.
- */
- void
- beginline(flags)
- int flags;
- {
- if ((flags & BL_SOL) && !p_sol)
- coladvance(curwin->w_curswant);
- else
- {
- curwin->w_cursor.col = 0;
- if (flags & (BL_WHITE | BL_SOL))
- {
- char_u *ptr;
- for (ptr = ml_get_curline(); vim_iswhite(*ptr)
- && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
- ++curwin->w_cursor.col;
- }
- curwin->w_set_curswant = TRUE;
- }
- }
- /*
- * oneright oneleft cursor_down cursor_up
- *
- * Move one char {right,left,down,up}.
- * Return OK when successful, FAIL when we hit a line of file boundary.
- */
- int
- oneright()
- {
- char_u *ptr;
- ptr = ml_get_cursor();
- if (*ptr++ == NUL || *ptr == NUL)
- return FAIL;
- #ifdef MULTI_BYTE
- if (is_dbcs)
- {
- /* if the character on the current cursor is a multi-byte character,
- move two characters right */
- char_u *base;
- base = ml_get(curwin->w_cursor.lnum);
- if (*(ptr+1) != NUL && IsTrailByte(base, ptr))
- ++curwin->w_cursor.col;
- }
- #endif
- curwin->w_set_curswant = TRUE;
- ++curwin->w_cursor.col;
- return OK;
- }
- int
- oneleft()
- {
- if (curwin->w_cursor.col == 0)
- return FAIL;
- curwin->w_set_curswant = TRUE;
- --curwin->w_cursor.col;
- #ifdef MULTI_BYTE
- /* if the character on the left of the current cursor is a multi-byte
- * character, move two characters left */
- if (is_dbcs)
- AdjustCursorForMultiByteCharacter();
- #endif
- return OK;
- }
- int
- cursor_up(n, upd_topline)
- long n;
- int upd_topline; /* When TRUE: update topline */
- {
- if (n != 0)
- {
- if (curwin->w_cursor.lnum <= 1)
- return FAIL;
- if (n >= curwin->w_cursor.lnum)
- curwin->w_cursor.lnum = 1;
- else
- curwin->w_cursor.lnum -= n;
- }
- /* try to advance to the column we want to be at */
- coladvance(curwin->w_curswant);
- if (upd_topline)
- update_topline(); /* make sure curwin->w_topline is valid */
- return OK;
- }
- int
- cursor_down(n, upd_topline)
- long n;
- int upd_topline; /* When TRUE: update topline */
- {
- if (n != 0)
- {
- if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count)
- return FAIL;
- curwin->w_cursor.lnum += n;
- if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
- curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- }
- /* try to advance to the column we want to be at */
- coladvance(curwin->w_curswant);
- if (upd_topline)
- update_topline(); /* make sure curwin->w_topline is valid */
- return OK;
- }
- /*
- * Stuff the last inserted text in the read buffer.
- * Last_insert actually is a copy of the redo buffer, so we
- * first have to remove the command.
- */
- int
- stuff_inserted(c, count, no_esc)
- int c; /* Command character to be inserted */
- long count; /* Repeat this many times */
- int no_esc; /* Don't add an ESC at the end */
- {
- char_u *esc_ptr;
- char_u *ptr;
- char_u *last_ptr;
- char_u last = NUL;
- ptr = get_last_insert();
- if (ptr == NULL)
- {
- EMSG(e_noinstext);
- return FAIL;
- }
- /* may want to stuff the command character, to start Insert mode */
- if (c)
- stuffcharReadbuff(c);
- if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL)
- *esc_ptr = NUL; /* remove the ESC */
- /* when the last char is either "0" or "^" it will be quoted if no ESC
- * comes after it OR if it will inserted more than once and "ptr"
- * starts with ^D. -- Acevedo
- */
- last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
- if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
- && (no_esc || (*ptr == Ctrl('D') && count > 1)))
- {
- last = *last_ptr;
- *last_ptr = NUL;
- }
- do
- {
- stuffReadbuff(ptr);
- /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
- if (last)
- stuffReadbuff((char_u *)(last == '0' ? "