Code/Resource
Windows Develop
Linux-Unix program
Internet-Socket-Network
Web Server
Browser Client
Ftp Server
Ftp Client
Browser Plugins
Proxy Server
Email Server
Email Client
WEB Mail
Firewall-Security
Telnet Server
Telnet Client
ICQ-IM-Chat
Search Engine
Sniffer Package capture
Remote Control
xml-soap-webservice
P2P
WEB(ASP,PHP,...)
TCP/IP Stack
SNMP
Grid Computing
SilverLight
DNS
Cluster Service
Network Security
Communication-Mobile
Game Program
Editor
Multimedia program
Graph program
Compiler program
Compress-Decompress algrithms
Crypt_Decrypt algrithms
Mathimatics-Numerical algorithms
MultiLanguage
Disk/Storage
Java Develop
assembly language
Applications
Other systems
Database system
Embeded-SCM Develop
FlashMX/Flex
source in ebook
Delphi VCL
OS Develop
MiddleWare
MPI
MacOS develop
LabView
ELanguage
Software/Tools
E-Books
Artical/Document
edit.c
Package: vim53src.zip [view]
Upload User: gddssl
Upload Date: 2007-01-06
Package Size: 1003k
Code Size: 128k
Category:
Editor
Development Platform:
DOS
- /* 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.
- */
- /*
- * edit.c: functions for Insert mode
- */
- #include "vim.h"
- #ifdef INSERT_EXPAND
- /*
- * definitions used for CTRL-X submode
- */
- #define CTRL_X_WANT_IDENT 0x100
- #define CTRL_X_NOT_DEFINED_YET (1)
- #define CTRL_X_SCROLL (2)
- #define CTRL_X_WHOLE_LINE (3)
- #define CTRL_X_FILES (4)
- #define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
- #define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
- #define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
- #define CTRL_X_FINISHED (8)
- #define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
- #define C_X_SKIP (7) /* length of " Adding" */
- char *ctrl_x_msgs[] =
- {
- " Adding Keyword completion (^N/^P)", /* ctrl_x_mode == 0, ^P/^N compl. */
- " ^X mode (^E/^Y/^L/^]/^F/^I/^K/^D/^N/^P)",
- /* Scroll has it's own msgs, in it's place there is the msg for local
- * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo */
- " Adding Keyword Local completion (^N/^P)",
- " Adding Whole line completion (^L/^N/^P)",
- " Adding File name completion (^F/^N/^P)",
- " Adding Tag completion (^]/^N/^P)",
- " Adding Path pattern completion (^N/^P)",
- " Adding Definition completion (^D/^N/^P)",
- NULL,
- " Adding Dictionary completion (^K/^N/^P)"
- };
- char_u e_hitend[] = "Hit end of paragraph";
- char_u e_hitend_f[] = "Hit end of paragraph (forward)";
- char_u e_hitend_b[] = "Hit end of paragraph (backward)";
- char_u e_patnotf_f[] = "Pattern not found (forward)";
- char_u e_patnotf_b[] = "Pattern not found (backward)";
- /*
- * Structure used to store one match for insert completion.
- */
- struct Completion
- {
- struct Completion *next;
- struct Completion *prev;
- char_u *str; /* matched text */
- char_u *fname; /* file containing the match */
- int original; /* ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME */
- };
- /* the original text when the expansion begun */
- #define ORIGINAL_TEXT (1)
- #define FREE_FNAME (2)
- /*
- * All the current matches are stored in a list.
- * "first_match" points to the start of the list.
- * "curr_match" points to the currently selected entry.
- */
- static struct Completion *first_match = NULL;
- static struct Completion *curr_match = NULL;
- static int started_completion;
- static char_u *complete_pat;
- static int save_sm;
- static char_u *original_text = NULL; /* text before completion */
- static int continue_mode = 0;
- static int add_completion __ARGS((char_u *str, int len, char_u *, int dir, int reuse));
- static int make_cyclic __ARGS((void));
- static void complete_dictionaries __ARGS((char_u *dict, char_u *pat, int dir, int flags));
- static void free_completions __ARGS((void));
- static void clear_insexp __ARGS((void));
- static int ins_expand_pre __ARGS((int c));
- static BUF *next_buf __ARGS((BUF *buf, int flag));
- static int get_expansion __ARGS((FPOS *ini, int dir));
- static int ins_complete __ARGS((int c));
- static int quote_meta __ARGS((char_u *dest, char_u *str, int len));
- #endif /* INSERT_EXPAND */
- #define BACKSPACE_CHAR 1
- #define BACKSPACE_WORD 2
- #define BACKSPACE_WORD_NOT_SPACE 3
- #define BACKSPACE_LINE 4
- static void edit_putchar __ARGS((int c, int highlight));
- static void undisplay_dollar __ARGS((void));
- static void change_indent __ARGS((int type, int amount, int round, int replaced));
- static void insert_special __ARGS((int, int, int));
- static void redo_literal __ARGS((int c));
- static void start_arrow __ARGS((FPOS *end_insert_pos));
- static void stop_insert __ARGS((FPOS *end_insert_pos));
- static int echeck_abbr __ARGS((int));
- static void replace_push_off __ARGS((int c));
- static int replace_pop __ARGS((void));
- static void replace_join __ARGS((int off));
- static void replace_pop_ins __ARGS((void));
- static void replace_flush __ARGS((void));
- static void replace_do_bs __ARGS((void));
- static int ins_reg __ARGS((void));
- static int ins_esc __ARGS((long *count, int need_redraw, int cmdchar));
- #ifdef RIGHTLEFT
- static void ins_ctrl_ __ARGS((void));
- #endif
- static void ins_shift __ARGS((int c, int lastc));
- static void ins_del __ARGS((void));
- static int ins_bs __ARGS((int c, int mode, int *inserted_space_p));
- #ifdef USE_MOUSE
- static void ins_mouse __ARGS((int c));
- #endif
- static void ins_left __ARGS((void));
- static void ins_home __ARGS((void));
- static void ins_end __ARGS((void));
- static void ins_s_left __ARGS((void));
- static void ins_right __ARGS((void));
- static void ins_s_right __ARGS((void));
- static void ins_up __ARGS((void));
- static void ins_pageup __ARGS((void));
- static void ins_down __ARGS((void));
- static void ins_pagedown __ARGS((void));
- static int ins_tab __ARGS((void));
- static int ins_eol __ARGS((int c));
- #ifdef DIGRAPHS
- static int ins_digraph __ARGS((void));
- #endif
- static int ins_copychar __ARGS((linenr_t lnum));
- #ifdef SMARTINDENT
- static void ins_try_si __ARGS((int c));
- #endif
- static colnr_t get_nolist_virtcol __ARGS((void));
- static FPOS Insstart; /* This is where the latest
- * insert/append mode started. */
- static colnr_t Insstart_textlen; /* length of line when insert started */
- static colnr_t Insstart_blank_vcol; /* vcol for first inserted blank */
- static char_u *last_insert = NULL; /* the text of the previous insert */
- static int last_insert_skip; /* nr of chars in front of previous insert */
- static int new_insert_skip; /* nr of chars in front of current insert */
- #ifdef CINDENT
- static int can_cindent; /* may do cindenting on this line */
- #endif
- static int old_indent = 0; /* for ^^D command in insert mode */
- #ifdef RIGHTLEFT
- int revins_on; /* reverse insert mode on */
- int revins_chars; /* how much to skip after edit */
- int revins_legal; /* was the last char 'legal'? */
- int revins_scol; /* start column of revins session */
- #endif
- /*
- * edit(): Start insering text.
- *
- * "cmdchar" can be:
- * 'i' normal insert command
- * 'a' normal append command
- * 'R' replace command
- * 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
- * but still only one <CR> is inserted. The <Esc> is not used for redo.
- * 'g' "gI" command.
- *
- * This function is not called recursively. For CTRL-O commands, it returns
- * and lets the caller handle the Normal-mode command.
- *
- * Return TRUE if a CTRL-O command caused the return (insert mode pending).
- */
- int
- edit(cmdchar, startln, count)
- int cmdchar;
- int startln; /* if set, insert at start of line */
- long count;
- {
- int c = 0;
- char_u *ptr;
- int lastc;
- colnr_t mincol;
- static linenr_t o_lnum = 0;
- static int o_eol = FALSE;
- int need_redraw = FALSE;
- int i;
- int did_backspace = TRUE; /* previous char was backspace */
- #ifdef CINDENT
- int line_is_white = FALSE; /* line is empty before insert */
- #endif
- linenr_t old_topline = 0; /* topline before insertion */
- int inserted_space = FALSE; /* just inserted a space */
- int has_startsel; /* may start selection */
- /* sleep before redrawing, needed for "CTRL-O :" that results in an
- * error message */
- check_for_delay(TRUE);
- #ifdef INSERT_EXPAND
- clear_insexp(); /* clear stuff for ctrl-x mode */
- #endif
- #ifdef USE_MOUSE
- /*
- * When doing a paste with the middle mouse button, Insstart is set to
- * where the paste started.
- */
- if (where_paste_started.lnum != 0)
- Insstart = where_paste_started;
- else
- #endif
- {
- Insstart = curwin->w_cursor;
- if (startln)
- Insstart.col = 0;
- }
- Insstart_textlen = linetabsize(ml_get_curline());
- Insstart_blank_vcol = MAXCOL;
- if (cmdchar != NUL && !restart_edit)
- {
- ResetRedobuff();
- AppendNumberToRedobuff(count);
- AppendCharToRedobuff(cmdchar);
- if (cmdchar == 'g') /* "gI" command */
- AppendCharToRedobuff('I');
- else if (cmdchar == 'r') /* "r<CR>" command */
- count = 1; /* insert only one <CR> */
- }
- if (cmdchar == 'R')
- {
- #ifdef FKMAP
- if (p_fkmap && p_ri)
- {
- beep_flush();
- EMSG(farsi_text_3); /* encoded in Farsi */
- State = INSERT;
- }
- else
- #endif
- State = REPLACE;
- }
- else
- State = INSERT;
- #if defined(USE_GUI_WIN32) && defined(MULTI_BYTE_IME)
- ImeSetOriginMode();
- #endif
- /*
- * Need to recompute the cursor position, it might move when the cursor is
- * on a TAB or special character.
- */
- curs_columns(TRUE);
- #ifdef USE_MOUSE
- setmouse();
- #endif
- #ifdef SHOWCMD
- clear_showcmd();
- #endif
- #ifdef RIGHTLEFT
- /* there is no reverse replace mode */
- revins_on = (State == INSERT && p_ri);
- if (revins_on)
- undisplay_dollar();
- revins_chars = 0;
- revins_legal = 0;
- revins_scol = -1;
- #endif
- /* if 'keymodel' contains "startsel", may start selection on shifted
- * special key */
- has_startsel = (vim_strchr(p_km, 'a') != NULL);
- /*
- * Handle restarting Insert mode.
- * Don't do this for CTRL-O . (repeat an insert): we get here with
- * restart_edit non-zero, and something in the stuff buffer.
- */
- if (restart_edit && stuff_empty())
- {
- #ifdef USE_MOUSE
- /*
- * After a paste we consider text typed to be part of the insert for
- * the pasted text. You can backspace over the paste text too.
- */
- if (where_paste_started.lnum)
- arrow_used = FALSE;
- else
- #endif
- arrow_used = TRUE;
- restart_edit = 0;
- /*
- * If the cursor was after the end-of-line before the CTRL-O and it is
- * now at the end-of-line, put it after the end-of-line (this is not
- * correct in very rare cases).
- * Also do this if curswant is greater than the current virtual
- * column. Eg after "^O$" or "^O80|".
- */
- validate_virtcol();
- update_curswant();
- if ( ((o_eol && curwin->w_cursor.lnum == o_lnum)
- || curwin->w_curswant > curwin->w_virtcol)
- && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL
- && *(ptr + 1) == NUL)
- ++curwin->w_cursor.col;
- }
- else
- {
- arrow_used = FALSE;
- o_eol = FALSE;
- }
- #ifdef USE_MOUSE
- where_paste_started.lnum = 0;
- #endif
- #ifdef CINDENT
- can_cindent = TRUE;
- #endif
- /*
- * If 'showmode' is set, show the current (insert/replace/..) mode.
- * A warning message for changing a readonly file is given here, before
- * actually changing anything. It's put after the mode, if any.
- */
- i = 0;
- if (p_smd)
- i = showmode();
- if (!p_im)
- change_warning(i + 1);
- #ifdef CURSOR_SHAPE
- ui_cursor_shape(); /* may show different cursor shape */
- #endif
- #ifdef DIGRAPHS
- do_digraph(-1); /* clear digraphs */
- #endif
- /*
- * Get the current length of the redo buffer, those characters have to be
- * skipped if we want to get to the inserted characters.
- */
- ptr = get_inserted();
- if (ptr == NULL)
- new_insert_skip = 0;
- else
- {
- new_insert_skip = STRLEN(ptr);
- vim_free(ptr);
- }
- old_indent = 0;
- for (;;)
- {
- #ifdef RIGHTLEFT
- if (!revins_legal)
- revins_scol = -1; /* reset on illegal motions */
- else
- revins_legal = 0;
- #endif
- if (arrow_used) /* don't repeat insert when arrow key used */
- count = 0;
- /* set curwin->w_curswant for next K_DOWN or K_UP */
- if (!arrow_used)
- curwin->w_set_curswant = TRUE;
- /*
- * When emsg() was called msg_scroll will have been set.
- */
- msg_scroll = FALSE;
- /*
- * If we inserted a character at the last position of the last line in
- * the window, scroll the window one line up. This avoids an extra
- * redraw.
- * This is detected when the cursor column is smaller after inserting
- * something.
- * Don't do this when the topline changed already, it has
- * already been adjusted (by insertchar() calling open_line())).
- */
- if (need_redraw && curwin->w_p_wrap && !did_backspace &&
- curwin->w_topline == old_topline)
- {
- mincol = curwin->w_wcol;
- validate_cursor_col();
- if ((int)curwin->w_wcol < (int)mincol - curbuf->b_p_ts &&
- curwin->w_wrow == curwin->w_winpos +
- curwin->w_height - 1 - p_so &&
- curwin->w_cursor.lnum != curwin->w_topline)
- {
- set_topline(curwin, curwin->w_topline + 1);
- update_topline();
- #ifdef SYNTAX_HL
- /* recompute syntax hl., starting with current line */
- syn_changed(curwin->w_cursor.lnum);
- #endif
- update_screen(VALID_TO_CURSCHAR);
- need_redraw = FALSE;
- }
- else
- update_topline();
- }
- else
- update_topline();
- did_backspace = FALSE;
- /*
- * redraw is postponed until here to make 'dollar' option work
- * correctly.
- */
- validate_cursor(); /* may set must_redraw */
- if (need_redraw || must_redraw)
- {
- update_screenline();
- if (curwin->w_redr_status == TRUE)
- win_redr_status(curwin); /* display [+] if required */
- need_redraw = FALSE;
- }
- else if (clear_cmdline || redraw_cmdline)
- showmode(); /* clear cmdline, show mode and ruler */
- showruler(FALSE);
- setcursor();
- update_curswant();
- emsg_on_display = FALSE; /* may remove error message now */
- old_topline = curwin->w_topline;
- #ifdef USE_GUI_WIN32
- dont_scroll = FALSE; /* allow scrolling here */
- #endif
- lastc = c; /* remember previous char for CTRL-D */
- c = vgetc();
- #ifdef RIGHTLEFT
- if (p_hkmap && KeyTyped)
- c = hkmap(c); /* Hebrew mode mapping */
- #endif
- #ifdef FKMAP
- if (p_fkmap && KeyTyped)
- c = fkmap(c); /* Farsi mode mapping */
- #endif
- #ifdef INSERT_EXPAND
- /*
- * Prepare for or stop ctrl-x mode.
- */
- need_redraw |= ins_expand_pre(c);
- #endif
- #ifdef DIGRAPHS
- c = do_digraph(c);
- #endif
- if (c == Ctrl('V') || c == Ctrl('Q'))
- {
- if (redrawing() && !char_avail())
- edit_putchar('^', TRUE);
- AppendToRedobuff((char_u *)"26"); /* CTRL-V */
- #ifdef SHOWCMD
- add_to_showcmd_c(c);
- #endif
- c = get_literal();
- #ifdef SHOWCMD
- clear_showcmd();
- #endif
- insert_special(c, FALSE, TRUE);
- need_redraw = TRUE;
- #ifdef RIGHTLEFT
- revins_chars++;
- revins_legal++;
- #endif
- c = Ctrl('V'); /* pretend CTRL-V is last typed character */
- continue;
- }
- #ifdef MULTI_BYTE
- # if defined(USE_GUI) && !defined(USE_GUI_WIN32)
- if (!gui.in_use)
- # endif
- if (is_dbcs && IsLeadByte(c))
- {
- int c2;
- c2 = get_literal();
- insert_special(c, FALSE, FALSE);
- insert_special(c2, FALSE, FALSE);
- need_redraw = TRUE;
- continue;
- }
- #endif
- #ifdef CINDENT
- if (curbuf->b_p_cin
- # ifdef INSERT_EXPAND
- && !ctrl_x_mode
- # endif
- )
- {
- line_is_white = inindent(0);
- /*
- * A key name preceded by a bang means that this
- * key wasn't destined to be inserted. Skip ahead
- * to the re-indenting if we find one.
- */
- if (in_cinkeys(c, '!', line_is_white))
- goto force_cindent;
- /*
- * A key name preceded by a star means that indenting
- * has to be done before inserting the key.
- */
- if (can_cindent && in_cinkeys(c, '*', line_is_white))
- {
- stop_arrow();
- /* re-indent the current line */
- fixthisline(get_c_indent);
- /* draw the changes on the screen later */
- need_redraw = TRUE;
- }
- }
- #endif /* CINDENT */
- #ifdef RIGHTLEFT
- if (curwin->w_p_rl)
- switch (c)
- {
- case K_LEFT: c = K_RIGHT; break;
- case K_S_LEFT: c = K_S_RIGHT; break;
- case K_RIGHT: c = K_LEFT; break;
- case K_S_RIGHT: c = K_S_LEFT; break;
- }
- #endif
- /* if 'keymodel' contains "startsel", may start selection */
- if (has_startsel)
- switch (c)
- {
- case K_KHOME:
- case K_KEND:
- case K_PAGEUP:
- case K_KPAGEUP:
- case K_PAGEDOWN:
- case K_KPAGEDOWN:
- if (!(mod_mask & MOD_MASK_SHIFT))
- break;
- /* FALLTHROUGH */
- case K_S_LEFT:
- case K_S_RIGHT:
- case K_S_UP:
- case K_S_DOWN:
- case K_S_END:
- case K_S_HOME:
- /* Start selection right away, the cursor can move with
- * CTRL-O when beyond the end of the line. */
- start_selection();
- /* Execute the key in (insert) Select mode, unless it's
- * shift-left and beyond the end of the line (the CTRL-O
- * will move the cursor left already). */
- stuffcharReadbuff(Ctrl('O'));
- if (c != K_S_LEFT || gchar_cursor() != NUL)
- {
- if (mod_mask)
- {
- char_u buf[4];
- buf[0] = K_SPECIAL;
- buf[1] = KS_MODIFIER;
- buf[2] = mod_mask;
- buf[3] = NUL;
- stuffReadbuff(buf);
- }
- stuffcharReadbuff(c);
- }
- continue;
- }
- /*
- * The big switch to handle a character in insert mode.
- */
- switch (c)
- {
- case K_INS: /* toggle insert/replace mode */
- #ifdef FKMAP
- if (p_fkmap && p_ri)
- {
- beep_flush();
- EMSG(farsi_text_3); /* encoded in Farsi */
- break;
- }
- #endif
- if (State == REPLACE)
- State = INSERT;
- else
- State = REPLACE;
- AppendCharToRedobuff(K_INS);
- showmode();
- #ifdef CURSOR_SHAPE
- ui_cursor_shape(); /* may show different cursor shape */
- #endif
- break;
- #ifdef INSERT_EXPAND
- case Ctrl('X'): /* Enter ctrl-x mode */
- /* if the next ^X<> won't ADD nothing, then reset continue_status */
- continue_status = continue_status & CONT_N_ADDS ?
- continue_status | CONT_INTRPT : 0;
- /* We're not sure which ctrl-x mode it will be yet */
- ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
- edit_submode = (char_u *)ctrl_x_msgs[ctrl_x_mode & 15];
- showmode();
- break;
- #endif
- case K_SELECT: /* end of Select mode mapping - ignore */
- break;
- case Ctrl('Z'): /* suspend when 'insertmode' set */
- if (!p_im)
- goto normalchar; /* insert CTRL-Z as normal char */
- stuffReadbuff((char_u *)":str");
- c = Ctrl('O');
- /*FALLTHROUGH*/
- case Ctrl('O'): /* execute one command */
- if (echeck_abbr(Ctrl('O') + ABBR_OFF))
- break;
- count = 0;
- if (State == INSERT)
- restart_edit = 'I';
- else
- restart_edit = 'R';
- o_lnum = curwin->w_cursor.lnum;
- o_eol = (gchar_cursor() == NUL);
- goto doESCkey;
- #ifdef USE_SNIFF
- case K_SNIFF:
- stuffcharReadbuff(K_SNIFF);
- goto doESCkey;
- #endif
- /* Hitting the help key in insert mode is like <ESC> <Help> */
- case K_HELP:
- case K_F1:
- stuffcharReadbuff(K_HELP);
- if (p_im)
- stuffcharReadbuff('i');
- goto doESCkey;
- case ESC: /* an escape ends input mode */
- if (echeck_abbr(ESC + ABBR_OFF))
- break;
- /*FALLTHROUGH*/
- case Ctrl('C'):
- #ifdef UNIX
- do_intr:
- #endif
- /* when 'insertmode' set, and not halfway a mapping, don't leave
- * Insert mode */
- if (goto_im())
- {
- if (got_int)
- {
- (void)vgetc(); /* flush all buffers */
- got_int = FALSE;
- }
- else
- vim_beep();
- break;
- }
- doESCkey:
- /*
- * This is the ONLY return from edit()!
- */
- if (ins_esc(&count, need_redraw, cmdchar))
- return (c == Ctrl('O'));
- continue;
- /*
- * Insert the previously inserted text.
- * For ^@ the trailing ESC will end the insert, unless there
- * is an error.
- */
- case K_ZERO:
- case NUL:
- case Ctrl('A'):
- if (stuff_inserted(NUL, 1L, (c == Ctrl('A'))) == FAIL
- && c != Ctrl('A') && !p_im)
- goto doESCkey; /* quit insert mode */
- break;
- /*
- * insert the contents of a register
- */
- case Ctrl('R'):
- need_redraw |= ins_reg();
- break;
- #ifdef RIGHTLEFT
- case Ctrl('_'):
- if (!p_ari)
- goto normalchar;
- ins_ctrl_();
- break;
- #endif
- /* Make indent one shiftwidth smaller. */
- case Ctrl('D'):
- #if defined(INSERT_EXPAND) && defined(FIND_IN_PATH)
- if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
- goto docomplete;
- #endif
- /* FALLTHROUGH */
- /* Make indent one shiftwidth greater. */
- case Ctrl('T'):
- ins_shift(c, lastc);
- need_redraw = TRUE;
- break;
- /* delete character under the cursor */
- case K_DEL:
- ins_del();
- need_redraw = TRUE;
- break;
- /* delete character before the cursor */
- case K_BS:
- case Ctrl('H'):
- did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space);
- need_redraw = TRUE;
- break;
- /* delete word before the cursor */
- case Ctrl('W'):
- did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space);
- need_redraw = TRUE;
- break;
- /* delete all inserted text in current line */
- case Ctrl('U'):
- did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
- need_redraw = TRUE;
- break;
- #ifdef USE_MOUSE
- case K_LEFTMOUSE:
- case K_LEFTDRAG:
- case K_LEFTRELEASE:
- case K_MIDDLEMOUSE:
- case K_MIDDLEDRAG:
- case K_MIDDLERELEASE:
- case K_RIGHTMOUSE:
- case K_RIGHTDRAG:
- case K_RIGHTRELEASE:
- ins_mouse(c);
- break;
- case K_IGNORE:
- break;
- #endif
- #ifdef USE_GUI
- case K_SCROLLBAR:
- ins_scroll();
- break;
- case K_HORIZ_SCROLLBAR:
- ins_horscroll();
- break;
- #endif
- case K_HOME:
- case K_KHOME:
- case K_S_HOME:
- ins_home();
- break;
- case K_END:
- case K_KEND:
- case K_S_END:
- ins_end();
- break;
- case K_LEFT:
- if (mod_mask & MOD_MASK_CTRL)
- ins_s_left();
- else
- ins_left();
- break;
- case K_S_LEFT:
- ins_s_left();
- break;
- case K_RIGHT:
- if (mod_mask & MOD_MASK_CTRL)
- ins_s_right();
- else
- ins_right();
- break;
- case K_S_RIGHT:
- ins_s_right();
- break;
- case K_UP:
- ins_up();
- break;
- case K_S_UP:
- case K_PAGEUP:
- case K_KPAGEUP:
- ins_pageup();
- break;
- case K_DOWN:
- ins_down();
- break;
- case K_S_DOWN:
- case K_PAGEDOWN:
- case K_KPAGEDOWN:
- ins_pagedown();
- break;
- /* keypad keys: When not mapped they produce a normal char */
- case K_KPLUS: c = '+'; goto normalchar;
- case K_KMINUS: c = '-'; goto normalchar;
- case K_KDIVIDE: c = '/'; goto normalchar;
- case K_KMULTIPLY: c = '*'; goto normalchar;
- /* When <S-Tab> isn't mapped, use it like a normal TAB */
- case K_S_TAB:
- c = TAB;
- /* FALLTHROUGH */
- /* TAB or Complete patterns along path */
- case TAB:
- #if defined(INSERT_EXPAND) && defined(FIND_IN_PATH)
- if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
- goto docomplete;
- #endif
- inserted_space = FALSE;
- if (ins_tab())
- goto normalchar; /* insert TAB as a normal char */
- need_redraw = TRUE;
- break;
- case K_KENTER:
- c = CR;
- /* FALLTHROUGH */
- case CR:
- case NL:
- if (ins_eol(c) && !p_im)
- goto doESCkey; /* out of memory */
- break;
- #if defined(DIGRAPHS) || defined (INSERT_EXPAND)
- case Ctrl('K'):
- # ifdef INSERT_EXPAND
- if (ctrl_x_mode == CTRL_X_DICTIONARY)
- {
- if (*p_dict == NUL)
- {
- ctrl_x_mode = 0;
- msg_attr((char_u *)"'dictionary' option is empty",
- hl_attr(HLF_E));
- vim_beep();
- setcursor();
- out_flush();
- ui_delay(2000L, FALSE);
- break;
- }
- goto docomplete;
- }
- # endif
- # ifdef DIGRAPHS
- c = ins_digraph();
- if (c == NUL)
- {
- need_redraw = TRUE;
- break;
- }
- # endif
- goto normalchar;
- #endif /* DIGRAPHS || INSERT_EXPAND */
- #ifdef INSERT_EXPAND
- case Ctrl(']'): /* Tag name completion after ^X */
- if (ctrl_x_mode != CTRL_X_TAGS)
- goto normalchar;
- goto docomplete;
- case Ctrl('F'): /* File name completion after ^X */
- if (ctrl_x_mode != CTRL_X_FILES)
- goto normalchar;
- goto docomplete;
- #endif
- case Ctrl('L'): /* Whole line completion after ^X */
- #ifdef INSERT_EXPAND
- if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
- #endif
- {
- /* CTRL-L with 'insertmode' set: Leave Insert mode */
- if (p_im)
- {
- if (echeck_abbr(Ctrl('L') + ABBR_OFF))
- break;
- goto doESCkey;
- }
- goto normalchar;
- }
- #ifdef INSERT_EXPAND
- /* FALLTHROUGH */
- case Ctrl('P'): /* Do previous pattern completion */
- case Ctrl('N'): /* Do next pattern completion */
- /* if 'complete' is empty then plain ^P is no longer special,
- * but it is under other ^X modes */
- if ( *curbuf->b_p_cpt == NUL && !ctrl_x_mode
- && !(continue_status & CONT_LOCAL))
- goto normalchar;
- docomplete:
- i = ins_complete(c);
- if (i)
- need_redraw |= i;
- else
- continue_status = 0;
- break;
- #endif /* INSERT_EXPAND */
- case Ctrl('Y'): /* copy from previous line or scroll down */
- case Ctrl('E'): /* copy from next line or scroll up */
- #ifdef INSERT_EXPAND
- if (ctrl_x_mode == CTRL_X_SCROLL)
- {
- if (c == Ctrl('Y'))
- scrolldown_clamp();
- else
- scrollup_clamp();
- update_screen(VALID);
- }
- else
- #endif
- {
- c = ins_copychar(curwin->w_cursor.lnum
- + (c == Ctrl('Y') ? -1 : 1));
- if (c != NUL)
- {
- long tw_save;
- /* The character must be taken literally, insert like it
- * was typed after a CTRL-V, and pretend 'textwidth'
- * wasn't set. Digits, 'o' and 'x' are special after a
- * CTRL-V, don't use it for these. */
- if (!isalnum(c))
- AppendToRedobuff((char_u *)"26"); /* CTRL-V */
- tw_save = curbuf->b_p_tw;
- curbuf->b_p_tw = -1;
- insert_special(c, TRUE, TRUE);
- curbuf->b_p_tw = tw_save;
- need_redraw = TRUE;
- #ifdef RIGHTLEFT
- revins_chars++;
- revins_legal++;
- #endif
- c = Ctrl('V'); /* pretend CTRL-V is last character */
- }
- }
- break;
- default:
- #ifdef UNIX
- if (c == intr_char) /* special interrupt char */
- goto do_intr;
- #endif
- normalchar:
- #ifdef SMARTINDENT
- /*
- * Try to perform smart-indenting.
- */
- ins_try_si(c);
- #endif
- if (c == ' ')
- {
- inserted_space = TRUE;
- #ifdef CINDENT
- if (inindent(0))
- can_cindent = FALSE;
- #endif
- if (Insstart_blank_vcol == MAXCOL
- && curwin->w_cursor.lnum == Insstart.lnum)
- Insstart_blank_vcol = get_nolist_virtcol();
- }
- if (vim_iswordc(c) || !echeck_abbr(c))
- {
- insert_special(c, FALSE, FALSE);
- need_redraw = TRUE;
- #ifdef RIGHTLEFT
- revins_legal++;
- revins_chars++;
- #endif
- }
- break;
- } /* end of switch (c) */
- #ifdef CINDENT
- if (curbuf->b_p_cin && can_cindent
- # ifdef INSERT_EXPAND
- && !ctrl_x_mode
- # endif
- )
- {
- force_cindent:
- /*
- * Indent now if a key was typed that is in 'cinkeys'.
- */
- if (in_cinkeys(c, ' ', line_is_white))
- {
- stop_arrow();
- /* re-indent the current line */
- fixthisline(get_c_indent);
- /* draw the changes on the screen later */
- need_redraw = TRUE;
- }
- }
- #endif /* CINDENT */
- } /* for (;;) */
- /* NOTREACHED */
- }
- /*
- * Put a character directly onto the screen. It's not stored in a buffer.
- * Used while handling CTRL-K, CTRL-V, etc. in Insert mode.
- */
- static void
- edit_putchar(c, highlight)
- int c;
- int highlight;
- {
- int attr;
- if (NextScreen != NULL)
- {
- update_topline(); /* just in case w_topline isn't valid */
- validate_cursor();
- if (highlight)
- attr = hl_attr(HLF_8);
- else
- attr = 0;
- screen_putchar(c, curwin->w_winpos + curwin->w_wrow,
- #ifdef RIGHTLEFT
- curwin->w_p_rl ? (int)Columns - 1 - curwin->w_wcol :
- #endif
- curwin->w_wcol, attr);
- }
- }
- /*
- * Called when p_dollar is set: display a '$' at the end of the changed text
- * Only works when cursor is in the line that changes.
- */
- void
- display_dollar(col)
- colnr_t col;
- {
- colnr_t save_col;
- if (!redrawing())
- return;
- cursor_off();
- save_col = curwin->w_cursor.col;
- curwin->w_cursor.col = col;
- curs_columns(FALSE); /* recompute w_wrow and w_wcol */
- if (curwin->w_wcol < Columns)
- {
- edit_putchar('$', FALSE);
- dollar_vcol = curwin->w_virtcol;
- }
- curwin->w_cursor.col = save_col;
- }
- /*
- * Call this function before moving the cursor from the normal insert position
- * in insert mode.
- */
- static void
- undisplay_dollar()
- {
- if (dollar_vcol)
- {
- dollar_vcol = 0;
- update_screenline();
- }
- }
- /*
- * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
- * Keep the cursor on the same character.
- * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
- * type == INDENT_DEC decrease indent (for CTRL-D)
- * type == INDENT_SET set indent to "amount"
- * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
- */
- static void
- change_indent(type, amount, round, replaced)
- int type;
- int amount;
- int round;
- int replaced; /* replaced character, put on replace stack */
- {
- int vcol;
- int last_vcol;
- int insstart_less; /* reduction for Insstart.col */
- int new_cursor_col;
- int i;
- char_u *ptr;
- int save_p_list;
- int start_col;
- colnr_t vc;
- /* for the following tricks we don't want list mode */
- save_p_list = curwin->w_p_list;
- curwin->w_p_list = FALSE;
- getvcol(curwin, &curwin->w_cursor, NULL, &vc, NULL);
- vcol = vc;
- /*
- * For Replace mode we need to fix the replace stack later, which is only
- * possible when the cursor is in the indent. Remember the number of
- * characters before the cursor if it's possible.
- */
- start_col = curwin->w_cursor.col;
- /* determine offset from first non-blank */
- new_cursor_col = curwin->w_cursor.col;
- beginline(BL_WHITE);
- new_cursor_col -= curwin->w_cursor.col;
- insstart_less = curwin->w_cursor.col;
- /*
- * If the cursor is in the indent, compute how many screen columns the
- * cursor is to the left of the first non-blank.
- */
- if (new_cursor_col < 0)
- vcol = get_indent() - vcol;
- if (new_cursor_col > 0) /* can't fix replace stack */
- start_col = -1;
- /*
- * Set the new indent. The cursor will be put on the first non-blank.
- */
- if (type == INDENT_SET)
- set_indent(amount, TRUE);
- else
- shift_line(type == INDENT_DEC, round, 1);
- insstart_less -= curwin->w_cursor.col;
- /*
- * Try to put cursor on same character.
- * If the cursor is at or after the first non-blank in the line,
- * compute the cursor column relative to the column of the first
- * non-blank character.
- * If we are not in insert mode, leave the cursor on the first non-blank.
- * If the cursor is before the first non-blank, position it relative
- * to the first non-blank, counted in screen columns.
- */
- if (new_cursor_col >= 0)
- new_cursor_col += curwin->w_cursor.col;
- else if (!(State & INSERT))
- new_cursor_col = curwin->w_cursor.col;
- else
- {
- /*
- * Compute the screen column where the cursor should be.
- */
- vcol = get_indent() - vcol;
- curwin->w_virtcol = (vcol < 0) ? 0 : vcol;
- /*
- * Advance the cursor until we reach the right screen column.
- */
- vcol = last_vcol = 0;
- new_cursor_col = -1;
- ptr = ml_get_curline();
- while (vcol <= (int)curwin->w_virtcol)
- {
- last_vcol = vcol;
- ++new_cursor_col;
- vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_t)vcol);
- }
- vcol = last_vcol;
- /*
- * May need to insert spaces to be able to position the cursor on
- * the right screen column.
- */
- if (vcol != (int)curwin->w_virtcol)
- {
- curwin->w_cursor.col = new_cursor_col;
- i = (int)curwin->w_virtcol - vcol;
- ptr = alloc(i + 1);
- if (ptr != NULL)
- {
- new_cursor_col += i;
- ptr[i] = NUL;
- while (--i >= 0)
- ptr[i] = ' ';
- ins_str(ptr);
- vim_free(ptr);
- }
- }
- /*
- * When changing the indent while the cursor is in it, reset
- * Insstart_col to 0.
- */
- insstart_less = Insstart.col;
- }
- curwin->w_p_list = save_p_list;
- if (new_cursor_col <= 0)
- curwin->w_cursor.col = 0;
- else
- curwin->w_cursor.col = new_cursor_col;
- curwin->w_set_curswant = TRUE;
- changed_cline_bef_curs();
- /*
- * May have to adjust the start of the insert.
- */
- if ((State & INSERT) && curwin->w_cursor.lnum == Insstart.lnum &&
- Insstart.col != 0)
- {
- if ((int)Insstart.col <= insstart_less)
- Insstart.col = 0;
- else
- Insstart.col -= insstart_less;
- }
- /*
- * May have to fix the replace stack, if it's possible.
- * If the number of characters before the cursor decreased, need to pop a
- * few characters from the replace stack.
- * If the number of characters before the cursor increased, need to push a
- * few NULs onto the replace stack.
- */
- if (State == REPLACE && start_col >= 0)
- {
- while (start_col > (int)curwin->w_cursor.col)
- {
- replace_join(0); /* remove a NUL from the replace stack */
- --start_col;
- }
- while (start_col < (int)curwin->w_cursor.col || replaced)
- {
- replace_push(NUL);
- if (replaced)
- {
- replace_push(replaced);
- replaced = NUL;
- }
- ++start_col;
- }
- }
- }
- #ifdef INSERT_EXPAND
- /*
- * Is the character 'c' a valid key to keep us in the current ctrl-x mode?
- * -- webb
- */
- int
- vim_is_ctrl_x_key(c)
- int c;
- {
- switch (ctrl_x_mode)
- {
- case 0: /* Not in any ctrl-x mode */
- break;
- case CTRL_X_NOT_DEFINED_YET:
- if ( c == Ctrl('X') || c == Ctrl('Y') || c == Ctrl('E')
- || c == Ctrl('L') || c == Ctrl('F') || c == Ctrl(']')
- || c == Ctrl('I') || c == Ctrl('D') || c == Ctrl('P')
- || c == Ctrl('N'))
- return TRUE;
- break;
- case CTRL_X_SCROLL:
- if (c == Ctrl('Y') || c == Ctrl('E'))
- return TRUE;
- break;
- case CTRL_X_WHOLE_LINE:
- if (c == Ctrl('L') || c == Ctrl('P') || c == Ctrl('N'))
- return TRUE;
- break;
- case CTRL_X_FILES:
- if (c == Ctrl('F') || c == Ctrl('P') || c == Ctrl('N'))
- return TRUE;
- break;
- case CTRL_X_DICTIONARY:
- if (c == Ctrl('K') || c == Ctrl('P') || c == Ctrl('N'))
- return TRUE;
- break;
- case CTRL_X_TAGS:
- if (c == Ctrl(']') || c == Ctrl('P') || c == Ctrl('N'))
- return TRUE;
- break;
- #ifdef FIND_IN_PATH
- case CTRL_X_PATH_PATTERNS:
- if (c == Ctrl('P') || c == Ctrl('N'))
- return TRUE;
- break;
- case CTRL_X_PATH_DEFINES:
- if (c == Ctrl('D') || c == Ctrl('P') || c == Ctrl('N'))
- return TRUE;
- break;
- #endif
- default:
- emsg(e_internal);
- break;
- }
- return FALSE;
- }
- /*
- * This is like add_completion(), but if ic and inf are set, then the
- * case of the originally typed text is used, and the case of the completed
- * text is infered, ie this tries to work out what case you probably wanted
- * the rest of the word to be in -- webb
- */
- int
- add_completion_and_infercase(str, len, fname, dir, reuse)
- char_u *str;
- int len;
- char_u *fname;
- int dir;
- int reuse;
- {
- int has_lower = FALSE;
- int was_letter = FALSE;
- int idx;
- if (p_ic && curbuf->b_p_inf && len < IOSIZE)
- {
- /* Infer case of completed part -- webb */
- /* Use IObuff, str would change text in buffer! */
- STRNCPY(IObuff, str, len);
- IObuff[len] = NUL;
- /* Rule 1: Were any chars converted to lower? */
- for (idx = 0; idx < completion_length; ++idx)
- {
- if (islower(original_text[idx]))
- {
- has_lower = TRUE;
- if (isupper(IObuff[idx]))
- {
- /* Rule 1 is satisfied */
- for (idx = completion_length; idx < len; ++idx)
- IObuff[idx] = TO_LOWER(IObuff[idx]);
- break;
- }
- }
- }
- /*
- * Rule 2: No lower case, 2nd consecutive letter converted to
- * upper case.
- */
- if (!has_lower)
- {
- for (idx = 0; idx < completion_length; ++idx)
- {
- if (was_letter && isupper(original_text[idx]) &&
- islower(IObuff[idx]))
- {
- /* Rule 2 is satisfied */
- for (idx = completion_length; idx < len; ++idx)
- IObuff[idx] = TO_UPPER(IObuff[idx]);
- break;
- }
- was_letter = isalpha(original_text[idx]);
- }
- }
- /* Copy the original case of the part we typed */
- STRNCPY(IObuff, original_text, completion_length);
- return add_completion(IObuff, len, fname, dir, reuse);
- }
- return add_completion(str, len, fname, dir, reuse);
- }
- /*
- * Add a match to the list of matches.
- * If the given string is already in the list of completions, then return
- * FAIL, otherwise add it to the list and return OK. If there is an error,
- * maybe because alloc returns NULL, then RET_ERROR is returned -- webb.
- */
- static int
- add_completion(str, len, fname, dir, reuse)
- char_u *str;
- int len;
- char_u *fname;
- int dir;
- int reuse;
- {
- struct Completion *match;
- ui_breakcheck();
- if (got_int)
- return RET_ERROR;
- if (len < 0)
- len = STRLEN(str);
- /*
- * If the same match is already present, don't add it.
- */
- if (first_match != NULL)
- {
- match = first_match;
- do
- {
- if ( !(match->original & ORIGINAL_TEXT)
- && STRNCMP(match->str, str, (size_t)len) == 0
- && match->str[len] == NUL)
- return FAIL;
- match = match->next;
- } while (match != NULL && match != first_match);
- }
- /*
- * Allocate a new match structure.
- * Copy the values to the new match structure.
- */
- match = (struct Completion *)alloc((unsigned)sizeof(struct Completion));
- if (match == NULL)
- return RET_ERROR;
- if (reuse & ORIGINAL_TEXT)
- match->str = original_text;
- else if ((match->str = vim_strnsave(str, len)) == NULL)
- {
- vim_free(match);
- return RET_ERROR;
- }
- /* match-fname is:
- * - curr_match->fname if it is a string equal to fname.
- * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
- * - NULL otherwise. --Acevedo */
- if (fname && curr_match && curr_match->fname
- && STRCMP(fname, curr_match->fname) == 0)
- match->fname = curr_match->fname;
- else if (fname && (match->fname = vim_strsave(fname)) != NULL)
- reuse |= FREE_FNAME;
- else
- match->fname = NULL;
- match->original = reuse;
- /*
- * Link the new match structure in the list of matches.
- */
- if (first_match == NULL)
- match->next = match->prev = NULL;
- else if (dir == FORWARD)
- {
- match->next = curr_match->next;
- match->prev = curr_match;
- }
- else /* BACKWARD */
- {
- match->next = curr_match;
- match->prev = curr_match->prev;
- }
- if (match->next)
- match->next->prev = match;
- if (match->prev)
- match->prev->next = match;
- else /* if there's nothing before, it is the first match */
- first_match = match;
- curr_match = match;
- return OK;
- }
- /* Make the completion list cyclic.
- * Return the number of matches (excluding the original).
- */
- static int
- make_cyclic()
- {
- struct Completion *match;
- int count = 0;
- if (first_match != NULL)
- {
- /*
- * Find the end of the list.
- */
- match = first_match;
- /* there's always an entry for the original_text, it doesn't count. */
- while (match->next != NULL && match->next != first_match)
- {
- match = match->next;
- ++count;
- }
- match->next = first_match;
- first_match->prev = match;
- }
- return count;
- }
- #define DICT_FIRST (1) /* use just first element in "dict" */
- #define DICT_EXACT (2) /* "dict" is the exact name of a file */
- /*
- * Add any identifiers that match the given pattern to the list of
- * completions.
- */
- static void
- complete_dictionaries(dict, pat, dir, flags)
- char_u *dict;
- char_u *pat;
- int dir;
- int flags;
- {
- char_u *ptr;
- char_u *buf;
- int at_start;
- FILE *fp;
- vim_regexp *prog;
- int add_r;
- char_u **files;
- int count;
- int i;
- buf = alloc(LSIZE);
- set_reg_ic(pat); /* set reg_ic according to p_ic, p_scs and pat */
- prog = vim_regcomp(pat, (int)p_magic);
- expand_interactively = TRUE;
- while (buf && prog && *dict != NUL && !got_int)
- {
- /* copy one dictionary file name into buf */
- if (flags == DICT_EXACT)
- {
- count = 1;
- files = &dict;
- }
- else
- {
- copy_option_part(&dict, buf, LSIZE, ",");
- if (expand_wildcards(1, &buf, &count, &files, EW_FILE|EW_DIR) != OK)
- count = 0;
- }
- for (i = 0; i < count && !got_int; i++)
- {
- fp = fopen((char *)files[i], "r"); /* open dictionary file */
- if (flags != DICT_EXACT)
- {
- sprintf((char*)IObuff, "Scanning dictionary: %s",
- (char *)files[i]);
- msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
- }
- if (fp != NULL)
- {
- /*
- * Read dictionary file line by line.
- * Check each line for a match.
- */
- while (!got_int && !vim_fgets(buf, LSIZE, fp))
- {
- ptr = buf;
- at_start = TRUE;
- while (vim_regexec(prog, ptr, at_start))
- {
- at_start = FALSE;
- ptr = prog->startp[0];
- while (vim_iswordc(*ptr))
- ++ptr;
- add_r = add_completion_and_infercase(prog->startp[0],
- (int)(ptr - prog->startp[0]), files[i], dir, 0);
- if (add_r == OK)
- /* if dir was BACKWARD then honor it just once */
- dir = FORWARD;
- else if (add_r == RET_ERROR)
- break;
- }
- line_breakcheck();
- }
- fclose(fp);
- }
- }
- if (flags != DICT_EXACT && count > 0)
- FreeWild(count, files);
- if (flags)
- break;
- }
- expand_interactively = FALSE;
- vim_free(prog);
- vim_free(buf);
- }
- /*
- * Free the list of completions
- */
- static void
- free_completions()
- {
- struct Completion *match;
- if (first_match == NULL)
- return;
- curr_match = first_match;
- do
- {
- match = curr_match;
- curr_match = curr_match->next;
- vim_free(match->str);
- /* several entries may use the same fname, free it just once. */
- if (match->original & FREE_FNAME)
- vim_free(match->fname);
- vim_free(match);
- } while (curr_match != NULL && curr_match != first_match);
- first_match = curr_match = NULL;
- }
- static void
- clear_insexp()
- {
- continue_status = 0;
- started_completion = FALSE;
- complete_pat = NULL;
- save_sm = -1;
- }
- /*
- * Prepare for insert-expand, or stop it.
- */
- static int
- ins_expand_pre(c)
- int c;
- {
- char_u *ptr;
- char_u *tmp_ptr;
- int temp;
- linenr_t lnum;
- int need_redraw = FALSE;
- if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
- {
- /*
- * We have just entered ctrl-x mode and aren't quite sure which
- * ctrl-x mode it will be yet. Now we decide -- webb
- */
- switch (c)
- {
- case Ctrl('E'):
- case Ctrl('Y'):
- ctrl_x_mode = CTRL_X_SCROLL;
- if (State == INSERT)
- edit_submode = (char_u *)" (insert) Scroll (^E/^Y)";
- else
- edit_submode = (char_u *)" (replace) Scroll (^E/^Y)";
- showmode();
- break;
- case Ctrl('L'):
- ctrl_x_mode = CTRL_X_WHOLE_LINE;
- break;
- case Ctrl('F'):
- ctrl_x_mode = CTRL_X_FILES;
- break;
- case Ctrl('K'):
- ctrl_x_mode = CTRL_X_DICTIONARY;
- break;
- case Ctrl(']'):
- ctrl_x_mode = CTRL_X_TAGS;
- break;
- #ifdef FIND_IN_PATH
- case Ctrl('I'):
- case K_S_TAB:
- ctrl_x_mode = CTRL_X_PATH_PATTERNS;
- break;
- case Ctrl('D'):
- ctrl_x_mode = CTRL_X_PATH_DEFINES;
- break;
- #endif
- case Ctrl('P'):
- case Ctrl('N'):
- /* ^X^P means LOCAL expansion if nothing interrupted (eg we
- * just started ^X mode, or there were enough ^X's to cancel
- * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
- * do normal expansion when interrupting a different mode (say
- * ^X^F^X^P or ^P^X^X^P, see below)
- * nothing changes if interrupting mode 0, (eg, the flag
- * doesn't change when going to ADDING mode -- Acevedo */
- if (!(continue_status & CONT_INTRPT))
- continue_status |= CONT_LOCAL;
- else if (continue_mode)
- continue_status &=~CONT_LOCAL;
- /* FALLTHROUGH */
- default:
- /* if we have typed at least 2 ^X's... for modes != 0, we set
- * continue_status = 0 (eg, as if we had just started ^X mode)
- * for mode 0, we set continue_mode to an impossible value, in
- * both cases ^X^X can be used to restart the same mode
- * (avoiding ADDING mode). Undocumented feature:
- * In a mode != 0 ^X^P and ^X^X^P start 'complete' and local
- * ^P expansions respectively. In mode 0 an extra ^X is
- * needed since ^X^P goes to ADDING mode -- Acevedo */
- if (c == Ctrl('X'))
- {
- if (continue_mode)
- continue_status = 0;
- else
- continue_mode = CTRL_X_NOT_DEFINED_YET;
- }
- ctrl_x_mode = 0;
- edit_submode = NULL;
- showmode();
- break;
- }
- }
- else if (ctrl_x_mode)
- {
- /* We we're already in ctrl-x mode, do we stay in it? */
- if (!vim_is_ctrl_x_key(c))
- {
- if (ctrl_x_mode == CTRL_X_SCROLL)
- ctrl_x_mode = 0;
- else
- ctrl_x_mode = CTRL_X_FINISHED;
- edit_submode = NULL;
- }
- showmode();
- }
- if (started_completion || ctrl_x_mode == CTRL_X_FINISHED)
- {
- /* Show error message from attempted keyword completion (probably
- * 'Pattern not found') until another key is hit, then go back to
- * showing what mode we are in.
- */
- showmode();
- if ((ctrl_x_mode == 0 && c != Ctrl('N') && c != Ctrl('P')) ||
- ctrl_x_mode == CTRL_X_FINISHED)
- {
- /* Get here when we have finished typing a sequence of ^N and
- * ^P or other completion characters in CTRL-X mode. Free up
- * memory that was used, and make sure we can redo the insert
- * -- webb.
- */
- if (curr_match != NULL)
- {
- /*
- * If any of the original typed text has been changed,
- * eg when ignorecase is set, we must add back-spaces to
- * the redo buffer. We add as few as necessary to delete
- * just the part of the original text that has changed
- * -- webb
- */
- ptr = curr_match->str;
- tmp_ptr = original_text;
- while (*tmp_ptr && *tmp_ptr == *ptr)
- {
- ++tmp_ptr;
- ++ptr;
- }
- for (temp = 0; tmp_ptr[temp]; ++temp)
- AppendCharToRedobuff(K_BS);
- while (*ptr)
- {
- /* Put a string of normal characters in the redo buffer */
- tmp_ptr = ptr;
- while (*ptr >= ' ' && *ptr < DEL)
- ++ptr;
- /* Don't put '0' or '^' as last character, just in case a
- * CTRL-D is typed next */
- if (*ptr == NUL && (ptr[-1] == '0' || ptr[-1] == '^'))
- --ptr;
- if (ptr > tmp_ptr)
- {
- temp = *ptr;
- *ptr = NUL;
- AppendToRedobuff(tmp_ptr);
- *ptr = temp;
- }
- if (*ptr)
- {
- /* quote special chars with a CTRL-V */
- AppendCharToRedobuff(Ctrl('V'));
- AppendCharToRedobuff(*ptr);
- /* CTRL-V '0' must be inserted as CTRL-V 048 */
- if (*ptr++ == '0')
- AppendToRedobuff((char_u *)"48");
- }
- }
- }
- /*
- * When completing whole lines: fix indent for 'cindent'.
- * Otherwise, break line if it's too long.
- */
- lnum = curwin->w_cursor.lnum;
- if (continue_mode == CTRL_X_WHOLE_LINE)
- {
- #ifdef CINDENT
- /* re-indent the current line */
- if (curbuf->b_p_cin)
- fixthisline(get_c_indent);
- #endif
- }
- else
- {
- /* put the cursor on the last char, for 'tw' formatting */
- curwin->w_cursor.col--;
- insertchar(NUL, FALSE, -1, FALSE);
- curwin->w_cursor.col++;
- }
- if (lnum != curwin->w_cursor.lnum)
- {
- update_topline();
- update_screen(NOT_VALID);
- }
- else
- need_redraw = TRUE;
- vim_free(complete_pat);
- complete_pat = NULL;
- free_completions();
- started_completion = FALSE;
- ctrl_x_mode = 0;
- p_sm = save_sm;
- if (edit_submode != NULL)
- {
- edit_submode = NULL;
- showmode();
- }
- }
- }
- /* reset continue_* if we left expansion-mode, if we stay they'll be
- * (re)set properly in ins_complete */
- if (!ctrl_x_mode && c != Ctrl('P') && c != Ctrl('N') && c != Ctrl('X'))
- continue_status = continue_mode = 0;
- return need_redraw;
- }
- /*
- * Loops through the list of windows, loaded-buffers or non-loaded-buffers
- * (depending on flag) starting from buf and looking for a non-scanned
- * buffer (other than curbuf). curbuf is special, if it is called with
- * buf=curbuf then it has to be the first call for a given flag/expansion.
- *
- * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
- */
- static BUF*
- next_buf(buf, flag)
- BUF *buf;
- int flag;
- {
- static WIN *w;
- if (flag == 'w') /* just windows */
- {
- if (buf == curbuf) /* first call for this flag/expansion */
- w = curwin;
- while ((w = w->w_next ? w->w_next : firstwin) != curwin
- && w->w_buffer->b_scanned)
- ;
- buf = w->w_buffer;
- }
- else /* 'b' (just loaded buffers) or 'u' (just non-loaded buffers) */
- while ((buf = buf->b_next ? buf->b_next : firstbuf) != curbuf
- && ((buf->b_ml.ml_mfp == NULL) != (flag == 'u')
- || buf->b_scanned))
- ;
- return buf;
- }
- /*
- * Get the next expansion(s) for the text starting at the initial curbuf
- * position "ini" and in the direction dir.
- * Return the total of matches or -1 if still unknown -- Acevedo
- */
- static int
- get_expansion(ini, dir)
- FPOS *ini;
- int dir;
- {
- static FPOS first_match_pos;
- static FPOS last_match_pos;
- static char_u *e_cpt = (char_u *)""; /* curr. entry in 'complete' */
- static int done_info = 0; /* Found all matches in this dir. */
- static BUF *ins_buf = NULL;
- FPOS *pos;
- char_u **matches;
- int save_p_scs;
- int save_p_ws;
- int i;
- int temp;
- int type = ctrl_x_mode;
- char_u *ptr;
- char_u *tmp_ptr;
- char_u *dict = NULL;
- int dict_f = 0;
- struct Completion *old_match;
- if (!started_completion)
- {
- for (ins_buf = firstbuf; ins_buf; ins_buf = ins_buf->b_next)
- ins_buf->b_scanned = 0;
- done_info = 0;
- ins_buf = curbuf;
- e_cpt = continue_status & CONT_LOCAL ? (char_u *)"." : curbuf->b_p_cpt;
- last_match_pos = first_match_pos = *ini;
- }
- old_match = curr_match; /* remember the last current match */
- pos = (dir == FORWARD) ? &last_match_pos : &first_match_pos;
- /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
- for (;;)
- {
- temp = FAIL;
- /* in mode 0 pick a new entry from e_cpt if started_completion is off,
- * or if done_info says this entry is done -- Acevedo */
- if (!ctrl_x_mode && (!started_completion || done_info == 6))
- {
- done_info = 0;
- while (*e_cpt == ',' || *e_cpt == ' ')
- e_cpt++;
- if (*e_cpt == '.' && !curbuf->b_scanned)
- {
- ins_buf = curbuf;
- first_match_pos = *ini;
- /* So that ^N can match word immediately after cursor */
- if (ctrl_x_mode == 0)
- dec(&first_match_pos);
- last_match_pos = first_match_pos;
- type = 0;
- }
- else if (vim_strchr((char_u *)"buw", *e_cpt) != NULL
- && (ins_buf = next_buf(ins_buf, *e_cpt)) != curbuf)
- {
- if (*e_cpt != 'u')
- {
- started_completion = TRUE;
- first_match_pos.col = last_match_pos.col = 0;
- first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
- last_match_pos.lnum = 0;
- type = 0;
- }
- else
- {
- done_info = 6;
- if (ins_buf->b_fname == NULL)
- continue;
- type = CTRL_X_DICTIONARY;
- dict = ins_buf->b_fname;
- dict_f = DICT_EXACT;
- }
- sprintf((char*)IObuff, "Scanning: %s",
- ins_buf->b_sfname == NULL ? "No File"
- : (char *)ins_buf->b_sfname);
- msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
- }
- else if (*e_cpt == NUL)
- break;
- else
- {
- if (*e_cpt == 'k')
- {
- type = CTRL_X_DICTIONARY;
- if (*++e_cpt != ',' && *e_cpt != NUL)
- {
- dict = e_cpt;
- dict_f = DICT_FIRST;
- }
- }
- #ifdef FIND_IN_PATH
- else if (*e_cpt == 'i')
- type = CTRL_X_PATH_PATTERNS;
- #endif
- else if (*e_cpt == ']' || *e_cpt == 't')
- {
- type = CTRL_X_TAGS;
- sprintf((char*)IObuff, "Scanning tags.");
- msg_trunc_attr(IObuff, TRUE, hl_attr(HLF_R));
- }
- else
- type = -1;
- /* in any case e_cpt is advanced to the next entry */
- (void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
- done_info = 6;
- if (type == -1)
- continue;
- }
- }
- switch (type)
- {
- case -1:
- break;
- #ifdef FIND_IN_PATH
- case CTRL_X_PATH_PATTERNS:
- case CTRL_X_PATH_DEFINES:
- find_pattern_in_path(complete_pat, dir,
- (int)STRLEN(complete_pat), FALSE, FALSE,
- (type == CTRL_X_PATH_DEFINES
- && !(continue_status & CONT_SOL))
- ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
- (linenr_t)1, (linenr_t)MAXLNUM);
- break;
- #endif
- case CTRL_X_DICTIONARY:
- complete_dictionaries(dict ? dict : p_dict, complete_pat, dir,
- dict ? dict_f : 0);
- dict = NULL;
- break;
- case CTRL_X_TAGS:
- /* set reg_ic according to p_ic, p_scs and pat */
- set_reg_ic(complete_pat);
- if (find_tags(complete_pat, &temp, &matches,
- TAG_REGEXP | TAG_NAMES | (ctrl_x_mode ? TAG_VERBOSE : 0),
- MAXCOL) == OK && temp > 0)
- {
- int add_r = OK;
- int ldir = dir;
- for (i = 0; i < temp && add_r != RET_ERROR; i++)
- if ((add_r = add_completion(matches[i], -1, NULL, ldir, 0))
- == OK)
- /* if dir was BACKWARD then honor it just once */
- ldir = FORWARD;
- FreeWild(temp, matches);
- }
- break;
- case CTRL_X_FILES:
- expand_interactively = TRUE;
- if (expand_wildcards(1, &complete_pat, &temp, &matches,
- EW_FILE|EW_DIR) == OK)
- {
- int add_r = OK;
- int ldir = dir;
- /* May change home directory back to "~". */
- tilde_replace(complete_pat, temp, matches);
- for (i = 0; i < temp && add_r != RET_ERROR; i++)
- if ((add_r = add_completion(matches[i], -1, NULL, ldir, 0))
- == OK)
- /* if dir was BACKWARD then honor it just once */
- ldir = FORWARD;
- FreeWild(temp, matches);
- }
- expand_interactively = FALSE;
- break;
- default: /* normal ^P/^N and ^X^L */
- /*
- * If 'infercase' is set, don't use 'smartcase' here
- */
- save_p_scs = p_scs;
- if (ins_buf->b_p_inf)
- p_scs = FALSE;
- /* buffers other than curbuf are scanned from the beginning or the
- * end but never from the middle, thus setting nowrapscan in this
- * buffers is a good idea -- Acevedo */
- save_p_ws = p_ws;
- if (ins_buf != curbuf)
- p_ws = FALSE;
- for (;;)
- {
- int reuse = 0;
- /* ctrl_x_mode == CTRL_X_WHOLE_LINE || word-wise search that has
- * added a word that was at the beginning of the line */
- if ( ctrl_x_mode == CTRL_X_WHOLE_LINE
- || (continue_status & CONT_SOL))
- temp = search_for_exact_line(ins_buf, pos,
- dir, complete_pat);
- else
- temp = searchit(ins_buf, pos, dir, complete_pat, 1L,
- SEARCH_KEEP + SEARCH_NFMSG, RE_LAST);
- if (!started_completion)
- {
- /* set started_completion even on fail */
- started_completion = TRUE;
- first_match_pos = *pos;
- last_match_pos = *pos;
- }
- else if (first_match_pos.lnum == last_match_pos.lnum
- && first_match_pos.col == last_match_pos.col)
- temp = FAIL;
- if ( temp == FAIL && ins_buf == curbuf
- && (done_info |= p_ws ? 6 : dir + 3) < 6)
- /* With nowrapscan, we haven't finished looking in the
- * other direction yet -- webb */
- temp = -OK;
- if (temp != OK)
- break;
- /* when ADDING, the text before the cursor matches, skip it */
- if ( (continue_status & CONT_ADDING) && ins_buf == curbuf
- && ini->lnum == pos->lnum
- && ini->col == pos->col)
- continue;
- ptr = ml_get_buf(ins_buf, pos->lnum, FALSE) + pos->col;
- if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
- {
- if (continue_status & CONT_ADDING)
- {
- if (pos->lnum >= ins_buf->b_ml.ml_line_count)
- continue;
- ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
- if (!p_paste)
- ptr = skipwhite(ptr);
- }
- temp = STRLEN(ptr);
- }
- else
- {
- tmp_ptr = ptr;
- if (continue_status & CONT_ADDING)
- {
- tmp_ptr += completion_length;
- if (vim_iswordc(*tmp_ptr))
- continue;
- while (*tmp_ptr && !vim_iswordc(*tmp_ptr++))
- ;
- }
- while (vim_iswordc(*tmp_ptr))
- tmp_ptr++;
- temp = tmp_ptr - ptr;
- if ((continue_status & CONT_ADDING)
- && temp == completion_length)
- {
- if (pos->lnum < ins_buf->b_ml.ml_line_count)
- {
- /* Try next line, if any. the new word will be
- * "join" as if the normal command "J" was used.
- * IOSIZE is always greater than
- * completion_length, so the next STRNCPY always
- * works -- Acevedo */
- STRNCPY(IObuff, ptr, temp);
- ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
- tmp_ptr = ptr = skipwhite(ptr);
- while (*tmp_ptr && !vim_iswordc(*tmp_ptr++))
- ;
- while (vim_iswordc(*tmp_ptr))
- tmp_ptr++;
- if (tmp_ptr > ptr)
- {
- if (*ptr != ')' && IObuff[temp-1] != TAB)
- {
- if (IObuff[temp-1] != ' ')
- IObuff[temp++] = ' ';
- /* IObuf =~ "k.* ", thus temp >= 2 */
- if (p_js
- && (IObuff[temp-2] == '.'
- || (vim_strchr(p_cpo, CPO_JOINSP)
- == NULL
- && (IObuff[temp-2] == '?'
- || IObuff[temp-2] == '!'))))
- IObuff[temp++] = ' ';
- }
- /* copy as much as posible of the new word */
- if (tmp_ptr - ptr >= IOSIZE - temp)
- tmp_ptr = ptr + IOSIZE - temp - 1;
- STRNCPY(IObuff + temp, ptr, tmp_ptr - ptr);
- temp += tmp_ptr - ptr;
- reuse |= CONT_S_IPOS;
- }
- IObuff[temp] = NUL;
- ptr = IObuff;
- }
- if (temp == completion_length)
- continue;
- }
- }
- if (add_completion_and_infercase(ptr, temp, ins_buf == curbuf ?
- NULL : ins_buf->b_sfname, dir, reuse) != FAIL)
- {
- temp = OK;
- break;
- }
- }
- p_scs = save_p_scs;
- p_ws = save_p_ws;
- }
- /* check if curr_match has changed, (e.g. other type of expansion
- * added somenthing) */
- if (curr_match != old_match)
- temp = OK;
- /* break the loop for specialized modes (use 'complete' just for the
- * generic ctrl_x_mode == 0) and when temp != FAIL */
- if (ctrl_x_mode || temp)
- break;
- if (type == 0 || type == CTRL_X_PATH_PATTERNS)
- ins_buf->b_scanned = TRUE;
- started_completion = FALSE;
- }
- started_completion = TRUE;
- i = -1; /* total of matches, unknown */
- if (temp == FAIL || (ctrl_x_mode != 0 && ctrl_x_mode != CTRL_X_WHOLE_LINE))
- i = make_cyclic();
- else if (temp == -OK && (curr_match->original & ORIGINAL_TEXT))
- {
- edit_submode_extra = (continue_status & CONT_ADDING)
- && completion_length > 1
- ? (dir == FORWARD ? e_hitend_f : e_hitend_b)
- : (dir == FORWARD ? e_patnotf_f : e_patnotf_b);
- edit_submode_highl = HLF_E;
- }
- /* If several matches were added (FORWARD) or the search failed and has
- * just been made cyclic then we have to move curr_match to the next or
- * previous entry (if any, when search failed with 'nows') -- Acevedo */
- curr_match = dir == FORWARD ? old_match->next : old_match->prev;
- if (curr_match == NULL)
- curr_match = old_match;
- return i;
- }
- static int
- ins_complete(c)
- int c;
- {
- int complete_direction;
- char_u *ptr;
- char_u *tmp_ptr = NULL; /* init for gcc */
- static colnr_t complete_col = 0; /* init for gcc */
- int temp = 0;
- int i;
- int cc;
- static FPOS initial_pos;
- if (c == Ctrl('P') || c == Ctrl('L'))
- complete_direction = BACKWARD;
- else
- complete_direction = FORWARD;
- if (!started_completion)
- {
- /* First time we hit ^N or ^P (in a row, I mean) */
- /* Turn off 'sm' so we don't show matches with ^X^L */
- save_sm = p_sm;
- p_sm = FALSE;
- did_ai = FALSE;
- #ifdef SMARTINDENT
- did_si = FALSE;
- can_si = FALSE;
- can_si_back = FALSE;
- #endif
- stop_arrow();
- ptr = ml_get(curwin->w_cursor.lnum);
- complete_col = curwin->w_cursor.col;
- /* if this same ctrl_x_mode has been interrupted use the text from
- * initial_pos to the cursor as a pattern to add a new word instead of
- * expand the one before the cursor, in word-wise if "initial_pos" is
- * not in the same line as the cursor then fix it (the line has been
- * split because it was longer than 'tw'). if SOL is set then skip
- * the previous pattern, a word at the beginning of the line has been
- * inserted, we'll look for that -- Acevedo. */
- if ((continue_status & CONT_INTRPT) && continue_mode == ctrl_x_mode)
- { /* it is a continued search */
- continue_status &= ~CONT_INTRPT; /* remove INTRPT */
- if (ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_PATH_PATTERNS
- || ctrl_x_mode == CTRL_X_PATH_DEFINES)
- {
- if (initial_pos.lnum != curwin->w_cursor.lnum)
- {
- /* line (probably) wrapped, set initial_pos to the first
- * non_blank in the line, if it is not a wordchar include
- * it to get a better pattern, but then we don't want the
- * "\<" prefix, check it bellow */
- tmp_ptr = skipwhite(ptr);
- initial_pos.col = tmp_ptr - ptr;
- initial_pos.lnum = curwin->w_cursor.lnum;
- continue_status &= ~CONT_SOL; /* clear SOL if present */
- }
- else
- {
- /* S_IPOS was set when we inserted a word that was at the
- * beginning of the line, which means that we'll go to SOL
- * mode but first we need to redefine initial_pos */
- if (continue_status & CONT_S_IPOS)
- {
- continue_status |= CONT_SOL;
- initial_pos.col = skipwhite(ptr + completion_length +
- initial_pos.col) - ptr;
- }
- tmp_ptr = ptr + initial_pos.col;
- }
- temp = curwin->w_cursor.col - (tmp_ptr-ptr);
- /* IObuf is used to add a "word from the next line" would we
- * have enough space? just being paranoic */
- #define MIN_SPACE 75
- if (temp > (IOSIZE - MIN_SPACE))
- {
- continue_status &= ~CONT_SOL;
- temp = (IOSIZE - MIN_SPACE);
- tmp_ptr = curwin->w_cursor.col - temp + ptr;
- }
- continue_status |= CONT_ADDING | CONT_N_ADDS;
- if (temp < 1)
- continue_status &= CONT_LOCAL;
- }
- else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
- continue_status = CONT_ADDING | CONT_N_ADDS;
- else
- continue_status = 0;
- }
- else
- continue_status &= CONT_LOCAL;
- if (!(continue_status & CONT_ADDING)) /* normal expansion */
- {
- continue_mode = ctrl_x_mode;
- if (ctrl_x_mode) /* Remove LOCAL iff ctrl_x_mode != 0 */
- continue_status = 0;
- continue_status |= CONT_N_ADDS;
- initial_pos = curwin->w_cursor;
- temp = (int)complete_col;
- tmp_ptr = ptr;
- }
- /* Work out completion pattern and original text -- webb */
- if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT))
- {
- if ( (continue_status & CONT_SOL)
- || ctrl_x_mode == CTRL_X_PATH_DEFINES)
- {
- if (!(continue_status & CONT_ADDING))
- {
- while (--temp >= 0 && vim_isIDc(ptr[temp]))
- ;
- tmp_ptr += ++temp;
- temp = complete_col - temp;
- }
- complete_pat = vim_strnsave(tmp_ptr, temp);
- if (complete_pat == NULL)
- return FALSE;
- if (p_ic)
- for (i = 0; i < temp; i++)
- complete_pat[i] = TO_LOWER(complete_pat[i]);
- }
- else if (continue_status & CONT_ADDING)
- {
- char_u *prefix = (char_u *)"\<";
- /* we need 3 extra chars, 1 for the NUL and
- * 2 >= strlen(prefix) -- Acevedo */
- complete_pat = alloc(quote_meta(NULL, tmp_ptr, temp) + 3);
- if (complete_pat == NULL)
- return FALSE;
- if (!vim_iswordc(*tmp_ptr) ||
- (tmp_ptr > ptr && vim_iswordc(*(tmp_ptr-1))))
- prefix = (char_u *)"";
- STRCPY((char *)complete_pat, prefix);
- (void)quote_meta(complete_pat + STRLEN(prefix), tmp_ptr, temp);
- }
- else if (--temp < 0 || !vim_iswordc(ptr[temp]))
- {
- /* Match any word of at least two chars */
- complete_pat = vim_strsave((char_u *)"\<\k\k");
- if (complete_pat == NULL)
- return FALSE;
- tmp_ptr += complete_col;
- temp = 0;
- }
- else
- {
- while (--temp >= 0 && vim_iswordc(ptr[temp]))
- ;
- tmp_ptr += ++temp;
- if ((temp = (int)complete_col - temp) == 1)
- {
- /* Only match word with at least two chars -- webb
- * there's no need to call quote_meta,
- * alloc(7) is enough -- Acevedo
- */
- complete_pat = alloc(7);
- if (complete_pat == NULL)
- return FALSE;
- STRCPY((char *)complete_pat, "\<");
- (void)quote_meta(complete_pat + 2, tmp_ptr, 1);
- STRCAT((char *)complete_pat, "\k");
- }
- else
- {
- complete_pat = alloc(quote_meta(NULL, tmp_ptr, temp) + 3);
- if (complete_pat == NULL)
- return FALSE;
- STRCPY((char *)complete_pat, "\<");
- (void)quote_meta(complete_pat + 2, tmp_ptr, temp);
- }
- }
- }
- else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
- {
- tmp_ptr = skipwhite(ptr);
- temp = (int)complete_col - (tmp_ptr - ptr);
- complete_pat = vim_strnsave(tmp_ptr, temp);
- if (complete_pat == NULL)
- return FALSE;
- if (p_ic)
- for (i = 0; i < temp; i ++)
- complete_pat[i] = TO_LOWER(complete_pat[i]);
- }
- else if (ctrl_x_mode == CTRL_X_FILES)
- {
- while (--temp >= 0 && vim_isfilec(ptr[temp]))
- ;
- tmp_ptr += ++temp;
- temp = (int)complete_col - temp;
- complete_pat = addstar(tmp_ptr, temp);
- if (complete_pat == NULL)
- return FALSE;
- }
- complete_col = tmp_ptr - ptr;
- if (continue_status & CONT_ADDING)
- {
- if (continue_status & CONT_LOCAL)
- edit_submode = (char_u *)ctrl_x_msgs[2];
- else
- edit_submode = (char_u *)ctrl_x_msgs[ctrl_x_mode & 15];
- if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
- {
- /* Insert a new line, keep indentation but ignore 'comments' */
- char_u *old = curbuf->b_p_com;
- initial_pos.lnum = curwin->w_cursor.lnum;
- initial_pos.col = complete_col;
- curbuf->b_p_com = (char_u *)"";
- ins_eol('r');
- curbuf->b_p_com = old;
- tmp_ptr = (char_u *)"";
- temp = 0;
- complete_col = curwin->w_cursor.col;
- }
- }
- else
- {
- /* msg. without the " Adding" part. */
- if (continue_status & CONT_LOCAL)
- edit_submode = (char_u *)ctrl_x_msgs[2] + C_X_SKIP;
- else
- edit_submode = (char_u *)ctrl_x_msgs[ctrl_x_mode & 15] + C_X_SKIP;
- initial_pos.col = complete_col;
- }
- completion_length = temp;
- /* Always "add completion" for the "original text", it uses
- * "original_text" not a copy -- Acevedo */
- if ((original_text = vim_strnsave(tmp_ptr, temp)) == NULL
- || add_completion(original_text, -1, NULL, 0, ORIGINAL_TEXT) != OK)
- {
- vim_free(complete_pat);
- complete_pat = NULL;
- return FALSE;
- }
- /* showmode might reset the internal line pointers, so it must
- * be called before ptr = ml_get, or when this address is no
- * longer needed. -- Acevedo.
- */
- edit_submode_extra = (char_u *)"-- Searching...";
- edit_submode_highl = HLF_COUNT;
- showmode();
- edit_submode_extra = NULL;
- out_flush();
- }
- /*
- * In insert mode: Delete the typed part.
- * In replace mode: Put the old characters back, if any.
- */
- i = complete_col + (continue_status & CONT_ADDING ? completion_length : 0);
- while ((int)curwin->w_cursor.col > i)
- {
- curwin->w_cursor.col--;
- if (State == REPLACE)
- {
- /*
- * First character popped from the replace stack replaces a
- * character that's already there. Further popped characters need
- * to be inserted.
- */
- if ((cc = replace_pop()) > 0)
- {
- pchar(curwin->w_cursor, cc);
- replace_pop_ins();
- }
- }
- else
- (void)del_char(FALSE);
- }
- changed_cline_bef_curs();
- if (complete_direction == FORWARD && curr_match->next != NULL)
- curr_match = curr_match->next;
- else if (complete_direction == BACKWARD && curr_match->prev != NULL)
- curr_match = curr_match->prev;
- else
- temp = get_expansion(&initial_pos, complete_direction);
- /* we found no match if the list has only the original_text-entry */
- if (first_match == first_match->next)
- {
- edit_submode_extra = (continue_status & CONT_ADDING)
- && completion_length > 1 ? e_hitend : e_patnotf;
- edit_submode_highl = HLF_E;
- /* remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
- * because we couldn't expand anything at first place, but if we used
- * ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
- * (such as M in M'exico) if not tried already. -- Acevedo */
- if ( completion_length > 1
- || (continue_status & CONT_ADDING)
- || (ctrl_x_mode != 0
- && ctrl_x_mode != CTRL_X_PATH_PATTERNS
- && ctrl_x_mode != CTRL_X_PATH_DEFINES))
- continue_status &= ~CONT_N_ADDS;
- }
- /* eat the ESC to avoid leaving insert mode */
- if (got_int && !global_busy)
- {
- (void)vgetc();
- got_int = FALSE;
- }
- if (curr_match->original & CONT_S_IPOS)
- continue_status |= CONT_S_IPOS;
- else
- continue_status &= ~CONT_S_IPOS;
- if (edit_submode_extra == NULL)
- {
- if (curr_match->original & ORIGINAL_TEXT)
- {
- edit_submode_extra = (char_u *)"Back at original";
- edit_submode_highl = HLF_W;
- }
- else if (continue_status & CONT_S_IPOS)
- {
- edit_submode_extra = (char_u *)"Word from other line";
- edit_submode_highl = HLF_COUNT;
- }
- else if (curr_match->next == curr_match->prev)
- {
- edit_submode_extra = (char_u *)"The only match";
- edit_submode_highl = HLF_COUNT;
- }
- }
- /*